STL の読み込み

2022年9月25日

はじめに

STL ファイルの読み込みについて。

STL とは

STL は CAD で用いられるファイルフォーマットである。曲面を三角形の集まりで表す。フォーマットとして ASCII 形式とバイナリ形式がある。

ASCII 形式の読み込み

たとえば、単純に三角形 1 つからなる形状が 2 つある場合は、次のようになる。

triangle.stl

solid triangle
  facet normal 0 0 1
    outer loop
      vertex 0 0 0
      vertex 1 0 0
      vertex 1 1 0
    endloop
  endfacet
endsolid triangle

solid triangle2
  facet normal 0 0 1
    outer loop
      vertex 0 0 0
      vertex 1 1 0
      vertex 0 1 0
    endloop
  endfacet
endsolid triangle2

STL は solid という単位で形状を扱う。

solid <name>
...
endsolid <name>

任意の名前を指定できる (指定しない場合もある)。

solid は facet と呼ばれる三角形から構成される。

  facet normal <nx> <ny> <nz>
    outer loop
      vertex <x1> <y1> <z1>
      vertex <x2> <y2> <z2>
      vertex <x3> <y3> <z3>
    endloop
  endfacet
  ...

facet ではまず面の表側の法線ベクトル (nx ny nz) を指定する。そのあと、三角形を構成する点 (vertex) の座標を指定する。手で打ち込むと間違えがちだが、"outer loop"、"endloop"、"endfacet" などの空白の有無は区別される ("end loop" としてはダメ)。

この形式の読み取り手順は、次のようになる。

mode: 読み取りモード (none, solid, facet, outer_loop)
vi: vertex のインデックス

while ファイルの末尾まで do
  line に 1 行読み取る
  line を空白で分割して、リストとして itmes に入れる
  
  if mode = none
    if items[0] = "solid" then
      mode = solid
      名前があれば読み取る
    end if
  else if mode = solid then
    if items[0] = "facet" and items[1] = "normal" then
      mode = facet
      ベクトルを読み取る
      vi = 0
    else if items[0] = "endsolid" then
      solid の読み取り完了処理
      mode = mode_none
    else
      構文エラー
    end if
  else if mode = facet then
    if items[0] = "outer" and items[1] = "loop"
      mode = outer_loop
    else if items[0] = "endfacet" then
      facet の読み取り完了処理
      mode = solid
    else
      構文エラー
    end if
  else if mode = outer_loop then
    if items[0] = "vertex" then
      if vi >= 3 then
        構文エラー
      else
        ベクトルを読み取る
        vi = vi + 1
      end if
    else if items[0] = "endloop" then
      mode = facet
    else
      構文エラー
    end if
  else
    内部エラー
  end if
end do

バイナリ形式の読み込み

バイナリ形式は単純である。最初にヘッダーと三角形の数がある。

header (80バイト)
num_triangle (4バイト)

あとは三角形の数の分だけ法線ベクトル、点3つ、あと謎の属性が並んでいる。

normal (4バイト x 3)
vertex1 (4バイト x 3)
vertex2 (4バイト x 3)
vertex3 (4バイト x 3)
attribute (2バイト)

attribute は読み飛ばせばよいようである。

ASCIIとバイナリの判別

ASCII かバイナリかを判別するには、1行読んでみて空行か "solid" が出てくるなら ASCII、そうでなければバイナリと判断すればよい (たぶん)。

参考