Mesh to Part/jp

From FreeCAD Documentation
Jump to: navigation, search

Partオブジェクトをメッシュに変換する

Part形状のような上位レベルのオブジェクトを メッシュのような単純なオブジェクトに変換するのは比較的簡単な処理です。Partオブジェクトの全ての面を三角形に変換して、結果の三角形(モザイク)をメッシュ構築に使用すればいいのです:

# ドキュメントには一つだけPartオブジェクトが入っているとしましょう
import Mesh
faces = []
shape = FreeCAD.ActiveDocument.ActiveObject.Shape
triangles = shape.tessellate(1) # この数値がモザイクの精度を表します
for tri in triangles[1]:
    face = []
    for i in range(3):
        vindex = tri[i]
        face.append(triangles[0][vindex])
    faces.append(face)
m = Mesh.Mesh(faces)
Mesh.show(m)

ときたまOpenCascadeが出力する特定の面の三角形が非常にいびつな場合があります。もし面に長方形パラメータ空間があり、穴やトリム曲線が無ければ独自にメッシュを作成することもできます:

import Mesh
def makeMeshFromFace(u,v,face):
	(a,b,c,d)=face.ParameterRange
	pts=[]
	for j in range(v):
		for i in range(u):
			s=1.0/(u-1)*(i*b+(u-1-i)*a)
			t=1.0/(v-1)*(j*d+(v-1-j)*c)
			pts.append(face.valueAt(s,t))

	mesh=Mesh.Mesh()
	for j in range(v-1):
		for i in range(u-1):
			mesh.addFacet(pts[u*j+i],pts[u*j+i+1],pts[u*(j+1)+i])
			mesh.addFacet(pts[u*(j+1)+i],pts[u*j+i+1],pts[u*(j+1)+i+1])

	return mesh

メッシュをPartオブジェクトに変換する

メッシュからPartオブジェクトへの変換はCADでの作業でも非常に重要な操作です。他の人たちからメッシュ形式の3Dデータを受け取ったり、他のアプリケーションからメッシュ形式の3Dデータを出力するというのはよくあることだからです。自由形状や大きな描画シーンを表現する場合にはメッシュは非常に実用的です。とても軽量だからです。しかしCADでの用途を考えた場合、一般的には三角形ではなく曲線で作成された面やソリッドなど、もっと多くの情報を保持できるより上位のオブジェクトの方が好まれます。

メッシュからこういった(FreeCADのパートモジュールで扱われる様な )上位オブジェクトへの変換は簡単な処理ではありません。メッシュは数千もの三角形で構成されている場合もありますし(例えば3Dスキャナーによって生成されている場合)、面と同じだけの数のソリッドを持った場合には処理がとんでもなく重くなることも考えられます。従って多くの場合、変換時に最適化を施す必要があるのです。

FreeCADでは現在、メッシュをPartオブジェクトに変換する二つのメソッドが用意されています。一つ目は単純なもので何の最適化も施さずに直接変換を行います:

import Mesh,Part
mesh = Mesh.createTorus()
shape = Part.Shape()
shape.makeShapeFromMesh(mesh.Topology,0.05) # 二つ目の引数は縫い合わせの許容誤差です
solid = Part.makeSolid(shape)
Part.show(solid)

二つ目のメソッドではメッシュの二つのファセットが作る角度が特定の値を下回る場合にその二つを同一面とみなします。これによってより単純な形状が作成できるのです:

# ドキュメントには一つだけMeshオブジェクトが入っているとしましょう
import Mesh,Part,MeshPart
faces = []
mesh = App.ActiveDocument.ActiveObject.Mesh
segments = mesh.getPlanes(0.00001) # ここではより厳しい許容誤差を使用します

for i in segments:
  if len(i) > 0:
     # 線分は内部に穴を持つことができます
     wires = MeshPart.wireFromSegment(mesh, i)
     # 外部境界が最大のバウンディングボックスを持つものであると仮定します
     if len(wires) > 0:
        ext=None
        max_length=0
        for i in wires:
           if i.BoundBox.DiagonalLength > max_length:
              max_length = i.BoundBox.DiagonalLength
              ext = i

        wires.remove(ext)
        # 内部のワイヤーが全てマークされ、向きが反転されなければなりません。さもなければPart.Faceが失敗します
        for i in wires:
           i.reverse()

        # 外部のワイヤーがリストの先頭になっていることを確認してください
        wires.insert(0, ext)
        faces.append(Part.Face(wires))

shell=Part.Compound(faces)
Part.show(shell)
#solid = Part.Solid(Part.Shell(faces))
#Part.show(solid)
ご利用可能な言語: Flag-en.jpg Flag-es.jpg Flag-fr.jpg Flag-it.jpg Flag-ru.jpg