はじめに
最近、こんな投稿を見つけ驚愕しました。
https://community.powerbi.com/t5/Community-Blog/PowerQuery-Decompress-zip-Files/ba-p/1326035
クエリ内でZipを強引に解凍しとる…!!
このテクニックを使えば、実質ZipのPowerpointやwordのコンテンツも集計できますね。
Web.Page関数内でjavascriptを呼べば正規表現も使えるので、文書検索ツールも簡単に構築できてしまいそうです。
…PowerQueryはじまったな(上記は2020の記事であり筆者が無知なだけです)。
本題
Zip解凍に感動したので、STL(3Dモデル)読み込み関数を作ってみました。
3Dデータのノード座標読み取り用カスタム関数です。
Zipの3Dモデルといえば3MFですが、今回扱うのはSTLです。3MFを期待した人にはすいません。
(STLFile) =>
let
Vertex = BinaryFormat.Record([
NX1 = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
NY1 = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
NZ1 = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
X1 = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
Y1 = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
Z1 = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
X2 = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
Y2 = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
Z2 = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
X3 = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
Y3 = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
Z3 = BinaryFormat.ByteOrder(BinaryFormat.Single, ByteOrder.LittleEndian),
Blank = BinaryFormat.ByteOrder(BinaryFormat.SignedInteger16, ByteOrder.LittleEndian)
]),
GetData = BinaryFormat.List(Vertex),
Entries = List.Transform(GetData(Binary.Range(STLFile,84)),
(e) =>
{
[I=1,X=e[X1],Y=e[Y1],Z=e[Z1]],
[I=2,X=e[X2],Y=e[Y2],Z=e[Z2]],
[I=3,X=e[X3],Y=e[Y3],Z=e[Z3]]
}
),
Expanded = Table.ExpandListColumn(Table.FromList(Entries, Splitter.SplitByNothing(), null, null, ExtraValues.Error),"Column1"),
Expanded2 = Table.ExpandRecordColumn(Expanded, "Column1", {"I", "X", "Y", "Z"}, {"I", "X", "Y", "Z"}),
Transformed = Table.TransformColumnTypes(Expanded2,{{"I", Int64.Type}, {"X", type number}, {"Y", type number}, {"Z", type number}})
in
Transformed
簡単な解説
STL(バイナリ型)の読み込み関数です。
STLファイルの構造として、先頭80バイトは気にする必要はありません。
次の4バイトは構成される三角形の数(4バイト整数型)ですが、
ここも今回は必要ありません。
なので、最初にBinary.Range関数で最初の84バイトを飛ばします。
ここから50バイト毎にデータが続くので、Vertexとして定義をします。
構造体みたいすね
12 :面の法線ベクトル(XYZ 3×4バイト[単精度])
36 :三角メッシュを構成する座標データ(XYZ 3×4バイト[単精度]×3)
2 :ブランクデータ
法線データはいらないので、List.Transformで座標データだけ指定しています。
また、集計結果に対してTable.TransformColumnTypesで型を指定しています。
後でわざわざ数値型にするのは面倒くさいですからね。
使い方
下の感じで読み込めます。
例では直接読み込んでますが、カスタム列の追加で、
STLReader(File.Contents([フルパス列名]))とかSTLReader[バイナリ列名]とかでOKです。
let
source =STLReader(File.Contents(Filepath))
in
source
試しにトリケラトプスの化石の3DファイルをPowerBIに取り込み表示してみます。