def findEdge(anEdge, aList): """Return True if edge is found in list of edges.""" for e in range(len(aList)): if str(anEdge.Curve) == str(aList[e].Curve): if DraftVecUtils.equals(anEdge.Vertexes[0].Point, aList[e].Vertexes[0].Point): if DraftVecUtils.equals(anEdge.Vertexes[-1].Point, aList[e].Vertexes[-1].Point): return e return None
def edge_to_path(lastpt, edge, Z): if isinstance(edge.Curve, Part.Circle): # FreeCAD.Console.PrintMessage("arc\n") arcstartpt = edge.valueAt(edge.FirstParameter) midpt = edge.valueAt( (edge.FirstParameter + edge.LastParameter) * 0.5) arcendpt = edge.valueAt(edge.LastParameter) # arcchkpt = edge.valueAt(edge.LastParameter * .99) if DraftVecUtils.equals(lastpt, arcstartpt): startpt = arcstartpt endpt = arcendpt else: startpt = arcendpt endpt = arcstartpt center = edge.Curve.Center relcenter = center.sub(lastpt) # start point and end point fall together in the given output precision? if fmt(startpt.x) == fmt(endpt.x) and fmt(startpt.y) == fmt( endpt.y): if edge.Length < 0.5 * 2 * math.pi * edge.Curve.Radius: # because it is a very small circle -> omit, as that gcode would produce a full circle return endpt, "" else: # it is an actual full circle, emit a line for this pass # FreeCAD.Console.PrintMessage("arc startpt= " + str(startpt)+ "\n") # FreeCAD.Console.PrintMessage("arc midpt= " + str(midpt)+ "\n") # FreeCAD.Console.PrintMessage("arc endpt= " + str(endpt)+ "\n") arc_cw = check_clockwise([(startpt.x, startpt.y), (midpt.x, midpt.y), (endpt.x, endpt.y)]) # FreeCAD.Console.PrintMessage("arc_cw="+ str(arc_cw)+"\n") if arc_cw: output = "G2" else: output = "G3" output += " X" + str(fmt(endpt.x)) + " Y" + \ str(fmt(endpt.y)) + " Z" + str(fmt(Z)) + " F" + str(hf) output += " I" + str(fmt(relcenter.x)) + " J" + \ str(fmt(relcenter.y)) + " K" + str(fmt(relcenter.z)) output += "\n" lastpt = endpt # FreeCAD.Console.PrintMessage("last pt arc= " + str(lastpt)+ "\n") else: point = edge.Vertexes[-1].Point if DraftVecUtils.equals(point, lastpt): # edges can come flipped point = edge.Vertexes[0].Point output = "G1 X" + str(fmt(point.x)) + " Y" + str(fmt(point.y)) + \ " Z" + str(fmt(Z)) + " F" + str(hf) + "\n" lastpt = point # FreeCAD.Console.PrintMessage("line\n") # FreeCAD.Console.PrintMessage("last pt line= " + str(lastpt)+ "\n") return lastpt, output
def convert(toolpath, Side, radius, clockwise=False, Z=0.0, firstedge=None, vf=1.0, hf=2.0): '''convert(toolpath,Side,radius,clockwise=False,Z=0.0,firstedge=None) Converts lines and arcs to G1,G2,G3 moves. Returns a string.''' last = None output = "" # create the path from the offset shape for edge in toolpath: if not last: # set the first point last = edge.Vertexes[0].Point # FreeCAD.Console.PrintMessage("last pt= " + str(last)+ "\n") output += "G1 X" + str(fmt(last.x)) + " Y" + str(fmt(last.y)) + \ " Z" + str(fmt(Z)) + " F" + str(vf) + "\n" if isinstance(edge.Curve, Part.Circle): # FreeCAD.Console.PrintMessage("arc\n") arcstartpt = edge.valueAt(edge.FirstParameter) midpt = edge.valueAt( (edge.FirstParameter + edge.LastParameter) * 0.5) arcendpt = edge.valueAt(edge.LastParameter) # arcchkpt = edge.valueAt(edge.LastParameter * .99) if DraftVecUtils.equals(last, arcstartpt): startpt = arcstartpt endpt = arcendpt else: startpt = arcendpt endpt = arcstartpt center = edge.Curve.Center relcenter = center.sub(last) # FreeCAD.Console.PrintMessage("arc startpt= " + str(startpt)+ "\n") # FreeCAD.Console.PrintMessage("arc midpt= " + str(midpt)+ "\n") # FreeCAD.Console.PrintMessage("arc endpt= " + str(endpt)+ "\n") arc_cw = check_clockwise( [(startpt.x, startpt.y), (midpt.x, midpt.y), (endpt.x, endpt.y)]) # FreeCAD.Console.PrintMessage("arc_cw="+ str(arc_cw)+"\n") if arc_cw: output += "G2" else: output += "G3" output += " X" + str(fmt(endpt.x)) + " Y" + \ str(fmt(endpt.y)) + " Z" + str(fmt(Z)) + " F" + str(hf) output += " I" + str(fmt(relcenter.x)) + " J" + \ str(fmt(relcenter.y)) + " K" + str(fmt(relcenter.z)) output += "\n" last = endpt # FreeCAD.Console.PrintMessage("last pt arc= " + str(last)+ "\n") else: point = edge.Vertexes[-1].Point if DraftVecUtils.equals(point, last): # edges can come flipped point = edge.Vertexes[0].Point output += "G1 X" + str(fmt(point.x)) + " Y" + str(fmt(point.y)) + \ " Z" + str(fmt(Z)) + " F" + str(hf) + "\n" last = point # FreeCAD.Console.PrintMessage("line\n") # FreeCAD.Console.PrintMessage("last pt line= " + str(last)+ "\n") return output
def alignToFace(self, shape, offset=0): """Align the plane to a face. It uses the center of mass of the face as `position`, and its normal in the center of the face as `axis`, then calls `alignToPointAndAxis(position, axis, offset)`. If the face is a quadrilateral, then it adjusts the position of the plane according to its reported X direction and Y direction. Also set `weak` to `False`. Parameter -------- shape : Part.Face A shape of type `'Face'`. offset : float Defaults to zero. A value which will be used to offset the plane in the direction of its `axis`. Returns ------- bool `True` if the operation was successful, and `False` if the shape is not a `'Face'`. See Also -------- alignToPointAndAxis, DraftGeomUtils.getQuad """ # Set face to the unique selected face, if found if shape.ShapeType == 'Face': self.alignToPointAndAxis(shape.Faces[0].CenterOfMass, shape.Faces[0].normalAt(0, 0), offset) import DraftGeomUtils q = DraftGeomUtils.getQuad(shape) if q: self.u = q[1] self.v = q[2] if not DraftVecUtils.equals(self.u.cross(self.v), self.axis): self.u = q[2] self.v = q[1] if DraftVecUtils.equals(self.u, Vector(0, 0, 1)): # the X axis is vertical: rotate 90 degrees self.u, self.v = self.v.negative(), self.u elif DraftVecUtils.equals(self.u, Vector(0, 0, -1)): self.u, self.v = self.v, self.u.negative() self.weak = False return True else: return False
def edge_to_path(lastpt, edge, Z): if isinstance(edge.Curve, Part.Circle): # FreeCAD.Console.PrintMessage("arc\n") arcstartpt = edge.valueAt(edge.FirstParameter) midpt = edge.valueAt( (edge.FirstParameter + edge.LastParameter) * 0.5) arcendpt = edge.valueAt(edge.LastParameter) # arcchkpt = edge.valueAt(edge.LastParameter * .99) if DraftVecUtils.equals(lastpt, arcstartpt): startpt = arcstartpt endpt = arcendpt else: startpt = arcendpt endpt = arcstartpt center = edge.Curve.Center relcenter = center.sub(lastpt) # start point and end point fall together in the given output precision? if fmt(startpt.x) == fmt(endpt.x) and fmt(startpt.y) == fmt(endpt.y): if edge.Length < 0.5 * 2 * math.pi * edge.Curve.Radius: # because it is a very small circle -> omit, as that gcode would produce a full circle return endpt, "" else: # it is an actual full circle, emit a line for this pass # FreeCAD.Console.PrintMessage("arc startpt= " + str(startpt)+ "\n") # FreeCAD.Console.PrintMessage("arc midpt= " + str(midpt)+ "\n") # FreeCAD.Console.PrintMessage("arc endpt= " + str(endpt)+ "\n") arc_cw = check_clockwise( [(startpt.x, startpt.y), (midpt.x, midpt.y), (endpt.x, endpt.y)]) # FreeCAD.Console.PrintMessage("arc_cw="+ str(arc_cw)+"\n") if arc_cw: output = "G2" else: output = "G3" output += " X" + str(fmt(endpt.x)) + " Y" + \ str(fmt(endpt.y)) + " Z" + str(fmt(Z)) + " F" + str(hf) output += " I" + str(fmt(relcenter.x)) + " J" + \ str(fmt(relcenter.y)) + " K" + str(fmt(relcenter.z)) output += "\n" lastpt = endpt # FreeCAD.Console.PrintMessage("last pt arc= " + str(lastpt)+ "\n") else: point = edge.Vertexes[-1].Point if DraftVecUtils.equals(point, lastpt): # edges can come flipped point = edge.Vertexes[0].Point output = "G1 X" + str(fmt(point.x)) + " Y" + str(fmt(point.y)) + \ " Z" + str(fmt(Z)) + " F" + str(hf) + "\n" lastpt = point # FreeCAD.Console.PrintMessage("line\n") # FreeCAD.Console.PrintMessage("last pt line= " + str(lastpt)+ "\n") return lastpt, output
def isSameEdge(e1, e2): """isSameEdge(e1,e2): return True if the 2 edges are both lines or arcs/circles and have the same points - inspired by Yorik's function isSameLine""" if not (isinstance(e1.Curve, Part.Line) or isinstance(e1.Curve, Part.Circle)): return False if not (isinstance(e2.Curve, Part.Line) or isinstance(e2.Curve, Part.Circle)): return False if type(e1.Curve) != type(e2.Curve): return False if isinstance(e1.Curve, Part.Line): if (DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[0].Point)) and \ (DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[-1].Point)): return True elif (DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[0].Point)) and \ (DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[-1].Point)): return True if isinstance(e1.Curve, Part.Circle): center = False radius = False endpts = False if e1.Curve.Center == e2.Curve.Center: center = True if e1.Curve.Radius == e2.Curve.Radius: radius = True if (DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[0].Point)) and \ (DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[-1].Point)): endpts = True elif (DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[0].Point)) and \ (DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[-1].Point)): endpts = True if (center and radius and endpts): return True return False
def isSameEdge(e1, e2): """isSameEdge(e1,e2): return True if the 2 edges are both lines or arcs/circles and have the same points - inspired by Yorik's function isSameLine""" if not (isinstance(e1.Curve, Part.Line) or isinstance(e1.Curve, Part.Circle)): return False if not (isinstance(e2.Curve, Part.Line) or isinstance(e2.Curve, Part.Circle)): return False if type(e1.Curve) <> type(e2.Curve): return False if isinstance(e1.Curve, Part.Line): if (DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[0].Point)) and \ (DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[-1].Point)): return True elif (DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[0].Point)) and \ (DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[-1].Point)): return True if isinstance(e1.Curve, Part.Circle): center = False radius = False endpts = False if e1.Curve.Center == e2.Curve.Center: center = True if e1.Curve.Radius == e2.Curve.Radius: radius = True if (DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[0].Point)) and \ (DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[-1].Point)): endpts = True elif (DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[0].Point)) and \ (DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[-1].Point)): endpts = True if (center and radius and endpts): return True return False
def join_two_wires(wire1, wire2): """join_two_wires(object, object): joins two wires if they share a common point as a start or an end. """ wire1AbsPoints = [wire1.Placement.multVec(point) for point in wire1.Points] wire2AbsPoints = [wire2.Placement.multVec(point) for point in wire2.Points] if ((DraftVecUtils.equals(wire1AbsPoints[0], wire2AbsPoints[-1]) and DraftVecUtils.equals(wire1AbsPoints[-1], wire2AbsPoints[0])) or (DraftVecUtils.equals(wire1AbsPoints[0], wire2AbsPoints[0]) and DraftVecUtils.equals(wire1AbsPoints[-1], wire2AbsPoints[-1]))): wire2AbsPoints.pop() wire1.Closed = True elif DraftVecUtils.equals(wire1AbsPoints[0], wire2AbsPoints[0]): wire1AbsPoints = list(reversed(wire1AbsPoints)) elif DraftVecUtils.equals(wire1AbsPoints[0], wire2AbsPoints[-1]): wire1AbsPoints = list(reversed(wire1AbsPoints)) wire2AbsPoints = list(reversed(wire2AbsPoints)) elif DraftVecUtils.equals(wire1AbsPoints[-1], wire2AbsPoints[-1]): wire2AbsPoints = list(reversed(wire2AbsPoints)) elif DraftVecUtils.equals(wire1AbsPoints[-1], wire2AbsPoints[0]): pass else: return False wire2AbsPoints.pop(0) wire1.Points = ([wire1.Placement.inverse().multVec(point) for point in wire1AbsPoints] + [wire1.Placement.inverse().multVec(point) for point in wire2AbsPoints]) App.ActiveDocument.removeObject(wire2.Name) return True
def touches(e1, e2): """Return True if two edges connect at the edges.""" if len(e1.Vertexes) < 2: return False if len(e2.Vertexes) < 2: return False if DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[0].Point): return True if DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[-1].Point): return True if DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[0].Point): return True if DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[-1].Point): return True return False
def isSameLine(e1, e2): """Return True if the 2 edges are lines and have the same points.""" if not isinstance(e1.Curve, Part.LineSegment): return False if not isinstance(e2.Curve, Part.LineSegment): return False if (DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[0].Point) and DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[-1].Point)): return True elif (DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[0].Point) and DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[-1].Point)): return True return False
def calc(self): import Part if (self.p1 != None) and (self.p2 != None): points = [ DraftVecUtils.tup(self.p1, True), DraftVecUtils.tup(self.p2, True), DraftVecUtils.tup(self.p1, True), DraftVecUtils.tup(self.p2, True), ] if self.p3 != None: p1 = self.p1 p4 = self.p2 if DraftVecUtils.equals(p1, p4): proj = None else: base = Part.Line(p1, p4).toShape() proj = DraftGeomUtils.findDistance(self.p3, base) if not proj: p2 = p1 p3 = p4 else: p2 = p1.add(proj.negative()) p3 = p4.add(proj.negative()) points = [DraftVecUtils.tup(p1), DraftVecUtils.tup(p2), DraftVecUtils.tup(p3), DraftVecUtils.tup(p4)] self.coords.point.setValues(0, 4, points)
def circleInversion(circle, circle2): """Circle inversion of a circle, inverting the center point. Returns the new circle created from the inverted center of circle2. """ if geomType(circle) != "Circle" or geomType(circle2) != "Circle": print("debug: circleInversion bad parameters! Must be circles.") return None cen1 = circle.Curve.Center cen2 = circle2.Curve.Center rad2 = circle2.Curve.Radius if DraftVecUtils.equals(cen1, cen2): return None invCen2 = pointInversion(circle, cen2) pointOnCircle2 = App.Vector.add(cen2, App.Vector(rad2, 0, 0)) invPointOnCircle2 = pointInversion(circle, pointOnCircle2) return Part.Circle(invCen2, NORM, DraftVecUtils.dist(invCen2, invPointOnCircle2))
def pointInversion(circle, point): """Return the circle inversion of a point. It will return `None` if the given point is equal to the center of the circle. """ if geomType(circle) != "Circle" or isinstance(point, App.Vector): print("debug: pointInversion bad parameters!") return None cen = circle.Curve.Center rad = circle.Curve.Radius if DraftVecUtils.equals(cen, point): return None # Inverse the distance of the point # dist(cen -> P) = r^2 / dist(cen -> invP) dist = DraftVecUtils.dist(point, cen) invDist = rad**2 / dist invPoint = App.Vector(0, 0, point.z) invPoint.x = cen.x + (point.x - cen.x) * invDist / dist invPoint.y = cen.y + (point.y - cen.y) * invDist / dist return invPoint
def edg(p1, p2): """Return an edge from 2 vectors.""" if isinstance(p1, FreeCAD.Vector) and isinstance(p2, FreeCAD.Vector): if DraftVecUtils.equals(p1, p2): return None return Part.LineSegment(p1, p2).toShape()
def execute(self,obj): import Part import DraftGeomUtils if obj.Base and obj.PathObj: pl = obj.Placement #placement of whole pathArray if obj.PathSubs: w = self.getWireFromSubs(obj) elif (hasattr(obj.PathObj.Shape,'Wires') and obj.PathObj.Shape.Wires): w = obj.PathObj.Shape.Wires[0] elif obj.PathObj.Shape.Edges: w = Part.Wire(obj.PathObj.Shape.Edges) else: App.Console.PrintLog ("PathArray.execute: path " + obj.PathObj.Name + " has no edges\n") return if (hasattr(obj, "TangentVector")) and (obj.AlignMode == "Tangent") and (obj.Align): basePlacement = obj.Base.Shape.Placement baseRotation = basePlacement.Rotation stdX = App.Vector(1.0, 0.0, 0.0) #default TangentVector if (not DraftVecUtils.equals(stdX, obj.TangentVector)): preRotation = App.Rotation(stdX, obj.TangentVector) #make rotation from X to TangentVector netRotation = baseRotation.multiply(preRotation) else: netRotation = baseRotation base = calculatePlacementsOnPath( netRotation,w,obj.Count,obj.Xlate,obj.Align, obj.AlignMode, obj.ForceVertical, obj.VerticalVector) else: base = calculatePlacementsOnPath( obj.Base.Shape.Placement.Rotation,w,obj.Count,obj.Xlate,obj.Align, obj.AlignMode, obj.ForceVertical, obj.VerticalVector) return super(PathArray, self).buildShape(obj, pl, base)
def numericRadius(self, rad): """Validate the entry radius in the user interface. This function is called by the toolbar or taskpanel interface when a valid radius has been entered in the input field. """ import DraftGeomUtils plane = App.DraftWorkingPlane if self.step == 1: self.rad = rad if len(self.tangents) == 2: cir = DraftGeomUtils.circleFrom2tan1rad(self.tangents[0], self.tangents[1], rad) if self.center: _c = DraftGeomUtils.findClosestCircle(self.center, cir) self.center = _c.Center else: self.center = cir[-1].Center elif self.tangents and self.tanpoints: cir = DraftGeomUtils.circleFrom1tan1pt1rad(self.tangents[0], self.tanpoints[0], rad) if self.center: _c = DraftGeomUtils.findClosestCircle(self.center, cir) self.center = _c.Center else: self.center = cir[-1].Center if self.closedCircle: self.drawArc() else: self.step = 2 self.arctrack.setCenter(self.center) self.ui.labelRadius.setText(translate("draft", "Start angle")) self.ui.radiusValue.setToolTip(translate("draft", "Start angle")) self.linetrack.p1(self.center) self.linetrack.on() self.ui.radiusValue.setText("") self.ui.radiusValue.setFocus() _msg(translate("draft", "Pick start angle")) elif self.step == 2: self.ui.labelRadius.setText(translate("draft", "Aperture angle")) self.ui.radiusValue.setToolTip(translate("draft", "Aperture angle")) self.firstangle = math.radians(rad) if DraftVecUtils.equals(plane.axis, App.Vector(1, 0, 0)): u = App.Vector(0, self.rad, 0) else: u = DraftVecUtils.scaleTo(App.Vector(1, 0, 0).cross(plane.axis), self.rad) urotated = DraftVecUtils.rotate(u, math.radians(rad), plane.axis) self.arctrack.setStartAngle(self.firstangle) self.step = 3 self.ui.radiusValue.setText("") self.ui.radiusValue.setFocus() _msg(translate("draft", "Pick aperture angle")) else: self.updateAngle(rad) self.angle = math.radians(rad) self.step = 4 self.drawArc()
def execute(self, obj): """Method run when the object is recomputed. Move its children if its placement has changed since the previous recompute. Set any child Walls and Structures to have the height of the floor if they have not Height value set. """ # move children with this floor if hasattr(obj, "Placement"): if not hasattr(self, "OldPlacement"): self.OldPlacement = obj.Placement.copy() else: pl = obj.Placement.copy() if not DraftVecUtils.equals(pl.Base, self.OldPlacement.Base): print("placement moved") delta = pl.Base.sub(self.OldPlacement.Base) for o in obj.Group: if hasattr(o, "Placement"): o.Placement.move(delta) self.OldPlacement = pl # adjust childrens heights if obj.Height.Value: for o in obj.Group: if Draft.getType(o) in ["Wall", "Structure"]: if not o.Height.Value: o.Proxy.execute(o)
def pointInversion(circle, point): """Circle inversion of a point. pointInversion(Circle, Vector) Will calculate the inversed point an return it. If the given point is equal to the center of the circle "None" will be returned. See also: http://en.wikipedia.org/wiki/Inversive_geometry """ if (geomType(circle) == "Circle") and isinstance(point, FreeCAD.Vector): cen = circle.Curve.Center rad = circle.Curve.Radius if DraftVecUtils.equals(cen, point): return None # Inverse the distance of the point # dist(cen -> P) = r^2 / dist(cen -> invP) dist = DraftVecUtils.dist(point, cen) invDist = rad**2 / d invPoint = Vector(0, 0, point.z) invPoint.x = cen.x + (point.x - cen.x) * invDist / dist invPoint.y = cen.y + (point.y - cen.y) * invDist / dist return invPoint else: FreeCAD.Console.PrintMessage("debug: pointInversion bad parameters!\n") return None
def circleInversion(circle, circle2): """ pointInversion(Circle, Circle) Circle inversion of a circle. """ if (geomType(circle) == "Circle") and (geomType(circle2) == "Circle"): cen1 = circle.Curve.Center rad1 = circle.Curve.Radius if DraftVecUtils.equals(cen1, point): return None invCen2 = Inversion(circle, circle2.Curve.Center) pointOnCircle2 = Vector.add(circle2.Curve.Center, Vector(circle2.Curve.Radius, 0, 0)) invPointOnCircle2 = Inversion(circle, pointOnCircle2) return Part.Circle(invCen2, norm, DraftVecUtils.dist(invCen2, invPointOnCircle2)) else: FreeCAD.Console.PrintMessage( "debug: circleInversion bad parameters!\n") return None
def calc(self): import Part if (self.p1 != None) and (self.p2 != None): points = [DraftVecUtils.tup(self.p1,True),DraftVecUtils.tup(self.p2,True),\ DraftVecUtils.tup(self.p1,True),DraftVecUtils.tup(self.p2,True)] if self.p3 != None: p1 = self.p1 p4 = self.p2 if DraftVecUtils.equals(p1, p4): proj = None else: base = Part.LineSegment(p1, p4).toShape() proj = DraftGeomUtils.findDistance(self.p3, base) if not proj: p2 = p1 p3 = p4 else: p2 = p1.add(proj.negative()) p3 = p4.add(proj.negative()) points = [ DraftVecUtils.tup(p1), DraftVecUtils.tup(p2), DraftVecUtils.tup(p3), DraftVecUtils.tup(p4) ] self.coords.point.setValues(0, 4, points)
def circleFrom3LineTangents(edge1, edge2, edge3): """Return a list of circles from three edges. It calculates up to 6 possible centers. """ def rot(ed): geo = Part.LineSegment(v1(ed), v1(ed).add(DraftVecUtils.rotate(vec(ed), math.pi/2))) return geo.toShape() bis12 = angleBisection(edge1, edge2) bis23 = angleBisection(edge2, edge3) bis31 = angleBisection(edge3, edge1) intersections = [] intsec = findIntersection(bis12, bis23, True, True) if intsec: radius = findDistance(intsec[0], edge1).Length intersections.append(Part.Circle(intsec[0], NORM, radius)) intsec = findIntersection(bis23, bis31, True, True) if intsec: radius = findDistance(intsec[0], edge1).Length intersections.append(Part.Circle(intsec[0], NORM, radius)) intsec = findIntersection(bis31, bis12, True, True) if intsec: radius = findDistance(intsec[0], edge1).Length intersections.append(Part.Circle(intsec[0], NORM, radius)) intsec = findIntersection(rot(bis12), rot(bis23), True, True) if intsec: radius = findDistance(intsec[0], edge1).Length intersections.append(Part.Circle(intsec[0], NORM, radius)) intsec = findIntersection(rot(bis23), rot(bis31), True, True) if intsec: radius = findDistance(intsec[0], edge1).Length intersections.append(Part.Circle(intsec[0], NORM, radius)) intsec = findIntersection(rot(bis31), rot(bis12), True, True) if intsec: radius = findDistance(intsec[0], edge1).Length intersections.append(Part.Circle(intsec[0], NORM, radius)) circles = [] for intsec in intersections: exists = False for cir in circles: if DraftVecUtils.equals(cir.Center, intsec.Center): exists = True break if not exists: circles.append(intsec) if circles: return circles else: return None
def execute(self,obj): import Part pl = obj.Placement shapes = [] if obj.isDerivedFrom("Part::Part2DObject"): # if our clone is 2D, make sure all its linked geometry is 2D too for o in obj.Objects: if not o.getLinkedObject(True).isDerivedFrom("Part::Part2DObject"): App.Console.PrintWarning("Warning 2D Clone "+obj.Name+" contains 3D geometry") return for o in obj.Objects: sh = Part.getShape(o) if not sh.isNull(): shapes.append(sh) if shapes: sh = self.join(obj, shapes) m = App.Matrix() if hasattr(obj,"Scale") and not sh.isNull(): sx,sy,sz = obj.Scale if not DraftVecUtils.equals(obj.Scale,App.Vector(1, 1, 1)): op = sh.Placement sh.Placement = App.Placement() m.scale(obj.Scale) if sx == sy == sz: sh.transformShape(m) else: sh = sh.transformGeometry(m) sh.Placement = op obj.Shape = sh obj.Placement = pl if hasattr(obj,"positionBySupport"): obj.positionBySupport()
def execute(self, obj): """Execute when the object is created or recomputed.""" if not obj.Base or not obj.PathObject: return # placement of entire PathArray object array_placement = obj.Placement w = self.get_wires(obj.PathObject, obj.PathSubelements) if not w: _err(obj.PathObject.Label + translate("draft", ", path object doesn't have 'Edges'.")) return base_rotation = obj.Base.Shape.Placement.Rotation final_rotation = base_rotation if (obj.Align and obj.AlignMode == "Tangent" and hasattr(obj, "TangentVector")): Xaxis = App.Vector(1.0, 0.0, 0.0) # default TangentVector if not DraftVecUtils.equals(Xaxis, obj.TangentVector): # make rotation from TangentVector to X pre_rotation = App.Rotation(obj.TangentVector, Xaxis) final_rotation = base_rotation.multiply(pre_rotation) copy_placements = placements_on_path(final_rotation, w, obj.Count, obj.ExtraTranslation, obj.Align, obj.AlignMode, obj.ForceVertical, obj.VerticalVector) return super(PathArray, self).buildShape(obj, array_placement, copy_placements)
def isReallyClosed(wire): """Check if a wire is really closed.""" # TODO yet to find out why not use wire.isClosed() direct, # in isReallyClosed(wire) # Remark out below - Found not true if a vertex is used again # in a wire in sketch (e.g. wire with shape like 'd', 'b', 'g', ...) # if len(wire.Edges) == len(wire.Vertexes): return True # Found cases where Wire[-1] are not 'last' vertexes # e.g. Part.Wire( Part.__sortEdges__(<Rectangle Geometries>.toShape())) # aboveWire.isClosed() == True, but Wire[-1] are the 3rd vertex # for the rectangle - use Edges[i].Vertexes[0/1] instead length = len(wire.Edges) # Test if it is full circle / ellipse first if length == 1: if len(wire.Edges[0].Vertexes) == 1: return True # This is a closed wire - full circle/ellipse else: # TODO Should be False if 1 edge but not single vertex, correct? # No need to test further below. return False # If more than 1 edge, further test below v1 = wire.Edges[0].Vertexes[0].Point # v1 = wire.Vertexes[0].Point v2 = wire.Edges[length - 1].Vertexes[1].Point # v2 = wire.Vertexes[-1].Point if DraftVecUtils.equals(v1, v2): return True return False
def findRadicalAxis(circle1, circle2): """Calculate the radical axis of two circles. On the radical axis (also called power line) of two circles any tangents drawn from a point on the axis to both circles have the same length. http://en.wikipedia.org/wiki/Radical_axis http://mathworld.wolfram.com/RadicalLine.html See Also -------- findRadicalCenter """ if (geomType(circle1) == "Circle") and (geomType(circle2) == "Circle"): print("debug: findRadicalAxis bad parameters! Must be circles.") return None if DraftVecUtils.equals(circle1.Curve.Center, circle2.Curve.Center): return None r1 = circle1.Curve.Radius r2 = circle1.Curve.Radius cen1 = circle1.Curve.Center # dist .. the distance from cen1 to cen2. dist = DraftVecUtils.dist(cen1, circle2.Curve.Center) cenDir = cen1.sub(circle2.Curve.Center) cenDir.normalize() # Get the perpedicular vector. perpCenDir = cenDir.cross(App.Vector(0, 0, 1)) perpCenDir.normalize() # J ... The radical center. # K ... The point where the cadical axis crosses the line of cen1->cen2. # k1 ... Distance from cen1 to K. # k2 ... Distance from cen2 to K. # dist = k1 + k2 k1 = (dist + (r1**2 - r2**2) / dist) / 2.0 # k2 = dist - k1 K = App.Vector.add(cen1, cenDir.multiply(k1)) # K_ .. A point somewhere between K and J; actually with a distance # of 1 unit from K. K_ = App.Vector.add(K, perpCenDir) # Original code didn't specify the value of origin nor dir, # so this is a guess: # radicalAxis = Part.LineSegment(K, Vector.add(origin, dir)) origin = App.Vector(0, 0, 0) radicalAxis = Part.LineSegment(K, App.Vector.add(origin, perpCenDir)) if radicalAxis: return radicalAxis else: return None
def findHomotheticCenterOfCircles(circle1, circle2): """Calculate the homothetic center(s) of two circles. http://en.wikipedia.org/wiki/Homothetic_center http://mathworld.wolfram.com/HomotheticCenter.html """ if (geomType(circle1) == "Circle") and (geomType(circle2) == "Circle"): if DraftVecUtils.equals(circle1.Curve.Center, circle2.Curve.Center): return None cen1_cen2 = Part.LineSegment(circle1.Curve.Center, circle2.Curve.Center).toShape() cenDir = vec(cen1_cen2) cenDir.normalize() # Get the perpedicular vector. perpCenDir = cenDir.cross(Vector(0, 0, 1)) perpCenDir.normalize() # Get point on first circle p1 = Vector.add(circle1.Curve.Center, Vector(perpCenDir).multiply(circle1.Curve.Radius)) centers = [] # Calculate inner homothetic center # Get point on second circle p2_inner = Vector.add( circle1.Curve.Center, Vector(perpCenDir).multiply(-circle1.Curve.Radius)) hCenterInner = DraftVecUtils.intersect(circle1.Curve.Center, circle2.Curve.Center, p1, p2_inner, True, True) if hCenterInner: centers.append(hCenterInner) # Calculate outer homothetic center (only exists of the circles have different radii) if circle1.Curve.Radius != circle2.Curve.Radius: # Get point on second circle p2_outer = Vector.add( circle1.Curve.Center, Vector(perpCenDir).multiply(circle1.Curve.Radius)) hCenterOuter = DraftVecUtils.intersect(circle1.Curve.Center, circle2.Curve.Center, p1, p2_outer, True, True) if hCenterOuter: centers.append(hCenterOuter) if len(centers): return centers else: return None else: FreeCAD.Console.PrintMessage( "debug: findHomotheticCenterOfCirclescleFrom3tan bad parameters!\n" ) return None
def findHomotheticCenterOfCircles(circle1, circle2): """Calculate the homothetic centers from two circles. Return None if the objects are not circles, or if they are concentric. http://en.wikipedia.org/wiki/Homothetic_center http://mathworld.wolfram.com/HomotheticCenter.html """ if (geomType(circle1) == "Circle" and geomType(circle2) == "Circle"): print("debug: findHomotheticCenterOfCircles bad parameters!") return None if DraftVecUtils.equals(circle1.Curve.Center, circle2.Curve.Center): return None cen1_cen2 = Part.LineSegment(circle1.Curve.Center, circle2.Curve.Center).toShape() cenDir = vec(cen1_cen2) cenDir.normalize() # Get the perpedicular vector. perpCenDir = cenDir.cross(App.Vector(0, 0, 1)) perpCenDir.normalize() # Get point on first circle p1 = App.Vector.add(circle1.Curve.Center, App.Vector(perpCenDir).multiply(circle1.Curve.Radius)) centers = [] # Calculate inner homothetic center # Get point on second circle p2_inner = App.Vector.add(circle1.Curve.Center, App.Vector(perpCenDir).multiply(-circle1.Curve.Radius)) hCenterInner = DraftVecUtils.intersect(circle1.Curve.Center, circle2.Curve.Center, p1, p2_inner, True, True) if hCenterInner: centers.append(hCenterInner) # Calculate outer homothetic center; it only exists if the circles # have different radii if circle1.Curve.Radius != circle2.Curve.Radius: # Get point on second circle p2_outer = App.Vector.add(circle1.Curve.Center, App.Vector(perpCenDir).multiply(circle1.Curve.Radius)) hCenterOuter = DraftVecUtils.intersect(circle1.Curve.Center, circle2.Curve.Center, p1, p2_outer, True, True) if hCenterOuter: centers.append(hCenterOuter) if centers: return centers else: return None
def edge_to_path(lastpt, edge, Z, hf=2.0): if isinstance(edge.Curve, Part.Circle): # FreeCAD.Console.PrintMessage("arc\n") arcstartpt = edge.valueAt(edge.FirstParameter) midpt = edge.valueAt( (edge.FirstParameter + edge.LastParameter) * 0.5) arcendpt = edge.valueAt(edge.LastParameter) # arcchkpt = edge.valueAt(edge.LastParameter * .99) if DraftVecUtils.equals(lastpt, arcstartpt): startpt = arcstartpt endpt = arcendpt else: startpt = arcendpt endpt = arcstartpt center = edge.Curve.Center relcenter = center.sub(lastpt) # FreeCAD.Console.PrintMessage("arc startpt= " + str(startpt)+ "\n") # FreeCAD.Console.PrintMessage("arc midpt= " + str(midpt)+ "\n") # FreeCAD.Console.PrintMessage("arc endpt= " + str(endpt)+ "\n") arc_cw = check_clockwise( [(startpt.x, startpt.y), (midpt.x, midpt.y), (endpt.x, endpt.y)]) # FreeCAD.Console.PrintMessage("arc_cw="+ str(arc_cw)+"\n") if arc_cw: output = "G2" else: output = "G3" output += " X" + str(fmt(endpt.x)) + " Y" + \ str(fmt(endpt.y)) + " Z" + str(fmt(Z)) + " F" + str(hf) output += " I" + str(fmt(relcenter.x)) + " J" + \ str(fmt(relcenter.y)) + " K" + str(fmt(relcenter.z)) output += "\n" lastpt = endpt # FreeCAD.Console.PrintMessage("last pt arc= " + str(lastpt)+ "\n") else: point = edge.Vertexes[-1].Point if DraftVecUtils.equals(point, lastpt): # edges can come flipped point = edge.Vertexes[0].Point output = "G1 X" + str(fmt(point.x)) + " Y" + str(fmt(point.y)) + \ " Z" + str(fmt(Z)) + " F" + str(hf) + "\n" lastpt = point # FreeCAD.Console.PrintMessage("line\n") # FreeCAD.Console.PrintMessage("last pt line= " + str(lastpt)+ "\n") return lastpt, output
def alignToFace(self, shape, offset=0): # Set face to the unique selected face, if found if shape.ShapeType == 'Face': self.alignToPointAndAxis(shape.Faces[0].CenterOfMass, shape.Faces[0].normalAt(0,0), offset) import DraftGeomUtils q = DraftGeomUtils.getQuad(shape) if q: self.u = q[1] self.v = q[2] if not DraftVecUtils.equals(self.u.cross(self.v),self.axis): self.u = q[2] self.v = q[1] if DraftVecUtils.equals(self.u,Vector(0,0,1)): # the X axis is vertical: rotate 90 degrees self.u,self.v = self.v.negative(),self.u self.weak = False return True else: return False
def onChanged(self,obj,prop): if prop == "Placement": # make fixtures move along with host if hasattr(obj,"Fixtures"): vo = obj.Shape.Placement.Base vn = obj.Placement.Base import DraftVecUtils if not DraftVecUtils.equals(vo,vn): delta = vn.sub(vo) for o in obj.Fixtures: o.Placement.move(delta)
def onChanged(self, obj, prop): if prop == "Placement": # make fixtures move along with host if hasattr(obj, "Fixtures"): vo = obj.Shape.Placement.Base vn = obj.Placement.Base import DraftVecUtils if not DraftVecUtils.equals(vo, vn): delta = vn.sub(vo) for o in obj.Fixtures: o.Placement.move(delta)
def alignToPointAndAxis(self, point, axis, offset, upvec=None): self.doc = FreeCAD.ActiveDocument self.axis = axis; self.axis.normalize() if (DraftVecUtils.equals(axis, Vector(1,0,0))): self.u = Vector(0,1,0) self.v = Vector(0,0,1) elif (DraftVecUtils.equals(axis, Vector(-1,0,0))): self.u = Vector(0,-1,0) self.v = Vector(0,0,1) elif upvec: self.v = upvec self.v.normalize() self.u = self.v.cross(self.axis) else: self.v = axis.cross(Vector(1,0,0)) self.v.normalize() self.u = DraftVecUtils.rotate(self.v, -math.pi/2, self.axis) offsetVector = Vector(axis); offsetVector.multiply(offset) self.position = point.add(offsetVector) self.weak = False
def alignToPointAndAxis(self, point, axis, offset=0, upvec=None): self.doc = FreeCAD.ActiveDocument self.axis = axis; self.axis.normalize() if (DraftVecUtils.equals(axis, Vector(1,0,0))): self.u = Vector(0,1,0) self.v = Vector(0,0,1) elif (DraftVecUtils.equals(axis, Vector(-1,0,0))): self.u = Vector(0,-1,0) self.v = Vector(0,0,1) elif upvec: self.v = upvec self.v.normalize() self.u = self.v.cross(self.axis) else: self.v = axis.cross(Vector(1,0,0)) self.v.normalize() self.u = DraftVecUtils.rotate(self.v, -math.pi/2, self.axis) offsetVector = Vector(axis); offsetVector.multiply(offset) self.position = point.add(offsetVector) self.weak = False
def alignToFace(self, shape, offset=0): # Set face to the unique selected face, if found if shape.ShapeType == 'Face': self.alignToPointAndAxis(shape.Faces[0].CenterOfMass, shape.Faces[0].normalAt(0,0), offset) import DraftGeomUtils q = DraftGeomUtils.getQuad(shape) if q: self.u = q[1] self.v = q[2] if not DraftVecUtils.equals(self.u.cross(self.v),self.axis): self.u = q[2] self.v = q[1] if DraftVecUtils.equals(self.u,Vector(0,0,1)): # the X axis is vertical: rotate 90 degrees self.u,self.v = self.v.negative(),self.u elif DraftVecUtils.equals(self.u,Vector(0,0,-1)): self.u,self.v = self.v,self.u.negative() self.weak = False return True else: return False
def onChanged(self,obj,prop): self.hideSubobjects(obj,prop) # propagate movements to children windows if prop == "Placement": if obj.Shape: if not obj.Shape.isNull(): vo = obj.Shape.Placement.Base vn = obj.Placement.Base if not DraftVecUtils.equals(vo,vn): delta = vn.sub(vo) for o in obj.OutList: if (Draft.getType(o) == "Window") or Draft.isClone(o,"Window"): o.Placement.move(delta) ArchComponent.Component.onChanged(self,obj,prop)
def execute(self, obj): # move children with this floor if hasattr(obj, "Placement"): if not hasattr(self, "OldPlacement"): self.OldPlacement = obj.Placement.copy() else: pl = obj.Placement.copy() if not DraftVecUtils.equals(pl.Base, self.OldPlacement.Base): print "placement moved" delta = pl.Base.sub(self.OldPlacement.Base) for o in obj.Group: if hasattr(o, "Placement"): o.Placement.move(delta) self.OldPlacement = pl
def findRadicalAxis(circle1, circle2): """Calculate the radical axis of two circles. On the radical axis (also called power line) of two circles any tangents drawn from a point on the axis to both circles have the same length. http://en.wikipedia.org/wiki/Radical_axis http://mathworld.wolfram.com/RadicalLine.html @sa findRadicalCenter """ if (geomType(circle1) == "Circle") and (geomType(circle2) == "Circle"): if DraftVecUtils.equals(circle1.Curve.Center, circle2.Curve.Center): return None r1 = circle1.Curve.Radius r2 = circle1.Curve.Radius cen1 = circle1.Curve.Center # dist .. the distance from cen1 to cen2. dist = DraftVecUtils.dist(cen1, circle2.Curve.Center) cenDir = cen1.sub(circle2.Curve.Center) cenDir.normalize() # Get the perpedicular vector. perpCenDir = cenDir.cross(Vector(0, 0, 1)) perpCenDir.normalize() # J ... The radical center. # K ... The point where the cadical axis crosses the line of cen1->cen2. # k1 ... Distance from cen1 to K. # k2 ... Distance from cen2 to K. # dist = k1 + k2 k1 = (dist + (r1 ^ 2 - r2 ^ 2) / dist) / 2.0 #k2 = dist - k1 K = Vector.add(cen1, cenDir.multiply(k1)) # K_ .. A point somewhere between K and J (actually with a distance of 1 unit from K). K_ = Vector, add(K, perpCenDir) radicalAxis = Part.LineSegment(K, Vector.add(origin, dir)) if radicalAxis: return radicalAxis else: return None else: FreeCAD.Console.PrintMessage( "debug: findRadicalAxis bad parameters!\n") return None
def onChanged(self,obj,prop): self.hideSubobjects(obj,prop) if prop in ["Base","Height","Width","Align","Additions","Subtractions"]: self.createGeometry(obj) # propagate movements to children windows if prop == "Placement": if obj.Shape: if not obj.Shape.isNull(): vo = obj.Shape.Placement.Base vn = obj.Placement.Base if not DraftVecUtils.equals(vo,vn): delta = vn.sub(vo) for o in obj.OutList: if (Draft.getType(o) == "Window") or Draft.isClone(o,"Window"): o.Placement.move(delta)
def alignToFace(self, shape, offset=0): # Set face to the unique selected face, if found if shape.ShapeType == 'Face': self.alignToPointAndAxis(shape.Faces[0].CenterOfMass, shape.Faces[0].normalAt(0,0), offset) import DraftGeomUtils q = DraftGeomUtils.getQuad(shape) if q: self.u = q[1] self.v = q[2] if not DraftVecUtils.equals(self.u.cross(self.v),self.axis): self.u = q[2] self.v = q[1] return True else: return False
def execute(self, obj): # move children with this floor if hasattr(obj, "Placement"): if not hasattr(self, "OldPlacement"): self.OldPlacement = obj.Placement.copy() else: pl = obj.Placement.copy() if not DraftVecUtils.equals(pl.Base, self.OldPlacement.Base): print "placement moved" delta = pl.Base.sub(self.OldPlacement.Base) for o in obj.Group: if hasattr(o, "Placement"): o.Placement.move(delta) self.OldPlacement = pl # adjust childrens heights for o in obj.Group: if Draft.getType(o) in ["Wall", "Structure"]: if not o.Height: o.Proxy.execute(o)
def makeAreaCurve(edges,direction,startpt=None,endpt=None): curveobj = area.Curve() cleanededges = PathUtils.cleanedges(edges, 0.01) #sort the edges vlist,edgestart,common = PathSelection.Sort2Edges([cleanededges[0],cleanededges[1]]) if cleanededges[0].valueAt(cleanededges[0].FirstParameter)<>edgestart: firstedge=PathUtils.reverseEdge(cleanededges[0]) else: firstedge=cleanededges[0] edgelist=[] edgelist.append(firstedge) #get start and end points of each edge aligned for e in cleanededges[1:]: if DraftVecUtils.equals(common,e.valueAt(e.FirstParameter)): edgelist.append(e) common= e.valueAt(e.LastParameter) else: newedge = PathUtils.reverseEdge(e) common= newedge.valueAt(newedge.LastParameter) edgelist.append(newedge) curveobj.append(area.Point(edgestart.x,edgestart.y)) # seglist =[] # if direction=='CW': # edgelist.reverse() # for e in edgelist: # seglist.append(PathUtils.reverseEdge(e)) #swap end points on every segment # else: # for e in edgelist: # seglist.append(e) for s in edgelist: curveobj.append(makeAreaVertex(s)) if startpt: # future nearest point code yet to be worked out -fixme # v1 = Vector(startpt.X,startpt.Y,startpt.Z) # perppoint1 = DraftGeomUtils.findPerpendicular(v1,firstedge) # perppoint1 = DraftGeomUtils.findDistance(v1,firstedge) # if perppoint1: # curveobj.ChangeStart(area.Point(perppoint1[0].x,perppoint1[0].y)) # else: # curveobj.ChangeStart(area.Point(startpt.X,startpt.Y)) curveobj.ChangeStart(area.Point(startpt.X,startpt.Y)) if endpt: # future nearest point code yet to be worked out -fixme # v2 = Vector(endpt.X,endpt.Y,endpt.Z) # perppoint2 = DraftGeomUtils.findPerpendicular(v2,lastedge) # if perppoint2: # curveobj.ChangeEnd(area.Point(perppoint2[0].x,perppoint2[0].y)) # else: # curveobj.ChangeEnd(area.Point(endpt.X,endpt.Y)) curveobj.ChangeEnd(area.Point(endpt.X,endpt.Y)) if direction == 'CW': curveobj.Reverse() return curveobj
def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tessellation=1): """returns an IfcShapeRepresentation object or None""" import Part,math,DraftGeomUtils,DraftVecUtils shapes = [] placement = None productdef = None shapetype = "no shape" if not forcebrep: profile = None if hasattr(obj,"Proxy"): if hasattr(obj.Proxy,"getProfiles"): p = obj.Proxy.getProfiles(obj,noplacement=True) extrusionv = obj.Proxy.getExtrusionVector(obj,noplacement=True) if (len(p) == 1) and extrusionv: p = p[0] r = obj.Proxy.getPlacement(obj) if len(p.Edges) == 1: pxvc = ifcfile.createIfcDirection((1.0,0.0)) povc = ifcfile.createIfcCartesianPoint((0.0,0.0)) pt = ifcfile.createIfcAxis2Placement2D(povc,pxvc) # extruded circle if isinstance(p.Edges[0].Curve,Part.Circle): profile = ifcfile.createIfcCircleProfileDef("AREA",None,pt, p.Edges[0].Curve.Radius) # extruded ellipse elif isinstance(p.Edges[0].Curve,Part.Ellipse): profile = ifcfile.createIfcEllipseProfileDef("AREA",None,pt, p.Edges[0].Curve.MajorRadius, p.Edges[0].Curve.MinorRadius) else: curves = False for e in p.Edges: if isinstance(e.Curve,Part.Circle): curves = True # extruded polyline if not curves: w = Part.Wire(DraftGeomUtils.sortEdges(p.Edges)) pts = [ifcfile.createIfcCartesianPoint(tuple(v.Point)[:2]) for v in w.Vertexes+[w.Vertexes[0]]] pol = ifcfile.createIfcPolyline(pts) # extruded composite curve else: segments = [] last = None edges = DraftGeomUtils.sortEdges(p.Edges) for e in edges: if isinstance(e.Curve,Part.Circle): follow = True if last: if not DraftVecUtils.equals(last,e.Vertexes[0].Point): follow = False last = e.Vertexes[0].Point else: last = e.Vertexes[-1].Point else: last = e.Vertexes[-1].Point p1 = math.degrees(-DraftVecUtils.angle(e.Vertexes[0].Point.sub(e.Curve.Center))) p2 = math.degrees(-DraftVecUtils.angle(e.Vertexes[-1].Point.sub(e.Curve.Center))) da = DraftVecUtils.angle(e.valueAt(e.FirstParameter+0.1).sub(e.Curve.Center),e.Vertexes[0].Point.sub(e.Curve.Center)) if p1 < 0: p1 = 360 + p1 if p2 < 0: p2 = 360 + p2 if da > 0: follow = not(follow) xvc = ifcfile.createIfcDirection((1.0,0.0)) ovc = ifcfile.createIfcCartesianPoint(tuple(e.Curve.Center)[:2]) plc = ifcfile.createIfcAxis2Placement2D(ovc,xvc) cir = ifcfile.createIfcCircle(plc,e.Curve.Radius) curve = ifcfile.createIfcTrimmedCurve(cir,[ifcfile.create_entity("IfcParameterValue",p1)],[ifcfile.create_entity("IfcParameterValue",p2)],follow,"PARAMETER") else: verts = [vertex.Point for vertex in e.Vertexes] if last: if not DraftVecUtils.equals(last,verts[0]): verts.reverse() last = e.Vertexes[0].Point else: last = e.Vertexes[-1].Point else: last = e.Vertexes[-1].Point pts = [ifcfile.createIfcCartesianPoint(tuple(v)[:2]) for v in verts] curve = ifcfile.createIfcPolyline(pts) segment = ifcfile.createIfcCompositeCurveSegment("CONTINUOUS",True,curve) segments.append(segment) pol = ifcfile.createIfcCompositeCurve(segments,False) profile = ifcfile.createIfcArbitraryClosedProfileDef("AREA",None,pol) if profile: xvc = ifcfile.createIfcDirection(tuple(r.Rotation.multVec(FreeCAD.Vector(1,0,0)))) zvc = ifcfile.createIfcDirection(tuple(r.Rotation.multVec(FreeCAD.Vector(0,0,1)))) ovc = ifcfile.createIfcCartesianPoint(tuple(r.Base)) lpl = ifcfile.createIfcAxis2Placement3D(ovc,zvc,xvc) edir = ifcfile.createIfcDirection(tuple(FreeCAD.Vector(extrusionv).normalize())) shape = ifcfile.createIfcExtrudedAreaSolid(profile,lpl,edir,extrusionv.Length) shapes.append(shape) solidType = "SweptSolid" shapetype = "extrusion" if not shapes: # brep representation fcshape = None solidType = "Brep" if subtraction: if hasattr(obj,"Proxy"): if hasattr(obj.Proxy,"getSubVolume"): fcshape = obj.Proxy.getSubVolume(obj) if not fcshape: if hasattr(obj,"Shape"): if obj.Shape: if not obj.Shape.isNull(): fcshape = obj.Shape elif hasattr(obj,"Terrain"): if obj.Terrain: if hasattr(obj.Terrain,"Shape"): if obj.Terrain.Shape: if not obj.Terrain.Shape.isNull(): fcshape = obj.Terrain.Shape if fcshape: solids = [] if fcshape.Solids: dataset = fcshape.Solids else: dataset = fcshape.Shells print "Warning! object contains no solids" for fcsolid in dataset: faces = [] curves = False for fcface in fcsolid.Faces: for e in fcface.Edges: if not isinstance(e.Curve,Part.Line): curves = True if curves: tris = fcsolid.tessellate(tessellation) for tri in tris[1]: pts = [ifcfile.createIfcCartesianPoint(tuple(tris[0][i])) for i in tri] loop = ifcfile.createIfcPolyLoop(pts) bound = ifcfile.createIfcFaceOuterBound(loop,True) face = ifcfile.createIfcFace([bound]) faces.append(face) else: for fcface in fcsolid.Faces: loops = [] verts = [v.Point for v in Part.Wire(DraftGeomUtils.sortEdges(fcface.OuterWire.Edges)).Vertexes] c = fcface.CenterOfMass v1 = verts[0].sub(c) v2 = verts[1].sub(c) n = fcface.normalAt(0,0) if DraftVecUtils.angle(v2,v1,n) >= 0: verts.reverse() # inverting verts order if the direction is couterclockwise pts = [ifcfile.createIfcCartesianPoint(tuple(v)) for v in verts] loop = ifcfile.createIfcPolyLoop(pts) bound = ifcfile.createIfcFaceOuterBound(loop,True) loops.append(bound) for wire in fcface.Wires: if wire.hashCode() != fcface.OuterWire.hashCode(): verts = [v.Point for v in Part.Wire(DraftGeomUtils.sortEdges(wire.Edges)).Vertexes] v1 = verts[0].sub(c) v2 = verts[1].sub(c) if DraftVecUtils.angle(v2,v1,DraftVecUtils.neg(n)) >= 0: verts.reverse() pts = [ifcfile.createIfcCartesianPoint(tuple(v)) for v in verts] loop = ifcfile.createIfcPolyLoop(pts) bound = ifcfile.createIfcFaceBound(loop,True) loops.append(bound) face = ifcfile.createIfcFace(loops) faces.append(face) shell = ifcfile.createIfcClosedShell(faces) shape = ifcfile.createIfcFacetedBrep(shell) shapes.append(shape) shapetype = "brep" if shapes: if FreeCAD.GuiUp and (not subtraction) and hasattr(obj.ViewObject,"ShapeColor"): rgb = obj.ViewObject.ShapeColor col = ifcfile.createIfcColourRgb(None,rgb[0],rgb[1],rgb[2]) ssr = ifcfile.createIfcSurfaceStyleRendering(col,None,None,None,None,None,None,None,"FLAT") iss = ifcfile.createIfcSurfaceStyle(None,"BOTH",[ssr]) psa = ifcfile.createIfcPresentationStyleAssignment([iss]) for shape in shapes: isi = ifcfile.createIfcStyledItem(shape,[psa],None) xvc = ifcfile.createIfcDirection((1.0,0.0,0.0)) zvc = ifcfile.createIfcDirection((0.0,0.0,1.0)) ovc = ifcfile.createIfcCartesianPoint((0.0,0.0,0.0)) gpl = ifcfile.createIfcAxis2Placement3D(ovc,zvc,xvc) placement = ifcfile.createIfcLocalPlacement(None,gpl) representation = ifcfile.createIfcShapeRepresentation(context,'Body',solidType,shapes) productdef = ifcfile.createIfcProductDefinitionShape(None,None,[representation]) return productdef,placement,shapetype