English Summary
Automated 3D Print Estimation from STL Files Using Power Query with copilot-san
今回の筆者(copilot君)について
以前のわたしの記事の感想をcopilot(gpt-5)君に聞いたところ、
ニッチだし実用性がないというまっとうな意見が得られました。
じゃあ、君ならどんな記事書くねん(半ギレ)と
問い詰めた意見を伺ったところ、
『3Dプリンタユーザーに向けて、表面積や体積、サイズ、コストを出せば
実用性があるからいいんじゃない(意訳)』と、
記事の文例とM言語のサンプルまでつけて返事してくれました。
思ったよりちゃんとしたものが返ってきたので、ちょっと修正して載せることにしました。
(関数に関して若干の修正は必要でした)
注意事項
- 体積計算で誤差が予想されます。ご注意ください
- そのため、体積が関係する重量やコスト等もあくまで目安になります
はじめに
前回の記事では、Power Queryを使ってSTLファイル(3Dモデル)の座標データを読み込む方法を紹介しました。 今回はその応用として、3Dプリントに必要な主要パラメータ(寸法・表面積・体積・重量・コスト・プリンタ適合可否)を自動算出し、Power BIで可視化する仕組みを作ります。
ゴール
- STLファイルを読み込むだけで以下を自動計算
- Width / Length / Height(造形サイズ)
- Surface Area(表面積)
- Volume(体積)
- 材料重量(g)
- 推定コスト(円)
- Power BIでダッシュボード化し、複数モデルを一括管理
STL解析関数"STLReader"(Mコード)
(STLBinary as binary) =>
let
DataStart = Binary.Range(STLBinary, 84),
TriangleFormat = BinaryFormat.Record([
NormalX = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
NormalY = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
NormalZ = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
V1X = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
V1Y = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
V1Z = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
V2X = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
V2Y = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
V2Z = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
V3X = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
V3Y = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
V3Z = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
AttributeByteCount = BinaryFormat.ByteOrder(BinaryFormat.SignedInteger16, ByteOrder.LittleEndian)
]),
TriangleList = BinaryFormat.List(TriangleFormat)(DataStart),
AllPoints = List.Combine(
List.Transform(TriangleList, each {
{[V1X],[V1Y],[V1Z]},
{[V2X],[V2Y],[V2Z]},
{[V3X],[V3Y],[V3Z]}
})
),
Xs = List.Transform(AllPoints, each _{0}),
Ys = List.Transform(AllPoints, each _{1}),
Zs = List.Transform(AllPoints, each _{2}),
MinX = List.Min(Xs), MaxX = List.Max(Xs),
MinY = List.Min(Ys), MaxY = List.Max(Ys),
MinZ = List.Min(Zs), MaxZ = List.Max(Zs),
Width = MaxX - MinX,
Length = MaxY - MinY,
Height = MaxZ - MinZ,
// 全頂点を抽出して重心を計算
G = {
List.Average(Xs),
List.Average(Ys),
List.Average(Zs)
},
// 三角形ごとの面積と体積(重心基準)を計算
AddCalc = List.Transform(TriangleList, each
let
A = {[V1X],[V1Y],[V1Z]},
B = {[V2X],[V2Y],[V2Z]},
C = {[V3X],[V3Y],[V3Z]},
// 相対座標
Arel = {A{0}-G{0}, A{1}-G{1}, A{2}-G{2}},
Brel = {B{0}-G{0}, B{1}-G{1}, B{2}-G{2}},
Crel = {C{0}-G{0}, C{1}-G{1}, C{2}-G{2}},
// 面積
AB = {B{0}-A{0}, B{1}-A{1}, B{2}-A{2}},
AC = {C{0}-A{0}, C{1}-A{1}, C{2}-A{2}},
Cross = {
AB{1}*AC{2} - AB{2}*AC{1},
AB{2}*AC{0} - AB{0}*AC{2},
AB{0}*AC{1} - AB{1}*AC{0}
},
Area = 0.5 * Number.Sqrt(Cross{0}*Cross{0} + Cross{1}*Cross{1} + Cross{2}*Cross{2}),
// 体積(重心基準)
Volume = (Arel{0}*(Brel{1}*Crel{2} - Brel{2}*Crel{1})
- Arel{1}*(Brel{0}*Crel{2} - Brel{2}*Crel{0})
+ Arel{2}*(Brel{0}*Crel{1} - Brel{1}*Crel{0})) / 6
in
[Area=Area, Volume=Volume]
),
TableCalc = Table.FromList(AddCalc, Splitter.SplitByNothing(), {"Record"}),
Expanded = Table.ExpandRecordColumn(TableCalc, "Record", {"Area","Volume"}),
TotalArea = List.Sum(Expanded[Area]),
TotalVolume = Number.Abs(List.Sum(Expanded[Volume])),
Weight = (TotalVolume / 1000) * 1.24,
Cost = Weight * 3,
Result = #table(
{"Width[mm]","Length[mm]","Height[mm]","SurfaceArea[mm^2]","Volume[mm^3]","Weight[g]","Cost[yen]"},
{{Width as number, Length as number, Height as number, TotalArea as number, TotalVolume as number,Weight as number,Cost as number}}
)
in
Result
呼び出しの例(Mコード)
Kドライブのフォルダ"stl"内にstlファイルが格納されている前提
let
source = Folder.Files("K:\stl"),
row_selected = Table.SelectRows(source, each [Extension] = ".stl"),
column_added = Table.AddColumn(row_selected, "stl", each STLReader([Content])),
column_selected = Table.SelectColumns(column_added,{"Name", "stl"}),
column_names = Table.ColumnNames(column_selected[stl]{0}),
column_expanded = Table.ExpandTableColumn(column_selected, "stl", column_names, column_names)
in
column_expanded
Power BIでの可視化例
- 推定コスト(重量 × 単価)
- 体積(Volume)
- 表面積(SurfaceArea)
- 材料重量(Volume × 材料密度)
- 寸法(Width / Length / Height)
- 放射状ゲージグラフの最大値は3DプリンタのMAX造形サイズとしてください
応用アイデア
- 材料別コスト比較(PLA / ABS / PETG)
- プリント時間予測(Volume ÷ 造形速度)
- 断面ヒートマップ表示
- 複数モデルの一括解析
まとめ
Power Queryは表形式データだけでなく、バイナリ解析を通じて3Dモデルの幾何情報も扱えることが分かりました。 この仕組みを使えば、3Dプリントの前工程(造形可否チェック※・材料見積もり・コスト計算)を大幅に効率化できます。
※サイズ確認
補足
- 体積計算:メッシュ(三角形)と原点を結ぶ四面体の総和
- 面積計算:メッシュ(三角形)の面積の総和
で求めているようです。
計算はできてそうなので、時間ができたときに検算します。