LoginSignup
0
0

PowerQueryで3Dファイルを読み込む

Last updated at Posted at 2023-01-22

はじめに

最近、こんな投稿を見つけ驚愕しました。
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を期待した人にはすいません。

STLReader (STLFileはBinary型)
(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です。

MainTable(Filepath=*.stl)
let
    source =STLReader(File.Contents(Filepath))
in
    source

試しにトリケラトプスの化石の3DファイルをPowerBIに取り込み表示してみます。

(Z座標:全範囲)
trk1.png
(Z座標:フィルタ後)
trk3.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0