def backSmaller(self, i): import DraftGeomUtils profilCurrent = self.findProfil(i) profilBack1 = self.findProfil(i - 1) dec = profilBack1["height"] / math.tan(math.radians(profilCurrent["angle"])) edgeRidgeOnPane = DraftGeomUtils.offset( profilCurrent["edge"], self.getPerpendicular(profilCurrent["vec"], profilCurrent["rot"], dec) ) ptInter1 = DraftGeomUtils.findIntersection( edgeRidgeOnPane, profilBack1["ridge"], infinite1=True, infinite2=True ) edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInter1[0]), profilCurrent["edge"].Vertexes[0].Point) ptInter2 = edgeHip.Vertexes[0].Point vecInterRidges = DraftGeomUtils.findPerpendicular(ptInter2, [profilCurrent["ridge"].Edges[0]], force=0) ptInterRidges = ptInter2.add(vecInterRidges[0]) self.ptsPaneProject.append(FreeCAD.Vector(ptInterRidges)) self.ptsPaneProject.append(FreeCAD.Vector(ptInter1[0])) ptInterHipEave = DraftGeomUtils.findIntersection( edgeHip, profilCurrent["eave"], infinite1=True, infinite2=False ) if ptInterHipEave: self.ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave[0])) else: ptInterHipEave = DraftGeomUtils.findIntersection( edgeHip, profilBack1["eaveD"], infinite1=True, infinite2=True ) self.ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave[0])) self.ptsPaneProject.append(FreeCAD.Vector(profilCurrent["eave"].Vertexes[0].Point[0]))
def nextHigher(self, i): import DraftGeomUtils profilCurrent = self.findProfil(i) profilNext1 = self.findProfil(i + 1) dec = profilCurrent["height"] / math.tan(math.radians(profilNext1["angle"])) edgeRidgeOnPane = DraftGeomUtils.offset( profilNext1["edge"], self.getPerpendicular(profilNext1["vec"], profilNext1["rot"], dec) ) ptInter = DraftGeomUtils.findIntersection( profilCurrent["ridge"], edgeRidgeOnPane, infinite1=True, infinite2=True ) edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInter[0]), profilCurrent["edge"].Vertexes[-1].Point) ptInterHipEave = DraftGeomUtils.findIntersection( edgeHip, profilCurrent["eave"], infinite1=True, infinite2=False ) if ptInterHipEave: self.ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave[0])) else: ptInterHipEave = DraftGeomUtils.findIntersection( edgeHip, profilNext1["eaveD"], infinite1=True, infinite2=True ) self.ptsPaneProject.append(FreeCAD.Vector(profilCurrent["eave"].Vertexes[-1].Point[0])) self.ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave[0])) self.ptsPaneProject.append(FreeCAD.Vector(ptInter[0])) ptInterRidges = DraftGeomUtils.findIntersection( profilCurrent["ridge"], profilNext1["ridge"], infinite1=True, infinite2=True ) self.ptsPaneProject.append(FreeCAD.Vector(ptInterRidges[0]))
def calcEave(self, i): import DraftGeomUtils pt0Eave1 = DraftGeomUtils.findIntersection(self.findProfil(i-1)["eaveD"],self.findProfil(i)["eaveD"],infinite1=True,infinite2=True,) pt1Eave1 = DraftGeomUtils.findIntersection(self.findProfil(i)["eaveD"],self.findProfil(i+1)["eaveD"],infinite1=True,infinite2=True,) eave = DraftGeomUtils.edg(FreeCAD.Vector(pt0Eave1[0]),FreeCAD.Vector(pt1Eave1[0])) self.profilsDico[i]["eave"] = eave
def nextSmaller(self, i): print("Next : ht2 < ht1") profilCurrent = self.findProfil(i) profilNext1 = self.findProfil(i+1) dec = profilNext1["height"]/math.tan(math.radians(profilCurrent["angle"])) edgeRidgeOnPane = DraftGeomUtils.offset(profilCurrent["edge"],self.getPerpendicular(profilCurrent["vec"],profilCurrent["rot"],dec)) ptInter = DraftGeomUtils.findIntersection(profilNext1["ridge"],edgeRidgeOnPane,infinite1=True,infinite2=True,) edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInter[0]),profilCurrent["edge"].Vertexes[-1].Point) ptInterHipEave = DraftGeomUtils.findIntersection(edgeHip,profilCurrent["eave"],infinite1=True,infinite2=False,) if ptInterHipEave: print "a ",FreeCAD.Vector(ptInterHipEave[0]) self.ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave[0])) else: ptInterHipEave = DraftGeomUtils.findIntersection(edgeHip,profilNext1["eaveD"],infinite1=True,infinite2=True,) print "b ",FreeCAD.Vector(profilCurrent["eave"].Vertexes[-1].Point[0]) print "c ",FreeCAD.Vector(ptInterHipEave[0]) self.ptsPaneProject.append(FreeCAD.Vector(profilCurrent["eave"].Vertexes[-1].Point[0])) self.ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave[0])) print "d ",FreeCAD.Vector(ptInter[0]) self.ptsPaneProject.append(FreeCAD.Vector(ptInter[0])) ptInter = edgeHip.Vertexes[0].Point vecInterRidges = DraftGeomUtils.findPerpendicular(ptInter, [profilCurrent["ridge"].Edges[0],], force=0) ptInterRidges = ptInter.add(vecInterRidges[0]) print "e ",FreeCAD.Vector(ptInterRidges) self.ptsPaneProject.append(FreeCAD.Vector(ptInterRidges))
def backSameHeight(self, i): import DraftGeomUtils profilCurrent = self.findProfil(i) profilBack1 = self.findProfil(i-1) ptInterRidges = DraftGeomUtils.findIntersection(profilCurrent["ridge"],profilBack1["ridge"],infinite1=True,infinite2=True,) self.ptsPaneProject.append(FreeCAD.Vector(ptInterRidges[0])) edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInterRidges[0]),profilCurrent["edge"].Vertexes[0].Point) ptInterHipEave = DraftGeomUtils.findIntersection(edgeHip,profilCurrent["eave"],infinite1=True,infinite2=False,) if ptInterHipEave: self.ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave[0])) else: ptInterHipEave = DraftGeomUtils.findIntersection(edgeHip,profilBack1["eaveD"],infinite1=True,infinite2=True,) self.ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave[0])) self.ptsPaneProject.append(FreeCAD.Vector(profilCurrent["eave"].Vertexes[0].Point))
def findPivotIntersection(self, pivot, pivotEdge, edge, refPt, d, color): debugPrint( "Intersection (%.2f, %.2f)^%.2f - [(%.2f, %.2f), (%.2f, %.2f)]" % ( pivotEdge.Curve.Center.x, pivotEdge.Curve.Center.y, pivotEdge.Curve.Radius, edge.Vertexes[0].Point.x, edge.Vertexes[0].Point.y, edge.Vertexes[1].Point.x, edge.Vertexes[1].Point.y, ) ) ppt = None pptDistance = 0 for pt in DraftGeomUtils.findIntersection(edge, pivotEdge, dts=False): # debugMarker(pt, "pti.%d-%s.in" % (self.boneId, d), color, 0.2) distance = (pt - refPt).Length debugPrint(" --> (%.2f, %.2f): %.2f" % (pt.x, pt.y, distance)) if not ppt or pptDistance < distance: ppt = pt pptDistance = distance if not ppt: tangent = DraftGeomUtils.findDistance(pivot, edge) if tangent: debugPrint("Taking tangent as intersect %s" % tangent) ppt = pivot + tangent else: debugPrint("Taking chord start as intersect %s" % inChordStart) ppt = inChord.Start # debugMarker(ppt, "ptt.%d-%s.in" % (self.boneId, d), color, 0.2) debugPrint(" --> (%.2f, %.2f)" % (ppt.x, ppt.y)) return ppt
def intersectionCLines(thing1=None, thing2=None): ''' intersectionCLines(thing1=None, thing2=None) Returns the intersection (vector) of the center lines of thing1 and thing2. Things can be any combination of intersecting beams, pipes or edges. If less than 2 arguments are given, thing1 and thing2 are the first 2 beams or pipes found in the selection set. ''' if not (thing1 and thing2): try: thing1,thing2=beams()[:2] except: FreeCAD.Console.PrintError('Insufficient arguments for intersectionCLines\n') return None edges=[] for thing in [thing1,thing2]: if beams([thing]): edges.append(vec2edge(thing.Placement.Base,beamAx(thing))) elif hasattr(thing,'ShapeType') and thing.ShapeType=='Edge': edges.append(thing) intersections=dgu.findIntersection(*edges, infinite1=True, infinite2=True) if len(intersections): return rounded(intersections[0]) else: FreeCAD.Console.PrintError('No intersection found\n') return None
def connectNodes(self,other=None): if not other: self.observer = StructSelectionObserver(self.connectNodes) FreeCADGui.Selection.addObserver(self.observer) FreeCAD.Console.PrintMessage(translate("Arch","Pick another Structure object: ")) else: FreeCADGui.Selection.removeObserver(self.observer) self.observer = None if Draft.getType(other) != "Structure": FreeCAD.Console.PrintError(translate("Arch","The picked object is not a Structure\n")) else: if not other.Nodes: FreeCAD.Console.PrintError(translate("Arch","The picked object has no structural nodes\n")) else: if (len(self.Object.Nodes) != 2) or (len(other.Nodes) != 2): FreeCAD.Console.PrintError(translate("Arch","One of these objects has more than 2 nodes\n")) else: import DraftGeomUtils nodes1 = [self.Object.Placement.multVec(v) for v in self.Object.Nodes] nodes2 = [other.Placement.multVec(v) for v in other.Nodes] intersect = DraftGeomUtils.findIntersection(nodes1[0],nodes1[1],nodes2[0],nodes2[1],True,True) if not intersect: FreeCAD.Console.PrintError(translate("Arch","Unable to find a suitable intersection point\n")) else: intersect = intersect[0] FreeCAD.Console.PrintMessage(translate("Arch","Intersection found.\n")) if DraftGeomUtils.findClosest(intersect,nodes1) == 0: self.Object.Nodes = [self.Object.Placement.inverse().multVec(intersect),self.Object.Nodes[1]] else: self.Object.Nodes = [self.Object.Nodes[0],self.Object.Placement.inverse().multVec(intersect)] if DraftGeomUtils.findClosest(intersect,nodes2) == 0: other.Nodes = [other.Placement.inverse().multVec(intersect),other.Nodes[1]] else: other.Nodes = [other.Nodes[0],other.Placement.inverse().multVec(intersect)]
def getAxisPoints(self,obj): "returns the gridpoints of linked axes" import DraftGeomUtils pts = [] if len(obj.Axes) == 1: if hasattr(obj,"Align"): if obj.Align == True : p0 = obj.Axes[0].Shape.Edges[0].Vertexes[1].Point for e in obj.Axes[0].Shape.Edges: p = e.Vertexes[1].Point p = p.sub(p0) pts.append(p) else: for e in obj.Axes[0].Shape.Edges: pts.append(e.Vertexes[0].Point) else: for e in obj.Axes[0].Shape.Edges: pts.append(e.Vertexes[0].Point) elif len(obj.Axes) >= 2: set1 = obj.Axes[0].Shape.Edges set2 = obj.Axes[1].Shape.Edges for e1 in set1: for e2 in set2: pts.extend(DraftGeomUtils.findIntersection(e1,e2)) return pts
def nextSameHeight(self, i): print("Next : ht1 = ht2") profilCurrent = self.findProfil(i) profilNext1 = self.findProfil(i+1) ptInterRidges = DraftGeomUtils.findIntersection(profilCurrent["ridge"],profilNext1["ridge"],infinite1=True,infinite2=True,) edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInterRidges[0]),profilCurrent["edge"].Vertexes[-1].Point) ptInterHipEave = DraftGeomUtils.findIntersection(edgeHip,profilCurrent["eave"],infinite1=True,infinite2=False,) if ptInterHipEave: print "a ",FreeCAD.Vector(ptInterHipEave[0]) self.ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave[0])) else: ptInterHipEave = DraftGeomUtils.findIntersection(edgeHip,profilNext1["eaveD"],infinite1=True,infinite2=True,) print "b ",FreeCAD.Vector(profilCurrent["eave"].Vertexes[-1].Point) print "c ",FreeCAD.Vector(ptInterHipEave[0]) self.ptsPaneProject.append(FreeCAD.Vector(profilCurrent["eave"].Vertexes[-1].Point)) self.ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave[0])) print "d ",FreeCAD.Vector(ptInterRidges[0]) self.ptsPaneProject.append(FreeCAD.Vector(ptInterRidges[0]))
def snapToElines(self,e1,e2): "returns a snap location at the infinite intersection of the given edges" snaps = [] if self.isEnabled("intersection") and self.isEnabled("extension"): if e1 and e2: # get the intersection points pts = DraftGeomUtils.findIntersection(e1,e2,True,True) if pts: for p in pts: snaps.append([p,'intersection',p]) return snaps
def backHigher(self, i): print("Back : ht1 < ht0") profilCurrent = self.findProfil(i) profilBack1 = self.findProfil(i-1) dec = profilCurrent["height"]/math.tan(math.radians(profilBack1["angle"])) edgeRidgeOnPane = DraftGeomUtils.offset(profilBack1["edge"],self.getPerpendicular(profilBack1["vec"],profilBack1["rot"],dec)) ptInterRidges = DraftGeomUtils.findIntersection(edgeRidgeOnPane,profilCurrent["ridge"],infinite1=True,infinite2=True,) print "a ",FreeCAD.Vector(ptInterRidges[0]) self.ptsPaneProject.append(FreeCAD.Vector(ptInterRidges[0])) edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInterRidges[0]),profilCurrent["edge"].Vertexes[0].Point) ptInterHipEave = DraftGeomUtils.findIntersection(edgeHip,profilCurrent["eave"],infinite1=True,infinite2=False,) if ptInterHipEave: print "b ",FreeCAD.Vector(ptInterHipEave[0]) self.ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave[0])) else: ptInterHipEave = DraftGeomUtils.findIntersection(edgeHip,profilBack1["eaveD"],infinite1=True,infinite2=True,) print "c ",FreeCAD.Vector(ptInterHipEave[0]) print "d ",FreeCAD.Vector(profilCurrent["eave"].Vertexes[0].Point[0]) self.ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave[0])) self.ptsPaneProject.append(FreeCAD.Vector(profilCurrent["eave"].Vertexes[0].Point[0]))
def snapToExtOrtho(self,last,constrain,eline): "returns an ortho X extension snap location" if self.isEnabled("extension") and self.isEnabled("ortho"): if constrain and last and self.constraintAxis and self.extLine: tmpEdge1 = Part.Line(last,last.add(self.constraintAxis)).toShape() tmpEdge2 = Part.Line(self.extLine.p1(),self.extLine.p2()).toShape() # get the intersection points pt = DraftGeomUtils.findIntersection(tmpEdge1,tmpEdge2,True,True) if pt: return [pt[0],'ortho',pt[0]] if eline: try: tmpEdge2 = Part.Line(self.extLine.p1(),self.extLine.p2()).toShape() # get the intersection points pt = DraftGeomUtils.findIntersection(eline,tmpEdge2,True,True) if pt: return [pt[0],'ortho',pt[0]] except: return None return None
def findInterPoint(edge1,edge2): # give two edges and then return the inter_point pt1a = edge1.Vertex1.Point pt1b = edge1.Vertex2.Point pt2a = edge2.Vertex1.Point pt2b = edge2.Vertex2.Point nor1 = pt1a.sub(pt1b).normalize() nor2 = pt2a.sub(pt2b).normalize() line1 = Part.makeLine(pt1a+nor1*1000,pt1a+nor1*-1000) line2 = Part.makeLine(pt2a+nor2*1000,pt2a+nor2*-1000) p=DraftGeomUtils.findIntersection(line1,line2) if p: return(p[0]) return(prf('cen not find the inter point!'))
def nextPignon(self, i): print("Next : pignon") profilCurrent = self.findProfil(i) profilNext1 = self.findProfil(i+1) profilNext2 = self.findProfil(i+2) point = DraftGeomUtils.findIntersection(profilCurrent["eave"],profilNext1["eave"],infinite1=True,infinite2=True,) print "a ",FreeCAD.Vector(point[0]) self.ptsPaneProject.append(FreeCAD.Vector(point[0])) pt1 = DraftGeomUtils.findIntersection(profilCurrent["edge"],profilNext1["eave"],infinite1=True,infinite2=True,) pt2 = DraftGeomUtils.findIntersection(profilNext2["edge"],profilNext1["eave"],infinite1=True,infinite2=True,) eaveWithoutOverhang = DraftGeomUtils.edg(pt1[0],pt2[0]) if profilCurrent["run"]+profilNext2["run"] != eaveWithoutOverhang.Length : points = [FreeCAD.Vector(0.0,0.0,0.0),] points.append(FreeCAD.Vector(profilCurrent["run"],profilCurrent["height"],0.0)) rampantCurrent = DraftGeomUtils.edg(points[0],points[1]) points = [FreeCAD.Vector(eaveWithoutOverhang.Length,0.0,0.0),] points.append(FreeCAD.Vector(eaveWithoutOverhang.Length-profilNext2["run"],profilNext2["height"],0.0)) rampantNext2 = DraftGeomUtils.edg(points[0],points[1]) point = DraftGeomUtils.findIntersection(rampantCurrent,rampantNext2,infinite1=True,infinite2=True,) ridgeCurrent = DraftGeomUtils.offset(profilCurrent["edge"],self.getPerpendicular(profilCurrent["vec"],profilCurrent["rot"],point[0].x)) point = DraftGeomUtils.findIntersection(ridgeCurrent,profilNext1["eave"],infinite1=True,infinite2=True,) else: point = DraftGeomUtils.findIntersection(profilCurrent["ridge"],profilNext1["eaveD"],infinite1=True,infinite2=True,) print "b ",FreeCAD.Vector(point[0]) self.ptsPaneProject.append(FreeCAD.Vector(point[0]))
def backPignon(self, i): import DraftGeomUtils profilCurrent = self.findProfil(i) profilBack1 = self.findProfil(i - 1) profilBack2 = self.findProfil(i - 2) pt1 = DraftGeomUtils.findIntersection( profilCurrent["edge"], profilBack1["eave"], infinite1=True, infinite2=True ) pt2 = DraftGeomUtils.findIntersection(profilBack2["edge"], profilBack1["eave"], infinite1=True, infinite2=True) eaveWithoutOverhang = DraftGeomUtils.edg(pt1[0], pt2[0]) if profilCurrent["run"] + profilBack2["run"] != eaveWithoutOverhang.Length: points = [FreeCAD.Vector(0.0, 0.0, 0.0)] points.append(FreeCAD.Vector(profilCurrent["run"], profilCurrent["height"], 0.0)) rampantCurrent = DraftGeomUtils.edg(points[0], points[1]) points = [FreeCAD.Vector(eaveWithoutOverhang.Length, 0.0, 0.0)] points.append(FreeCAD.Vector(eaveWithoutOverhang.Length - profilBack2["run"], profilBack2["height"], 0.0)) rampantBack2 = DraftGeomUtils.edg(points[0], points[1]) point = DraftGeomUtils.findIntersection(rampantCurrent, rampantBack2, infinite1=True, infinite2=True) ridgeCurrent = DraftGeomUtils.offset( profilCurrent["edge"], self.getPerpendicular(profilCurrent["vec"], profilCurrent["rot"], point[0].x) ) point = DraftGeomUtils.findIntersection(ridgeCurrent, profilBack1["eave"], infinite1=True, infinite2=True) else: point = DraftGeomUtils.findIntersection( profilCurrent["ridge"], profilBack1["eave"], infinite1=True, infinite2=True ) self.ptsPaneProject.append(FreeCAD.Vector(point[0])) point = DraftGeomUtils.findIntersection( profilCurrent["eave"], profilBack1["eave"], infinite1=True, infinite2=True ) self.ptsPaneProject.append(FreeCAD.Vector(point[0]))
def getAxisPoints(self,obj): "returns the gridpoints of linked axes" import DraftGeomUtils pts = [] if len(obj.Axes) == 1: for e in obj.Axes[0].Shape.Edges: pts.append(e.Vertexes[0].Point) elif len(obj.Axes) >= 2: set1 = obj.Axes[0].Shape.Edges set2 = obj.Axes[1].Shape.Edges for e1 in set1: for e2 in set2: pts.extend(DraftGeomUtils.findIntersection(e1,e2)) return pts
def zOverlaps(self,face1,face2): "Checks if face1 overlaps face2 in Z direction" face1 = self.flattenFace(face1) face2 = self.flattenFace(face2) # first we check if one of the verts is inside the other face for v in face1[0].Vertexes: if self.isInside(v,face2): return True # even so, faces can still overlap if their edges cross each other for e1 in face1[0].Edges: for e2 in face2[0].Edges: if DraftGeomUtils.findIntersection(e1,e2): return True return False
def snapToOrtho(self,shape,last,constrain): "returns a list of ortho snap locations" snaps = [] if self.isEnabled("ortho"): if constrain: if isinstance(shape,Part.Edge): if last: if DraftGeomUtils(shape) == "Line": if self.constraintAxis: tmpEdge = Part.Line(last,last.add(self.constraintAxis)).toShape() # get the intersection points pt = DraftGeomUtils.findIntersection(tmpEdge,shape,True,True) if pt: for p in pt: snaps.append([p,'ortho',p]) return snaps
def snapToIntersection(self,shape): "returns a list of intersection snap locations" snaps = [] if self.isEnabled("intersection"): # get the stored objects to calculate intersections if self.lastObj[0]: obj = FreeCAD.ActiveDocument.getObject(self.lastObj[0]) if obj: if obj.isDerivedFrom("Part::Feature"): if (not self.maxEdges) or (len(obj.Shape.Edges) <= self.maxEdges): for e in obj.Shape.Edges: # get the intersection points pt = DraftGeomUtils.findIntersection(e,shape) if pt: for p in pt: snaps.append([p,'intersection',p]) return snaps
def removePathCrossing(self, commands, bone1, bone2): commands.append(bone2.lastCommand) bones = bone2.commands if True and hasattr(bone1, "outCommands") and hasattr(bone2, "inCommands"): inEdges = edgesForCommands(bone1.outCommands, bone1.tip) outEdges = edgesForCommands(bone2.inCommands, bone2.inChord.Start) for i in range(len(inEdges)): e1 = inEdges[i] for j in range(len(outEdges)-1, -1, -1): e2 = outEdges[j] cutoff = DraftGeomUtils.findIntersection(e1, e2) for pt in cutoff: # debugCircle(e1.Curve.Center, e1.Curve.Radius, "bone.%d-1" % (self.boneId), (1.,0.,0.)) # debugCircle(e2.Curve.Center, e2.Curve.Radius, "bone.%d-2" % (self.boneId), (0.,1.,0.)) if PathGeom.pointsCoincide(pt, e1.valueAt(e1.LastParameter)) or PathGeom.pointsCoincide(pt, e2.valueAt(e2.FirstParameter)): continue # debugMarker(pt, "it", (0.0, 1.0, 1.0)) # 1. remove all redundant commands commands = commands[:-(len(inEdges) - i)] # 2., correct where c1 ends c1 = bone1.outCommands[i] c1Params = c1.Parameters c1Params.update({'X': pt.x, 'Y': pt.y, 'Z': pt.z}) c1 = Path.Command(c1.Name, c1Params) commands.append(c1) # 3. change where c2 starts, this depends on the command itself c2 = bone2.inCommands[j] if c2.Name in movearc: center = e2.Curve.Center offset = center - pt c2Params = c2.Parameters c2Params.update({'I': offset.x, 'J': offset.y, 'K': offset.z}) c2 = Path.Command(c2.Name, c2Params) bones = [c2] bones.extend(bone2.commands[j+1:]) else: bones = bone2.commands[j:] # there can only be the one ... return commands, bones return commands, bones
def backPignon(self, i): import DraftGeomUtils profilCurrent = self.findProfil(i) profilBack1 = self.findProfil(i - 1) profilBack2 = self.findProfil(i - 2) pt1 = DraftGeomUtils.findIntersection( profilCurrent["edge"], profilBack1["eave"], infinite1=True, infinite2=True, ) pt2 = DraftGeomUtils.findIntersection( profilBack2["edge"], profilBack1["eave"], infinite1=True, infinite2=True, ) eaveWithoutOverhang = DraftGeomUtils.edg(pt1[0], pt2[0]) if profilCurrent["run"] + profilBack2[ "run"] != eaveWithoutOverhang.Length: points = [ FreeCAD.Vector(0.0, 0.0, 0.0), ] points.append( FreeCAD.Vector(profilCurrent["run"], profilCurrent["height"], 0.0)) rampantCurrent = DraftGeomUtils.edg(points[0], points[1]) points = [ FreeCAD.Vector(eaveWithoutOverhang.Length, 0.0, 0.0), ] points.append( FreeCAD.Vector(eaveWithoutOverhang.Length - profilBack2["run"], profilBack2["height"], 0.0)) rampantBack2 = DraftGeomUtils.edg(points[0], points[1]) point = DraftGeomUtils.findIntersection( rampantCurrent, rampantBack2, infinite1=True, infinite2=True, ) ridgeCurrent = DraftGeomUtils.offset( profilCurrent["edge"], self.getPerpendicular(profilCurrent["vec"], profilCurrent["rot"], point[0].x)) point = DraftGeomUtils.findIntersection( ridgeCurrent, profilBack1["eave"], infinite1=True, infinite2=True, ) else: point = DraftGeomUtils.findIntersection( profilCurrent["ridge"], profilBack1["eave"], infinite1=True, infinite2=True, ) self.ptsPaneProject.append(FreeCAD.Vector(point[0])) point = DraftGeomUtils.findIntersection( profilCurrent["eave"], profilBack1["eave"], infinite1=True, infinite2=True, ) self.ptsPaneProject.append(FreeCAD.Vector(point[0]))
def smoothChordCommands(self, bone, inChord, outChord, edge, wire, corner, smooth, color=None): if smooth == 0: PathLog.info(" No smoothing requested") return [bone.lastCommand, outChord.g1Command(bone.F)] d = 'in' refPoint = inChord.Start if smooth == Smooth.Out: d = 'out' refPoint = outChord.End if DraftGeomUtils.areColinear(inChord.asEdge(), outChord.asEdge()): PathLog.info(" straight edge %s" % d) return [outChord.g1Command(bone.F)] pivot = None pivotDistance = 0 PathLog.info("smooth: (%.2f, %.2f)-(%.2f, %.2f)" % (edge.Vertexes[0].Point.x, edge.Vertexes[0].Point.y, edge.Vertexes[1].Point.x, edge.Vertexes[1].Point.y)) for e in wire.Edges: self.dbg.append(e) if type(e.Curve) == Part.LineSegment or type(e.Curve) == Part.Line: PathLog.debug(" (%.2f, %.2f)-(%.2f, %.2f)" % (e.Vertexes[0].Point.x, e.Vertexes[0].Point.y, e.Vertexes[1].Point.x, e.Vertexes[1].Point.y)) else: PathLog.debug(" (%.2f, %.2f)^%.2f" % (e.Curve.Center.x, e.Curve.Center.y, e.Curve.Radius)) for pt in DraftGeomUtils.findIntersection(edge, e, True, findAll=True): if not PathGeom.pointsCoincide(pt, corner) and self.pointIsOnEdge(pt, e): # debugMarker(pt, "candidate-%d-%s" % (self.boneId, d), color, 0.05) PathLog.debug(" -> candidate") distance = (pt - refPoint).Length if not pivot or pivotDistance > distance: pivot = pt pivotDistance = distance else: PathLog.debug(" -> corner intersect") if pivot: # debugCircle(pivot, self.toolRadius, "pivot.%d-%s" % (self.boneId, d), color) pivotEdge = Part.Edge(Part.Circle(pivot, FreeCAD.Vector(0, 0, 1), self.toolRadius)) t1 = self.findPivotIntersection(pivot, pivotEdge, inChord.asEdge(), inChord.End, d, color) t2 = self.findPivotIntersection(pivot, pivotEdge, outChord.asEdge(), inChord.End, d, color) commands = [] if not PathGeom.pointsCoincide(t1, inChord.Start): PathLog.debug(" add lead in") commands.append(Chord(inChord.Start, t1).g1Command(bone.F)) if bone.obj.Side == Side.Left: PathLog.debug(" add g3 command") commands.append(Chord(t1, t2).g3Command(pivot, bone.F)) else: PathLog.debug(" add g2 command center=(%.2f, %.2f) -> from (%2f, %.2f) to (%.2f, %.2f" % (pivot.x, pivot.y, t1.x, t1.y, t2.x, t2.y)) commands.append(Chord(t1, t2).g2Command(pivot, bone.F)) if not PathGeom.pointsCoincide(t2, outChord.End): PathLog.debug(" add lead out") commands.append(Chord(t2, outChord.End).g1Command(bone.F)) # debugMarker(pivot, "pivot.%d-%s" % (self.boneId, d), color, 0.2) # debugMarker(t1, "pivot.%d-%s.in" % (self.boneId, d), color, 0.1) # debugMarker(t2, "pivot.%d-%s.out" % (self.boneId, d), color, 0.1) return commands PathLog.info(" no pivot found - straight command") return [inChord.g1Command(bone.F), outChord.g1Command(bone.F)]
def execute(self,obj): import Part, math, DraftGeomUtils pl = obj.Placement self.baseface = None base = None if obj.Base and obj.Angles: w = None if obj.Base.isDerivedFrom("Part::Feature"): if (obj.Base.Shape.Faces and obj.Face): w = obj.Base.Shape.Faces[obj.Face-1].Wires[0] elif obj.Base.Shape.Wires: w = obj.Base.Shape.Wires[0] if w: if w.isClosed(): self.profilsDico = [] self.shps = [] self.subVolshps = [] heights = [] edges = DraftGeomUtils.sortEdges(w.Edges) l = len(edges) print("le contour contient "+str(l)+" aretes") for i in range(l): self.makeRoofProfilsDic(i, obj.Angles[i], obj.Runs[i], obj.IdRel[i], obj.Overhang[i], obj.Thickness[i]) for i in range(l): self.calcMissingData(i) for p in self.profilsDico: heights.append(p["height"]) obj.Heights = heights for i in range(l): edgesForward = edges[:] edgesForward.append(edges[0]) ptsPaneProject=[] profil0 =self.profilsDico[i-1] profil1 =self.profilsDico[i] if i == l-1: profil2 =self.profilsDico[0] else: profil2 =self.profilsDico[i+1] vec0 = edges[i-1].Vertexes[-1].Point.sub(edges[i-1].Vertexes[0].Point) vec1 = edges[i].Vertexes[-1].Point.sub(edges[i].Vertexes[0].Point) vec2 = edgesForward[i+1].Vertexes[-1].Point.sub(edgesForward[i+1].Vertexes[0].Point) rotEdge0 = math.degrees(DraftVecUtils.angle(vec0)) rotEdge1 = math.degrees(DraftVecUtils.angle(vec1)) rotEdge2 = math.degrees(DraftVecUtils.angle(vec2)) edgeEave0 = DraftGeomUtils.offset(edges[i-1],self.getPerpendicular(vec0,rotEdge0,profil0["overhang"]).negative()) edgeEave1 = DraftGeomUtils.offset(edges[i],self.getPerpendicular(vec1,rotEdge1,profil1["overhang"]).negative()) edgeEave2 = DraftGeomUtils.offset(edgesForward[i+1],self.getPerpendicular(vec2,rotEdge2,profil2["overhang"]).negative()) pt0Eave1 = DraftGeomUtils.findIntersection(edgeEave0,edgeEave1,infinite1=True,infinite2=True,) pt1Eave1 = DraftGeomUtils.findIntersection(edgeEave1,edgeEave2,infinite1=True,infinite2=True,) edgeEave1 = DraftGeomUtils.edg(FreeCAD.Vector(pt0Eave1[0]),FreeCAD.Vector(pt1Eave1[0])) edgeRidge0 = DraftGeomUtils.offset(edges[i-1],self.getPerpendicular(vec0,rotEdge0,profil0["run"])) edgeRidge1 = DraftGeomUtils.offset(edges[i],self.getPerpendicular(vec1,rotEdge1,profil1["run"])) edgeRidge2 = DraftGeomUtils.offset(edgesForward[i+1],self.getPerpendicular(vec2,rotEdge2,profil2["run"])) midpoint = DraftGeomUtils.findMidpoint(edges[i]) pt0Edge1 = edges[i].Vertexes[0].Point pt1Edge1 = edges[i].Vertexes[-1].Point print("Analyse profil " + str(i)) if profil1["angle"] != 90.: if profil2["angle"] == 90. : print("situation a droite : pignon") ptsPaneProject.append(FreeCAD.Vector(pt1Eave1[0])) point = DraftGeomUtils.findIntersection(edgeRidge1,edgeEave2,infinite1=True,infinite2=True,) ptsPaneProject.append(FreeCAD.Vector(point[0])) elif profil1["height"] == profil2["height"] : print("situation a droite : ht1 = ht2") ptInterRidges = DraftGeomUtils.findIntersection(edgeRidge1,edgeRidge2,infinite1=True,infinite2=True,) edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInterRidges[0]),pt1Edge1) ptInterHipEave1 = DraftGeomUtils.findIntersection(edgeHip,edgeEave1,infinite1=True,infinite2=False,) if ptInterHipEave1: ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave1[0])) else: ptInterHipEave2 = DraftGeomUtils.findIntersection(edgeHip,edgeEave2,infinite1=True,infinite2=True,) ptsPaneProject.append(FreeCAD.Vector(pt1Eave1[0])) ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave2[0])) ptsPaneProject.append(FreeCAD.Vector(ptInterRidges[0])) elif profil1["height"] > profil2["height"]: print("situation a droite : ht1 > ht2") dec = profil2["height"]/math.tan(math.radians(profil1["angle"])) edgeRidge2OnPane = DraftGeomUtils.offset(edges[i],self.getPerpendicular(vec1,rotEdge1,dec)) ptInter1 = DraftGeomUtils.findIntersection(edgeRidge2,edgeRidge2OnPane,infinite1=True,infinite2=True,) edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInter1[0]),pt1Edge1) ptInterHipEave1 = DraftGeomUtils.findIntersection(edgeHip,edgeEave1,infinite1=True,infinite2=False,) if ptInterHipEave1: ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave1[0])) else: ptInterHipEave2 = DraftGeomUtils.findIntersection(edgeHip,edgeEave2,infinite1=True,infinite2=True,) ptsPaneProject.append(FreeCAD.Vector(pt1Eave1[0])) ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave2[0])) ptsPaneProject.append(FreeCAD.Vector(ptInter1[0])) ptInter2 = edgeHip.Vertexes[0].Point vecInterRidges = DraftGeomUtils.findPerpendicular(ptInter2, [edgeRidge1.Edges[0],], force=0) ptInterRidges = ptInter2.add(vecInterRidges[0]) ptsPaneProject.append(FreeCAD.Vector(ptInterRidges)) elif profil1["height"] < profil2["height"]: print("situation a droite : ht1 < ht2") dec = profil1["height"]/math.tan(math.radians(profil2["angle"])) edgeRidge2OnPane = DraftGeomUtils.offset(edgesForward[i+1],self.getPerpendicular(vec2,rotEdge2,dec)) ptInter1 = DraftGeomUtils.findIntersection(edgeRidge1,edgeRidge2OnPane,infinite1=True,infinite2=True,) edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInter1[0]),pt1Edge1) ptInterHipEave1 = DraftGeomUtils.findIntersection(edgeHip,edgeEave1,infinite1=True,infinite2=False,) if ptInterHipEave1: ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave1[0])) else: ptInterHipEave2 = DraftGeomUtils.findIntersection(edgeHip,edgeEave2,infinite1=True,infinite2=True,) ptsPaneProject.append(FreeCAD.Vector(pt1Eave1[0])) ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave2[0])) ptsPaneProject.append(FreeCAD.Vector(ptInter1[0])) ptInterRidges = DraftGeomUtils.findIntersection(edgeRidge1,edgeRidge2,infinite1=True,infinite2=True,) ptsPaneProject.append(FreeCAD.Vector(ptInterRidges[0])) else: print("Cas de figure non pris en charge") if profil0["angle"] == 90. : print("situation a gauche : pignon") point = DraftGeomUtils.findIntersection(edgeRidge1,edgeEave0,infinite1=True,infinite2=True,) ptsPaneProject.append(FreeCAD.Vector(point[0])) ptsPaneProject.append(FreeCAD.Vector(pt0Eave1[0])) elif profil0["height"] == profil1["height"]: print("situation a gauche : ht1 = ht0") edgeRidge0 = DraftGeomUtils.offset(edges[i-1],self.getPerpendicular(vec0,rotEdge0,profil0["run"])) ptInterRidges = DraftGeomUtils.findIntersection(edgeRidge1,edgeRidge0,infinite1=True,infinite2=True,) ptsPaneProject.append(FreeCAD.Vector(ptInterRidges[0])) edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInterRidges[0]),pt0Edge1) ptInterHipEave3 = DraftGeomUtils.findIntersection(edgeHip,edgeEave1,infinite1=True,infinite2=False,) if ptInterHipEave3: ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave3[0])) else: ptInterHipEave4 = DraftGeomUtils.findIntersection(edgeHip,edgeEave0,infinite1=True,infinite2=True,) ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave4[0])) ptsPaneProject.append(FreeCAD.Vector(pt0Eave1[0])) elif profil1["height"] > profil0["height"]: print("situation a gauche : ht1 > ht0") dec = profil0["height"]/math.tan(math.radians(profil1["angle"])) edgeRidge0OnPane = DraftGeomUtils.offset(edges[i],self.getPerpendicular(vec1,rotEdge1,dec)) ptInter1 = DraftGeomUtils.findIntersection(edgeRidge0OnPane,edgeRidge0,infinite1=True,infinite2=True,) edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInter1[0]),pt0Edge1) ptInter2 = edgeHip.Vertexes[0].Point vecInterRidges = DraftGeomUtils.findPerpendicular(ptInter2, [edgeRidge1.Edges[0],], force=0) ptInterRidges = ptInter2.add(vecInterRidges[0]) ptsPaneProject.append(FreeCAD.Vector(ptInterRidges)) ptsPaneProject.append(FreeCAD.Vector(ptInter1[0])) ptInterHipEave3 = DraftGeomUtils.findIntersection(edgeHip,edgeEave1,infinite1=True,infinite2=False,) if ptInterHipEave3: ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave3[0])) else: ptInterHipEave4 = DraftGeomUtils.findIntersection(edgeHip,edgeEave0,infinite1=True,infinite2=True,) ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave4[0])) ptsPaneProject.append(FreeCAD.Vector(pt0Eave1[0])) elif profil1["height"] < profil0["height"]: print("situation a gauche : ht1 < ht0") dec = profil1["height"]/math.tan(math.radians(profil0["angle"])) edgeRidge0OnPane = DraftGeomUtils.offset(edges[i-1],self.getPerpendicular(vec0,rotEdge0,dec)) ptInterRidges = DraftGeomUtils.findIntersection(edgeRidge0OnPane,edgeRidge1,infinite1=True,infinite2=True,) ptsPaneProject.append(FreeCAD.Vector(ptInterRidges[0])) edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInterRidges[0]),pt0Edge1) ptInterHipEave3 = DraftGeomUtils.findIntersection(edgeHip,edgeEave1,infinite1=True,infinite2=False,) if ptInterHipEave3: ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave3[0])) else: ptInterHipEave4 = DraftGeomUtils.findIntersection(edgeHip,edgeEave0,infinite1=True,infinite2=True,) ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave4[0])) ptsPaneProject.append(FreeCAD.Vector(pt0Eave1[0])) else: print("Cas de figure non pris en charge") ptsPaneProject = DraftVecUtils.removeDoubles(ptsPaneProject) print("ptsPaneProject",ptsPaneProject) print("Fin Analyse profil " + str(i)) self.profilsDico[i]["points"] = ptsPaneProject lp = len(ptsPaneProject) ptsPaneProject.append(ptsPaneProject[0]) edgesWire = [] for i in range(lp): edge = Part.makeLine(ptsPaneProject[i],ptsPaneProject[i+1]) edgesWire.append(edge) wire = Part.Wire(edgesWire) d = wire.BoundBox.DiagonalLength thicknessV = profil1["thickness"]/(math.cos(math.radians(profil1["angle"]))) overhangV = profil1["overhang"]*math.tan(math.radians(profil1["angle"])) if wire.isClosed(): f = Part.Face(wire) f = f.extrude(FreeCAD.Vector(0,0,profil1["height"]+2*thicknessV+2*overhangV)) f.translate(FreeCAD.Vector(0.0,0.0,-2*overhangV)) ptsPaneProfil=[FreeCAD.Vector(-profil1["overhang"],-overhangV,0.0),FreeCAD.Vector(profil1["run"],profil1["height"],0.0),FreeCAD.Vector(profil1["run"],profil1["height"]+thicknessV,0.0),FreeCAD.Vector(-profil1["overhang"],-overhangV+thicknessV,0.0)] self.createProfilShape (ptsPaneProfil, midpoint, rotEdge1, vec1, profil1["run"], d, self.shps, f) ## subVolume shape ptsSubVolumeProfil=[FreeCAD.Vector(-profil1["overhang"],-overhangV,0.0),FreeCAD.Vector(profil1["run"],profil1["height"],0.0),FreeCAD.Vector(profil1["run"],profil1["height"]+10000,0.0),FreeCAD.Vector(0.0,profil1["height"]+10000,0.0)] self.createProfilShape (ptsSubVolumeProfil, midpoint, rotEdge1, vec1, profil1["run"], d, self.subVolshps, f) else: #TODO PIGNON pass ## SubVolume self.sub = self.subVolshps.pop() for s in self.subVolshps: self.sub = self.sub.fuse(s) self.sub = self.sub.removeSplitter() if not self.sub.isNull(): if not DraftGeomUtils.isNull(pl): self.sub.Placement = pl ## BaseVolume base = Part.makeCompound(self.shps) if not base.isNull(): if not DraftGeomUtils.isNull(pl): base.Placement = pl base = self.processSubShapes(obj,base) if base: if not base.isNull(): obj.Shape = base
def redraw(self, point, snapped=None, shift=False, alt=False, real=None): """Redraw the ghost normally.""" # initializing reverse = False for g in self.ghost: g.off() if real: newedges = [] import DraftGeomUtils import Part # finding the active point vlist = [] for e in self.edges: vlist.append(e.Vertexes[0].Point) vlist.append(self.edges[-1].Vertexes[-1].Point) if shift: npoint = self.activePoint else: npoint = DraftGeomUtils.findClosest(point, vlist) if npoint > len(self.edges) / 2: reverse = True if alt: reverse = not reverse self.activePoint = npoint # sorting out directions if reverse and (npoint > 0): npoint = npoint - 1 if (npoint > len(self.edges) - 1): edge = self.edges[-1] ghost = self.ghost[-1] else: edge = self.edges[npoint] ghost = self.ghost[npoint] if reverse: v1 = edge.Vertexes[-1].Point v2 = edge.Vertexes[0].Point else: v1 = edge.Vertexes[0].Point v2 = edge.Vertexes[-1].Point # snapping if snapped: snapped = self.doc.getObject(snapped['Object']) if hasattr(snapped, "Shape"): pts = [] for e in snapped.Shape.Edges: int = DraftGeomUtils.findIntersection(edge, e, True, True) if int: pts.extend(int) if pts: point = pts[DraftGeomUtils.findClosest(point, pts)] # modifying active edge if DraftGeomUtils.geomType(edge) == "Line": ve = DraftGeomUtils.vec(edge) chord = v1.sub(point) n = ve.cross(chord) if n.Length == 0: self.newpoint = point else: perp = ve.cross(n) proj = DraftVecUtils.project(chord, perp) self.newpoint = App.Vector.add(point, proj) dist = v1.sub(self.newpoint).Length ghost.p1(self.newpoint) ghost.p2(v2) self.ui.labelRadius.setText(translate("draft", "Distance")) self.ui.radiusValue.setToolTip( translate("draft", "The offset distance")) if real: if self.force: ray = self.newpoint.sub(v1) ray.multiply(self.force / ray.Length) self.newpoint = App.Vector.add(v1, ray) newedges.append(Part.LineSegment(self.newpoint, v2).toShape()) else: center = edge.Curve.Center rad = edge.Curve.Radius ang1 = DraftVecUtils.angle(v2.sub(center)) ang2 = DraftVecUtils.angle(point.sub(center)) _rot_rad = DraftVecUtils.rotate(App.Vector(rad, 0, 0), -ang2) self.newpoint = App.Vector.add(center, _rot_rad) self.ui.labelRadius.setText(translate("draft", "Angle")) self.ui.radiusValue.setToolTip( translate("draft", "The offset angle")) dist = math.degrees(-ang2) # if ang1 > ang2: # ang1, ang2 = ang2, ang1 # print("last calculated:", # math.degrees(-ang1), # math.degrees(-ang2)) ghost.setEndAngle(-ang2) ghost.setStartAngle(-ang1) ghost.setCenter(center) ghost.setRadius(rad) if real: if self.force: angle = math.radians(self.force) newray = DraftVecUtils.rotate(App.Vector(rad, 0, 0), -angle) self.newpoint = App.Vector.add(center, newray) chord = self.newpoint.sub(v2) perp = chord.cross(App.Vector(0, 0, 1)) scaledperp = DraftVecUtils.scaleTo(perp, rad) midpoint = App.Vector.add(center, scaledperp) _sh = Part.Arc(self.newpoint, midpoint, v2).toShape() newedges.append(_sh) ghost.on() # resetting the visible edges if not reverse: li = list(range(npoint + 1, len(self.edges))) else: li = list(range(npoint - 1, -1, -1)) for i in li: edge = self.edges[i] ghost = self.ghost[i] if DraftGeomUtils.geomType(edge) == "Line": ghost.p1(edge.Vertexes[0].Point) ghost.p2(edge.Vertexes[-1].Point) else: ang1 = DraftVecUtils.angle(edge.Vertexes[0].Point.sub(center)) ang2 = DraftVecUtils.angle(edge.Vertexes[-1].Point.sub(center)) # if ang1 > ang2: # ang1, ang2 = ang2, ang1 ghost.setEndAngle(-ang2) ghost.setStartAngle(-ang1) ghost.setCenter(edge.Curve.Center) ghost.setRadius(edge.Curve.Radius) if real: newedges.append(edge) ghost.on() # finishing if real: return newedges else: return dist
def trim():# main global mysel obj = mysel[0] pos = mysel[1] sub = mysel[2] myobj = obj obj = downgrade_start_obj(obj)# downgrade for i in obj: # delete what you click if DraftGeomUtils.isSameLine(i.Shape.Edge1,sub): myobj = i #FreeCAD.ActiveDocument.removeObject(i) break FreeCAD.ActiveDocument.recompute() allobjs=FreeCAD.ActiveDocument.Objects allobjs.remove(myobj) connet_edge_list = [] connet_obj_list = [] for i in allobjs: if str(type(i)) <> "<type 'App.DocumentObjectGroup'>" and FreeCADGui.ActiveDocument.getObject(i.Name).Visibility==True: for edge in i.Shape.Edges: # edges in obj if DraftGeomUtils.findIntersection(edge,sub): # if there is a interpoint in edge and sub_edge(click)... connet_edge_list.append(edge) connet_obj_list.append(i) prf('Edge Inter ( click edge )',i.Name) prf('connet edge num',len(connet_edge_list)) if len(connet_edge_list) == 0: prf('find no intersectionpoint,delete the obj!') FreeCAD.ActiveDocument.removeObject(myobj.Name) elif len(connet_edge_list) == 1: objs = downgrade_obj([myobj,mkobj(connet_edge_list[0])]) myedge = getinteredge(objs,pos) FreeCAD.ActiveDocument.removeObject(myedge.Name) elif len(connet_edge_list) > 1: myedge = mkobj(getinteredge(connet_edge_list,pos,True)) obj1 = downgrade_obj([myobj,myedge]) myedge = getinteredge(obj1,pos) if len(obj1) == 1: FreeCAD.ActiveDocument.removeObject(obj1[0].Name) return() if obj1[0].Name == myedge.Name: another_edge = obj1[1] else: another_edge = obj1[0] click_edge = myedge my_new_connet_edge = [] for i in connet_edge_list: if DraftGeomUtils.findIntersection(i,click_edge.Shape.Edge1): if not DraftGeomUtils.findIntersection(i,another_edge.Shape.Edge1): my_new_connet_edge.append(i) if my_new_connet_edge: myedge1 = mkobj(getinteredge(my_new_connet_edge,pos,True)) myobj = downgrade_obj([myedge,myedge1]) myedge = getinteredge(myobj,pos) # del obj FreeCAD.ActiveDocument.removeObject(myedge.Name) else: FreeCAD.ActiveDocument.removeObject(click_edge.Name) FreeCAD.ActiveDocument.recompute()
def run(self): """run(): Runs a nesting operation. Returns a list of lists of shapes, each primary list being one filled container, or None if the operation failed.""" # reset abort mechanism and variables self.running = True self.progress = 0 starttime = datetime.now() # general conformity tests print("Executing conformity tests ... ",end="") if not self.container: print("Empty container. Aborting") return if not self.shapes: print("Empty shapes. Aborting") return if not isinstance(self.container,Part.Face): print("Container is not a face. Aborting") return normal = self.container.normalAt(0,0) for s in self.shapes: if not self.update(): return if len(s.Faces) != 1: print("One of the shapes does not contain exactly one face. Aborting") return # check if all faces correctly oriented (same normal) if s.Faces[0].normalAt(0,0).getAngle(normal) > TOLERANCE: # let pass faces with inverted normal if s.Faces[0].normalAt(0,0).getAngle(normal)-math.pi > TOLERANCE: print("One of the face doesn't have the same orientation as the container. Aborting") return # TODO # allow to use a non-rectangular container # manage margins/paddings # allow to prevent or force specific rotations for a piece # LONG-TERM TODO # add genetic algo to swap pieces, and check if the result is better # track progresses step = 100.0/(len(self.shapes)*len(ROTATIONS)) # store hashCode together with the face so we can change the order # and still identify the original face, so we can calculate a transform afterwards self.indexedfaces = [[shape.hashCode(),shape] for shape in self.shapes] # build a clean copy so we don't touch the original faces = list(self.indexedfaces) # replace shapes by their face faces = [[f[0],f[1].Faces[0]] for f in faces] # order by area faces = sorted(faces,key=lambda face: face[1].Area) # discretize non-linear edges and remove holes nfaces = [] for face in faces: if not self.update(): return nedges = [] allLines = True for edge in face[1].OuterWire.OrderedEdges: if isinstance(edge.Curve,(Part.LineSegment,Part.Line)): nedges.append(edge) else: allLines = False last = edge.Vertexes[0].Point for i in range(DISCRETIZE): s = float(i+1)/DISCRETIZE par = edge.FirstParameter + (edge.LastParameter-edge.FirstParameter)*s new = edge.valueAt(par) nedges.append(Part.LineSegment(last,new).toShape()) last = new f = Part.Face(Part.Wire(nedges)) if not f.isValid(): if allLines: print("Invalid face found in set. Aborting") else: print("Face distretizing failed. Aborting") return nfaces.append([face[0],f]) faces = nfaces # container for sheets with a first, empty sheet sheets = [[]] print("Everything OK (",datetime.now()-starttime,")") # main loop facenumber = 1 facesnumber = len(faces) #print("Vertices per face:",[len(face[1].Vertexes) for face in faces]) while faces: print("Placing piece",facenumber,"/",facesnumber,"Area:",FreeCAD.Units.Quantity(faces[-1][1].Area,FreeCAD.Units.Area).getUserPreferred()[0],": ",end="") face = faces.pop() boc = self.container.BoundBox # this stores the available solutions for each rotation of a piece # contains [sheetnumber,face,xlength] lists, # face being [hascode,transformed face] and xlength # the X size of all boundboxes of placed pieces available = [] # this stores the possible positions on a blank # sheet, in case we need to create a new one initials = [] # this checks if the piece don't fit in the container unfit = True for rotation in ROTATIONS: if not self.update(): return self.progress += step print(rotation,", ",end="") hashcode = face[0] rotface = face[1].copy() if rotation: rotface.rotate(rotface.CenterOfMass,normal,rotation) bof = rotface.BoundBox rotverts = self.order(rotface) #for i,v in enumerate(rotverts): # Draft.makeText([str(i)],point=v) basepoint = rotverts[0] # leftmost point of the rotated face basecorner = boc.getPoint(0) # lower left corner of the container # See if the piece fits in the container dimensions if (bof.XLength < boc.XLength) and (bof.YLength < boc.YLength): unfit = False # Get the fit polygon of the container # that is, the polygon inside which basepoint can # circulate, and the face still be fully inside the container v1 = basecorner.add(basepoint.sub(bof.getPoint(0))) v2 = v1.add(FreeCAD.Vector(0,boc.YLength-bof.YLength,0)) v3 = v2.add(FreeCAD.Vector(boc.XLength-bof.XLength,0,0)) v4 = v3.add(FreeCAD.Vector(0,-(boc.YLength-bof.YLength),0)) binpol = Part.Face(Part.makePolygon([v1,v2,v3,v4,v1])) initials.append([binpol,[hashcode,rotface],basepoint]) # check for available space on each existing sheet for sheetnumber,sheet in enumerate(sheets): # Get the no-fit polygon for each already placed face in # current sheet. That is, a polygon in which basepoint # cannot be, if we want our face to not overlap with the # placed face. # To do this, we "circulate" the face around the placed face if not self.update(): return nofitpol = [] for placed in sheet: pts = [] pi = 0 for placedvert in self.order(placed[1],right=True): fpts = [] for i,rotvert in enumerate(rotverts): if not self.update(): return facecopy = rotface.copy() facecopy.translate(placedvert.sub(rotvert)) # test if all the points of the face are outside the # placed face (except the base point, which is coincident) outside = True faceverts = self.order(facecopy) for vert in faceverts: if (vert.sub(placedvert)).Length > TOLERANCE: if placed[1].isInside(vert,TOLERANCE,True): outside = False break # also need to test for edge intersection, because even # if all vertices are outside, the pieces could still # overlap if outside: for e1 in facecopy.OuterWire.Edges: for e2 in placed[1].OuterWire.Edges: if not self.update(): return if True: # Draft code (SLOW) p = DraftGeomUtils.findIntersection(e1,e2) if p: p = p[0] p1 = e1.Vertexes[0].Point p2 = e1.Vertexes[1].Point p3 = e2.Vertexes[0].Point p4 = e2.Vertexes[1].Point if (p.sub(p1).Length > TOLERANCE) and (p.sub(p2).Length > TOLERANCE) \ and (p.sub(p3).Length > TOLERANCE) and (p.sub(p4).Length > TOLERANCE): outside = False break else: # alt code: using distToShape (EVEN SLOWER!) p = e1.distToShape(e2) if p: if p[0] < TOLERANCE: # allow vertex-to-vertex intersection if (p[2][0][0] != "Vertex") or (p[2][0][3] != "Vertex"): outside = False break if outside: fpts.append([faceverts[0],i]) #Draft.makeText([str(i)],point=faceverts[0]) # reorder available solutions around a same point if needed # ensure they are in the correct order idxs = [p[1] for p in fpts] if (0 in idxs) and (len(faceverts)-1 in idxs): slicepoint = len(fpts) last = len(faceverts) for p in reversed(fpts): if p[1] == last-1: slicepoint -= 1 last -= 1 else: break fpts = fpts[slicepoint:]+fpts[:slicepoint] #print(fpts) pts.extend(fpts) # create the polygon if len(pts) < 3: print("Error calculating a no-fit polygon. Aborting") return pts = [p[0] for p in pts] pol = Part.Face(Part.makePolygon(pts+[pts[0]])) if not pol.isValid(): # fix overlapping edges overlap = True while overlap: overlap = False for i in range(len(pol.OuterWire.Edges)-1): if not self.update(): return v1 = DraftGeomUtils.vec(pol.OuterWire.OrderedEdges[i]) v2 = DraftGeomUtils.vec(pol.OuterWire.OrderedEdges[i+1]) if abs(v1.getAngle(v2)-math.pi) <= TOLERANCE: overlap = True ne = Part.LineSegment(pol.OuterWire.OrderedEdges[i].Vertexes[0].Point, pol.OuterWire.OrderedEdges[i+1].Vertexes[-1].Point).toShape() pol = Part.Face(Part.Wire(pol.OuterWire.OrderedEdges[:i]+[ne]+pol.OuterWire.OrderedEdges[i+2:])) break if not pol.isValid(): # trying basic OCC fix pol.fix(0,0,0) if pol.isValid(): if pol.ShapeType == "Face": pol = Part.Face(pol.OuterWire) # discard possible inner holes elif pol.Faces: # several faces after the fix, keep the biggest one a = 0 ff = None for f in pol.Faces: if f.Area > a: a = f.Area ff = f if ff: pol = ff else: print("Unable to fix invalid no-fit polygon. Aborting") Part.show(pol) return if not pol.isValid(): # none of the fixes worked. Epic fail. print("Invalid no-fit polygon. Aborting") Part.show(pol.OuterWire) for p in sheet: Part.show(p[1]) Part.show(facecopy) #for i,p in enumerate(faceverts): # Draft.makeText([str(i)],point=p) return if pol.isValid(): nofitpol.append(pol) #Part.show(pol) # Union all the no-fit pols into one if len(nofitpol) == 1: nofitpol = nofitpol[0] elif len(nofitpol) > 1: b = nofitpol.pop() for n in nofitpol: if not self.update(): return b = b.fuse(n) nofitpol = b # remove internal edges (discard edges shared by 2 faces) lut = {} for f in fitpol.Faces: for e in f.Edges: h = e.hashCode() if h in lut: lut[h].append(e) else: lut[h] = [e] edges = [e[0] for e in lut.values() if len(e) == 1] try: pol = Part.Face(Part.Wire(edges)) except: # above method can fail sometimes. Try a slower method w = DraftGeomUtils.findWires(edges) if len(w) == 1: if w[0].isClosed(): try: pol = Part.Face(w[0]) except: print("Error merging polygons. Aborting") try: Part.show(Part.Wire(edges)) except: for e in edges: Part.show(e) return # subtract the no-fit polygon from the container's fit polygon # we then have the zone where the face can be placed if nofitpol: fitpol = binpol.cut(nofitpol) else: fitpol = binpol.copy() # check that we have some space on this sheet if (fitpol.Area > 0) and fitpol.Vertexes: # order the fitpol vertexes by smallest X # and try to place the piece, making sure it doesn't # intersect with already placed pieces fitverts = sorted([v.Point for v in fitpol.Vertexes],key=lambda v: v.x) for p in fitverts: if not self.update(): return trface = rotface.copy() trface.translate(p.sub(basepoint)) ok = True for placed in sheet: if ok: for vert in trface.Vertexes: if placed[1].isInside(vert.Point,TOLERANCE,False): ok = False break if ok: for e1 in trface.OuterWire.Edges: for e2 in placed[1].OuterWire.Edges: p = DraftGeomUtils.findIntersection(e1,e2) if p: p = p[0] p1 = e1.Vertexes[0].Point p2 = e1.Vertexes[1].Point p3 = e2.Vertexes[0].Point p4 = e2.Vertexes[1].Point if (p.sub(p1).Length > TOLERANCE) and (p.sub(p2).Length > TOLERANCE) \ and (p.sub(p3).Length > TOLERANCE) and (p.sub(p4).Length > TOLERANCE): ok = False break if not ok: break if ok: rotface = trface break else: print("Couldn't determine location on sheet. Aborting") return # check the X space occupied by this solution bb = rotface.BoundBox for placed in sheet: bb.add(placed[1].BoundBox) available.append([sheetnumber,[hashcode,rotface],bb.XMax,fitpol]) if unfit: print("One face doesn't fit in the container. Aborting") return if available: # order by smallest X size and take the first one available = sorted(available,key=lambda sol: sol[2]) print("Adding piece to sheet",available[0][0]+1) sheets[available[0][0]].append(available[0][1]) #Part.show(available[0][3]) else: # adding to the leftmost vertex of the binpol sheet = [] print("Creating new sheet, adding piece to sheet",len(sheets)) # order initial positions by smallest X size initials = sorted(initials,key=lambda sol: sol[1][1].BoundBox.XLength) hashcode = initials[0][1][0] face = initials[0][1][1] # order binpol vertexes by X coord verts = sorted([v.Point for v in initials[0][0].Vertexes],key=lambda v: v.x) face.translate(verts[0].sub(initials[0][2])) sheet.append([hashcode,face]) sheets.append(sheet) facenumber += 1 print("Run time:",datetime.now()-starttime) self.results.append(sheets) return sheets
def trimObjects(self, objectslist): """Attempt to trim two objects together.""" import Part import DraftGeomUtils wires = [] for obj in objectslist: if not utils.getType(obj) in ["Wire", "Circle"]: _err( translate( "draft", "Unable to trim these objects, " "only Draft wires and arcs are supported.")) return if len(obj.Shape.Wires) > 1: _err( translate( "draft", "Unable to trim these objects, " "too many wires")) return if len(obj.Shape.Wires) == 1: wires.append(obj.Shape.Wires[0]) else: wires.append(Part.Wire(obj.Shape.Edges)) ints = [] edge1 = None edge2 = None for i1, e1 in enumerate(wires[0].Edges): for i2, e2 in enumerate(wires[1].Edges): i = DraftGeomUtils.findIntersection(e1, e2, dts=False) if len(i) == 1: ints.append(i[0]) edge1 = i1 edge2 = i2 if not ints: _err(translate("draft", "These objects don't intersect.")) return if len(ints) != 1: _err(translate("draft", "Too many intersection points.")) return v11 = wires[0].Vertexes[0].Point v12 = wires[0].Vertexes[-1].Point v21 = wires[1].Vertexes[0].Point v22 = wires[1].Vertexes[-1].Point if DraftVecUtils.closest(ints[0], [v11, v12]) == 1: last1 = True else: last1 = False if DraftVecUtils.closest(ints[0], [v21, v22]) == 1: last2 = True else: last2 = False for i, obj in enumerate(objectslist): if i == 0: ed = edge1 la = last1 else: ed = edge2 la = last2 if utils.getType(obj) == "Wire": if la: pts = obj.Points[:ed + 1] + ints else: pts = ints + obj.Points[ed + 1:] obj.Points = pts else: vec = ints[0].sub(obj.Placement.Base) vec = obj.Placement.inverse().Rotation.multVec(vec) _x = App.Vector(1, 0, 0) _ang = -DraftVecUtils.angle(vec, obj.Placement.Rotation.multVec(_x), obj.Shape.Edges[0].Curve.Axis) ang = math.degrees(_ang) if la: obj.LastAngle = ang else: obj.FirstAngle = ang self.doc.recompute()