def makeHelix(cls, pitch, height, radius, angle=360.0): """ Make a helix with a given pitch, height and radius By default a cylindrical surface is used to create the helix. If the fourth parameter is set (the apex given in degree) a conical surface is used instead' """ return Wire(FreeCADPart.makeHelix(pitch, height, radius, angle))
def generateModel(self): self.status.updateStatus("Creating .FCStd file") doc = FreeCAD.newDocument(self.fileName) pitch = math.pi * self.module * self.teeth / math.tan(self.helixAngle) self.status.updateStatus("Calculating parameters for helix") pitchRadius = self.module * self.teeth / 2 self.status.updateStatus("Drafting helix") helix = Part.makeHelix(pitch, self.faceWidth * self.module, pitchRadius, 0, self.leftHand, False) doc.addObject("Part::Feature", "helix") doc.helix.Shape = helix self.status.updateStatus("Generating involute profile") doc.addObject("Part::Sweep", "helicalGear") profile, height=InvoluteProfile.generateProfile(self.pressureAngle,\ self.module,self.teeth,\ self.faceWidth,\ self.clearance,self.fillet,\ self.status) self.status.updateStatus("Sweeping involute profile") doc.helicalGear.Sections = doc.findObjects("Part::Feature", profile.Name) doc.helicalGear.Spine = doc.helix doc.helicalGear.Solid = True doc.helicalGear.Frenet = True FreeCADGui.ActiveDocument.getObject(profile.Name).Visibility = False FreeCADGui.ActiveDocument.getObject("helix").Visibility = False doc.recompute() self.status.updateStatus("Done")
def helical_path(pitch, length, radius, angle=0, lefthand=False): # FIXME: update to master branch of cadquery wire = cadquery.Wire(FreeCADPart.makeHelix(pitch, length, radius, angle, lefthand)) #wire = cadquery.Wire.makeHelix(pitch, length, radius, angle=angle, lefthand=lefthand) shape = cadquery.Wire.combine([wire]) path = cadquery.Workplane("XY").newObject([shape]) return path
def __init__(self, doc, name='helix'): self.data = { 'len lo': 70., # mm 'len up': 120., # mm 'int diameter': 36., # mm 'thick': 1., # mm } len_lo = self.data['len lo'] # blocking thread (pas de vis de blocage) radius = self.data['int diameter'] / 2 helix = Part.makeHelix(4., 16., radius) p0 = (radius, 0, 0) p1 = (radius, 0, 3) p2 = (radius - 1, 0, 2) p3 = (radius - 1, 0, 1) e0 = Part.makeLine(p0, p1) e1 = Part.makeLine(p1, p2) e2 = Part.makeLine(p2, p3) e3 = Part.makeLine(p3, p0) section = Part.Wire([e0, e1, e2, e3]) helix = Part.Wire(helix).makePipeShell([section], 1, 1) helix.translate(Vector(0, 0, len_lo - 20)) helix = helix.fuse(helix) comp = helix MecaComponent.__init__(self, doc, comp, name, (1., 1., 0.))
def helical_path(pitch, length, radius, angle=0, lefthand=False): # FIXME: update to master branch of cadquery wire = cadquery.Wire( FreeCADPart.makeHelix(pitch, length, radius, angle, lefthand)) #wire = cadquery.Wire.makeHelix(pitch, length, radius, angle=angle, lefthand=lefthand) shape = cadquery.Wire.combine([wire]) path = cadquery.Workplane("XY").newObject([shape]) return path
def make_helix(pitch, height, radius, apex_angle=0): # FIXME: in FreeCAD pydoc, there is also "makeLongHelix", # which seems to be more suitable here because it said to be "multi-edge"; # However, in my experiments, makeLongHelix always makes # a helix with exactly one turn, while makeHelix makes as many # turns as necessary. wire = Part.makeHelix(pitch, height, radius, apex_angle) fc_edge = wire.Edges[0] curve = SvSolidEdgeCurve(fc_edge) return curve
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 d == 0: # 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) R = A.Length #print("arc: p1=(%.2f, %.2f) p2=(%.2f, %.2f) -> center=(%.2f, %.2f)" % (startPoint.x, startPoint.y, endPoint.x, endPoint.y, center.x, center.y)) #print("arc: A=(%.2f, %.2f) B=(%.2f, %.2f) -> d=%.2f" % (A.x, A.y, B.x, B.y, d)) #print("arc: R=%.2f angle=%.2f" % (R, angle/math.pi)) if startPoint.z == endPoint.z: midPoint = center + FreeCAD.Vector(math.cos(angle), math.sin(angle), 0) * R 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 edgeForCmd(cmd, startPoint): """(cmd, startPoint). Returns an Edge representing the given command, assuming a given startPoint.""" endPoint = commandEndPoint(cmd, startPoint) if (cmd.Name in CmdMoveStraight) or (cmd.Name in CmdMoveRapid): if pointsCoincide(startPoint, endPoint): return None return Part.Edge(Part.LineSegment(startPoint, endPoint)) if cmd.Name in CmdMoveArc: center = startPoint + commandEndPoint(cmd, Vector(0,0,0), 'I', 'J', 'K') A = xy(startPoint - center) B = xy(endPoint - center) d = -B.x * A.y + B.y * A.x if 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 = getAngle(A) + math.pi/2 if cmd.Name in CmdMoveCW: angle -= math.pi else: C = A + B angle = 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 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' % (getAngle(A)/math.pi, getAngle(B)/math.pi)) if cmd.Name in CmdMoveCW: cw = True else: cw = False angle = diffAngle(getAngle(A), 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 * getAngle(A) / math.pi) e = helix.Edges[0] helix.translate(startPoint - e.valueAt(e.FirstParameter)) return helix.Edges[0] return None
def edgeForCmd(cmd, startPoint): """edgeForCmd(cmd, startPoint). Returns an Edge representing the given command, assuming a given startPoint.""" endPoint = commandEndPoint(cmd, startPoint) if (cmd.Name in CmdMoveStraight) or (cmd.Name in CmdMoveRapid): if pointsCoincide(startPoint, endPoint): return None return Part.Edge(Part.LineSegment(startPoint, endPoint)) if cmd.Name in CmdMoveArc: center = startPoint + commandEndPoint(cmd, Vector(0,0,0), 'I', 'J', 'K') A = xy(startPoint - center) B = xy(endPoint - center) d = -B.x * A.y + B.y * A.x if 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 = getAngle(A) + math.pi/2 if cmd.Name in CmdMoveCW: angle -= math.pi else: C = A + B angle = 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 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' % (getAngle(A)/math.pi, getAngle(B)/math.pi)) if cmd.Name in CmdMoveCW: cw = True else: cw = False angle = diffAngle(getAngle(A), 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 * getAngle(A) / math.pi) e = helix.Edges[0] helix.translate(startPoint - e.valueAt(e.FirstParameter)) return helix.Edges[0] return None
def makeHelix(cls, pitch, height, radius, angle=0, lefthand=False, heightstyle=False): """ Make a helix along +z axis :param pitch: displacement of 1 turn measured along surface. :param height: full length of helix surface (measured sraight along surface's face) :param radius: starting radius of helix :param angle: if > 0, conical surface is used instead of a cylindrical. (angle < 0 not supported) :param lefthand: if True, helix direction is reversed :param heightstyle: if True, pitch and height are measured parallel to z-axis """ # FreeCAD doc: https://www.freecadweb.org/wiki/Part_API (search for makeHelix) return Wire(FreeCADPart.makeHelix(pitch, height, radius, angle, lefthand, heightstyle))
def createGeometry(self, fp): import FreeCAD, Part, math, sys if fp.Base and fp.Height and fp.Base.Shape.isValid(): solids = [] for lower_face in fp.Base.Shape.Faces: upper_face = lower_face.copy() face_transform = FreeCAD.Matrix() face_transform.rotateZ(math.radians(fp.Angle.Value)) face_transform.scale(fp.Scale[0], fp.Scale[1], 1.0) face_transform.move(FreeCAD.Vector(0, 0, fp.Height.Value)) upper_face.transformShape( face_transform, False, True) # True to check for non-uniform scaling spine = Part.makePolygon([(0, 0, 0), (0, 0, fp.Height.Value)]) if fp.Angle.Value == 0.0: auxiliary_spine = Part.makePolygon([ (1, 1, 0), (fp.Scale[0], fp.Scale[1], fp.Height.Value) ]) else: num_revolutions = abs(fp.Angle.Value) / 360.0 pitch = fp.Height.Value / num_revolutions height = fp.Height.Value radius = 1.0 if fp.Angle.Value < 0.0: left_handed = True else: left_handed = False auxiliary_spine = Part.makeHelix(pitch, height, radius, 0.0, left_handed) faces = [lower_face, upper_face] for wire1, wire2 in zip(lower_face.Wires, upper_face.Wires): pipe_shell = Part.BRepOffsetAPI.MakePipeShell(spine) pipe_shell.setSpineSupport(spine) pipe_shell.add(wire1) pipe_shell.add(wire2) pipe_shell.setAuxiliarySpine(auxiliary_spine, True, 0) print(pipe_shell.getStatus()) assert (pipe_shell.isReady()) pipe_shell.build() faces.extend(pipe_shell.shape().Faces) try: fullshell = Part.Shell(faces) solid = Part.Solid(fullshell) if solid.Volume < 0: solid.reverse() assert (solid.Volume >= 0) solids.append(solid) except Part.OCCError: solids.append(Part.Compound(faces)) fp.Shape = Part.Compound(solids)
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.CmdMoveFast): 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 d == 0: # 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) R = A.Length #print("arc: p1=(%.2f, %.2f) p2=(%.2f, %.2f) -> center=(%.2f, %.2f)" % (startPoint.x, startPoint.y, endPoint.x, endPoint.y, center.x, center.y)) #print("arc: A=(%.2f, %.2f) B=(%.2f, %.2f) -> d=%.2f" % (A.x, A.y, B.x, B.y, d)) #print("arc: R=%.2f angle=%.2f" % (R, angle/math.pi)) if startPoint.z == endPoint.z: midPoint = center + FreeCAD.Vector(math.cos(angle), math.sin(angle), 0) * R 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 generateModel(self): XAXIS = FreeCAD.Vector(1, 0, 0) INTERFERANCE = 0.1 ORIGIN = FreeCAD.Vector(0, 0, 0) COPY = True # doc=FreeCAD.newDocument(self.fileName); doc = FreeCAD.newDocument("Worm Gear") #temporary file name for testing # tooth=InvoluteProfile.generateTooth(self.pressureAngle,self.module,\ # self.teeth,self.clearance,\ # self.fillet); ### #temporary variables for testing MODULE = 4 TEETH = 18 PRESSURE_ANGLE = 20 CLEARANCE = 0.5 FILLET = 0.25 clearance = CLEARANCE * MODULE ### tooth = InvoluteProfile.generateTooth(PRESSURE_ANGLE, MODULE, TEETH, CLEARANCE, FILLET) tooth = Draft.rotate(tooth, 90, ORIGIN, XAXIS, not (COPY)) pitch = math.pi * MODULE helixRadius = MODULE * TEETH * math.cos( math.radians(PRESSURE_ANGLE)) / 2 - clearance helix = Part.makeHelix(pitch, MODULE * 20, helixRadius) doc.addObject("Part::Feature", "helix") doc.helix.Shape = helix doc.addObject("Part::Sweep", "threads") doc.threads.Sections = doc.findObjects("Part::Feature", tooth.Name) doc.threads.Spine = doc.helix doc.threads.Solid = True doc.threads.Frenet = True worm = Part.makeCylinder(tooth.Shape.BoundBox.XMin + INTERFERANCE, MODULE * 20) doc.addObject("Part::Feature", "worm") doc.worm.Shape = worm doc.addObject("Part::MultiFuse", "wormGear") doc.wormGear.Shapes = [ doc.threads, doc.worm, ] FreeCADGui.ActiveDocument.getObject(tooth.Name).Visibility = False FreeCADGui.ActiveDocument.getObject("helix").Visibility = False FreeCADGui.ActiveDocument.getObject("threads").Visibility = False FreeCADGui.ActiveDocument.getObject("worm").Visibility = False doc.recompute()
def execute(self, fp): pitch = fp.Pitch radius = fp.Diameter/2 height = fp.Height barradius = fp.BarDiameter/2 myhelix=Part.makeHelix(pitch,height,radius) g=myhelix.Edges[0].Curve c=Part.Circle() c.Center=g.value(0) # start point of the helix c.Axis=(0,1,0) c.Radius=barradius p=c.toShape() section = Part.Wire([p]) makeSolid=1 #change to 1 to make a solid isFrenet=1 myspring=Part.Wire(myhelix).makePipeShell([section],makeSolid,isFrenet) fp.Shape = myspring
def drawsolid(d,l,p,wd): pitch = p; height= l; radius = d/2.0;barradius = wd/2 myhelix=Part.makeHelix(pitch,height,radius) g=myhelix.Edges[0].Curve c=Part.Circle() c.Center=g.value(0) # start point of the helix c.Axis=(0,1,0) c.Radius=barradius p=c.toShape() section = Part.Wire([p]) makeSolid=True isFrenet=True myspring=Part.Wire(myhelix).makePipeShell([section],makeSolid,True) solidlist= [myspring] result = '' result+= exportWebGL.getHTML(solidlist) return result
def execute(self, fp): pitch = fp.Pitch radius = fp.Diameter / 2 height = fp.Height barradius = fp.BarDiameter / 2 myhelix = Part.makeHelix(pitch, height, radius) g = myhelix.Edges[0].Curve c = Part.Circle() c.Center = g.value(0) # start point of the helix c.Axis = (0, 1, 0) c.Radius = barradius p = c.toShape() section = Part.Wire([p]) makeSolid = 1 #change to 1 to make a solid isFrenet = 1 myspring = Part.Wire(myhelix).makePipeShell([section], makeSolid, isFrenet) fp.Shape = myspring
def drawsolid(d, l, p, wd): pitch = p height = l radius = d / 2.0 barradius = wd / 2 myhelix = Part.makeHelix(pitch, height, radius) g = myhelix.Edges[0].Curve c = Part.Circle() c.Center = g.value(0) # start point of the helix c.Axis = (0, 1, 0) c.Radius = barradius p = c.toShape() section = Part.Wire([p]) makeSolid = True isFrenet = True myspring = Part.Wire(myhelix).makePipeShell([section], makeSolid, True) solidlist = [myspring] result = '' result += exportWebGL.getHTML(solidlist) return result
def cone_setup(doc, profil, data): """create all the shapes needed for the cone parts""" # if the final shapes already existed (true if one shape exists) # return them immediatly cone_top_obj = doc.getObject('_cone_top_base') cone_side_obj = doc.getObject('_cone_side_base') cone_struct_obj = doc.getObject('_cone_struct_base') cone_top_thread_obj = doc.getObject('_cone_top_thread') cone_struct_thread_obj = doc.getObject('_cone_struct_thread') if cone_top_obj: cone_top = cone_top_obj.Shape.copy() cone_side0 = cone_side_obj.Shape.copy() cone_side1 = cone_side_obj.Shape.copy() cone_side2 = cone_side_obj.Shape.copy() cone_struct = cone_struct_obj.Shape.copy() cone_top_thread = cone_top_thread_obj.Shape.copy() cone_struct_thread = cone_struct_thread_obj.Shape.copy() return cone_top, cone_side0, cone_side1, cone_side2, cone_struct, \ cone_top_thread, cone_struct_thread side = profil['side'] radius = profil['radius'] diam_int = data['diameter'] diam_ext = data['diameter'] + data['thick'] length = data['len_lo'] + data['len_hi'] struct_thick = data['struct_thick'] # to modify the sphere to make it a ellipsoid matrix = Matrix() matrix.scale(1., 1., length / (diam_ext / 2)) # to suppress the lower half of the sphere/ellipsoid lower = Part.makeBox(diam_ext, diam_ext, length) lower.translate(Vector(-diam_ext / 2, -diam_ext / 2, 0)) gui_doc = FreeCADGui.ActiveDocument # make the external shape base of the cone sphere = Part.makeSphere(diam_ext / 2) sphere = sphere.transformGeometry(matrix) cone_base_ext = sphere.common(lower) cone_base_ext_obj = doc.addObject("Part::Feature", '_cone_base_ext') cone_base_ext_obj.Shape = cone_base_ext gui_doc.getObject('_cone_base_ext').Visibility = False # make the internal shape base of the cone sphere = Part.makeSphere(diam_int / 2) sphere = sphere.transformGeometry(matrix) cone_base_int = sphere.common(lower) cone_base_int_obj = doc.addObject("Part::Feature", '_cone_base_int') cone_base_int_obj.Shape = cone_base_int gui_doc.getObject('_cone_base_int').Visibility = False # make the skin skin = cone_base_ext.cut(cone_base_int) skin_obj = doc.addObject("Part::Feature", '_skin') skin_obj.Shape = skin gui_doc.getObject('_skin').Visibility = False # use profile shapes to make suppressed parts of the skin # full profil part shape = [] shape.append(Vector(radius - 10, side / 2, 0)) shape.append(Vector(radius + diam_ext, side / 2, 0)) shape.append(Vector(radius + diam_ext, -side / 2, 0)) shape.append(Vector(radius - 10, -side / 2, 0)) shape.append(Vector(radius - 10, side / 2, 0)) wire = Part.makePolygon(shape) face = Part.Face(wire) # make the volume long_cut_base = face.extrude(Vector(0, 0, length)) long_cut_obj = doc.addObject("Part::Feature", '_long_cut_base') long_cut_obj.Shape = long_cut_base gui_doc.getObject('_long_cut_base').Visibility = False # full profil part shape = [] shape.append(Vector(radius, side / 2, 0)) shape.append(Vector(radius + diam_ext, side / 2, 0)) shape.append(Vector(radius + diam_ext, -side / 2, 0)) shape.append(Vector(radius, -side / 2, 0)) shape.append(Vector(radius, side / 2, 0)) wire = Part.makePolygon(shape) face = Part.Face(wire) # make the volume short_cut_base = face.extrude(Vector(0, 0, data['len_lo'])) short_cut_obj = doc.addObject("Part::Feature", '_short_cut_base') short_cut_obj.Shape = short_cut_base gui_doc.getObject('_short_cut_base').Visibility = False # create 1/3 cylinder cylinder = Part.makeCylinder(diam_ext / 2, length, Vector(0, 0, 0), Vector(0, 0, 1), 120) cylinder_obj = doc.addObject("Part::Feature", '_cylinder_1_3') cylinder_obj.Shape = cylinder gui_doc.getObject('_cylinder_1_3').Visibility = False # thread bases radius_ext = diam_ext / 2 - struct_thick - 5 thread_ext = Part.makeHelix(8, struct_thick - 8, radius_ext) radius_int = diam_ext / 2 - struct_thick - 9 thread_int = Part.makeHelix(8, struct_thick, radius_int) # tube to make the space for threads tube_thread_ext = Part.makeCylinder(radius_ext, struct_thick) tube_thread_int = Part.makeCylinder(radius_int, struct_thick) tube_thread = tube_thread_ext.cut(tube_thread_int) tube_thread_obj = doc.addObject("Part::Feature", '_tube_thread') tube_thread_obj.Shape = tube_thread gui_doc.getObject('_tube_thread').Visibility = False # tube to cut the top of the structure tube_cut_ext = Part.makeCylinder(diam_ext / 2 - struct_thick / 2, struct_thick) tube_cut_int = tube_thread_int tube_cut = tube_cut_ext.cut(tube_cut_int) tube_cut_obj = doc.addObject("Part::Feature", '_tube_cut') tube_cut_obj.Shape = tube_cut gui_doc.getObject('_tube_cut').Visibility = False # tube to make the locking of the cone tube_lock_0 = Part.makeCylinder(diam_ext / 2 - struct_thick - 2, struct_thick / 2) tube_lock_1 = Part.makeCylinder(diam_ext / 2 - struct_thick + 2, struct_thick / 2) tube_lock_2 = Part.makeCylinder(diam_ext / 2, struct_thick / 4) tube_lock_int = tube_lock_1.cut(tube_lock_0) tube_lock_int.translate(Vector(0, 0, data['len_lo'] - 0.25 * data['struct_thick'])) tube_lock_obj = doc.addObject("Part::Feature", '_tube_lock_int') tube_lock_obj.Shape = tube_lock_int gui_doc.getObject('_tube_lock_int').Visibility = False tube_lock_ext = tube_lock_2.cut(tube_lock_0) tube_lock_ext.translate(Vector(0, 0, data['len_lo'] - 0.25 * data['struct_thick'])) tube_lock_obj = doc.addObject("Part::Feature", '_tube_lock_ext') tube_lock_obj.Shape = tube_lock_ext gui_doc.getObject('_tube_lock_ext').Visibility = False # make cone top part cone_top = cone_top_make(doc, gui_doc, data, skin, lower, cone_base_int, tube_cut, tube_thread, tube_lock_int) cone_top = cone_top.copy() cone_side = cone_side_make(doc, gui_doc, skin, lower, data, cone_base_int, long_cut_base, cylinder, tube_lock_int, tube_lock_ext) cone_side0 = cone_side.copy() cone_side0.rotate(Vector(0, 0, 0), Vector(0, 0, 1), 0) cone_side1 = cone_side.copy() cone_side1.rotate(Vector(0, 0, 0), Vector(0, 0, 1), 120) cone_side2 = cone_side.copy() cone_side2.rotate(Vector(0, 0, 0), Vector(0, 0, 1), 240) cone_struct = cone_struct_make(doc, gui_doc, cone_base_ext, short_cut_base, data, cone_top, cone_side, tube_thread) # internal thread profile p0 = (radius_int, 0, 0) p1 = (radius_int + 4, 0, 4) p2 = (radius_int, 0, 8) e0 = Part.makeLine(p0, p1) e1 = Part.makeLine(p1, p2) e2 = Part.makeLine(p2, p0) section = Part.Wire([e0, e1, e2]) cone_struct_thread = Part.Wire(thread_int).makePipeShell([section], 1, 1) cone_struct_thread_obj = doc.addObject("Part::Feature", '_cone_struct_thread') cone_struct_thread_obj.Shape = cone_struct_thread.copy() gui_doc.getObject('_cone_struct_thread').Visibility = False # external thread profile p0 = (radius_ext, 0, 0) p1 = (radius_ext - 4, 0, 4) p2 = (radius_ext, 0, 8) e0 = Part.makeLine(p0, p1) e1 = Part.makeLine(p1, p2) e2 = Part.makeLine(p2, p0) section = Part.Wire([e0, e1, e2]) cone_top_thread = Part.Wire(thread_ext).makePipeShell([section], 1, 1) cone_top_thread_obj = doc.addObject("Part::Feature", '_cone_top_thread') cone_top_thread_obj.Shape = cone_top_thread.copy() gui_doc.getObject('_cone_top_thread').Visibility = False return cone_top, cone_side0, cone_side1, cone_side2, cone_struct, \ cone_top_thread, cone_struct_thread
def createGeometry(self, fp): import FreeCAD, Part, math, sys if fp.Base and fp.Height and fp.Base.Shape.isValid(): solids = [] for lower_face in fp.Base.Shape.Faces: upper_face = lower_face.copy() face_transform = FreeCAD.Matrix() face_transform.rotateZ(math.radians(fp.Angle.Value)) face_transform.scale(fp.Scale[0], fp.Scale[1], 1.0) face_transform.move(FreeCAD.Vector(0, 0, fp.Height.Value)) upper_face.transformShape( face_transform, False, True) # True to check for non-uniform scaling spine = Part.makePolygon([(0, 0, 0), (0, 0, fp.Height.Value)]) if fp.Angle.Value == 0.0: auxiliary_spine = Part.makePolygon([ (1, 1, 0), (fp.Scale[0], fp.Scale[1], fp.Height.Value) ]) else: num_revolutions = abs(fp.Angle.Value) / 360.0 pitch = fp.Height.Value / num_revolutions height = fp.Height.Value radius = 1.0 if fp.Angle.Value < 0.0: left_handed = True else: left_handed = False auxiliary_spine = Part.makeHelix(pitch, height, radius, 0.0, left_handed) # OCC versions before 7.5 had a problem with using a helix as the auxilliary spine, so approximate # it piecewise occ_version = Part.OCC_VERSION.split(".") if int(occ_version[0]) <= 7 and int(occ_version[1]) < 5: num_points = int( max(3, num_revolutions * 36)) # Every ten degrees is adequate wire = auxiliary_spine.Wires[0] points = wire.discretize(Number=num_points) auxiliary_spine = Part.makePolygon(points) faces = [lower_face, upper_face] for wire1, wire2 in zip(lower_face.Wires, upper_face.Wires): pipe_shell = Part.BRepOffsetAPI.MakePipeShell(spine) pipe_shell.setSpineSupport(spine) pipe_shell.add(wire1) pipe_shell.add(wire2) pipe_shell.setAuxiliarySpine(auxiliary_spine, True, 0) print(pipe_shell.getStatus()) assert (pipe_shell.isReady()) pipe_shell.build() faces.extend(pipe_shell.shape().Faces) try: fullshell = Part.Shell(faces) solid = Part.Solid(fullshell) if solid.Volume < 0: solid.reverse() assert (solid.Volume >= 0) solids.append(solid) except Part.OCCError: solids.append(Part.Compound(faces)) fp.Shape = Part.Compound(solids)