def make_node_xz(width, height, thickness, x_positive=True): p1 = FreeCAD.Vector(0., -thickness / 2.0, height / 2.0) p2 = FreeCAD.Vector(0., -thickness / 2.0, -height / 2.0) if x_positive is True: pa = FreeCAD.Vector(width, -thickness / 2.0, 0.) else: pa = FreeCAD.Vector(-width, -thickness / 2.0, 0.) l1 = Part.makeLine(p1, p2) a2 = Part.Arc(p2, pa, p1).toShape() wire = Part.Wire([l1, a2]) face = Part.Face(wire) node = face.extrude(FreeCAD.Vector(0, thickness, 0)) return node
def fretboardSection(c, r, w, t, v): """ Creates a Wire for a Fretboard Loft c: center Vector r: Radius float w: Width float t: Thickness float v: Direction Vector """ # Half angle of the top Arc alpha = math.asin(w/(2*r)) alpha_deg = todeg(alpha) # Guess top Arc arc = Part.makeCircle(r, c, v, -alpha_deg, alpha_deg) # If arc fails: Guess at 90deg if arc.Vertexes[0].Point.z <= 0: arc = Part.makeCircle(r, c, v, 90-alpha_deg, 90+alpha_deg) # If arc fails again: Impossible if arc.Vertexes[0].Point.z <= 0: raise ModelException("Current Fretboard's radius is inconsistent with Fretboard's geometry") # Arc end points a = arc.Vertexes[0].Point b = arc.Vertexes[1].Point # Side fretboard height h = r * math.cos(alpha) - r + t # Fretboard bottom at side a x = Vector(a.x, a.y, a.z -h) # Fretboard bottom at side b d = Vector(b.x, b.y, b.z -h) # Fretboard top at center p = Vector(c.x, c.y, c.z +r) # Finally, the wire: arc(ba) -> seg(ax) -> seg(xd) -> seg(db) return Part.Wire(Part.Shape([ Part.Arc(a,p,b), Part.LineSegment(a,x), Part.LineSegment(x,d), Part.LineSegment(d,b)]).Edges)
def make_node_yz(width, height, thickness, x_positive=True): p1 = FreeCAD.Vector(-thickness / 2.0, 0, height / 2.0) p2 = FreeCAD.Vector(-thickness / 2.0, 0, -height / 2.0) if x_positive is True: pa = FreeCAD.Vector(-thickness / 2.0, width, 0.) else: pa = FreeCAD.Vector(-thickness / 2.0, -width, 0.) l1 = Part.Line(p1, p2) a2 = Part.Arc(p2, pa, p1) shape = Part.Shape([l1, a2]) wire = Part.Wire(shape.Edges) face = Part.Face(wire) node = face.extrude(FreeCAD.Vector(thickness, 0, 0)) return node
def getreversed(self, edges): """ Reverses the edge array and the direction of each edge """ outedges = [] for edge in reversed(edges): # reverse the start and end points startPoint = edge.valueAt(edge.LastParameter) endPoint = edge.valueAt(edge.FirstParameter) if type(edge.Curve) == Part.Line or type(edge.Curve) == Part.LineSegment: outedges.append(Part.makeLine(startPoint, endPoint)) elif type(edge.Curve) == Part.Circle: arcMid = edge.valueAt((edge.FirstParameter + edge.LastParameter) / 2) outedges.append(Part.Arc(startPoint, arcMid, endPoint).toShape()) else: PathLog.error("Edge should not be helix") return outedges
def getarc(data): "turns an OCA arc definition into a FreeCAD Part Edge" print "found arc ", data c = None if (data[0] == "ARC"): # 3-points arc pts = data[1:] verts = [] for p in range(len(pts)): if (pts[p] == "P"): verts.append(getpoint(pts[p:p + 3])) elif (pts[p][0] == "P"): verts.append(getpoint([pts[p]])) if verts[0] and verts[1] and verts[2]: c = Part.Arc(verts[0], verts[1], verts[2]) elif (data[0][0] == "P"): # 2-point circle verts = [] rad = None for p in range(len(data)): if (data[p] == "P"): verts.append(getpoint(data[p:p + 4])) elif (data[p][0] == "P"): verts.append(getpoint([data[p]])) elif (data[p] == "VAL"): rad = float(data[p + 1]) elif (data[p][0] == "L"): lines.append(objects[data[p]]) c = Part.Circle() c.Center = verts[0] if rad: c.Radius = rad else: c.Radius = DraftVecUtils.new(verts[0], verts[1]).Length elif (data[0][0] == "L"): # 2-lines circle lines = [] rad = None for p in range(len(data)): if (data[p] == "VAL"): rad = float(data[p + 1]) elif (data[p][0] == "L"): lines.append(objects[data[p]]) circles = DraftGeomUtils.circleFrom2LinesRadius( lines[0], lines[1], rad) if circles: c = circles[0] if c: return c.toShape()
def make_truncated_arched_cutout_aperture( aperture_height, centre_position, aperture_width, arc_radius ): """Creates a wire outline of a rectangle with an arc removed from the centre of one edge. Args: arc_radius (float): Radius of the arc. centre_position (float): position along width making the centre of the cutout arc. aperture_height (float): Total height of the aperture aperture_width (float): Total width of the aperture Returns: wire1 (FreeCAD wire definition): An outline description of the shape. face1 (FreeCAD face definition): A surface description of the shape. """ # Create the initial four vertices where line meets curve. v1 = Base.Vector(0, aperture_height - arc_radius, -aperture_width + centre_position) v2 = Base.Vector(0, aperture_height - arc_radius, centre_position) v3 = Base.Vector( 0, -float(arc_radius) + sqrt(arc_radius ** 2 - centre_position ** 2), centre_position, ) v4 = Base.Vector(0, -arc_radius, -arc_radius) v5 = Base.Vector(0, -arc_radius, -aperture_width + centre_position) cv1 = Base.Vector( 0, 0, 0, ) # Create lines line1 = Part.LineSegment(v5, v1) line2 = Part.LineSegment(v1, v2) line3 = Part.LineSegment(v2, v3) line4 = Part.LineSegment(v4, v5) # Create curves arc1 = Part.Arc(v3, cv1, v4) # Make a shape shape1 = Part.Shape([line1, line2, line3, arc1, line4]) # Make a wire outline. wire1 = Part.Wire(shape1.Edges) # Make a face. face1 = Part.Face(wire1) return wire1, face1
def generatePCB(self, PCB, doc, groupBRD, gruboscPlytki): doc.addObject('Sketcher::SketchObject', 'PCB_Border') doc.PCB_Border.Placement = FreeCAD.Placement( FreeCAD.Vector(0.0, 0.0, 0.0), FreeCAD.Rotation(0.0, 0.0, 0.0, 1.0)) # for i in PCB[0]: if i[0] == 'Arc': # arc by 3 points x1 = i[1] y1 = i[2] x2 = i[3] y2 = i[4] [x3, y3] = self.arcMidPoint([x2, y2], [x1, y1], i[5]) arc = Part.Arc(FreeCAD.Vector(x1, y1, 0.0), FreeCAD.Vector(x3, y3, 0.0), FreeCAD.Vector(x2, y2, 0.0)) doc.PCB_Border.addGeometry( self.Draft2Sketch(arc, doc.PCB_Border)) elif i[0] == 'Arc_2': # arc by center / start angle / stop angle / radius doc.PCB_Border.addGeometry( Part.ArcOfCircle( Part.Circle(FreeCAD.Vector(i[1], i[2], 0), FreeCAD.Vector(0, 0, 1), i[3]), i[4], i[5])) elif i[0] == 'Circle': doc.PCB_Border.addGeometry( Part.Circle(FreeCAD.Vector(i[1], i[2]), FreeCAD.Vector(0, 0, 1), i[3])) elif i[0] == 'Line': doc.PCB_Border.addGeometry( Part.Line(FreeCAD.Vector(i[1], i[2], 0), FreeCAD.Vector(i[3], i[4], 0))) # #if PCB[1]: PCBboard = doc.addObject("Part::FeaturePython", "Board") PCBboardObject(PCBboard) PCBboard.Thickness = gruboscPlytki PCBboard.Border = doc.PCB_Border viewProviderPCBboardObject(PCBboard.ViewObject) groupBRD.addObject(doc.Board) FreeCADGui.activeDocument().getObject( PCBboard.Name).ShapeColor = PCBconf.PCB_COLOR FreeCADGui.activeDocument().PCB_Border.Visibility = False self.updateView()
def make_keyhole_aperture_flat_end(pipe_radius, keyhole_height, keyhole_width): """Creates a wire outline of a circular pipe with a keyhole extension on the side. aperture_height and aperture_width are the full height and width (the same as if it were a rectangle). The end curves are defined as 180 degree arcs. Args: pipe_radius (Base.Unit): Radius of the main beam pipe. keyhole_height (Base.Unit): Total height of the keyhole slot. keyhole_width (Base.Unit): Total width of the keyhole slot. Returns: wire1 (FreeCAD wire definition): An outline description of the shape. face1 (FreeCAD face definition): A surface description of the shape. """ # X intersection of keyhole with pipe. x_intersection = Units.Quantity( sqrt(pipe_radius ** 2 - (keyhole_height / 2.0) ** 2), 1 ) # Create the initial four vertices for the lines. v1 = Base.Vector(0, keyhole_height / 2.0, x_intersection) v2 = Base.Vector(0, keyhole_height / 2.0, keyhole_width) v3 = Base.Vector(0, -keyhole_height / 2.0, keyhole_width) v4 = Base.Vector(0, -keyhole_height / 2.0, x_intersection) v5 = Base.Vector(0, 0, x_intersection + keyhole_width) # Create lines line1 = Part.LineSegment(v1, v2) line2 = Part.LineSegment(v2, v3) line3 = Part.LineSegment(v3, v4) # angle at which the keyhole intersects the pipe. half_angle = asin(keyhole_height / (2 * pipe_radius)) # Create curves curve1 = Part.Circle(Base.Vector(0, 0, 0), Base.Vector(1, 0, 0), pipe_radius) arc1 = Part.Arc( curve1, half_angle, (2 * pi) - half_angle ) # angles are in radian here # Make a shape shape1 = Part.Shape([arc1, line1, line2, line3]) # Make a wire outline. wire1 = Part.Wire(shape1.Edges) # Make a face. face1 = Part.Face(wire1) return wire1, face1
def makeBottle1(self): aPnt1 = Base.Vector(-self.width / 2., 0, 0) aPnt2 = Base.Vector(-self.width / 2., -self.thickness / 4., 0) aPnt3 = Base.Vector(0, -self.thickness / 2., 0) aPnt4 = Base.Vector(self.width / 2., -self.thickness / 4., 0) aPnt5 = Base.Vector(self.width / 2., 0, 0) ## 上面定义5个点:只与myThickness,myWidth有关 aArcOfCircle = Part.Arc(aPnt2, aPnt3, aPnt4) aSegment1 = Part.LineSegment(aPnt1, aPnt2) aSegment2 = Part.LineSegment(aPnt4, aPnt5) ## 上面构建2条线和一个圆弧: 线1: 1-2; 线2: 4-5; 圆弧:2-3-4 aEdge1 = aSegment1.toShape() aEdge2 = aArcOfCircle.toShape() aEdge3 = aSegment2.toShape() aWire = Part.Wire([aEdge1, aEdge2, aEdge3]) ## 由几何结构(line和circle)构造形状Shape:(Solid-Shell-Face-Wire-Edge-Vertex) aTrsf = Base.Matrix() ## 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, self.height) myBody = myFaceProfile.extrude(aPrismVec) # myBody=myBody.makeFillet(myThickness/12.0,myBody.Edges) ##上面语句为,先180镜像,之后形成一个closed face,之后 # 用extrude进行拉升 myHeight的高度 # 随后使用makeFillet,扣除 myThickness/12.0 的厚度 neckLocation = Base.Vector(0, 0, self.height) neckNormal = Base.Vector(0, 0, 1) myNeckRadius = self.thickness / 4. myNeckHeight = self.height / 10. myNeck = Part.makeCylinder(myNeckRadius, myNeckHeight, neckLocation, neckNormal) myBody = myBody.fuse(myNeck) # myBody = myBody.makeFillet(myThickness/12.0,myBody.Edges) # App.getDocument('Cube').addObject('Part::PartFeature','Shape') = myBody.toShape() # Gui.getDocument("Cube").getObject("Shape").ShapeColor=color Part.show(myBody) Gui.getDocument("Bottle").getObject("Shape001").ShapeColor = self.color
def make_arched_base_trapezoid_aperture( aperture_height, base_width, top_width, arc_radius ): """Creates a wire outline of a rectangle with an arc removed from one edge.. Args: arc_radius (float): Radius of the arc. aperture_height (float): Total height of the aperture. base_width (float): Total width of the base of the aperture. top_width (float): Total width of the top of the aperture. Returns: wire1 (FreeCAD wire definition): An outline description of the shape. face1 (FreeCAD face definition): A surface description of the shape. """ # Create the initial four vertices where line meets curve. v1 = Base.Vector(0, aperture_height / 2.0, -top_width / 2.0) v2 = Base.Vector(0, aperture_height / 2.0, top_width / 2.0) v3 = Base.Vector(0, -aperture_height / 2.0, base_width / 2.0) v4 = Base.Vector(0, -aperture_height / 2.0, -base_width / 2.0) cv1 = Base.Vector( 0, -aperture_height / 2.0 + arc_radius - sqrt(arc_radius ** 2 - (base_width ** 2) / 4), 0, ) # Create lines line1 = Part.LineSegment(v4, v1) line2 = Part.LineSegment(v1, v2) line3 = Part.LineSegment(v2, v3) # Create curves arc1 = Part.Arc(v3, cv1, v4) # arc1_edge = arc1.toShape() # Make a shape shape1 = Part.Shape([line1, line2, line3, arc1]) # Make a wire outline. wire1 = Part.Wire(shape1.Edges) # Make a face. face1 = Part.Face(wire1) return wire1, face1
def getTransitionEnd(trans, height, profile, tip): """Generate last profile""" height = height + trans.Length / 2 a = trans.Vertexes[0].Point b = trans.Vertexes[1].Point l1 = Part.LineSegment(Vector(a), Vector(a.x, a.y, a.z - height)) l2 = Part.LineSegment(Vector(b.x, b.y, b.z - height), Vector(b)) l3 = Part.LineSegment(Vector(b), Vector(a)) lX = geom.wireFromPrim([ Part.LineSegment(Vector(a.x, a.y, a.z - height), Vector(b.x, b.y, b.z - height)) ]) center = lX.CenterOfMass length = lX.Length arc = Part.Arc(Vector(a.x, a.y, a.z - height), Vector(center.x, center.y, center.z - length / 2), Vector(b.x, b.y, b.z - height)) wire = geom.wireFromPrim([l1, arc, l2, l3]) return wire
def getPoint(self, point, info): if not point: # cancelled self.tracker.off() return if not (point in self.points): # avoid same point twice self.points.append(point) if len(self.points) < 3: if len(self.points) == 2: self.tracker.on() FreeCADGui.Snapper.getPoint(last=self.points[-1], callback=self.getPoint, movecallback=self.drawArc) else: import Part e = Part.Arc(self.points[0], self.points[1], self.points[2]).toShape() o = FreeCAD.ActiveDocument.addObject("Part::Feature", "Arc") o.Shape = e self.tracker.off() FreeCAD.ActiveDocument.recompute()
def smMakeReliefFace(edge, dir, gap, reliefW, reliefD, reliefType): p1 = edge.valueAt(edge.FirstParameter + gap) p2 = edge.valueAt(edge.FirstParameter + gap + reliefW ) if reliefType == "Round" and reliefD > reliefW : p3 = edge.valueAt(edge.FirstParameter + gap + reliefW) + dir.normalize() * (reliefD-reliefW/2) p34 = edge.valueAt(edge.FirstParameter + gap + reliefW/2) + dir.normalize() * reliefD p4 = edge.valueAt(edge.FirstParameter + gap) + dir.normalize() * (reliefD-reliefW/2) e1 = Part.makeLine(p1, p2) e2 = Part.makeLine(p2, p3) e3 = Part.Arc(p3, p34, p4).toShape() e4 = Part.makeLine(p4, p1) else : p3 = edge.valueAt(edge.FirstParameter + gap + reliefW) + dir.normalize() * reliefD p4 = edge.valueAt(edge.FirstParameter + gap) + dir.normalize() * reliefD e1 = Part.makeLine(p1, p2) e2 = Part.makeLine(p2, p3) e3 = Part.makeLine(p3, p4) e4 = Part.makeLine(p4, p1) w = Part.Wire([e1,e2,e3,e4]) return Part.Face(w)
def _airfoil(self, base, thickness, diameter, length): # Calculate the tangent points radius = diameter / 2.0 theta = math.pi - math.atan2(length - radius, radius) x = -(radius * math.cos(theta)) y = radius * math.sin(theta) v1 = FreeCAD.Vector(-x, y, base) v2 = FreeCAD.Vector(-x, -y, base) v3 = FreeCAD.Vector(radius, 0, base) v4 = FreeCAD.Vector(radius - length, 0, base) arc = Part.Arc(v1, v3, v2) line1 = Part.LineSegment(v1, v4) line2 = Part.LineSegment(v2, v4) shape = Part.Shape([arc, line1, line2]) wire = Part.Wire(shape.Edges) face = Part.Face(wire) airfoil = face.extrude(FreeCAD.Vector(0, 0, thickness)) return airfoil
def make_arched_cutout_aperture(aperture_height, aperture_width, arc_radius): """Creates a wire outline of a rectangle with an arc removed from the centre of one edge. Args: arc_radius (float): Radius of the arc. aperture_height (float): Total height of the aperture aperture_width (float): Total width of the aperture Returns: wire1 (FreeCAD wire definition): An outline description of the shape. face1 (FreeCAD face definition): A surface description of the shape. """ # Create the initial four vertices where line meets curve. v1 = Base.Vector(0, aperture_height / 2.0, -aperture_width / 2.0) v2 = Base.Vector(0, aperture_height / 2.0, aperture_width / 2.0) v3 = Base.Vector(0, -aperture_height / 2.0, aperture_width / 2.0) v4 = Base.Vector(0, -aperture_height / 2.0, arc_radius) v5 = Base.Vector(0, -aperture_height / 2.0, -arc_radius) v6 = Base.Vector(0, -aperture_height / 2.0, -aperture_width / 2.0) cv1 = Base.Vector( 0, -aperture_height / 2.0 + arc_radius, 0, ) # Create lines line1 = Part.LineSegment(v6, v1) line2 = Part.LineSegment(v1, v2) line3 = Part.LineSegment(v2, v3) line4 = Part.LineSegment(v3, v4) line5 = Part.LineSegment(v5, v6) # Create curves arc1 = Part.Arc(v4, cv1, v5) # Make a shape shape1 = Part.Shape([line1, line2, line3, line4, arc1, line5]) # Make a wire outline. wire1 = Part.Wire(shape1.Edges) # Make a face. face1 = Part.Face(wire1) return wire1, face1
def makeBottleTut(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.copy() aMirroredWire.transformShape(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) return myBody
def generateGlue(self, wires, doc, grp, layerName, layerColor, layerNumber): if PCBconf.PCBlayers[PCBconf.softLayers[self.databaseType][layerNumber] [1]][0] == 1: side = 'TOP' else: side = 'BOTTOM' # for i, j in wires.items(): ser = doc.addObject('Sketcher::SketchObject', "Sketch_{0}".format(layerName)) ser.ViewObject.Visibility = False for k in j: if k[0] == 'line': ser.addGeometry( Part.Line(FreeCAD.Vector(k[1], k[2], 0), FreeCAD.Vector(k[3], k[4], 0))) elif k[0] == 'circle': ser.addGeometry( Part.Circle(FreeCAD.Vector(k[1], k[2]), FreeCAD.Vector(0, 0, 1), k[3])) elif k[0] == 'arc': x1 = k[1] y1 = k[2] x2 = k[3] y2 = k[4] [x3, y3] = self.arcMidPoint([x2, y2], [x1, y1], k[5]) arc = Part.Arc(FreeCAD.Vector(x1, y1, 0.0), FreeCAD.Vector(x3, y3, 0.0), FreeCAD.Vector(x2, y2, 0.0)) ser.addGeometry(self.Draft2Sketch(arc, ser)) # glue = createGlue() glue.base = ser glue.width = i glue.side = side glue.color = layerColor glue.generate()
def test62(self): """Verify splitArcAt returns proper subarcs.""" p1 = Vector(10,-10,0) p2 = Vector(0,0,0) p3 = Vector(10,10,0) arc = Part.Edge(Part.Arc(p1, p2, p3)) o = 10*math.sin(math.pi/4) p12 = Vector(10 - o, -o, 0) p23 = Vector(10 - o, +o, 0) e = PathGeom.splitArcAt(arc, p2) self.assertCurve(e[0], p1, p12, p2) self.assertCurve(e[1], p2, p23, p3) p34 = Vector(10 - 10*math.sin(1*math.pi/8), -10*math.cos(1*math.pi/8), 0) p45 = Vector(10 - 10*math.sin(5*math.pi/8), -10*math.cos(5*math.pi/8), 0) e = PathGeom.splitArcAt(arc, p12) self.assertCurve(e[0], p1, p34, p12) self.assertCurve(e[1], p12, p45, p3)
def test60(self): """Verify arcToHelix returns proper helix.""" p1 = Vector(10, -10, 0) p2 = Vector(0, 0, 0) p3 = Vector(10, 10, 0) e = PathGeom.arcToHelix(Part.Edge(Part.Arc(p1, p2, p3)), 0, 2) self.assertCurve(e, p1, p2 + Vector(0, 0, 1), p3 + Vector(0, 0, 2)) e = PathGeom.arcToHelix(Part.Edge(Part.Arc(p1, p2, p3)), 3, 7) self.assertCurve(e, p1 + Vector(0, 0, 3), p2 + Vector(0, 0, 5), p3 + Vector(0, 0, 7)) e = PathGeom.arcToHelix(Part.Edge(Part.Arc(p1, p2, p3)), 9, 1) self.assertCurve(e, p1 + Vector(0, 0, 9), p2 + Vector(0, 0, 5), p3 + Vector(0, 0, 1)) dz = Vector(0, 0, 3) p11 = p1 + dz p12 = p2 + dz p13 = p3 + dz e = PathGeom.arcToHelix(Part.Edge(Part.Arc(p11, p12, p13)), 0, 8) self.assertCurve(e, p1, p2 + Vector(0, 0, 4), p3 + Vector(0, 0, 8)) e = PathGeom.arcToHelix(Part.Edge(Part.Arc(p11, p12, p13)), 2, -2) self.assertCurve(e, p1 + Vector(0, 0, 2), p2, p3 + Vector(0, 0, -2)) o = 10 * math.sin(math.pi / 4) p1 = Vector(10, -10, 1) p2 = Vector(10 - 10 * math.sin(math.pi / 4), -10 * math.cos(math.pi / 4), 1) p3 = Vector(0, 0, 1) e = PathGeom.arcToHelix(Part.Edge(Part.Arc(p1, p2, p3)), 0, 5) self.assertCurve(e, Vector(10, -10, 0), Vector(p2.x, p2.y, 2.5), Vector(0, 0, 5))
def AddArc(self, x1, z1, x2, z2): midPoint = FreeCAD.Base.Vector(x1, 0, z1) endPoint = FreeCAD.Base.Vector(x2, 0, z2) self.edges.append( Part.Arc(self.lastPoint, midPoint, endPoint).toShape()) self.lastPoint = endPoint
def updateData(self, obj, prop): if hasattr(self, "arc"): from pivy import coin import Part, DraftGeomUtils import DraftGui arcsegs = 24 # calculate the arc data if DraftVecUtils.isNull(obj.Normal): norm = App.Vector(0, 0, 1) else: norm = obj.Normal radius = (obj.Dimline.sub(obj.Center)).Length self.circle = Part.makeCircle(radius, obj.Center, norm, obj.FirstAngle.Value, obj.LastAngle.Value) self.p2 = self.circle.Vertexes[0].Point self.p3 = self.circle.Vertexes[-1].Point mp = DraftGeomUtils.findMidpoint(self.circle.Edges[0]) ray = mp.sub(obj.Center) # set text value if obj.LastAngle.Value > obj.FirstAngle.Value: a = obj.LastAngle.Value - obj.FirstAngle.Value else: a = (360 - obj.FirstAngle.Value) + obj.LastAngle.Value su = True if hasattr(obj.ViewObject, "ShowUnit"): su = obj.ViewObject.ShowUnit if hasattr(obj.ViewObject, "Decimals"): self.string = DraftGui.displayExternal(a, obj.ViewObject.Decimals, 'Angle', su) else: self.string = DraftGui.displayExternal(a, None, 'Angle', su) if obj.ViewObject.Override: self.string = obj.ViewObject.Override.replace("$dim",\ self.string) self.text.string = self.text3d.string = utils.string_encode_coin( self.string) # check display mode try: m = obj.ViewObject.DisplayMode except: # swallow all exceptions here since it always fails on first run (Displaymode enum no set yet) m = ["2D", "3D"][utils.get_param("dimstyle", 0)] # set the arc if m == "3D": # calculate the spacing of the text spacing = (len(self.string) * obj.ViewObject.FontSize.Value) / 8.0 pts1 = [] cut = None pts2 = [] for i in range(arcsegs + 1): p = self.circle.valueAt(self.circle.FirstParameter + ( (self.circle.LastParameter - self.circle.FirstParameter) / arcsegs) * i) if (p.sub(mp)).Length <= spacing: if cut is None: cut = i else: if cut is None: pts1.append([p.x, p.y, p.z]) else: pts2.append([p.x, p.y, p.z]) self.coords.point.setValues(pts1 + pts2) i1 = len(pts1) i2 = i1 + len(pts2) self.arc.coordIndex.setValues( 0, len(pts1) + len(pts2) + 1, list(range(len(pts1))) + [-1] + list(range(i1, i2))) if (len(pts1) >= 3) and (len(pts2) >= 3): self.circle1 = Part.Arc( App.Vector(pts1[0][0], pts1[0][1], pts1[0][2]), App.Vector(pts1[1][0], pts1[1][1], pts1[1][2]), App.Vector(pts1[-1][0], pts1[-1][1], pts1[-1][2])).toShape() self.circle2 = Part.Arc( App.Vector(pts2[0][0], pts2[0][1], pts2[0][2]), App.Vector(pts2[1][0], pts2[1][1], pts2[1][2]), App.Vector(pts2[-1][0], pts2[-1][1], pts2[-1][2])).toShape() else: pts = [] for i in range(arcsegs + 1): p = self.circle.valueAt(self.circle.FirstParameter + ( (self.circle.LastParameter - self.circle.FirstParameter) / arcsegs) * i) pts.append([p.x, p.y, p.z]) self.coords.point.setValues(pts) self.arc.coordIndex.setValues(0, arcsegs + 1, list(range(arcsegs + 1))) # set the arrow coords and rotation self.trans1.translation.setValue((self.p2.x, self.p2.y, self.p2.z)) self.coord1.point.setValue((self.p2.x, self.p2.y, self.p2.z)) self.trans2.translation.setValue((self.p3.x, self.p3.y, self.p3.z)) self.coord2.point.setValue((self.p3.x, self.p3.y, self.p3.z)) # calculate small chords to make arrows look better arrowlength = 4 * obj.ViewObject.ArrowSize.Value u1 = (self.circle.valueAt(self.circle.FirstParameter + arrowlength) ).sub(self.circle.valueAt( self.circle.FirstParameter)).normalize() u2 = (self.circle.valueAt(self.circle.LastParameter)).sub( self.circle.valueAt(self.circle.LastParameter - arrowlength)).normalize() if hasattr(obj.ViewObject, "FlipArrows"): if obj.ViewObject.FlipArrows: u1 = u1.negative() u2 = u2.negative() w2 = self.circle.Curve.Axis w1 = w2.negative() v1 = w1.cross(u1) v2 = w2.cross(u2) q1 = App.Placement(DraftVecUtils.getPlaneRotation(u1, v1, w1)).Rotation.Q q2 = App.Placement(DraftVecUtils.getPlaneRotation(u2, v2, w2)).Rotation.Q self.trans1.rotation.setValue((q1[0], q1[1], q1[2], q1[3])) self.trans2.rotation.setValue((q2[0], q2[1], q2[2], q2[3])) # setting text pos & rot self.tbase = mp if hasattr(obj.ViewObject, "TextPosition"): if not DraftVecUtils.isNull(obj.ViewObject.TextPosition): self.tbase = obj.ViewObject.TextPosition u3 = ray.cross(norm).normalize() v3 = norm.cross(u3) r = App.Placement(DraftVecUtils.getPlaneRotation(u3, v3, norm)).Rotation offset = r.multVec(App.Vector(0, 1, 0)) if hasattr(obj.ViewObject, "TextSpacing"): offset = DraftVecUtils.scaleTo( offset, obj.ViewObject.TextSpacing.Value) else: offset = DraftVecUtils.scaleTo(offset, 0.05) if m == "3D": offset = offset.negative() self.tbase = self.tbase.add(offset) q = r.Q self.textpos.translation.setValue( [self.tbase.x, self.tbase.y, self.tbase.z]) self.textpos.rotation = coin.SbRotation(q[0], q[1], q[2], q[3]) # set the angle property if round(obj.Angle, utils.precision()) != round( a, utils.precision()): obj.Angle = a
def arc_through_to(self, through, to): points = (self.current_position, through, to) self.components.append( Part.Arc(*[self.vector(coordinates) for coordinates in points])) self.current_position = to
def edgeForCmd(cls, cmd, startPoint): """(cmd, startPoint). Returns an Edge representing the given command, assuming a given startPoint.""" endPoint = cls.commandEndPoint(cmd, startPoint) if (cmd.Name in cls.CmdMoveStraight) or (cmd.Name in cls.CmdMoveRapid): if cls.pointsCoincide(startPoint, endPoint): return None return Part.Edge(Part.LineSegment(startPoint, endPoint)) if cmd.Name in cls.CmdMoveArc: center = startPoint + cls.commandEndPoint(cmd, Vector(0, 0, 0), 'I', 'J', 'K') A = cls.xy(startPoint - center) B = cls.xy(endPoint - center) d = -B.x * A.y + B.y * A.x if cls.isRoughly(d, 0, 0.005): PathLog.debug("Half circle arc at: (%.2f, %.2f, %.2f)" % (center.x, center.y, center.z)) # we're dealing with half a circle here angle = cls.getAngle(A) + math.pi / 2 if cmd.Name in cls.CmdMoveCW: angle -= math.pi else: C = A + B angle = cls.getAngle(C) PathLog.debug( "Arc (%8f) at: (%.2f, %.2f, %.2f) -> angle=%f" % (d, center.x, center.y, center.z, angle / math.pi)) R = A.Length PathLog.debug( "arc: p1=(%.2f, %.2f) p2=(%.2f, %.2f) -> center=(%.2f, %.2f)" % (startPoint.x, startPoint.y, endPoint.x, endPoint.y, center.x, center.y)) PathLog.debug("arc: A=(%.2f, %.2f) B=(%.2f, %.2f) -> d=%.2f" % (A.x, A.y, B.x, B.y, d)) PathLog.debug("arc: R=%.2f angle=%.2f" % (R, angle / math.pi)) if cls.isRoughly(startPoint.z, endPoint.z): midPoint = center + Vector(math.cos(angle), math.sin(angle), 0) * R PathLog.debug( "arc: (%.2f, %.2f) -> (%.2f, %.2f) -> (%.2f, %.2f)" % (startPoint.x, startPoint.y, midPoint.x, midPoint.y, endPoint.x, endPoint.y)) return Part.Edge(Part.Arc(startPoint, midPoint, endPoint)) # It's a Helix #print('angle: A=%.2f B=%.2f' % (cls.getAngle(A)/math.pi, cls.getAngle(B)/math.pi)) if cmd.Name in cls.CmdMoveCW: cw = True else: cw = False angle = cls.diffAngle(cls.getAngle(A), cls.getAngle(B), 'CW' if cw else 'CCW') height = endPoint.z - startPoint.z pitch = height * math.fabs(2 * math.pi / angle) if angle > 0: cw = not cw #print("Helix: R=%.2f h=%.2f angle=%.2f pitch=%.2f" % (R, height, angle/math.pi, pitch)) helix = Part.makeHelix(pitch, height, R, 0, not cw) helix.rotate(Vector(), Vector(0, 0, 1), 180 * cls.getAngle(A) / math.pi) e = helix.Edges[0] helix.translate(startPoint - e.valueAt(e.FirstParameter)) return helix.Edges[0] return None
def makeArc(p): arc = Part.Arc(p[0], p[1], p[2]) return arc.toShape()
def inOutBoneCommands(self, bone, boneAngle, fixedLength): corner = bone.corner(self.toolRadius) bone.tip = bone.inChord.End # in case there is no bone PathLog.debug("corner = (%.2f, %.2f)" % (corner.x, corner.y)) #debugMarker(corner, 'corner', (1., 0., 1.), self.toolRadius) length = fixedLength if bone.obj.Incision == Incision.Custom: length = bone.obj.Custom if bone.obj.Incision == Incision.Adaptive: length = bone.adaptiveLength(boneAngle, self.toolRadius) if length == 0: PathLog.info("no bone after all ..") return [bone.lastCommand, bone.outChord.g1Command()] boneInChord = bone.inChord.move(length, boneAngle) boneOutChord = boneInChord.moveTo(bone.outChord.Start) #debugCircle(boneInChord.Start, self.toolRadius, 'boneStart') #debugCircle(boneInChord.End, self.toolRadius, 'boneEnd') bone.tip = boneInChord.End if bone.smooth == 0: return [ bone.lastCommand, boneInChord.g1Command(), boneOutChord.g1Command(), bone.outChord.g1Command() ] # reconstruct the corner and convert to an edge offset = corner - bone.inChord.End iChord = Chord(bone.inChord.Start + offset, bone.inChord.End + offset) oChord = Chord(bone.outChord.Start + offset, bone.outChord.End + offset) iLine = iChord.asLine() oLine = oChord.asLine() cornerShape = Part.Shape([iLine, oLine]) # construct a shape representing the cut made by the bone vt0 = FreeCAD.Vector(0, self.toolRadius, 0) vt1 = FreeCAD.Vector(length, self.toolRadius, 0) vb0 = FreeCAD.Vector(0, -self.toolRadius, 0) vb1 = FreeCAD.Vector(length, -self.toolRadius, 0) vm2 = FreeCAD.Vector(length + self.toolRadius, 0, 0) boneBot = Part.LineSegment(vb1, vb0) boneLid = Part.LineSegment(vb0, vt0) boneTop = Part.LineSegment(vt0, vt1) # what we actually want is an Arc - but findIntersect only returns the coincident if one exists # which really sucks because that's the one we're probably not interested in .... boneArc = Part.Arc(vt1, vm2, vb1) #boneArc = Part.Circle(FreeCAD.Vector(length, 0, 0), FreeCAD.Vector(0,0,1), self.toolRadius) boneWire = Part.Shape([boneTop, boneArc, boneBot, boneLid]) boneWire.rotate(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, 0, 1), boneAngle * 180 / math.pi) boneWire.translate(bone.inChord.End) self.boneShapes = [cornerShape, boneWire] bone.inCommands = self.smoothChordCommands(bone, bone.inChord, boneInChord, Part.Edge(iLine), boneWire, corner, bone.smooth & Smooth.In, (1., 0., 0.)) bone.outCommands = self.smoothChordCommands(bone, boneOutChord, bone.outChord, Part.Edge(oLine), boneWire, corner, bone.smooth & Smooth.Out, (0., 1., 0.)) return bone.inCommands + bone.outCommands
def part_arc_from_points_and_center(p_1, p_2, m): p_1, p_12, p_2 = arc_from_points_and_center(p_1, p_2, m) return Part.Arc(App.Vector(*p_1, 0.), App.Vector(*p_12, 0.), App.Vector(*p_2, 0.))
def execute(self, obj): "creates the panel shape" if self.clone(obj): return import Part, DraftGeomUtils # base tests if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.isNull(): return elif obj.Base.isDerivedFrom("Mesh::Feature"): if not obj.Base.Mesh.isSolid(): return else: if obj.Length.Value: length = obj.Length.Value else: return if obj.Width.Value: width = obj.Width.Value else: return if obj.Thickness.Value: thickness = obj.Thickness.Value else: if not obj.Base: return elif obj.Base.isDerivedFrom("Part::Feature"): if not obj.Base.Shape.Solids: return # creating base shape pl = obj.Placement base = None normal = None if hasattr(obj, "Normal"): if obj.Normal.Length > 0: normal = Vector(obj.Normal) normal.normalize() normal.multiply(thickness) baseprofile = None if obj.Base: base = obj.Base.Shape.copy() if not base.Solids: p = FreeCAD.Placement(obj.Base.Placement) if base.Faces: baseprofile = base if not normal: normal = baseprofile.Faces[0].normalAt( 0, 0).multiply(thickness) base = base.extrude(normal) elif base.Wires: fm = False if hasattr(obj, "FaceMaker"): if obj.FaceMaker != "None": try: base = Part.makeFace( base.Wires, "Part::FaceMaker" + str(obj.FaceMaker)) fm = True except: FreeCAD.Console.PrintError( translate("Arch", "Facemaker returned an error") + "\n") return if not fm: closed = True for w in base.Wires: if not w.isClosed(): closed = False if closed: baseprofile = ArchCommands.makeFace(base.Wires) if not normal: normal = baseprofile.normalAt( 0, 0).multiply(thickness) base = baseprofile.extrude(normal) elif obj.Base.isDerivedFrom("Mesh::Feature"): if obj.Base.Mesh.isSolid(): if obj.Base.Mesh.countComponents() == 1: sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh) if sh.isClosed() and sh.isValid() and sh.Solids: base = sh else: if not normal: normal = Vector(0, 0, 1).multiply(thickness) l2 = length / 2 or 0.5 w2 = width / 2 or 0.5 v1 = Vector(-l2, -w2, 0) v2 = Vector(l2, -w2, 0) v3 = Vector(l2, w2, 0) v4 = Vector(-l2, w2, 0) base = Part.makePolygon([v1, v2, v3, v4, v1]) baseprofile = Part.Face(base) base = baseprofile.extrude(normal) if hasattr(obj, "Area"): if baseprofile: obj.Area = baseprofile.Area if hasattr(obj, "WaveLength"): if baseprofile and obj.WaveLength.Value and obj.WaveHeight.Value: # corrugated element bb = baseprofile.BoundBox bb.enlarge(bb.DiagonalLength) p1 = Vector(bb.getPoint(0).x, bb.getPoint(0).y, bb.Center.z) if obj.WaveType == "Curved": p2 = p1.add( Vector(obj.WaveLength.Value / 2, 0, obj.WaveHeight.Value)) p3 = p2.add( Vector(obj.WaveLength.Value / 2, 0, -obj.WaveHeight.Value)) e1 = Part.Arc(p1, p2, p3).toShape() p4 = p3.add( Vector(obj.WaveLength.Value / 2, 0, -obj.WaveHeight.Value)) p5 = p4.add( Vector(obj.WaveLength.Value / 2, 0, obj.WaveHeight.Value)) e2 = Part.Arc(p3, p4, p5).toShape() else: if obj.WaveHeight.Value < obj.WaveLength.Value: p2 = p1.add( Vector(obj.WaveHeight.Value, 0, obj.WaveHeight.Value)) p3 = p2.add( Vector( obj.WaveLength.Value - 2 * obj.WaveHeight.Value, 0, 0)) p4 = p3.add( Vector(obj.WaveHeight.Value, 0, -obj.WaveHeight.Value)) e1 = Part.makePolygon([p1, p2, p3, p4]) p5 = p4.add( Vector(obj.WaveHeight.Value, 0, -obj.WaveHeight.Value)) p6 = p5.add( Vector( obj.WaveLength.Value - 2 * obj.WaveHeight.Value, 0, 0)) p7 = p6.add( Vector(obj.WaveHeight.Value, 0, obj.WaveHeight.Value)) e2 = Part.makePolygon([p4, p5, p6, p7]) else: p2 = p1.add( Vector(obj.WaveLength.Value / 2, 0, obj.WaveHeight.Value)) p3 = p2.add( Vector(obj.WaveLength.Value / 2, 0, -obj.WaveHeight.Value)) e1 = Part.makePolygon([p1, p2, p3]) p4 = p3.add( Vector(obj.WaveLength.Value / 2, 0, -obj.WaveHeight.Value)) p5 = p4.add( Vector(obj.WaveLength.Value / 2, 0, obj.WaveHeight.Value)) e2 = Part.makePolygon([p3, p4, p5]) edges = [e1, e2] for i in range(int(bb.XLength / (obj.WaveLength.Value * 2))): e1 = e1.copy() e1.translate(Vector(obj.WaveLength.Value * 2, 0, 0)) e2 = e2.copy() e2.translate(Vector(obj.WaveLength.Value * 2, 0, 0)) edges.extend([e1, e2]) basewire = Part.Wire(edges) baseface = basewire.extrude(Vector(0, bb.YLength, 0)) base = baseface.extrude(Vector(0, 0, thickness)) rot = FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), normal) base.rotate(bb.Center, rot.Axis, math.degrees(rot.Angle)) if obj.WaveDirection.Value: base.rotate(bb.Center, normal, obj.WaveDirection.Value) n1 = normal.negative().normalize().multiply( obj.WaveHeight.Value * 2) self.vol = baseprofile.copy() self.vol.translate(n1) self.vol = self.vol.extrude(n1.negative().multiply(2)) base = self.vol.common(base) base = base.removeSplitter() if not base: FreeCAD.Console.PrintError( transpate("Arch", "Error computing shape of ") + obj.Label + "\n") return False if base and (obj.Sheets > 1) and normal and thickness: bases = [base] for i in range(1, obj.Sheets): n = FreeCAD.Vector(normal).normalize().multiply(i * thickness) b = base.copy() b.translate(n) bases.append(b) base = Part.makeCompound(bases) if base and normal and hasattr(obj, "Offset"): if obj.Offset.Value: v = DraftVecUtils.scaleTo(normal, obj.Offset.Value) base.translate(v) # process subshapes base = self.processSubShapes(obj, base, pl) # applying if base: if not base.isNull(): if base.isValid() and base.Solids: if base.Volume < 0: base.reverse() if base.Volume < 0: FreeCAD.Console.PrintError( translate("Arch", "Couldn't compute a shape")) return base = base.removeSplitter() obj.Shape = base if not pl.isNull(): obj.Placement = pl
def superWireReverse(debuglist,closed=False): '''superWireReverse(debuglist,[closed]): forces a wire between edges that don't necessarily have coincident endpoints. If closed=True, wire will always be closed. debuglist has a tuple for every edge.The first entry is the edge, the second is the flag 'does not nedd to be inverted' ''' #taken from draftlibs def median(v1,v2): vd = v2.sub(v1) vd.scale(.5,.5,.5) return v1.add(vd) try: from DraftGeomUtils import findMidpoint except ImportError: #workaround for Version 0.12 from draftlibs.fcgeo import findMidpoint #workaround for Version 0.12 import Part #edges = sortEdges(edgeslist) print debuglist newedges = [] for i in range(len(debuglist)): curr = debuglist[i] if i == 0: if closed: prev = debuglist[-1] else: prev = None else: prev = debuglist[i-1] if i == (len(debuglist)-1): if closed: nexte = debuglist[0] else: nexte = None else: nexte = debuglist[i+1] print i,prev,curr,nexte if prev: if curr[0].Vertexes[-1*(not curr[1])].Point == \ prev[0].Vertexes[-1*prev[1]].Point: p1 = curr[0].Vertexes[-1*(not curr[1])].Point else: p1 = median(curr[0].Vertexes[-1*(not curr[1])].Point,\ prev[0].Vertexes[-1*prev[1]].Point) else: p1 = curr[0].Vertexes[-1*(not curr[1])].Point if nexte: if curr[0].Vertexes[-1*curr[1]].Point == \ nexte[0].Vertexes[-1*(not nexte[1])].Point: p2 = nexte[0].Vertexes[-1*(not nexte[1])].Point else: p2 = median(curr[0].Vertexes[-1*(curr[1])].Point,\ nexte[0].Vertexes[-1*(not nexte[1])].Point) else: p2 = curr[0].Vertexes[-1*(curr[1])].Point if isinstance(curr[0].Curve,Part.Line): print "line",p1,p2 newedges.append(Part.Line(p1,p2).toShape()) elif isinstance(curr[0].Curve,Part.Circle): p3 = findMidpoint(curr[0]) print "arc",p1,p3,p2 newedges.append(Part.Arc(p1,p3,p2).toShape()) else: print "Cannot superWire edges that are not lines or arcs" return None print newedges return Part.Wire(newedges)
import sys FREECADPATH = r"e:\FreeCAD 0.17x64\bin" sys.path.append(FREECADPATH) # шлях до бібліотек FreeCAD import math import FreeCAD as App # модуль для роботи з програмою import FreeCADGui as Gui # модуль для роботи з GUI import Part # workbench-модуль для створення і керування BRep об'єктами v1 = App.Vector(0, 0, 0) # вектор (або точка) v2 = App.Vector(0, 10, 0) v3 = App.Vector(5, 5, 0) l1 = Part.LineSegment(v1, v2) # лінія e1 = l1.toShape() # ребро # або e1=Part.makeLine((0,0,0),(0,10,0)) # ребро a1 = Part.Arc(v1, v3, v2) # дуга за трьома точками e2 = a1.toShape() # ребро # або e2=Part.makeCircle(5,App.Vector(0,5,0),App.Vector(0,0,1),-90,90) bs = Part.BSplineCurve() # B-сплайн bs.interpolate([(0, 0, 0), (0, 1, 1), (0, -1, 2)]) # шляхом інтерполяції # або #bs.approximate([(0,0,0),(0,1,1),(0,-1,2)]) # шляхом апроксимації #bs.buildFromPoles([(0,0,0),(0,1,1),(0,-1,2)]) # за списком полюсів e3 = bs.toShape() # ребро w1 = Part.Wire([e1, e2]) # цикл (сукупність ребер) f1 = Part.Face(w1) # грань trsf = App.Matrix() # матриця трансформації trsf.rotateZ(math.pi / 4) # повернути навколо осі z trsf.move(App.Vector(5, 0, 0)) # перемістити
def make_rounded_rectangle_aperture(aperture_height, aperture_width, corner_radius): """Creates a wire outline of a rectangle. aperture_height and aperture_width are the full height and width. Args: aperture_height (float): Total height of the aperture aperture_width (float): Total width of the aperture Returns: wire1 (FreeCAD wire definition): An outline description of the shape. face1 (FreeCAD face definition): A surface description of the shape. """ # Create the initial four vertices where line meets curve. v1 = Base.Vector(0, aperture_height / 2.0 - corner_radius, -aperture_width / 2.0) v2 = Base.Vector(0, aperture_height / 2.0, -aperture_width / 2.0 + corner_radius) v3 = Base.Vector(0, aperture_height / 2.0, aperture_width / 2.0 - corner_radius) v4 = Base.Vector(0, aperture_height / 2.0 - corner_radius, aperture_width / 2.0) v5 = Base.Vector(0, -aperture_height / 2.0 + corner_radius, aperture_width / 2.0) v6 = Base.Vector(0, -aperture_height / 2.0, aperture_width / 2.0 - corner_radius) v7 = Base.Vector(0, -aperture_height / 2.0, -aperture_width / 2.0 + corner_radius) v8 = Base.Vector(0, -aperture_height / 2.0 + corner_radius, -aperture_width / 2.0) # Create lines line1 = Part.LineSegment(v2, v3) line2 = Part.LineSegment(v4, v5) line3 = Part.LineSegment(v6, v7) line4 = Part.LineSegment(v8, v1) centre_curve_offset = corner_radius * (1 - 1 / sqrt(2)) vc1 = Base.Vector( 0, aperture_height / 2.0 - centre_curve_offset, -aperture_width / 2.0 + centre_curve_offset, ) vc2 = Base.Vector( 0, aperture_height / 2.0 - centre_curve_offset, aperture_width / 2.0 - centre_curve_offset, ) vc3 = Base.Vector( 0, -aperture_height / 2.0 + centre_curve_offset, aperture_width / 2.0 - centre_curve_offset, ) vc4 = Base.Vector( 0, -aperture_height / 2.0 + centre_curve_offset, -aperture_width / 2.0 + centre_curve_offset, ) arc1 = Part.Arc(v1, vc1, v2) arc2 = Part.Arc(v3, vc2, v4) arc3 = Part.Arc(v5, vc3, v6) arc4 = Part.Arc(v7, vc4, v8) # Make a shape shape1 = Part.Shape([arc1, line1, arc2, line2, arc3, line3, arc4, line4]) # Make a wire outline. wire1 = Part.Wire(shape1.Edges) # Make a face. face1 = Part.Face(wire1) return wire1, face1