def makeCone(cls, radius1, radius2, height, pnt=Vector(0, 0, 0), dir=Vector(0, 0, 1), angleDegrees=360): """ Make a cone with given radii and height By default pnt=Vector(0,0,0), dir=Vector(0,0,1) and angle=360' """ return Shape.cast(FreeCADPart.makeCone(radius1, radius2, height, pnt.wrapped, dir.wrapped, angleDegrees))
def revolve(cls, outerWire, innerWires, angleDegrees, axisStart, axisEnd): """ Attempt to revolve the list of wires into a solid in the provided direction :param outerWire: the outermost wire :param innerWires: a list of inner wires :param angleDegrees: the angle to revolve through. :type angleDegrees: float, anything less than 360 degrees will leave the shape open :param axisStart: the start point of the axis of rotation :type axisStart: tuple, a two tuple :param axisEnd: the end point of the axis of rotation :type axisEnd: tuple, a two tuple :return: a Solid object The wires must not intersect * all wires must be closed * there cannot be any intersecting or self-intersecting wires * wires must be listed from outside in * more than one levels of nesting is not supported reliably * the wire(s) that you're revolving cannot be centered This method will attempt to sort the wires, but there is much work remaining to make this method reliable. """ face = Face.makeFromWires(outerWire, innerWires) v1 = Vector(axisStart) v2 = Vector(axisEnd) v2 = v2 - v1 revol_builder = BRepPrimAPI_MakeRevol(face.wrapped, gp_Ax1(v1.toPnt(), v2.toDir()), angleDegrees * DEG2RAD, True) return cls(revol_builder.Shape())
def makeCylinder(cls, radius, height, pnt=Vector(0, 0, 0), dir=Vector(0, 0, 1), angleDegrees=360): """ makeCylinder(radius,height,[pnt,dir,angle]) -- Make a cylinder with a given radius and height By default pnt=Vector(0,0,0),dir=Vector(0,0,1) and angle=360' """ return Shape.cast(FreeCADPart.makeCylinder(radius, height, pnt.wrapped, dir.wrapped, angleDegrees))
def test_from_plane(self): plane = Plane(origin=(1,2,3), xDir=(0,1,0), normal=(1,0,0)) cs = CoordSystem.from_plane(plane) self.assertEqual(cs.origin, Vector(1,2,3)) self.assertEqual(cs.xDir, Vector(0,1,0)) self.assertEqual(cs.yDir, Vector(0,0,1)) self.assertEqual(cs.zDir, Vector(1,0,0))
def makePlane(cls, length, width, basePnt=(0, 0, 0), dir=(0, 0, 1)): basePnt = Vector(basePnt) dir = Vector(dir) pln_geom = gp_Pln(basePnt.toPnt(), dir.toDir()) return cls( BRepBuilderAPI_MakeFace(pln_geom, -width * 0.5, width * 0.5, -length * 0.5, length * 0.5).Face())
def makeCircle(cls, radius, pnt=(0, 0, 0), dir=(0, 0, 1), angle1=360.0, angle2=360): center = Vector(pnt) normal = Vector(dir) return Edge( FreeCADPart.makeCircle(radius, center.wrapped, normal.wrapped, angle1, angle2))
def __init__(self, *args): def sub(v1, v2): if isinstance(v1, Vertex): v1 = Vector(v1.X, v1.Y, v1.Z) if isinstance(v2, Vertex): v2 = Vector(v2.X, v2.Y, v2.Z) return (v1 - v2).normalized() if len(args) == 1 and isinstance(args[0], Shape): val = args[0] self.origin = val.Center() if val.geomType() in ["CIRCLE", "ELLIPSE"]: self.z_dir = val.normal() vertices = val.Vertices() if len(vertices) == 1: # full circle or ellipse # Use the vector defined by the circle's/ellipse's vertex and the origin as x direction self.x_dir = sub(vertices[0], self.origin) else: # arc # Use the vector defined by start and end of the arc as x direction self.x_dir = sub(vertices[1], vertices[0]) elif isinstance(val, Wire): self.z_dir = val.normal() vertices = val.Vertices() if len(vertices) == 1: # e.g. a single closed spline # Use the vector defined by the vertex and the origin as x direction self.x_dir = sub(vertices[0], self.origin) else: # Use the vector defined by the first two vertices as x direction self.x_dir = sub(vertices[1], vertices[0]) elif isinstance(val, Face): self.z_dir = val.normalAt(val.Center()) # x_dir will be derived from the local coord system of the underlying plane xd = val._geomAdaptor().Position().XDirection() self.x_dir = Vector(xd.X(), xd.Y(), xd.Z()) else: raise ValueError("Needs a Face, Wire, Circle or an Ellipse") else: c = lambda v: v if isinstance(v, Vector) else Vector(*v) self.origin = Vector(0, 0, 0) if len(args) == 0 else c(args[0]) self.x_dir = Vector(1, 0, 0) if len(args) <= 1 else c(args[1]) self.z_dir = Vector(0, 0, 1) if len(args) <= 2 else c(args[2]) self.y_dir = self.z_dir.cross(self.x_dir)
def makeBox(cls, length, width, height, pnt=Vector(0, 0, 0), dir=Vector(0, 0, 1)): """ makeBox(length,width,height,[pnt,dir]) -- Make a box located\nin pnt with the d imensions (length,width,height)\nBy default pnt=Vector(0,0,0) and dir=Vector(0,0,1)' """ return Shape.cast( FreeCADPart.makeBox(length, width, height, pnt.wrapped, dir.wrapped))
def makeBox(cls, length, width, height, pnt=Vector(0, 0, 0), dir=Vector(0, 0, 1)): """ makeBox(length,width,height,[pnt,dir]) -- Make a box located in pnt with the dimensions (length,width,height) By default pnt=Vector(0,0,0) and dir=Vector(0,0,1)' """ return cls( BRepPrimAPI_MakeBox(gp_Ax2(pnt.toPnt(), dir.toDir()), length, width, height).Shape())
def Center(self): # A Part.Shape object doesn't have the CenterOfMass function, but it's wrapped Solid(s) does if isinstance(self.wrapped, FreeCADPart.Shape): # If there are no Solids, we're probably dealing with a Face or something similar if len(self.Solids()) == 0: return Vector(self.wrapped.CenterOfMass) else: # TODO: compute the weighted average instead of using the first solid return Vector(self.Solids()[0].wrapped.CenterOfMass) elif isinstance(self.wrapped, FreeCADPart.Solid): return Vector(self.wrapped.CenterOfMass) else: raise ValueError("Cannot find the center of %s object type" % str(type(self.Solids()[0].wrapped)))
def Center(self): # A Part.Shape object doesn't have the CenterOfMass function, but it's wrapped Solid(s) does if isinstance(self.wrapped, FreeCADPart.Shape): # If there are no Solids, we're probably dealing with a Face or something similar if len(self.Solids()) == 0: return Vector(self.wrapped.CenterOfMass) elif len(self.Solids()) == 1: return Vector(self.Solids()[0].wrapped.CenterOfMass) elif len(self.Solids()) > 1: return self.CombinedCenter(self.Solids()) elif isinstance(self.wrapped, FreeCADPart.Solid): return Vector(self.wrapped.CenterOfMass) else: raise ValueError("Cannot find the center of %s object type" % str(type(self.Solids()[0].wrapped)))
def CenterOfBoundBox(self, tolerance = 0.1): self.wrapped.tessellate(tolerance) if isinstance(self.wrapped, FreeCADPart.Shape): # If there are no Solids, we're probably dealing with a Face or something similar if len(self.Solids()) == 0: return Vector(self.wrapped.BoundBox.Center) elif len(self.Solids()) == 1: return Vector(self.Solids()[0].wrapped.BoundBox.Center) elif len(self.Solids()) > 1: return self.CombinedCenterOfBoundBox(self.Solids()) elif isinstance(self.wrapped, FreeCADPart.Solid): return Vector(self.wrapped.BoundBox.Center) else: raise ValueError("Cannot find the center(BoundBox's) of %s object type" % str(type(self.Solids()[0].wrapped)))
def makeCylinder(cls, radius, height, pnt=Vector(0, 0, 0), dir=Vector(0, 0, 1), angleDegrees=360): """ makeCylinder(radius,height,[pnt,dir,angle]) -- Make a cylinder with a given radius and height By default pnt=Vector(0,0,0),dir=Vector(0,0,1) and angle=360' """ return cls( BRepPrimAPI_MakeCylinder(gp_Ax2(pnt.toPnt(), dir.toDir()), radius, height, angleDegrees * DEG2RAD).Shape())
def normalAt(self, locationVector=None): """ Computes the normal vector at the desired location on the face. :returns: a vector representing the direction :param locationVector: the location to compute the normal at. If none, the center of the face is used. :type locationVector: a vector that lies on the surface. """ # get the geometry surface = self._geomAdaptor() if locationVector is None: u0, u1, v0, v1 = self._uvBounds() u = 0.5 * (u0 + u1) v = 0.5 * (v0 + v1) else: # project point on surface projector = GeomAPI_ProjectPointOnSurf(locationVector.toPnt(), surface) u, v = projector.LowerDistanceParameters() p = gp_Pnt() vn = gp_Vec() BRepGProp_Face(self.wrapped).Normal(u, v, p, vn) return Vector(vn)
def tangentAt(self, locationVector=None): """ Compute tangent vector at the specified location. :param locationVector: location to use. Use the center point if None :return: tangent vector """ curve = self._geomAdaptor() if locationVector: raise NotImplementedError else: umin, umax = curve.FirstParameter(), curve.LastParameter() umid = 0.5 * (umin + umax) # TODO what are good parameters for those? curve_props = BRepLProp_CLProps(curve, 2, curve.Tolerance()) curve_props.SetParameter(umid) if curve_props.IsTangentDefined(): dir_handle = gp_Dir( ) # this is awkward due to C++ pass by ref in the API curve_props.Tangent(dir_handle) return Vector(dir_handle)
def makeSphere(cls, radius, pnt=Vector(0, 0, 0), dir=Vector(0, 0, 1), angleDegrees1=0, angleDegrees2=90, angleDegrees3=360): """ Make a sphere with a given radius By default pnt=Vector(0,0,0), dir=Vector(0,0,1), angle1=0, angle2=90 and angle3=360 """ return cls( BRepPrimAPI_MakeSphere(gp_Ax2(pnt.toPnt(), dir.toDir()), radius, angleDegrees1 * DEG2RAD, angleDegrees2 * DEG2RAD, angleDegrees3 * DEG2RAD).Shape())
def translate(self, vector): if type(vector) == tuple: vector = Vector(vector) tmp = self.wrapped.copy() tmp.translate(vector.wrapped) return Shape.cast(tmp)
def makeCone(cls, radius1, radius2, height, pnt=Vector(0, 0, 0), dir=Vector(0, 0, 1), angleDegrees=360): """ Make a cone with given radii and height By default pnt=Vector(0,0,0), dir=Vector(0,0,1) and angle=360' """ return cls( BRepPrimAPI_MakeCone(gp_Ax2(pnt.toPnt(), dir.toDir()), radius1, radius2, height, angleDegrees * DEG2RAD).Shape())
def rotate(self, startVector, endVector, angleDegrees): """ Rotates a shape around an axis :param startVector: start point of rotation axis either a 3-tuple or a Vector :param endVector: end point of rotation axis, either a 3-tuple or a Vector :param angleDegrees: angle to rotate, in degrees :return: a copy of the shape, rotated """ if type(startVector) == tuple: startVector = Vector(startVector) if type(endVector) == tuple: endVector = Vector(endVector) tmp = self.wrapped.copy() tmp.rotate(startVector.wrapped, endVector.wrapped, angleDegrees) return Shape.cast(tmp)
def makeHelix(cls, pitch, height, radius, center=Vector(0, 0, 0), dir=Vector(0, 0, 1), angle=360.0, lefthand=False): """ 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' """ # 1. build underlying cylindrical/conical surface if angle == 360.: geom_surf = Geom_CylindricalSurface( gp_Ax3(center.toPnt(), dir.toDir()), radius) else: geom_surf = Geom_ConicalSurface( gp_Ax3(center.toPnt(), dir.toDir()), angle * DEG2RAD, # TODO why no orientation? radius) # 2. construct an semgent in the u,v domain if lefthand: geom_line = Geom2d_Line(gp_Pnt2d(0.0, 0.0), gp_Dir2d(-2 * pi, pitch)) else: geom_line = Geom2d_Line(gp_Pnt2d(0.0, 0.0), gp_Dir2d(2 * pi, pitch)) # 3. put it together into a wire n_turns = height / pitch u_start = geom_line.Value(0.) u_stop = geom_line.Value(sqrt(n_turns * ((2 * pi)**2 + pitch**2))) geom_seg = GCE2d_MakeSegment(u_start, u_stop).Value() e = BRepBuilderAPI_MakeEdge(geom_seg, geom_surf.GetHandle()).Edge() # 4. Convert to wire and fix building 3d geom from 2d geom w = BRepBuilderAPI_MakeWire(e).Wire() breplib_BuildCurves3d(w) return cls(w)
def _getVector(self, pr): """ Translate parsed vector string into a CQ Vector """ if 'vector_dir' in pr: vec = pr.vector_dir return Vector(float(vec.x), float(vec.y), float(vec.z)) else: return self.axes[pr.simple_dir]
def translate(self, vector): if type(vector) == tuple: vector = Vector(vector) T = gp_Trsf() T.SetTranslation(vector.wrapped) return self._apply_transform(T)
def startPoint(self): """ :return: a vector representing the start poing of this edge Note, circles may have the start and end points the same """ # work around freecad bug where valueAt is unreliable curve = self.wrapped.Curve return Vector(curve.value(self.wrapped.ParameterRange[0]))
def tangentAt(self, locationVector=None): """ Compute tangent vector at the specified location. :param locationVector: location to use. Use the center point if None :return: tangent vector """ if locationVector is None: locationVector = self.Center() p = self.wrapped.Curve.parameter(locationVector.wrapped) return Vector(self.wrapped.tangentAt(p))
def rotate(self, startVector, endVector, angleDegrees): """ Rotates a shape around an axis :param startVector: start point of rotation axis either a 3-tuple or a Vector :param endVector: end point of rotation axis, either a 3-tuple or a Vector :param angleDegrees: angle to rotate, in degrees :return: a copy of the shape, rotated """ if type(startVector) == tuple: startVector = Vector(startVector) if type(endVector) == tuple: endVector = Vector(endVector) T = gp_Trsf() T.SetRotation( gp_Ax1(startVector.toPnt(), (endVector - startVector).toDir()), angleDegrees) return self._apply_transform(T)
def makeCircle(cls, radius, pnt=Vector(0, 0, 0), dir=Vector(0, 0, 1), angle1=360.0, angle2=360): """ """ pnt = Vector(pnt) dir = Vector(dir) circle_gp = gp_Circ(gp_Ax2(pnt.toPnt(), dir.toDir()), radius) if angle1 == angle2: # full circle case return cls(BRepBuilderAPI_MakeEdge(circle_gp).Edge()) else: # arc case circle_geom = GC_MakeArcOfCircle(circle_gp, angle1 * DEG2RAD, angle2 * DEG2RAD, True).Value() return cls(BRepBuilderAPI_MakeEdge(circle_geom).Edge())
def mirror(self, mirrorPlane="XY", basePointVector=(0, 0, 0)): if mirrorPlane == "XY" or mirrorPlane== "YX": mirrorPlaneNormalVector = FreeCAD.Base.Vector(0, 0, 1) elif mirrorPlane == "XZ" or mirrorPlane == "ZX": mirrorPlaneNormalVector = FreeCAD.Base.Vector(0, 1, 0) elif mirrorPlane == "YZ" or mirrorPlane == "ZY": mirrorPlaneNormalVector = FreeCAD.Base.Vector(1, 0, 0) if type(basePointVector) == tuple: basePointVector = Vector(basePointVector) return Shape.cast(self.wrapped.mirror(basePointVector.wrapped, mirrorPlaneNormalVector))
def centerOfMass(obj): """ Calculates the 'mass' of an object. """ Properties = GProp_GProps() calc_function = shape_properties_LUT[obj.wrapped.ShapeType()] if calc_function: calc_function(obj.wrapped, Properties) return Vector(Properties.CentreOfMass()) else: raise NotImplemented
def startPoint(self): """ :return: a vector representing the start poing of this edge Note, circles may have the start and end points the same """ curve = self._geomAdaptor() umin = curve.FirstParameter() return Vector(curve.Value(umin))
def makeWedge(cls, xmin, ymin, zmin, z2min, x2min, xmax, ymax, zmax, z2max, x2max, pnt=Vector(0, 0, 0), dir=Vector(0, 0, 1)): """ Make a wedge located in pnt By default pnt=Vector(0,0,0) and dir=Vector(0,0,1) """ return cls( BRepPrimAPI_MakeWedge(gp_Ax2(pnt.toPnt(), dir.toDir()), xmin, ymin, zmin, z2min, x2min, xmax, ymax, zmax, z2max, x2max).Solid())