このページではpythonからPart形状を作成・変更する複数の方法について説明しています。もしpythonを初めて使うのであればこのページを読む前にpythonのスクリプト処理とFreeCADでpythonのスクリプト処理がどの様に動作するのかについて読むことをお勧めします。
FreeCADのpythonインタプリタや外部のスクリプトから、直接、Partモジュールを操作する方法を説明します。まず スクリプティングを参照してください。FreeCADでのpythonスクリプトの方法についてより詳しい情報が必要な場合は FreeCADスクリプトの基本ページを参照してください。
これはPartモジュールの最も重要なクラスに関するUML (Unified Modeling Language)の概要図です:
ジオメトリーオブジェクトは、トポロジーオブジェクトを構成するための基本要素です:
次の種類のトポロジーのデータが利用できます:
単純なジオメトリーからトポロジーを構築して作成しましょう。 サンプルでは画像に示す四つの頂点と二つの円と二本のラインからできたパーツを使用します。
まずこのワイヤーの特徴的なジオメトリーパーツを作成しなければなりません。 また頂点のジオメトリーパーツが同じ位置に置かれるように注意する必要があります。 さもないと後でジオメトリーパーツをつなげてトポロジーにすることができなくなってしまいます!
さあ、まず点を作成します:
from FreeCAD import Base V1 = Base.Vector(0,10,0) V2 = Base.Vector(30,10,0) V3 = Base.Vector(30,-10,0) V4 = Base.Vector(0,-10,0)
円弧を作成するために補助点を作成し、三つの点を通る円弧を作成します:
VC1 = Base.Vector(-10,0,0) C1 = Part.Arc(V1,VC1,V4) # 2番目の円弧 VC2 = Base.Vector(40,0,0) C2 = Part.Arc(V2,VC2,V3)
ラインはシンプルに点から作成できます:
L1 = Part.Line(V1,V2) # and the second one L2 = Part.Line(V4,V3)
最後のステップとしてジオメトリーベースの要素をまとめ、トポロジカルな形状に固定します:
S1 = Part.Shape([C1,C2,L1,L2])
さてワイヤーを一定の方向に押し出して実際の3D形状を作成します:
W = Part.Wire(S1.Edges) P = W.extrude(Base.Vector(0,0,10))
Part.show(P)
Partモジュールの"make ...()"メソッドを使って、簡単に基本的なトポロジーオブジェクトを作成することができます。
b=Part.makeBox(100,100,100) Part.show(b)
使用可能な他のmake...()メソッドです:
Partモジュールで利用可能な全てのメソッドのリストについてはPart APIのページを見てください。
まずPartモジュールをインポートする必要があります。インポートを行うとその中身をpythonで使用できるようになります。 またFreeCADモジュール内にあるBaseモジュールもインポートします:
import Part from FreeCAD import Base
ベクトルは形状を作成する際に最も重要な情報の一つです。通常はデカルト座標のx、y、z、3つの数字を含みます(ただし必ずしも常にそうであるわけではありません)。次の様にするとベクトルが作成されます:
myVector = Base.Vector(3,2,0)
座標 x=3、y=2、z=0にベクトルを作成しました。Partではいろいろな場所でベクトルが使われています。 Partの形状ではVertex(頂点)と呼ばれる別の点表現も使用されています。これは実際の所はベクトル用のコンテナ 以外の何物でもありません。頂点のベクトルには次のようにしてアクセスします:
myVertex = myShape.Vertexes[0] print myVertex.Point > Vector (3, 2, 0)
エッジとは2つの頂点からなる線に他なりません:
edge = Part.makeLine((0,0,0), (10,0,0)) edge.Vertexes > [<Vertex object at 01877430>, <Vertex object at 014888E0>]
注意: 二つのベクトルを渡してエッジを作成することもできます:
vec1 = Base.Vector(0,0,0) vec2 = Base.Vector(10,0,0) line = Part.Line(vec1,vec2) edge = line.toShape()
エッジの長さと中心は次のようにするとわかります:
edge.Length > 10.0 edge.CenterOfMass > Vector (5, 0, 0)
さて今までエッジオブジェクトを作成して来ましたが画面上には何も表示されません。 これは今まではたんにpythonのオブジェクトを操作してきただけだからです。 FreeCADの3Dシーンは表示するように指示された場合にだけ表示されます。 これを行うには次の簡単なメソッドを使用します:
Part.show(edge)
FreeCADドキュメント内にオブジェクトが作成され、そのオブジェクトによって私たちの"エッジ"形状が設定されます。 作成したものを画面に表示する場合には常にこれを使用します。
ワイヤとは複数のエッジでエッジのリスト、またはワイヤのリストから作成することができます:
edge1 = Part.makeLine((0,0,0), (10,0,0)) edge2 = Part.makeLine((10,0,0), (10,10,0)) wire1 = Part.Wire([edge1,edge2]) edge3 = Part.makeLine((10,10,0), (0,10,0)) edge4 = Part.makeLine((0,10,0), (0,0,0)) wire2 = Part.Wire([edge3,edge4]) wire3 = Part.Wire([wire1,wire2]) wire3.Edges > [<Edge object at 016695F8>, <Edge object at 0197AED8>, <Edge object at 01828B20>, <Edge object at 0190A788>] Part.show(wire3)
Part.show(wire3)はワイヤーを構成する4つの線を表示します。他にも有用な情報を簡単に取得することができます:
wire3.Length > 40.0 wire3.CenterOfMass > Vector (5, 5, 0) wire3.isClosed() > True wire2.isClosed() > False
正しいフェイスは閉じたワイヤのみから作成することができます。 この例では、wire3は閉じたワイヤですが、wire2(上記参照)は閉じていません。
face = Part.Face(wire3) face.Area > 99.999999999999972 face.CenterOfMass > Vector (5, 5, 0) face.Length > 40.0 face.isValid() > True sface = Part.Face(wire2) face.isValid() > False
フェイスは面積を持ちますが、ワイヤやエッジは面積を持ちません。
円はこのようにシンプルに作成することができます:
circle = Part.makeCircle(10) circle.Curve > Circle (Radius : 10, Position : (0, 0, 0), Direction : (0, 0, 1))
位置と方向をもった円を作るにはこのように書きます。
ccircle = Part.makeCircle(10, Base.Vector(10,0,0), Base.Vector(1,0,0)) ccircle.Curve > Circle (Radius : 10, Position : (10, 0, 0), Direction : (1, 0, 0))
ccircleは、xの原点からの距離が10で、x軸を向くように作成されています。 注:makeCircleは、位置と法線として、タプルではなくBase.Vector()のみを受けとります。 また開始角と終了角を与えることによって、円の一部を作成することができます:
from math import pi arc1 = Part.makeCircle(10, Base.Vector(0,0,0), Base.Vector(0,0,1), 0, 180) arc2 = Part.makeCircle(10, Base.Vector(0,0,0), Base.Vector(0,0,1), 180, 360)
arc1とarc2の両方を合わせると円になります。 角度は度単位で指定する必要があります。ラジアンが必要な場合は次の様に変換することができます。 degrees = radians * 180/PI またはpythonの数学モジュールを使用します(import mathが必要です):
degrees = math.degrees(radians)
残念ながらmakeArc関数はありませんが、三点を通る弧を作成するPart.Arc関数があります。 この関数は、基本的には、中間点を通って開始点と終了点を結ぶ弧を仮定しています。 Part.Arcは弧オブジェクトを作成します。弧オブジェクトからエッジオブジェクトを作成するには.toShape()を呼びます。 これはPart.makeLineの代わりにPart.Lineを使用した時と同じです。
arc = Part.Arc(Base.Vector(0,0,0),Base.Vector(0,5,0),Base.Vector(5,5,0)) arc > <Arc object> arc_edge = arc.toShape()
注意:Arcは点としてタプルではなくBase.Vector()のみを受け取ります。 arc_edgeはPart.show(arc_edge)によって表示することができます。 円弧として円の一部を使用することも可能です:
from math import pi circle = Part.Circle(Base.Vector(0,0,0),Base.Vector(0,0,1),10) arc = Part.Arc(c,0,pi)
円弧はラインと同じようにエッジです。従ってこの方法はワイヤーに対しても使用することができます。
ポリゴンは複数の真っ直ぐなエッジからできたワイヤーに他なりません。 makePolygon関数は点のリストを受け取り、その点を通る線を作成します:
lshape_wire = Part.makePolygon([Base.Vector(0,5,0),Base.Vector(0,0,0),Base.Vector(5,0,0)])
平面は平坦な表面です。作成するためのメソッドはmakePlane(length,width,[start_pnt,dir_normal])です。 初期値はstart_pnt=Vector(0,0,0)とdir_normal=Vector(0,0,1)です。 dir_normal=Vector(0,0,1)はz軸に面した平面を作成します。 dir_normal=Vector(1,0,0)はx軸に面した平面を作成します。
plane = Part.makePlane(2,2) plane ><Face object at 028AF990> plane = Part.makePlane(2,2, Base.Vector(3,0,0), Base.Vector(0,1,0)) plane.BoundBox > BoundBox (3, 0, 0, 5, 0, 2)
BoundBoxは、その対角線が(3,0,0)から始まり(5,0,2)で終わる平面を囲む直方体です。 このBoundBoxのy軸の厚さはゼロです。 注:makePlaneは、start_pntとdir_normalとしてタプルではなくBase.Vector()のみを受け取ります。
楕円の作成にはいくつかの方法があります:
Part.Ellipse()
中心が(0,0,0)で、大半径2と小半径1の楕円を作成します。
Part.Ellipse(Ellipse)
楕円のコピーを作成します。
Part.Ellipse(S1,S2,Center)
点Centerを中心とする楕円を作成します。 楕円平面は、Center、S1とS2で定義されています。 主軸はCenterとS1で定義されています。 長径はCenterとS1の間の距離です 短径はS2と主軸との距離です。
Part.Ellipse(Center,MajorRadius,MinorRadius)
長径MajorRadius、短径MinorRadiusの楕円を作成し、 Centerと法線(0,0,1)で定義された平面上に配置します。
eli = Part.Ellipse(Base.Vector(10,0,0),Base.Vector(0,5,0),Base.Vector(0,0,0)) Part.show(eli.toShape())
上記のコードでは、S1、S2、および中心を渡しています。 Arcと同様に、Ellipseも楕円オブジェクトを作りますが、エッジは作成しません。 このため、楕円を表示するためにはtoShape()を使い、エッジに変換する必要があります。
注意:Arcはタプルではなく、Base.Vector()のみを受け取ります。
eli = Part.Ellipse(Base.Vector(0,0,0),10,5) Part.show(eli.toShape())
上記のEllipseのコンストラクタでは、中心座標、MajorRadius、MinorRadiusを渡しています。
makeTorus(radius1,radius2,[pnt,dir,angle1,angle2,angle])を使用します。 初期値は、pnt=Vector(0,0,0)、dir=Vector(0,0,1)、angle1=0、angle1=360、angle=360です。 トーラスは小さな円が、大きな円に沿ってスイープしているものと考えます。 radius1は大きい円の半径、radius2は小さい円の半径です。 pntはトーラスの中心、dirは法線方向です。 angle1とangle2は小さな円のラジアンの角度です。 最後のパラメータangleはトーラスの一部を作成するためのものです:
torus = Part.makeTorus(10, 2)
上記のコードは、直径20(半径10)と厚さ4(小さい円の半径2)のトーラスを作成します。
tor=Part.makeTorus(10,5,Base.Vector(0,0,0),Base.Vector(0,0,1),0,180)
上記のコードはトーラスのスライスを作成します。
tor=Part.makeTorus(10,5,Base.Vector(0,0,0),Base.Vector(0,0,1),0,360,180)
上記のコードは半分のトーラスを作成します。このコードでは最後のパラメータが変更されただけで、あとの角度は初期値のままです。 角度へ180与えた結果、0から180、つまり半分のトーラスを作成します。
makeBox(length,width,height,[pnt,dir])を使用します。 初期値はpnt=Vector(0,0,0)、dir=Vector(0,0,1)です。
box = Part.makeBox(10,10,10) len(box.Vertexes) > 8
makeSphere(radius,[pnt, dir, angle1,angle2,angle3])を使用します。 初期値はpnt=Vector(0,0,0)、dir=Vector(0,0,1)、angle1=-90、angle2=90、angle3=360です。 angle1とangle2は、球の垂直方向の最小値と最大値です。 angle3は球の直径です。
sphere = Part.makeSphere(10) hemisphere = Part.makeSphere(10,Base.Vector(0,0,0),Base.Vector(0,0,1),-90,90,180)
makeCylinder(radius,height,[pnt,dir,angle])を使用します。 初期値は、pnt=Vector(0,0,0)、dir=Vector(0,0,1)、angle=360=ベクトルです。
cylinder = Part.makeCylinder(5,20) partCylinder = Part.makeCylinder(5,20,Base.Vector(20,0,0),Base.Vector(0,0,1),180)
makeCone(radius1,radius2,height,[pnt,dir,angle])を使用します。 初期値は、pnt=Vector(0,0,0)、dir=Vector(0,0,1)、angle=360=ベクトルです。
cone = Part.makeCone(10,0,20) semicone = Part.makeCone(10,0,20,Base.Vector(20,0,0),Base.Vector(0,0,1),180)
形状を変更するには複数の方法があります。移動や回転などの簡単な変換操作もありますが 他の形状との結合や減算などの複雑などのもっと複雑なものもあります。
移動は形状をある場所から別の場所に動かす操作です。 任意の形状(エッジ、フェイス、立方体など)を同じ方法で移動させることができます:
myShape = Part.makeBox(2,2,2) myShape.translate(Base.Vector(2,0,0))
ここでは"myShape"を2単位分、X方向に移動させています。
形状を回転させるには回転中心、軸、回転角を指定する必要があります:
myShape.rotate(Vector(0,0,0),Vector(0,0,1),180)
上記のコードでは形状をZ軸の周りに180度回転させています。
行列は3D空間での変換操作を保持する際に非常に便利です。 一つの行列に対してオブジェクトに適用する移動、回転、拡大縮小の値を設定することができるのです。 例えば次のようにします:
myMat = Base.Matrix() myMat.move(Base.Vector(2,0,0)) myMat.rotateZ(math.pi/2)
注意:FreeCADの行列はラジアン単位で動作します。またほとんどのベクトルを引数に持つ行列操作は 3つの数値を引数に取ることもできます。従って以下の2行は同じ処理を行います:
myMat.move(2,0,0) myMat.move(Base.Vector(2,0,0))
行列が設定されるとそれを形状に対して適用できるようになります。FreeCADではそれを行うための 2つのメソッドが用意されています。transformShape()とtransformGeometry()です。違いは一つ目のメソッド では行列の変形が行われないということです(下記の"シェイプの拡大縮小"を参照)。 変換は以下のようにして適用します:
myShape.trasformShape(myMat)
または
myShape.transformGeometry(myMat)
形状の拡大縮小は危険な操作です。なぜなら移動や回転と異なり拡大縮小は非一様(x、y、zで異なる値を使って) に形状の構造を変更することができるからです。例えば垂直方向よりも水平方向に大きな値を使って円を 変換すれば楕円になり、楕円は円とは数学的に全く異なった振る舞いをします。拡大縮小では transformShape()を使うことはできず、transformGeometry()を使わなければなりません:
myMat = Base.Matrix() myMat.scale(2,1,1) myShape=myShape.transformGeometry(myMat)
ある形状から別の形状を取り除くことをOCC/FreeCADでは"カット"と呼び、次のようにして行います:
cylinder = Part.makeCylinder(3,10,Base.Vector(0,0,0),Base.Vector(1,0,0)) sphere = Part.makeSphere(5,Base.Vector(5,0,0)) diff = cylinder.cut(sphere)
同じように2つの形状の交差は"コモン"と呼び、次のようにして行います:
cylinder1 = Part.makeCylinder(3,10,Base.Vector(0,0,0),Base.Vector(1,0,0)) cylinder2 = Part.makeCylinder(3,10,Base.Vector(5,0,-5),Base.Vector(0,0,1)) common = cylinder1.common(cylinder2)
結合は"フューズ"と呼ばれ、同じようにして行うことができます:
cylinder1 = Part.makeCylinder(3,10,Base.Vector(0,0,0),Base.Vector(1,0,0)) cylinder2 = Part.makeCylinder(3,10,Base.Vector(5,0,-5),Base.Vector(0,0,1)) fuse = cylinder1.fuse(cylinder2)
セクションはソリッド形状と平面形状の間での交差です。 エッジで構成された交差曲線を返します:
cylinder1 = Part.makeCylinder(3,10,Base.Vector(0,0,0),Base.Vector(1,0,0)) cylinder2 = Part.makeCylinder(3,10,Base.Vector(5,0,-5),Base.Vector(0,0,1)) section = cylinder1.section(cylinder2) section.Wires > [] section.Edges > [<Edge object at 0D87CFE8>, <Edge object at 019564F8>, <Edge object at 0D998458>, <Edge object at 0D86DE18>, <Edge object at 0D9B8E80>, <Edge object at 012A3640>, <Edge object at 0D8F4BB0>]
押し出しは平面形状を一定方向に"押し出す"ことでソリッドボディーを作成する操作です。 "押し出し"によって円が管になるのを想像してください:
circle = Part.makeCircle(10) tube = circle.extrude(Base.Vector(0,0,2))
もし円が中空であれば中空の管が得られ、円が実際には円盤、 つまり面で埋まっていればソリッドな円柱が得られます。
wire = Part.Wire(circle) disc = Part.makeFace(wire) cylinder = disc.extrude(Base.Vector(0,0,2))
トポロジーのデータ構造は簡単に調べることができます:
import Part b = Part.makeBox(100,100,100) b.Wires w = b.Wires[0] w w.Wires w.Vertexes Part.show(w) w.Edges e = w.Edges[0] e.Vertexes v = e.Vertexes[0] v.Point
上記の内容をPythonインタープリタに入力することで、Partオブジェクトの構造をよく理解することができます。ここでmakeBox()コマンドはソリッド形状を作成します。このソリッドはすべてのPartソリッドと同様に複数のフェイスを含んでいます。フェイスは常にその境界となるエッジのリストであるワイヤーを持ちます。各フェイスは少なくとも1つの閉じたワイヤーを持ちます(フェイスが穴の場合は複数のワイヤーを持ちます)。ワイヤーでは各エッジを別々に調べることができ、またそのエッジでは各頂点を調べることができます。直線のエッジは当然2つの頂点のみを持っています。
エッジの場合、エッジは任意の曲線であるので、おそらく離散化したいと思うでしょう。FreeCADでは、エッジはその長さによってパラメータ化されています。つまりその長さでエッジ/曲線を操作できるということです:
import Part import Part box = Part.makeBox(100,100,100) anEdge = box.Edges[0] print anEdge.Length
この長さを位置として使用して多くのエッジのプロパティにアクセスすることができます。つまりエッジ長が100mmであれば、エッジの開始位置は0で終了位置は100であるということです。
anEdge.tangentAt(0.0) # 初期の接線方向です anEdge.valueAt(0.0) # エッジの開始点です anEdge.valueAt(100.0) # エッジの終点です anEdge.derivative1At(50.0) # 中点での曲線の一次導関数です anEdge.derivative2At(50.0) # 中点での曲線の二次導関数です anEdge.derivative3At(50.0) # 中点での曲線の三次導関数です anEdge.centerOfCurvatureAt(50) # この位置の曲率中心です anEdge.curvatureAt(50.0)# 曲率です anEdge.normalAt(50) # この位置の法線です(定義されている場合)
ここではユーザがビューア上で行う選択操作を使用する方法についてみていきます。 まず最初にボックスを作成しそれをビューアで表示します
import Part Part.show(Part.makeBox(100,100,100)) Gui.SendMsgToActiveView("ViewFit")
フェイスかエッジを選択します。このスクリプトを使うと 全ての選択したオブジェクトとその子要素を反復することができます。
for o in Gui.Selection.getSelectionEx(): print o.ObjectName for s in o.SubElementNames: print "name: ",s for s in o.SubObjects: print "object: ",s
エッジを選択し、このスクリプトでその長さを計算します:
length = 0.0 for o in Gui.Selection.getSelectionEx(): for s in o.SubObjects: length += s.Length print "Length of the selected edges:" ,length
OpenCasCadeをはじめようにはボトルの作成方法についての典型的な例があります。 これはFreeCADの教材としても最適です。実際に以下のページの例とOCCのページの内容とを同時に追うことによって、OCCの構造がどのようにFreeCADの中に実装されているか理解できるでしょう。 以下のスクリプトはFreeCADのインストールにも含まれています(Mod/Partフォルダ内)。pythonインタプリタから次のようにタイプすることで呼び出すことができます:
import Part import MakeBottle bottle = MakeBottle.makeBottle() Part.show(bottle)
MakeBottleスクリプト一式です:
import Part, FreeCAD, math from FreeCAD import Base def makeBottle(myWidth=50.0, myHeight=70.0, myThickness=30.0): aPnt1=Base.Vector(-myWidth/2.,0,0) aPnt2=Base.Vector(-myWidth/2.,-myThickness/4.,0) aPnt3=Base.Vector(0,-myThickness/2.,0) aPnt4=Base.Vector(myWidth/2.,-myThickness/4.,0) aPnt5=Base.Vector(myWidth/2.,0,0) aArcOfCircle = Part.Arc(aPnt2,aPnt3,aPnt4) aSegment1=Part.Line(aPnt1,aPnt2) aSegment2=Part.Line(aPnt4,aPnt5) aEdge1=aSegment1.toShape() aEdge2=aArcOfCircle.toShape() aEdge3=aSegment2.toShape() aWire=Part.Wire([aEdge1,aEdge2,aEdge3]) aTrsf=Base.Matrix() aTrsf.rotateZ(math.pi) # z軸周りを回転 aMirroredWire=aWire.transformGeometry(aTrsf) myWireProfile=Part.Wire([aWire,aMirroredWire]) myFaceProfile=Part.Face(myWireProfile) aPrismVec=Base.Vector(0,0,myHeight) myBody=myFaceProfile.extrude(aPrismVec) myBody=myBody.makeFillet(myThickness/12.0,myBody.Edges) neckLocation=Base.Vector(0,0,myHeight) neckNormal=Base.Vector(0,0,1) myNeckRadius = myThickness / 4. myNeckHeight = myHeight / 10 myNeck = Part.makeCylinder(myNeckRadius,myNeckHeight,neckLocation,neckNormal) myBody = myBody.fuse(myNeck) faceToRemove = 0 zMax = -1.0 for xp in myBody.Faces: try: surf = xp.Surface if type(surf) == Part.Plane: z = surf.Position.z if z > zMax: zMax = z faceToRemove = xp except: continue myBody = myBody.makeThickness([faceToRemove],-myThickness/50 , 1.e-3) return myBody
import Part, FreeCAD, math from FreeCAD import Base
PartモジュールはもちろんですがFreeCAD.Baseモジュールも必要です。このモジュールにはベクトルや行列といったFreeCADの基本構造が含まれています。
def makeBottle(myWidth=50.0, myHeight=70.0, myThickness=30.0): aPnt1=Base.Vector(-myWidth/2.,0,0) aPnt2=Base.Vector(-myWidth/2.,-myThickness/4.,0) aPnt3=Base.Vector(0,-myThickness/2.,0) aPnt4=Base.Vector(myWidth/2.,-myThickness/4.,0) aPnt5=Base.Vector(myWidth/2.,0,0)
ここではmakeBottle関数を定義します。この関数は、上記の例のように、引数無しでも呼ぶことができます。その場合には、幅、高さ、厚さの初期値が使用されます。次に基本的なプロファイルの構築に使用する点を定義します。
aArcOfCircle = Part.Arc(aPnt2,aPnt3,aPnt4) aSegment1=Part.Line(aPnt1,aPnt2) aSegment2=Part.Line(aPnt4,aPnt5)
ここでは実際のジオメトリを定義しています。円弧を一つ、点を三つ、そして二点で構成される線分を二つ作ります。
aEdge1=aSegment1.toShape() aEdge2=aArcOfCircle.toShape() aEdge3=aSegment2.toShape() aWire=Part.Wire([aEdge1,aEdge2,aEdge3])
ジオメトリとシェイプの違いを覚えているでしょうか?ここでは、作成したジオメトリを使ってシェイプを作り上げています。3つのエッジ(直線や曲線です)を作り、それらを使いワイヤーを一つ作成します。
aTrsf=Base.Matrix() aTrsf.rotateZ(math.pi) # rotate around the z-axis aMirroredWire=aWire.transformGeometry(aTrsf) myWireProfile=Part.Wire([aWire,aMirroredWire])
ここまでで、まだプロファイルは半分しか出来上がっていません。同じ方法でプロファイル全体を作成するよりも、これまで作成したものをミラーして、2つの半分を一つにくっつけるほうが簡単です。それにはまず行列を作成します。行列は3次元空間のオブジェクトを変換するとても一般的な方法です。 行列を使えば、3Dオブジェクトの厄介な基本的な変換(移動、回転、スケール)が一つで済むのです。ここでは行列を作成し、それを反転します。作成したワイヤーにこの変換行列を適用してコピーを作ります。ここまで、2本のワイヤーができました。ワイヤーは、実際にはエッジのリストですので、これらのワイヤーから3つ目のワイヤーを作ることができます。
myFaceProfile=Part.Face(myWireProfile) aPrismVec=Base.Vector(0,0,myHeight) myBody=myFaceProfile.extrude(aPrismVec) myBody=myBody.makeFillet(myThickness/12.0,myBody.Edges)
すでに閉じたワイヤーがあるので、これをフェイスに変換することができます。フェイスを作ってしまえば、それを押し出すことができるようになります。このようにしてソリッドができました。では、次にこのオブジェクトに素敵なフィレットを少し使ってみましょう。デザインには気を使うでしょ?
neckLocation=Base.Vector(0,0,myHeight) neckNormal=Base.Vector(0,0,1) myNeckRadius = myThickness / 4. myNeckHeight = myHeight / 10 myNeck = Part.makeCylinder(myNeckRadius,myNeckHeight,neckLocation,neckNormal)
これでボトルの本体はできました。あとはボトルの首を作成する必要があります。そこで、円柱で新しいソリッドを作成します。
myBody = myBody.fuse(myNeck)
他のアプリではユニオンとも呼ばれることもあるフューズ操作はとても強力な機能です。この操作は結合処理において結合すべきものと削除すべきものを管理します。
return myBody
次にこの関数の結果としてPartソリッドを返します。このPartソリッドは、他のPartシェイプと同様に以下の方法でFreeCADドキュメント内のオブジェクトの属性になります。
myObject = FreeCAD.ActiveDocument.addObject("Part::Feature","myObject") myObject.Shape = bottle
あるいはもっとシンプルな方法もあります:
Part.show(bottle)
Partモジュールの作業内容を保存する方法はいくつかあります。もちろんFreeCADドキュメントを保存することもできますが、PartオブジェクトをBREPやIGS、STEPやSTLなどの共通CADフォーマットに直接保存することもできます。
シェイプをファイルへ保存するのは簡単です。全てのシェイプオブジェクトで、exportBre()、pexportIges()、exportStl()、およびexportStep()メソッドが利用できます。ではやってみましょう:
import Part s = Part.makeBox(0,0,0,10,10,10) s.exportStep("test.stp")
ここではSTEPファイルへボックスを保存します。BREPやIGESやSTEPファイルを読み込むには、単純に反対の操作を行います:
import Part s = Part.Shape() s.read("test.stp")
BREPやIGES、STEPファイルのインポートは、メニューの「File -> Open」か「File -> Import」からも直接行えます。エクスポートは「File -> Export」で行えます。