Topological data scripting/jp

このページではpythonからPart形状を作成・変更する複数の方法について説明しています. もしpythonを初めて使うのであればこのページを読む前にpythonのスクリプト処理とFreeCADでpythonのスクリプト処理がどの様に動作するのかについて読むことをお勧めします.

はじめに
FreeCADのpythonインタプリタや外部のスクリプトから、直接、Partモジュールを操作する方法を説明します. まず スクリプティングを参照してください. FreeCADでのpythonスクリプトの方法についてより詳しい情報が必要な場合は FreeCADスクリプトの基本ページを参照してください.

クラス・ダイアグラム
これはPartモジュールの最も重要なクラスに関するUML (Unified Modeling Language)の概要図です：

ジオメトリー
ジオメトリーオブジェクトは、トポロジーオブジェクトを構成するための基本要素です：
 * Geom ジオメトリーオブジェクトの基底クラスです.
 * Line 始点と終点で定義された3次元の直線です.
 * Circle 中心と始点と終点で定義される円や円の断片です.
 * ...... じきに増えるでしょう;-)

トポロジー
次の種類のトポロジーのデータが利用できます：
 * Compound 任意の種類のトポロジーオブジェクトのグループです.
 * Compsolid ソリッドの合成とは、フェイスで接続するソリッドの集合です. ワイヤとシェルの概念をソリッドへ拡張したものです.
 * Solid（ソリッド） シェルで区切られた空間です. 3次元です.
 * Shell（シェル） エッジで接続しているフェイスの集合です. シェルは開閉できます.
 * Face（フェイス） 2次元では平面の一部分、3次元では表面の一部分です. 形状は輪郭線で律則されています（切り取られています）. 2次元です.
 * Wire（ワイヤ） 頂点で接続するエッジの集合です. エッジの接続に応じて、輪郭線は開閉します.
 * Edge（エッジ） 制約された曲線に対応する位相要素です. エッジは一般的に頂点によって律則されます. 1次元です.
 * Vertex（頂点） 点に対応するトポロジーの要素です. 0次元です.
 * Shape（シェイプ） 上記全ての一般的な総称です.

クイックサンプル：シンプルなトポロジーの作成
単純なジオメトリーからトポロジーを構築して作成しましょう. サンプルでは画像に示す四つの頂点と二つの円と二本のラインからできたパーツを使用します.

ジオメトリーの作成
まずこのワイヤーの特徴的なジオメトリーパーツを作成しなければなりません. また頂点のジオメトリーパーツが同じ位置に置かれるように注意する必要があります. さもないと後でジオメトリーパーツをつなげてトポロジーにすることができなくなってしまいます！

さあ、まず点を作成します：

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) VC2 = Base.Vector(40,0,0) C2 = Part.Arc(V2,VC2,V3)
 * 1) 2番目の円弧

ライン
ラインはシンプルに点から作成できます：

L1 = Part.Line(V1,V2) L2 = Part.Line(V4,V3)
 * 1) and the second one

一つにまとめる
最後のステップとしてジオメトリーベースの要素をまとめ、トポロジカルな形状に固定します：

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...メソッドです：


 * makeBox(l,w,h): 寸法が(l,w,h)で位置pからd方向を指す箱を作ります.
 * makeCircle(radius): 指定した半径の円を作ります.
 * makeCone(radius1,radius2,height): 指定した半径と高さの円錐を作成します.
 * makeCylinder(radius,height): 指定した半径と高さを持つ円柱を作成します.
 * makeLine((x1,y1,z1),(x2,y2,z2)): 二点間を結ぶ線を作成します.
 * makePlane(length,width): 指定した幅と長さの平面を作成します.
 * makePolygon(list): 点のリストからポリゴンを作成します.
 * makeSphere(radius): 指定された半径の球を作成します.
 * makeTorus(radius1,radius2): 指定した半径のトーラスを作ります.

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 > [, ]

注意: 二つのベクトルを渡してエッジを作成することもできます：

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 > [, , , ] 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_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 > 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つのシェイプ間の積を得るには？
同じように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 > [, , , , , , ]

押し出しを行うには？
押し出しは平面形状を一定方向に"押し出す"ことでソリッドボディーを作成する操作です. "押し出し"によって円が管になるのを想像してください：

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

OCCボトル
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」で行えます.