zoukankan      html  css  js  c++  java
  • FreeCAD二次开发-拓扑数据脚本【精华】

    FreeCAD作为一款基于OpenCasCAD内核的开源CAD软件,可以在GitHub上下载源代码。阅读源代码,有助于我们学习CAD软件架构,了解底层几何算法。

    本篇文章内容出自FreeCAD官方社区https://wiki.freecadweb.org/Topological_data_scripting/zh-cn,由博主Caesar卢尚宇自学整理,软件翻译可能不准确。(纯粹出于对三维CAD软件开发的热爱)

    *推荐读者去官方社区阅读原文*

    本篇描述了几种利用python来创建与修改零件形状(Part shapes)的方法。

    概述

    在本文中向您解释如何直接用FreeCAD的Python解释器来控制零件模块,或者从任意外部脚本来实现这一点。关于拓扑数据脚本的基本描述位于零件模块的概念介绍。

    类图

    这是零件模块中最关键类的 统一建模语言(Unified Modeling Language (UML))概述:

     几何图形

    这些几何图形对象是一切拓扑对象的基石:

    • Geom 几何图形对象的基类
    • Line 3D空间中的直线段,由起始点与终点定义而成
    • Circle 由中心点、起始点与终点定义的圆形或部分圆环段(circle segment)
    • ...... 以及后续更多的几何图形

     拓扑

    FreeCAD中有下列可用的拓扑数据类型:

    • 复合(Compound)对象 一组任意类型的拓扑对象。
    • 组合实体(Compsolid) 一个复合实体是一组由其面连接起来的实体。它会将连线(WIRE)与壳(SHELL)扩展为实体。
    • 实体(Solid) 由壳界定的部分空间。实体是3D对象。
    • 壳(Shell) 一组由其边连接起来的面。一个壳可以是开放或闭合的。
    • 面(Face) 在2D空间中,它是部分平面;而在3D空间中,它是部分表面。面的几何图形由轮廓来约束(调整)。面是2D对象。
    • 连线(Wire) 一组由其顶点连接起来的边。连线可以是开放或闭合的轮廓,这取决于其中的边是否互连。
    • 边(Edge) 一种对应于约束曲线的拓扑元素。一条边通常受其顶点限制。边是一种1D对象。
    • 顶点(Vertex) 一种对应于点的拓扑元素。顶点是零维对象。
    • 几何形状(Shape) 一种涵盖上述所有对象的通称。

    简易示例 :创建简单拓扑结构

     现在,我们将通过构造简单的几何图形来创建对应的拓扑。就用我们在图中看到的零件为例,它由4个顶点,2个半圆以及2条线段构成。

    创建几何图形

    首先,我们必须创建此连线中的不同几何图形部分。 而且,还要小心处理几何图形中位于相同位置的不同顶点。否则,我们随后可能无法将这些几何图形连接为一个拓扑结构。

    因此,我们先来创建其中的点:

    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)

     
    为了创建圆周上的弧,我们要做一个辅助点,并通过圆周上的3个点来创建对应的弧:

    VC1 = Base.Vector(-10,0,0)
    C1 = Part.Arc(V1,VC1,V4)
    # and the second one
    VC2 = Base.Vector(40,0,0)
    C2 = Part.Arc(V2,VC2,V3)

    众所周知,两点定一线段:

    L1 = Part.LineSegment(V1,V2)
    # and the second one
    L2 = Part.LineSegment(V3,V4)

    请注意:在FreeCAD 0.16版中使用的是Part.Line,而对于FreeCAD 0.17版则必须使用Part.LineSegment

    合而为一

    最后一步就是将上述基本几何元素放在一起,并烘焙出一个拓扑形状:

    S1 = Part.Shape([C1,L1,C2,L2])

    制作一个外框

    现在令连线在同一方向上挤压成型,构造一个实际的3D图形:

    W = Part.Wire(S1.Edges)
    P = W.extrude(Base.Vector(0,0,10))

    将结果呈现出来

    Part.show(P)

     创建基本的几何形状

    您可以利用零件模块中的"make...()"方法来轻松地创建一个基础的拓扑对象。

    b = Part.makeBox(100,100,100)
    Part.show(b)

    其他可用的make...()方法:

    • makeBox(l,w,h): 在点p(?)处创建一个维数为(l,w,h)且指向方向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 API页来查阅零件模块中的完整可用方法列表。

    创建一个向量

    在构建几何图形的过程中, 向量 是提供最关键信息的对象类型之一。向量属性中通常都有3个数字(但并非总是如此):即直角坐标系中的3种坐标分量:x、y、z。您可以按下列方式来创建一个向量:

    myVector = Base.Vector(3,2,0)

    我们刚刚在x=3, y=2, z=0坐标处创建了一个向量。在零件模块中,到处都能看到向量的身影。构建零件形状的过程中,也会用到另一种名为顶点的点表示法,它是一种向量的简易容器。您可像下面那样来访问一个点的向量:

    myVertex = myShape.Vertexes[0]
    print myVertex.Point
    > Vector (3, 2, 0)

    创建一条边

    一条边不过是具有两个顶点的线段:

    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.LineSegment(vec1,vec2)
    edge = line.toShape()

    您能通过下列方式来查看一条边的长度与中点:

    edge.Length
    > 10.0
    edge.CenterOfMass
    > Vector (5, 0, 0)

    将图形显示在屏幕上

    到目前为止,我们已经创建了一个边对象,但是它却并没有出现在屏幕上。 这是因为:只有在您告诉FreeCAD要呈现什么内容之后,它才会显示出对应的3D场景。为此,我们要通过下列简单函数来实现这一点:

    Part.show(edge)

    此show函数在我们当前的FreeCAD文档中创建了一个对象,并为之赋予此前创建的"edge"几何形状。每当需要在屏幕上显示您所创建的对象们时,使用此函数即可。

    创建一个连线

    一条连线(wire)由多条边构成。创建连线需要指定一个边列表,或者甚至是一个连线列表:

    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个单位处,并沿轴方向面向外侧。请注意:makeCircle仅接收Base.Vector()作为其位置以及方向参数,而非元组(tuples)。您也可以通过指定起始角度与结束角度来创建部分圆:

    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拼接起来即是一个圆。角度参数使用的是角度制;如果您采用的是弧度制,可简单的通过下列公式进行转换:角度 = 弧度 * 180/PI,或借助python的数学模块(当然啦,要在导入数学模块后才能使用):

    degrees = math.degrees(radians)

    沿多个点创建一条弧

    可惜的是,FreeCAD并没有提供makeArc函数,但是我们有Part.Arc函数可通过3个点来创建一条弧。它经过起始点、中点以及两者间的一个中间点来创建一个弧对象。另外,必须调用弧对象的.toShape()函数来得到一个边对象,与Arc用法相同的是Part.LineSegment而非Part.makeLine。

    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()作为绘弧所用的点,而非元组(tuples)。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(circle,0,pi)

    弧都是像线条那样的有效边,因此也可将其用作连线。

    创建一个多边形

    多边形是利用多条直边连接而成的简易连线。 makePolygon函数将获取一个点列表,并通过其中的多个点来创建一条连线:

    lshape_wire = Part.makePolygon([Base.Vector(0,5,0),Base.Vector(0,0,0),Base.Vector(5,0,0)])

    创建一条贝塞尔曲线

    贝塞尔曲线常用于模拟平滑的曲线,绘制贝塞尔曲线要借助一系列极点(poles)以及权值。下列函数根据一组FreeCAD.Vector点来创建一条Part.BezierCurve。(请注意:当“获取”或“设置”单个极点或权值时,起始索引为1而非0。)

    def makeBCurveEdge(Points):
       geomCurve = Part.BezierCurve()
       geomCurve.setPoles(Points)
       edge = Part.Edge(geomCurve)
       return(edge)

    创建一个平面

    平面就是一个简单的矩形平面。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轴上为0,这是因为被包围的对象是一个平面。

    请注意,makePlane仅接收Base.Vector()作为其start_pnt与dir_normal参数,而非元组(tuples)。

    创建一个椭圆

    有多种方法可以创建椭圆:

    Part.Ellipse()

    创建一个长半轴为2、短半轴为1,且中点位于(0,0,0)处的椭圆。

    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, angle2=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)

    上述代码将创建半个环面;只有最后一个参数发生了改变。 即除了最后的angle,其余角度皆为默认值。将angle指定为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)

    修改几何形状

    FreeCAD提供了若干方法来修改几何形状。其中一些是简单的变换操作,如移动或旋转几何形状,而其他的更为复杂,如令两个形状进行并集与差集操作。

    变换操作

    平移一个几何形状

    平移也就是将一个几何图形在不同的位置之间进行移动。 任意形状(边、面、立方体等等……)都可以通过下列同一种方式进行平移:

    myShape = Part.makeBox(2,2,2)
    myShape.translate(Base.Vector(2,0,0))

    上述代码将几何形状"myShape"在x轴方向上移动2个单位。

    旋转一个几何形状

    为了旋转一个几何形状,您需要指定旋转中心、旋转轴以及旋转角度:

    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中的矩阵采用的是弧度制。另外,基本所有的矩阵操作都会借助一个向量,也可以直接取三个对应的数值,因此以下两行代码是等价的:

    myMat.move(2,0,0)
    myMat.move(Base.Vector(2,0,0))

    一旦设置好矩阵中的值,我们就可以将其应用至待变换的几何形状。FreeCAD为此提供了两种方法:transformShape()与transformGeometry()。两者的不同之处在于:在使用前者时,您要确保执行的变换不会对目标形状造成形变(参见下文“缩放一个几何形状”)。我们可以像下面那样来执行变换:

    myShape.transformShape(myMat)

    或者

    myShape.transformGeometry(myMat)

    对几何形状进行缩放

    对一个几何形状进行缩放是一种更为危险的操作,因为这并不像平移或旋转那样,(以不同的x、y与z值)进行非等比缩放会修改原始形状的结构。例如,以相对于纵向值较大的水平值对圆形进行缩放,将使之成为一个椭圆形,以数学角度观之区别甚大。对于缩放操作而言,我们不能使用transformShape,而一定要采用transformGeometry():

    myMat = Base.Matrix()
    myMat.scale(2,1,1)
    myShape=myShape.transformGeometry(myMat)

    布尔运算

    差集

    从一个图形中去掉另一个图形在OCC/FreeCAD的术语中被称之为“切割(cut)”,可以这样来实现:

    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)

    交集

    类似地,两个图形之间的交集被称之为“共有(common)”,可以这样来实现:

    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)

    并集

    并集操作被称为“融合(fuse)”,可以实现如下:

    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)

    截面

    截面(section)是实体与平面的交集。它将返回一个交集曲线,一个由多条边复合而成的复合曲线。(?)

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

    挤型

    挤型(extrusion)是将一个平面几何形状以特定的方向“推进”从而构建对应实体的动作。试想,将一个圆形“推挤”为一个管子:

    circle = Part.makeCircle(10)
    tube = circle.extrude(Base.Vector(0,0,2))

    如果采用的是空心圆形,将得到一个空心管。如果使用的是具有填充面的圆盘,则将得到一个实心圆柱体:

    wire = Part.Wire(circle)
    disc = Part.Face(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解释器中输入以上代码,您将得到一个易于理解的零件对象结构。其中使用makeBox()命令创建了一个实体形状。此实体就像所有其他零件实体一样,含有许多面。而面里总是包含多条连线,也就是构成面的边界的一系列边。每个面都有至少一条闭合连线(如果面内有个洞,则可能存在更多的闭合连线)。在连线中,我们可以看到每个独立的边,在每条边内,又可看到其顶点。显而易见,直边仅有两个顶点。

    边的分析

    对于以一条任意曲线作为边的情况而言,想必大多用户都希望对它进行离散化处理。在FreeCAD中是通过边的长度来对其进行参数化的。这就意味您可以通过其长度来构造一条边/曲线:

    import Part
    box = Part.makeBox(100,100,100)
    anEdge = box.Edges[0]
    print anEdge.Length

    您现在可以将长度作为位置,借此来访问对应边的大量属性。这意味着,如果边长为100mm,则起始位置为0,而终点位置为100。

    anEdge.tangentAt(0.0)      # tangent direction at the beginning
    anEdge.valueAt(0.0)        # Point at the beginning
    anEdge.valueAt(100.0)      # Point at the end of the edge
    anEdge.derivative1At(50.0) # first derivative of the curve in the middle
    anEdge.derivative2At(50.0) # second derivative of the curve in the middle
    anEdge.derivative3At(50.0) # third derivative of the curve in the middle
    anEdge.centerOfCurvatureAt(50) # center of the curvature for that position
    anEdge.curvatureAt(50.0)   # the curvature
    anEdge.normalAt(50)        # normal vector at that position (if defined)

    使用选中的对象

    在此,我们来看看如何使用在视图中选择的对象。我们先来创建一个立方体,并令它在视图中显示出来。

    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.LineSegment(aPnt1,aPnt2)
       aSegment2=Part.LineSegment(aPnt4,aPnt5)
       aEdge1=aSegment1.toShape()
       aEdge2=aArcOfCircle.toShape()
       aEdge3=aSegment2.toShape()
       aWire=Part.Wire([aEdge1,aEdge2,aEdge3])
       
       aTrsf=Base.Matrix()
       aTrsf.rotateZ(math.pi) # rotate around the z-axis
       
       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.makeFillet(myThickness/12.0,myBody.Edges)
       
       return myBody
    
    el = makeBottle()
    Part.show(el)

    详细说明

    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.LineSegment(aPnt1,aPnt2)
       aSegment2=Part.LineSegment(aPnt4,aPnt5)

    以上代码分别:利用三个点构建了一条弧,依次利用两个点构建了两条线段。

    aEdge1=aSegment1.toShape()
       aEdge2=aArcOfCircle.toShape()
       aEdge3=aSegment2.toShape()
       aWire=Part.Wire([aEdge1,aEdge2,aEdge3])

    还记得几何图元与拓扑形状的区别吗?在此,我们利用此前创建的结构几何对象来构建拓扑形状。首先构建三条边(边可以是直边或曲边),随即利用它们创建一条连线。

    aTrsf=Base.Matrix()
       aTrsf.rotateZ(math.pi) # rotate around the z-axis
       aMirroredWire=aWire.transformGeometry(aTrsf)
       myWireProfile=Part.Wire([aWire,aMirroredWire])

    到目前为止,我们仅构建了半个瓶子的轮廓。构建整个瓶子其实再次重复同样的流程即可,我们这里取巧对此前的半个轮廓进行镜像操作,再将它们粘合起来。首先创建一个矩阵。矩阵是将变换作用于3D空间物体的常用手段,这是因为借助它就能仅在一个结构中囊括3D物体的所有基本变换(移动、旋转、缩放)。 创建矩阵后,将其设置为对应的镜像变换,再创建一个此前连线的副本,并为之应用变换矩阵。现在就有了两条连线,由于连线实际是一系列边,因此我们可借助这两条连线来创建第三条连线。

    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)

    融合(fuse)操作,在其他应用程序中有时也称并集,这是一种强大的工具。它负责小心地粘合需要粘合的部分,并去掉需要去掉的部分。

    return myBody

    随后,我们将Part零件实体作为函数的处理结果返回。

    el = makeBottle()
    Part.show(el)

    最后,我们调用此函数来创建实际零件,并将其显示粗来。

    盒体穿孔

    此实例为构建一个穿孔的盒子。

    构建的过程中,每次只构造一个面;当立方体创建完成后,再通过从中切割一个穿过它的圆柱体来实现穿孔。

    import Draft, Part, FreeCAD, math, PartGui, FreeCADGui, PyQt4
    from math import sqrt, pi, sin, cos, asin
    from FreeCAD import Base
    
    size = 10
    poly = Part.makePolygon( [ (0,0,0), (size, 0, 0), (size, 0, size), (0, 0, size), (0, 0, 0)])
    
    face1 = Part.Face(poly)
    face2 = Part.Face(poly)
    face3 = Part.Face(poly)
    face4 = Part.Face(poly)
    face5 = Part.Face(poly)
    face6 = Part.Face(poly)
         
    myMat = FreeCAD.Matrix()
    myMat.rotateZ(math.pi/2)
    face2.transformShape(myMat)
    face2.translate(FreeCAD.Vector(size, 0, 0))
    
    myMat.rotateZ(math.pi/2)
    face3.transformShape(myMat)
    face3.translate(FreeCAD.Vector(size, size, 0))
    
    myMat.rotateZ(math.pi/2)
    face4.transformShape(myMat)
    face4.translate(FreeCAD.Vector(0, size, 0))
    
    myMat = FreeCAD.Matrix()
    myMat.rotateX(-math.pi/2)
    face5.transformShape(myMat)
    
    face6.transformShape(myMat)               
    face6.translate(FreeCAD.Vector(0,0,size))
    
    myShell = Part.makeShell([face1,face2,face3,face4,face5,face6])   
    
    mySolid = Part.makeSolid(myShell)
    mySolidRev = mySolid.copy()
    mySolidRev.reverse()
    
    myCyl = Part.makeCylinder(2,20)
    myCyl.translate(FreeCAD.Vector(size/2, size/2, 0))
    
    cut_part = mySolidRev.cut(myCyl)
    
    Part.show(cut_part)

    加载与保存

    在零件模块中有若干种保存工作进度的方式。您可以保存自己的FreeCAD文件,也可以将零件对象直接保存为常见的CAD格式,例如BREP,IGS,STEP与STL。

    将一个几何形状保存至文件中是很方便的。FreeCAD针对所有图形提供了exportBrep()、exportIges()、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")

    为了将一个.stp文件转换为一个.igs文件可以:

    import Part
     s = Part.Shape()
     s.read("file.stp")       # incoming file igs, stp, stl, brep
     s.exportIges("file.igs") # outbound file igs

     Caesar卢尚宇

    2020年3月23日

  • 相关阅读:
    用实例来说明linux命令sort的用法
    shell 编程入门
    VMware sphere的使用
    linux进阶
    Windows系统下的TCP参数优化
    RFID Technology(上)——简介、市场应用与前景、工作原理
    RFID Technology(下)——面临的风险、安全与隐私策略
    TCP连接的状态与关闭方式,及其对Server与Client的影响
    Java Map遍历方式的选择
    博客处女贴
  • 原文地址:https://www.cnblogs.com/nxopen2018/p/12554639.html
Copyright © 2011-2022 走看看