def retrieve_thickness_from_biggest_face(freecad_object): area_faces = biggest_area_faces(freecad_object) list_edges_face1 = Part.__sortEdges__(area_faces[2][0].Edges) list_edges_face2 = Part.__sortEdges__(area_faces[2][1].Edges) list_pts_face1 = sort_quad_vertex(list_edges_face1, False) if list_pts_face1 is None: list_pts_face1 = sort_quad_vertex(list_edges_face1, True) if list_pts_face1 is None: raise ValueError("Error sorting vertex") list_pts_face2 = sort_quad_vertex(list_edges_face2, False) if list_pts_face2 is None: list_pts_face2 = sort_quad_vertex(list_edges_face2, True) if list_pts_face2 is None: raise ValueError("Error sorting vertex") min_array = [] for vec1 in list_pts_face1: tab_diff = [] for vec2 in list_pts_face2: tab_diff.append(vec1.sub(vec2).Length) min_array.append(min(tab_diff)) counter_list = collections.Counter(min_array) thickness_occ = counter_list.most_common(1) return thickness_occ[0][0]
def getArea(self,obj): "returns the horizontal area at the center of the space" import Part,DraftGeomUtils if not hasattr(obj.Shape,"CenterOfMass"): return 0 try: pl = Part.makePlane(1,1) pl.translate(obj.Shape.CenterOfMass) sh = obj.Shape.copy() cutplane,v1,v2 = ArchCommands.getCutVolume(pl,sh) e = sh.section(cutplane) e = Part.__sortEdges__(e.Edges) w = Part.Wire(e) f = Part.Face(w) except Part.OCCError: return 0 else: if hasattr(obj,"PerimeterLength"): if w.Length != obj.PerimeterLength.Value: obj.PerimeterLength = w.Length if hasattr(obj,"VerticalArea"): a = 0 for f in sh.Faces: ang = f.normalAt(0,0).getAngle(FreeCAD.Vector(0,0,1)) if (ang > 1.57) and (ang < 1.571): a += f.Area if a != obj.VerticalArea.Value: obj.VerticalArea = a #print "area of ",obj.Label," : ",f.Area return f.Area
def execute(self, obj): edge = _utils.getShape(obj, "Edge", "Edge") curve = curveExtend.getTrimmedCurve(edge) cont_start = 1 if hasattr(obj, "TypeStart"): if obj.TypeStart == "G2 curve": cont_start = 2 cont_end = 1 if hasattr(obj, "TypeEnd"): if obj.TypeEnd == "G2 curve": cont_end = 2 ext = [] if obj.LengthStart > 0: ext.append(curveExtend.extendCurve( curve, 0, obj.LengthStart, cont_start)) if obj.LengthEnd > 0: ext.append(curveExtend.extendCurve( curve, 1, obj.LengthEnd, cont_end)) if not ext == []: if hasattr(obj, "Output"): if obj.Output == "SingleEdge": for c in ext: curve.join(c.toBSpline()) obj.Shape = curve.toShape() else: ext.append(curve) edges = [] for c in ext: edges.append(Part.Edge(c)) w = Part.Wire(Part.__sortEdges__(edges)) w.fixWire() obj.Shape = w
def projectFace(self,face): "projects a single face on the WP" #print "VRM: projectFace start: ",len(face[0].Vertexes)," verts, ",len(face[0].Edges)," edges" wires = [] if not face[0].Wires: if DEBUG: print "Error: Unable to project face on the WP" return None norm = face[0].normalAt(0,0) for w in face[0].Wires: verts = [] edges = Part.__sortEdges__(w.Edges) #print len(edges)," edges after sorting" for e in edges: v = e.Vertexes[0].Point #print v v = self.wp.getLocalCoords(v) verts.append(v) verts.append(verts[0]) if len(verts) > 2: #print "new wire with ",len(verts) wires.append(Part.makePolygon(verts)) try: sh = ArchCommands.makeFace(wires) except: if DEBUG: print "Error: Unable to project face on the WP" return None else: # restoring flipped normals vnorm = self.wp.getLocalCoords(norm) if vnorm.getAngle(sh.normalAt(0,0)) > 1: sh.reverse() #print "VRM: projectFace end: ",len(sh.Vertexes)," verts" return [sh]+face[1:]
def execute(self, obj): import Part # math #DraftGeomUtils output = "" toolLoad = PathUtils.getLastToolLoad(obj) if toolLoad is None or toolLoad.ToolNumber == 0: self.vertFeed = 100 self.horizFeed = 100 self.vertRapid = 100 self.horizRapid = 100 self.radius = 0.25 obj.ToolNumber = 0 obj.ToolDescription = "UNDEFINED" else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = PathUtils.getTool(obj, toolLoad.ToolNumber) if not tool or tool.Diameter == 0: self.radius = 0.25 else: self.radius = tool.Diameter/2 obj.ToolNumber = toolLoad.ToolNumber obj.ToolDescription = toolLoad.Name self.setLabel(obj) output += "(" + obj.Label + ")" if not obj.UseComp: output += "(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")" else: output += "(Uncompensated Tool Path)" parentJob = PathUtils.findParentJob(obj) if parentJob is None: return baseobject = parentJob.Base if baseobject is None: return contourwire = TechDraw.findShapeOutline(baseobject.Shape,1, Vector(0,0,1)) edgelist = contourwire.Edges edgelist = Part.__sortEdges__(edgelist) try: output += self._buildPathLibarea(obj, edgelist) except: FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") if obj.Active: path = Path.Path(output) obj.Path = path if obj.ViewObject: obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False
def getIndices(shape,offset): "returns a list with 2 lists: vertices and face indexes, offsetted with the given amount" vlist = [] elist = [] flist = [] curves = None for e in shape.Edges: try: if not isinstance(e.Curve,Part.LineSegment): if not curves: curves = shape.tessellate(1) FreeCAD.Console.PrintWarning(translate("Arch","Found a shape containing curves, triangulating\n").decode('utf8')) break except: # unimplemented curve type curves = shape.tessellate(1) FreeCAD.Console.PrintWarning(translate("Arch","Found a shape containing curves, triangulating\n").decode('utf8')) break if curves: for v in curves[0]: vlist.append(" "+str(round(v.x,p))+" "+str(round(v.y,p))+" "+str(round(v.z,p))) for f in curves[1]: fi = "" for vi in f: fi += " " + str(vi + offset) flist.append(fi) else: for v in shape.Vertexes: vlist.append(" "+str(round(v.X,p))+" "+str(round(v.Y,p))+" "+str(round(v.Z,p))) if not shape.Faces: for e in shape.Edges: if DraftGeomUtils.geomType(e) == "Line": ei = " " + str(findVert(e.Vertexes[0],shape.Vertexes) + offset) ei += " " + str(findVert(e.Vertexes[-1],shape.Vertexes) + offset) elist.append(ei) for f in shape.Faces: if len(f.Wires) > 1: # if we have holes, we triangulate tris = f.tessellate(1) for fdata in tris[1]: fi = "" for vi in fdata: vdata = Part.Vertex(tris[0][vi]) fi += " " + str(findVert(vdata,shape.Vertexes) + offset) flist.append(fi) else: fi = "" # OCC vertices are unsorted. We need to sort in the right order... edges = Part.__sortEdges__(f.OuterWire.Edges) #print edges for e in edges: #print e.Vertexes[0].Point,e.Vertexes[1].Point v = e.Vertexes[0] ind = findVert(v,shape.Vertexes) if ind == None: return None,None,None fi += " " + str(ind + offset) flist.append(fi) return vlist,elist,flist
def recompute(self,fp): w=fp.wire eds=Part.__sortEdges__(w.Shape.Edges) pts=[] for e in eds: ees=e.discretize(2) pts += ees[0:-1] pts.append(ees[-1]) sp=Part.BSplineCurve() #sp.increaseDegree(3) if fp.mode=="poles": sp.buildFromPoles(pts) elif fp.mode=="interpolate": if fp.InitialTangent.Length<>0 and fp.FinalTangent.Length<>0: sp.interpolate(pts,InitialTangent=fp.InitialTangent,FinalTangent=fp.FinalTangent) elif 1: # tangenten an einzelne Punkte Tangents=[] Tangentflags=[] tt=fp.Tangents print tt for i,p in enumerate(pts): try: # print str(tt[i]) j=','.join(str(tt[i]).split()) # print j # print str(fp.TangentFlags[i]) v=eval("FreeCAD.Vector(" + j +")") v.normalize() Tangents.append(v) Tangentflags.append(str(fp.TangentFlags[i]) == '1') except: print "Fehler Tangenten Vektor ", i+1 Tangents.append(FreeCAD.Vector(1,0,0)) Tangentflags.append(0) try: sp.interpolate(pts,Tangents=Tangents,TangentFlags=Tangentflags) except: sp.interpolate(pts) else: sp.interpolate(pts) elif fp.mode=="approximate": paramtype=fp.paramtype if paramtype<>'Default': sp.approximate(Points=pts,ParamType=paramtype,DegMax=3) else: sp.approximate(pts) printinfo(sp) return sp
def execute(self, obj): import Part # math #DraftGeomUtils output = "" toolLoad = obj.ToolController if toolLoad is None or toolLoad.ToolNumber == 0: FreeCAD.Console.PrintError("No Tool Controller is selected. We need a tool to build a Path.") else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = toolLoad.Proxy.getTool(toolLoad) if not tool or tool.Diameter == 0: FreeCAD.Console.PrintError("No Tool found or diameter is zero. We need a tool to build a Path.") return else: self.radius = tool.Diameter/2 output += "(" + obj.Label + ")" if obj.UseComp: output += "(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")" else: output += "(Uncompensated Tool Path)" if obj.Base: wires = [] for b in obj.Base: edgelist = [] for sub in b[1]: edgelist.append(getattr(b[0].Shape, sub)) wires.extend(findWires(edgelist)) for wire in wires: edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) output += self._buildPathLibarea(obj, edgelist) if obj.Active: path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False
def getArea(self,obj): "returns the horizontal area at the center of the space" import Part,DraftGeomUtils if not hasattr(obj.Shape,"CenterOfMass"): return 0 try: pl = Part.makePlane(1,1) pl.translate(obj.Shape.CenterOfMass) sh = obj.Shape.copy() cutplane,v1,v2 = ArchCommands.getCutVolume(pl,sh) e = sh.section(cutplane) e = Part.__sortEdges__(e.Edges) w = Part.Wire(e) f = Part.Face(w) return f.Area except Part.OCCError: return 0
def flattenFace(self,face): "Returns a face where all vertices have Z = 0" wires = [] for w in face[0].Wires: verts = [] edges = Part.__sortEdges__(w.Edges) for e in edges: v = e.Vertexes[0].Point verts.append(FreeCAD.Vector(v.x,v.y,0)) verts.append(verts[0]) wires.append(Part.makePolygon(verts)) try: sh = Part.Face(wires) except Part.OCCError: if DEBUG: print "Error: Unable to flatten face" return None else: return [sh]+face[1:]
def getObjectData(obj): result = {'name': str(obj.Label.encode("utf8"))} if hasattr(obj, "Description"): result['description'] = str(obj.Description) if FreeCADGui: result['color'] = \ Draft.getrgb(obj.ViewObject.ShapeColor, testbw = False) if obj.isDerivedFrom("Part::Feature"): mesh = Mesh.Mesh(obj.Shape.tessellate(0.1)) # Add wires wires = [] for f in obj.Shape.Faces: for w in f.Wires: wo = Part.Wire(Part.__sortEdges__(w.Edges)) wires.append([[v.x, v.y, v.z] for v in wo.discretize(QuasiDeflection = 0.1)]) result['wires'] = wires elif obj.isDerivedFrom("Mesh::Feature"): mesh = obj.Mesh # Add vertices count = 0 vertices = [] vIndex = {} for p in mesh.Points: v = p.Vector vIndex[p.Index] = count count += 1 vertices.append([v.x, v.y, v.z]) result['vertices'] = vertices # Add facets & normals facets = [[vIndex[i] for i in f.PointIndices] for f in mesh.Facets] normals = [[f.Normal.x, f.Normal.y, f.Normal.z] for f in mesh.Facets] result['normals'] = normals result['facets'] = facets return result
def getPathData(self,w): "Returns a SVG path data string from a 2D wire" def tostr(val): return str(round(val,DraftVecUtils.precision())) edges = Part.__sortEdges__(w.Edges) v = edges[0].Vertexes[0].Point svg = 'M '+ tostr(v.x) +' '+ tostr(v.y) + ' ' for e in edges: if (DraftGeomUtils.geomType(e) == "Line") or (DraftGeomUtils.geomType(e) == "BSplineCurve"): v = e.Vertexes[-1].Point svg += 'L '+ tostr(v.x) +' '+ tostr(v.y) + ' ' elif DraftGeomUtils.geomType(e) == "Circle": r = e.Curve.Radius v = e.Vertexes[-1].Point svg += 'A '+ tostr(r) + ' '+ tostr(r) +' 0 0 1 '+ tostr(v.x) +' ' svg += tostr(v.y) + ' ' if len(edges) > 1: svg += 'Z ' return svg
def get_local_axis(face): list_edges = Part.__sortEdges__(face.Edges) list_points = sort_quad_vertex(list_edges, False) if list_points is None: list_points = sort_quad_vertex(list_edges, True) if list_points is None: raise ValueError("Error sorting vertex") normal_face = face.normalAt(0, 0) y_local = None z_local = None x_local = normal_face.negative() z_local_not_normalized = None y_local_not_normalized = None for x in range(0, 4): vector1 = list_points[(x + 1) % 4] - list_points[x] vector2 = list_points[(x - 1) % 4] - list_points[x] y_local = None z_local = None if vector1.Length >= vector2.Length: z_local_not_normalized = vector2 * 1 y_local_not_normalized = vector1 * 1 y_local = vector1.normalize() z_local = vector2.normalize() else: z_local_not_normalized = vector1 * 1 y_local_not_normalized = vector2 * 1 y_local = vector2.normalize() z_local = vector1.normalize() computed_x_local = y_local.cross(z_local) if compare_freecad_vector(computed_x_local, x_local): # FreeCAD.Console.PrintMessage("\nFound\n") # FreeCAD.Console.PrintMessage(x_local) # FreeCAD.Console.PrintMessage(y_local) # FreeCAD.Console.PrintMessage(z_local) # FreeCAD.Console.PrintMessage("\n\n") return x_local, y_local_not_normalized, z_local_not_normalized return None, None, None
def getFootprint(self,obj): "returns a face that represents the footprint of this space" import Part,DraftGeomUtils if not hasattr(obj.Shape,"CenterOfMass"): return None try: pl = Part.makePlane(1,1) pl.translate(obj.Shape.CenterOfMass) sh = obj.Shape.copy() cutplane,v1,v2 = ArchCommands.getCutVolume(pl,sh) e = sh.section(cutplane) e = Part.__sortEdges__(e.Edges) w = Part.Wire(e) dv = FreeCAD.Vector(obj.Shape.CenterOfMass.x,obj.Shape.CenterOfMass.y,obj.Shape.BoundBox.ZMin) dv = dv.sub(obj.Shape.CenterOfMass) w.translate(dv) return Part.Face(w) except Part.OCCError: return None
def p_polyhedron_action(p) : '''polyhedron_action : polyhedron LPAREN points EQ OSQUARE points_list_3d ESQUARE COMMA faces EQ OSQUARE path_set ESQUARE COMMA keywordargument_list RPAREN SEMICOL | polyhedron LPAREN points EQ OSQUARE points_list_3d ESQUARE COMMA triangles EQ OSQUARE points_list_3d ESQUARE COMMA keywordargument_list RPAREN SEMICOL''' if printverbose: print("Polyhedron Points") v = [] for i in p[6] : if printverbose: print(i) v.append(FreeCAD.Vector(float(i[0]),float(i[1]),float(i[2]))) if printverbose: print(v) print ("Polyhedron "+p[9]) print (p[12]) faces_list = [] mypolyhed = doc.addObject('Part::Feature',p[1]) for i in p[12] : if printverbose: print(i) v2 = FreeCAD.Vector pp =[v2(v[k]) for k in i] # Add first point to end of list to close polygon pp.append(pp[0]) print("pp") print(pp) w = Part.makePolygon(pp) print("w") print(w) try: f = Part.Face(w) except: secWireList = w.Edges[:] f = Part.makeFilledFace(Part.__sortEdges__(secWireList)) #f = make_face(v[int(i[0])],v[int(i[1])],v[int(i[2])]) faces_list.append(f) shell=Part.makeShell(faces_list) solid=Part.Solid(shell).removeSplitter() if solid.Volume < 0: solid.reverse() mypolyhed.Shape=solid p[0] = [mypolyhed]
def makeRoof2(baseobj=None, facenr=0, angles=[ 45., ], run=[], idrel=[ 0, ], thickness=[ 50., ], overhang=[ 100., ], name="Roof"): '''makeRoof(baseobj,[facenr],[angle],[name]) : Makes a roof based on a closed wire or an object. You can provide a list of angles, run, idrel, thickness, overhang for each edges in the wire to define the roof shape. The default for angle is 45 and the list is automatically complete to match with number of edges in the wire. If the base object is a solid the roof take the shape.''' if not FreeCAD.ActiveDocument: FreeCAD.Console.PrintError("No active document. Aborting\n") return import Part obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", name) obj.Label = translate("Arch", name) w = None _Roof(obj) if FreeCAD.GuiUp: _ViewProviderRoof(obj.ViewObject) if baseobj: obj.Base = baseobj if hasattr(obj.Base, 'Shape'): if obj.Base.Shape.Solids: FreeCAD.Console.PrintMessage("meng: Shape.Solids\n") if FreeCAD.GuiUp: obj.Base.ViewObject.hide() else: if (obj.Base.Shape.Faces and obj.Face): w = obj.Base.Shape.Faces[obj.Face - 1].Wires[0] if FreeCAD.GuiUp: obj.Base.ViewObject.hide() FreeCAD.Console.PrintMessage("meng: Shape.else Faces\n") elif obj.Base.Shape.Wires: w = obj.Base.Shape.Wires[0] if FreeCAD.GuiUp: FreeCAD.Console.PrintMessage( "meng: Shape.else Wires\n") obj.Base.ViewObject.hide() if w: FreeCAD.Console.PrintMessage("meng: Wires\n") if w.isClosed(): if FreeCAD.GuiUp: obj.Base.ViewObject.hide() edges = Part.__sortEdges__(w.Edges) l = len(edges) la = len(angles) alist = angles for i in range(l - la): alist.append(angles[0]) obj.Angles = alist rlist = [] minWireEdge = findMinWireEdge(w.Edges) minWireLength = minWireEdge['length'] minWireIndex = minWireEdge['index'] FreeCAD.Console.PrintMessage(str(minWireEdge) + "22222222 ,\n") for i in range(l): # rlist.append(250.) rlist.append(minWireLength / 2.) FreeCAD.Console.PrintMessage( str(minWireLength / 2.) + " ,\n") obj.Runs = rlist lidrel = len(idrel) rellist = idrel for i in range(l - lidrel): rellist.append(0) obj.IdRel = rellist lthick = len(thickness) tlist = thickness for i in range(l - lthick): tlist.append(thickness[0]) obj.Thickness = tlist lover = len(overhang) olist = overhang for i in range(l - lover): olist.append(overhang[0]) obj.Overhang = olist obj.Face = facenr return obj
def execute(self, obj): import Part # math #DraftGeomUtils output = "" toolLoad = PathUtils.getLastToolLoad(obj) if toolLoad is None or toolLoad.ToolNumber == 0: self.vertFeed = 100 self.horizFeed = 100 self.vertRapid = 100 self.horizRapid = 100 self.radius = 0.25 obj.ToolNumber = 0 obj.ToolDescription = "UNDEFINED" else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = PathUtils.getTool(obj, toolLoad.ToolNumber) if tool.Diameter == 0: self.radius = 0.25 else: self.radius = tool.Diameter/2 obj.ToolNumber = toolLoad.ToolNumber obj.ToolDescription = toolLoad.Name if obj.UserLabel == "": obj.Label = obj.Name + " :" + obj.ToolDescription else: obj.Label = obj.UserLabel + " :" + obj.ToolDescription output += "(" + obj.Label + ")" if obj.Side != "On": output += "(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")" else: output += "(Uncompensated Tool Path)" if obj.Base: holes = [] faces = [] for b in obj.Base: for sub in b[1]: shape = getattr(b[0].Shape, sub) if isinstance (shape, Part.Face): faces.append(shape) if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face holes += shape.Wires[1:] else: print ("found a base object which is not a face. Can't continue.") return profileshape = Part.makeCompound(faces) profilewire = TechDraw.findShapeOutline(profileshape, 1, Vector(0,0,1)) if obj.processHoles: for wire in holes: edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) output += self._buildPathLibarea(obj, edgelist, True) if obj.processPerimeter: edgelist = profilewire.Edges edgelist = Part.__sortEdges__(edgelist) output += self._buildPathLibarea(obj, edgelist, False) if obj.Active: path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False
def execute(self, obj): if self.clone(obj): return if not obj.Base: return if not obj.Base.Shape: return if not obj.Base.Shape.Wires: return pl = obj.Placement if obj.Base.Shape.Solids: obj.Shape = obj.Base.Shape.copy() if not pl.isNull(): obj.Placement = obj.Shape.Placement.multiply(pl) else: if not obj.Profile: return if not obj.Profile.isDerivedFrom("Part::Part2DObject"): return if not obj.Profile.Shape: return if not obj.Profile.Shape.Wires: return if not obj.Profile.Shape.Faces: for w in obj.Profile.Shape.Wires: if not w.isClosed(): return import DraftGeomUtils, Part, math baseprofile = obj.Profile.Shape.copy() if hasattr(obj, "ProfilePlacement"): if not obj.ProfilePlacement.isNull(): baseprofile.Placement = obj.ProfilePlacement.multiply( baseprofile.Placement) if not baseprofile.Faces: f = [] for w in baseprofile.Wires: f.append(Part.Face(w)) if len(f) == 1: baseprofile = f[0] else: baseprofile = Part.makeCompound(f) shapes = [] normal = DraftGeomUtils.getNormal(obj.Base.Shape) #for wire in obj.Base.Shape.Wires: edges = obj.Base.Shape.Edges if hasattr(obj, "Edges"): if obj.Edges == "Vertical edges": rv = obj.Base.Placement.Rotation.multVec( FreeCAD.Vector(0, 1, 0)) edges = [ e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)), 4) in [0, 3.1416] ] elif obj.Edges == "Horizontal edges": rv = obj.Base.Placement.Rotation.multVec( FreeCAD.Vector(1, 0, 0)) edges = [ e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)), 4) in [0, 3.1416] ] elif obj.Edges == "Top Horizontal edges": rv = obj.Base.Placement.Rotation.multVec( FreeCAD.Vector(1, 0, 0)) edges = [ e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)), 4) in [0, 3.1416] ] edges = sorted(edges, key=lambda x: x.CenterOfMass.z, reverse=True) z = edges[0].CenterOfMass.z edges = [ e for e in edges if abs(e.CenterOfMass.z - z) < 0.00001 ] elif obj.Edges == "Bottom Horizontal edges": rv = obj.Base.Placement.Rotation.multVec( FreeCAD.Vector(1, 0, 0)) edges = [ e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)), 4) in [0, 3.1416] ] edges = sorted(edges, key=lambda x: x.CenterOfMass.z) z = edges[0].CenterOfMass.z edges = [ e for e in edges if abs(e.CenterOfMass.z - z) < 0.00001 ] for e in edges: #e = wire.Edges[0] bvec = DraftGeomUtils.vec(e) bpoint = e.Vertexes[0].Point profile = baseprofile.copy() #basepoint = profile.Placement.Base if hasattr(obj, "BasePoint"): edges = Part.__sortEdges__(profile.Edges) basepointliste = [profile.CenterOfMass] for edge in edges: basepointliste.append( DraftGeomUtils.findMidpoint(edge)) basepointliste.append(edge.Vertexes[-1].Point) try: basepoint = basepointliste[obj.BasePoint] except IndexError: FreeCAD.Console.PrintMessage( translate( "Arch", "Crossing point not found in profile.\n")) basepoint = basepointliste[0] else: basepoint = profile.CenterOfMass profile.translate(bpoint.sub(basepoint)) if obj.Align: axis = profile.Placement.Rotation.multVec( FreeCAD.Vector(0, 0, 1)) angle = bvec.getAngle(axis) if round(angle, Draft.precision()) != 0: if round(angle, Draft.precision()) != round( math.pi, Draft.precision()): rotaxis = axis.cross(bvec) profile.rotate(DraftVecUtils.tup(bpoint), DraftVecUtils.tup(rotaxis), math.degrees(angle)) if obj.Rotation: profile.rotate( DraftVecUtils.tup(bpoint), DraftVecUtils.tup(FreeCAD.Vector(bvec).normalize()), obj.Rotation) #profile = wire.makePipeShell([profile],True,False,2) TODO buggy profile = profile.extrude(bvec) if obj.Offset: if not DraftVecUtils.isNull(obj.Offset): profile.translate(obj.Offset) shapes.append(profile) if shapes: if hasattr(obj, "Fuse"): if obj.Fuse: if len(shapes) > 1: s = shapes[0].multiFuse(shapes[1:]) s = s.removeSplitter() obj.Shape = s obj.Placement = pl return obj.Shape = Part.makeCompound(shapes) obj.Placement = pl
def makeRibs(self, obj, update): # obj.LeadingEdge, obj.traillingedge, obj.Path, obj.Hullcurves=[obj.leadingedge,obj.traillingedge] ribs = [] if update == True: FreeCAD.Console.PrintMessage( "MakeRibs update ------------------------------------\n") #for i in range(0,len(obj.Ribs)) : # direction=FreeCAD.Vector([0,0,0]) # chord=obj.Ribs[i].Chord ### angle=obj.Ribs[i].Placement.Rotation.Angle #self.updateRib(obj, obj.Ribs[i].Chord, obj.Ribs[i].Placement.Base,direction ,obj.Ribs[i].Placement.Rotation.Angle,i) #self.updateRib(obj, chord, posvecrib,direction, rotaxis,angle,i) ribs = obj.Ribs else: FreeCAD.Console.PrintMessage( "MakeRibs create ------------------------------------\n") FreeCAD.Console.PrintMessage(" Number of Hullcurves : " + str(len(obj.Hullcurves)) + "\n") #--------------CurvesPathArray code-------------------------- curvebox = FreeCAD.BoundBox(float("-inf"), float("-inf"), float("-inf"), float("inf"), float("inf"), float("inf")) for n in range(0, len(obj.Hullcurves)): cbbx = obj.Hullcurves[n].Shape.BoundBox if self.doScaleXYZ[n][0]: if cbbx.XMin > curvebox.XMin: curvebox.XMin = cbbx.XMin if cbbx.XMax < curvebox.XMax: curvebox.XMax = cbbx.XMax if self.doScaleXYZ[n][1]: if cbbx.YMin > curvebox.YMin: curvebox.YMin = cbbx.YMin if cbbx.YMax < curvebox.YMax: curvebox.YMax = cbbx.YMax if self.doScaleXYZ[n][2]: if cbbx.ZMin > curvebox.ZMin: curvebox.ZMin = cbbx.ZMin if cbbx.ZMax < curvebox.ZMax: curvebox.ZMax = cbbx.ZMax if len(obj.Hullcurves) > 0: if curvebox.XMin == float("-inf"): curvebox.XMin = obj.Hullcurves[0].Shape.BoundBox.XMin if curvebox.XMax == float("inf"): curvebox.XMax = obj.Hullcurves[0].Shape.BoundBox.XMax if curvebox.YMin == float("-inf"): curvebox.YMin = obj.Hullcurves[0].Shape.BoundBox.YMin if curvebox.YMax == float("inf"): curvebox.YMax = obj.Hullcurves[0].Shape.BoundBox.YMax if curvebox.ZMin == float("-inf"): curvebox.ZMin = obj.Hullcurves[0].Shape.BoundBox.ZMin if curvebox.ZMax == float("inf"): curvebox.ZMax = obj.Hullcurves[0].Shape.BoundBox.ZMax edges = Part.__sortEdges__(obj.Path.Shape.Edges) leadingedge_edges = Part.__sortEdges__( obj.LeadingEdge.Shape.Edges ) #leadingedge_edges=Part.sortEdges(obj.LeadingEdge.Shape.Edges) # deprecated ! FreeCAD.Console.PrintMessage(" Len of edges : " + str(len(edges)) + "\n") FreeCAD.Console.PrintMessage(" Items : " + str(int(obj.Items)) + "\n") maxlen = obj.LeadingEdge.Shape.Length for n in range(0, int(obj.Items)): FreeCAD.Console.PrintMessage( " Rib number : --- " + str(n) + " ---\n") plen = obj.OffsetStart if obj.Items > 1: plen += (maxlen - obj.OffsetStart - obj.OffsetEnd) * n / (float(obj.Items) - 1) for edge in edges: if plen > edge.Length: plen = edge.Length if plen > edge.Length: print(" plen > edge.Length:") #plen -= edge.Length else: param = edge.getParameterByLength(plen) direction = edge.tangentAt(param) # path direction posvec = edge.valueAt(param) #on path posvec_path = edge.valueAt(param) directionleadingedge = leadingedge_edges[0].tangentAt( param) # leadinedge direction param_leadingedge = leadingedge_edges[ 0].getParameterByLength(plen) posvec_leadingedge = leadingedge_edges[0].valueAt( param_leadingedge) normal = CurvedShapes.getNormal( obj.Base) # get the rib normal rotaxis = normal.cross(direction) angle = math.degrees(normal.getAngle(direction)) planEdge = Part.makePlane(edge.Length, edge.Length, FreeCAD.Vector(0, 0, 0), direction).Faces[0] FreeCAD.Console.PrintMessage( " planEdge : " + str(planEdge) + "\n") uv = planEdge.Surface.parameter(posvec_path) normaledge = planEdge.normalAt(uv[0], uv[1]) FreeCAD.Console.PrintMessage( " normaledge : --- " + str(normaledge) + " ---\n") planLeadingedge = Part.makePlane( leadingedge_edges[0].Length, leadingedge_edges[0].Length, FreeCAD.Vector(0, 0, 0), directionleadingedge) FreeCAD.Console.PrintMessage( " planLeadingedge : " + str(planLeadingedge) + "\n") uv = planLeadingedge.Surface.parameter( posvec_leadingedge) normaLeadingedge = planLeadingedge.normalAt( uv[0], uv[1]) FreeCAD.Console.PrintMessage( " normaLeadingedge c: --- " + str(normaLeadingedge) + " ---\n") #l=Part.Line(FreeCAD.Vector(posvec_path),normaledge) ##ll=Part.Line(FreeCAD.Vector(posvec_leadingedge),normaLeadingedge) #point=l.intersect(normaLeadingedge) #p=App.Vector(1,1,1) #posvec_path.projectToPlane(App.Vector(0,0,0),App.Vector(1,0,1)) #point =normaLeadingedge.cross() # point = FreeCAD.Vector( posvec_leadingedge.x, posvec_leadingedge.y, posvec_path.z ) #math.sqrt(posvec.x*posvec.x+posvec.y*posvec.y))#posvec_path.projectToPlane(planLeadingedge) #point=planLeadingedge.projectPoint.(FreeCAD.Vector(posvec_path)) FreeCAD.Console.PrintMessage( " Intercsection : --- " + str(point) + " ---\n") #normalleadingedge=leadingedge_edges[0].normalAt(param_leadingedge) #A=DraftGeomUtils.findIntersection(normaledge,normalleadingedge) #posvecrib=FreeCAD.Vector(posvec_leadingedge.x, posvec_leadingedge.y,posvec_path.z) #posvecrib=FreeCAD.Vector(posvec_path.x, posvec_path.y,posvec_path.z) posvecrib = FreeCAD.Vector(point.x, point.y, point.z) if len(obj.Ribs) < obj.Items: FreeCAD.Console.PrintMessage( " Rib normal : " + str(normal) + "\n") FreeCAD.Console.PrintMessage( " Path Plen : " + str(plen) + "\n") FreeCAD.Console.PrintMessage( " Path Param : " + str(param) + "\n") FreeCAD.Console.PrintMessage( " Path Position : " + str(posvec) + "\n") FreeCAD.Console.PrintMessage( " Path Direction : " + str(direction) + "\n") FreeCAD.Console.PrintMessage( " Path doScaleXYZ : " + str(self.doScaleXYZ) + "\n") FreeCAD.Console.PrintMessage( " LeadingEdge doScaleXYZ : " + str(self.doScaleXYZ) + "\n") FreeCAD.Console.PrintMessage( " Leading position : " + str(posvec_leadingedge) + "\n") FreeCAD.Console.PrintMessage( " Path position : " + str(posvec_path) + "\n") FreeCAD.Console.PrintMessage( " Rib Angle : " + str(angle) + "\n") FreeCAD.Console.PrintMessage( " Rotaxis : " + str(rotaxis) + "\n") FreeCAD.Console.PrintMessage( " Rotaxis.Length : " + str(rotaxis.Length) + "\n") #plane = Part.Plane(posvecrib, direction) #Part.show(plane) #bbox = CurvedShapes.boundbox_from_intersect(obj.Hullcurves, posvecrib, direction, self.doScaleXYZ,False) bbox = CurvedShapes.boundbox_from_intersect( obj.Hullcurves, posvec_leadingedge, direction, self.doScaleXYZ, False) if bbox: x, y, z, scalex, scaley, scalez = scaleByBoundbox2( obj.Base.Shape, bbox, self.doScaleXYZsum) FreeCAD.Console.PrintMessage(" scalex" + str(scalex) + " \n") FreeCAD.Console.PrintMessage(" scaley" + str(scaley) + " \n") FreeCAD.Console.PrintMessage(" scalez" + str(scalez) + " \n") chord = scalex rib = self.createRib( obj, chord, posvecrib, direction, rotaxis, angle) # posvec_leadingedge FreeCAD.Console.PrintMessage( " Rib.Label : " + str(rib.Label) + "\n") if rib: ribs.append(rib) else: FreeCAD.Console.PrintMessage( " Error : not bbox ------------\n") if len(ribs) > 1: FreeCAD.Console.PrintMessage(" Number of rib created : " + str(len(ribs)) + "\n") self.wingpshape(obj) if update == False: obj.Ribs = ribs print("------------End of makeRibs function------------")
def makeAreaCurve(edges, direction, startpt=None, endpt=None): curveobj = area.Curve() cleanededges = Part.__sortEdges__(cleanedges(edges, 0.01)) # for e in cleanededges: # print str(e.valueAt(e.FirstParameter)) + "," + # str(e.valueAt(e.LastParameter)) edgelist = [] if len(cleanededges) == 1: # user selected a single edge. edgelist = cleanededges else: # edgelist = [] #Multiple edges. Need to sequence the vetexes. # First get the first segment oriented correctly. # We first compare the last parameter of the first segment to see if it # matches either end of the second segment. If not, it must need # flipping. p0L = cleanededges[0].valueAt(cleanededges[0].LastParameter) if PathGeom.pointsCoincide( p0L, cleanededges[1].valueAt(cleanededges[1].FirstParameter) ) or PathGeom.pointsCoincide( p0L, cleanededges[1].valueAt(cleanededges[1].LastParameter)): edge0 = cleanededges[0] else: edge0 = PathUtils.reverseEdge(cleanededges[0]) edgelist.append(edge0) # Now iterate the rest of the edges matching the last parameter of the # previous segment. for edge in cleanededges[1:]: if PathGeom.pointsCoincide( edge.valueAt(edge.FirstParameter), edgelist[-1].valueAt(edgelist[-1].LastParameter)): nextedge = edge else: nextedge = PathUtils.reverseEdge(edge) edgelist.append(nextedge) # print "makeareacurve 87: " + "area.Point(" + # str(edgelist[0].Vertexes[0].X) + ", " + # str(edgelist[0].Vertexes[0].Y)+")" curveobj.append( area.Point(edgelist[0].Vertexes[0].X, edgelist[0].Vertexes[0].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 curveobj.IsClockwise() and direction == 'CCW': curveobj.Reverse() elif not curveobj.IsClockwise() and direction == 'CW': curveobj.Reverse() return curveobj
def execute(self,obj): if self.clone(obj): return if not obj.Base: return if not obj.Base.Shape: return if not obj.Base.Shape.Wires: return pl = obj.Placement if obj.Base.Shape.Solids: obj.Shape = obj.Base.Shape.copy() if not pl.isNull(): obj.Placement = obj.Shape.Placement.multiply(pl) else: if not obj.Profile: return if not obj.Profile.isDerivedFrom("Part::Part2DObject"): return if not obj.Profile.Shape: return if not obj.Profile.Shape.Wires: return if not obj.Profile.Shape.Faces: for w in obj.Profile.Shape.Wires: if not w.isClosed(): return import DraftGeomUtils, Part, math baseprofile = obj.Profile.Shape.copy() if hasattr(obj,"ProfilePlacement"): if not obj.ProfilePlacement.isNull(): baseprofile.Placement = obj.ProfilePlacement.multiply(baseprofile.Placement) if not baseprofile.Faces: f = [] for w in baseprofile.Wires: f.append(Part.Face(w)) if len(f) == 1: baseprofile = f[0] else: baseprofile = Part.makeCompound(f) shapes = [] normal = DraftGeomUtils.getNormal(obj.Base.Shape) #for wire in obj.Base.Shape.Wires: for e in obj.Base.Shape.Edges: #e = wire.Edges[0] bvec = DraftGeomUtils.vec(e) bpoint = e.Vertexes[0].Point profile = baseprofile.copy() #basepoint = profile.Placement.Base if hasattr(obj,"BasePoint"): edges = Part.__sortEdges__(profile.Edges) basepointliste = [profile.CenterOfMass] for edge in edges: basepointliste.append(DraftGeomUtils.findMidpoint(edge)) basepointliste.append(edge.Vertexes[-1].Point) try: basepoint = basepointliste[obj.BasePoint] except IndexError: FreeCAD.Console.PrintMessage(translate("Arch","Crossing point not found in profile.\n")) basepoint = basepointliste[0] else : basepoint = profile.CenterOfMass profile.translate(bpoint.sub(basepoint)) if obj.Align: axis = profile.Placement.Rotation.multVec(FreeCAD.Vector(0,0,1)) angle = bvec.getAngle(axis) if round(angle,Draft.precision()) != 0: if round(angle,Draft.precision()) != round(math.pi,Draft.precision()): rotaxis = axis.cross(bvec) profile.rotate(DraftVecUtils.tup(bpoint), DraftVecUtils.tup(rotaxis), math.degrees(angle)) if obj.Rotation: profile.rotate(DraftVecUtils.tup(bpoint), DraftVecUtils.tup(FreeCAD.Vector(bvec).normalize()), obj.Rotation) #profile = wire.makePipeShell([profile],True,False,2) TODO buggy profile = profile.extrude(bvec) if obj.Offset: if not DraftVecUtils.isNull(obj.Offset): profile.translate(obj.Offset) shapes.append(profile) if shapes: obj.Shape = Part.makeCompound(shapes) obj.Placement = pl
def execute(self, obj): import Part # math #DraftGeomUtils output = "" toolLoad = obj.ToolController if toolLoad is None or toolLoad.ToolNumber == 0: FreeCAD.Console.PrintError("No Tool Controller is selected. We need a tool to build a Path.") #return else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = toolLoad.Proxy.getTool(toolLoad) if not tool or tool.Diameter == 0: FreeCAD.Console.PrintError("No Tool found or diameter is zero. We need a tool to build a Path.") return else: self.radius = tool.Diameter/2 output += "(" + obj.Label + ")" if obj.UseComp: output += "(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")" else: output += "(Uncompensated Tool Path)" if obj.Base: holes = [] faces = [] for b in obj.Base: for sub in b[1]: shape = getattr(b[0].Shape, sub) if isinstance(shape, Part.Face): faces.append(shape) if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face holes += shape.Wires[1:] else: print ("found a base object which is not a face. Can't continue.") return profileshape = Part.makeCompound(faces) profilewire = TechDraw.findShapeOutline(profileshape, 1, Vector(0, 0, 1)) if obj.processHoles: for wire in holes: edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) output += self._buildPathLibarea(obj, edgelist, True) if obj.processPerimeter: edgelist = profilewire.Edges edgelist = Part.__sortEdges__(edgelist) output += self._buildPathLibarea(obj, edgelist, False) else: #Try to build targets frorm the job base parentJob = PathUtils.findParentJob(obj) if parentJob is None: return baseobject = parentJob.Base if baseobject is None: return if hasattr(baseobject, "Proxy"): if isinstance(baseobject.Proxy, ArchPanel.PanelSheet): # process the sheet if obj.processPerimeter: shapes = baseobject.Proxy.getOutlines(baseobject, transform=True) for shape in shapes: for wire in shape.Wires: edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) PathLog.debug("Processing panel perimeter. edges found: {}".format(len(edgelist))) try: output += self._buildPathLibarea(obj, edgelist, isHole=False) except: FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") shapes = baseobject.Proxy.getHoles(baseobject, transform=True) for shape in shapes: for wire in shape.Wires: drillable = PathUtils.isDrillable(baseobject.Proxy, wire) if (drillable and obj.processCircles) or (not drillable and obj.processHoles): edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) try: output += self._buildPathLibarea(obj, edgelist, isHole=True) except: FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") if obj.Active: path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False
def getExtrusionData(self, obj): """returns (shape,extrusion vector,placement) or None""" import Part, DraftGeomUtils data = ArchComponent.Component.getExtrusionData(self, obj) if data: if not isinstance(data[0], list): # multifuses not considered here return data length = obj.Length.Value width = obj.Width.Value height = obj.Height.Value if not height: for p in obj.InList: if Draft.getType(p) == "Floor": if p.Height.Value: height = p.Height.Value if obj.Normal == Vector(0, 0, 0): normal = Vector(0, 0, 1) else: normal = Vector(obj.Normal) base = None placement = None basewires = None # build wall layers layers = [] if hasattr(obj, "Material"): if obj.Material: if hasattr(obj.Material, "Materials"): varwidth = 0 restwidth = width - sum(obj.Material.Thicknesses) if restwidth > 0: varwidth = [ t for t in obj.Material.Thicknesses if t == 0 ] if varwidth: varwidth = restwidth / len(varwidth) for t in obj.Material.Thicknesses: if t: layers.append(t) elif varwidth: layers.append(varwidth) if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape: if obj.Base.Shape.Solids: return None elif obj.Face > 0: if len(obj.Base.Shape.Faces) >= obj.Face: face = obj.Base.Shape.Faces[obj.Face - 1] # this wall is based on a specific face of its base object normal = face.normalAt(0, 0) if normal.getAngle(Vector(0, 0, 1)) > math.pi / 4: normal.multiply(width) base = face.extrude(normal) if obj.Align == "Center": base.translate( normal.negative().multiply(0.5)) elif obj.Align == "Right": base.translate(normal.negative()) else: normal.multiply(height) base = face.extrude(normal) base, placement = self.rebase(base) return (base, normal, placement) elif obj.Base.Shape.Faces: if not DraftGeomUtils.isCoplanar(obj.Base.Shape.Faces): return None else: base, placement = self.rebase(obj.Base.Shape) elif obj.Base.Shape.Wires: basewires = obj.Base.Shape.Wires elif len(obj.Base.Shape.Edges) == 1: basewires = [Part.Wire(obj.Base.Shape.Edges)] if basewires and width: if (len(basewires) == 1) and layers: basewires = [basewires[0] for l in layers] layeroffset = 0 baseface = None for i, wire in enumerate(basewires): e = wire.Edges[0] if isinstance(e.Curve, Part.Circle): dvec = e.Vertexes[0].Point.sub(e.Curve.Center) else: dvec = DraftGeomUtils.vec( wire.Edges[0]).cross(normal) if not DraftVecUtils.isNull(dvec): dvec.normalize() sh = None if obj.Align == "Left": off = obj.Offset.Value if layers: off = off + layeroffset dvec.multiply(layers[i]) layeroffset += layers[i] else: dvec.multiply(width) if off: dvec2 = DraftVecUtils.scaleTo(dvec, off) wire = DraftGeomUtils.offsetWire( wire, dvec2) w2 = DraftGeomUtils.offsetWire(wire, dvec) w1 = Part.Wire(Part.__sortEdges__(wire.Edges)) sh = DraftGeomUtils.bind(w1, w2) elif obj.Align == "Right": dvec = dvec.negative() off = obj.Offset.Value if layers: off = off + layeroffset dvec.multiply(layers[i]) layeroffset += layers[i] else: dvec.multiply(width) if off: dvec2 = DraftVecUtils.scaleTo(dvec, off) wire = DraftGeomUtils.offsetWire( wire, dvec2) w2 = DraftGeomUtils.offsetWire(wire, dvec) w1 = Part.Wire(Part.__sortEdges__(wire.Edges)) sh = DraftGeomUtils.bind(w1, w2) elif obj.Align == "Center": if layers: off = width / 2 - layeroffset d1 = Vector(dvec).multiply(off) w1 = DraftGeomUtils.offsetWire(wire, d1) layeroffset += layers[i] off = width / 2 - layeroffset d1 = Vector(dvec).multiply(off) w2 = DraftGeomUtils.offsetWire(wire, d1) else: dvec.multiply(width / 2) w1 = DraftGeomUtils.offsetWire(wire, dvec) dvec = dvec.negative() w2 = DraftGeomUtils.offsetWire(wire, dvec) sh = DraftGeomUtils.bind(w1, w2) if sh: sh.fix(0.1, 0, 1) # fixes self-intersecting wires f = Part.Face(sh) if baseface: if layers: baseface.append(f) else: baseface = baseface.fuse(f) else: if layers: baseface = [f] else: baseface = f if baseface: base, placement = self.rebase(baseface) else: if layers: totalwidth = sum(layers) offset = 0 base = [] for l in layers: l2 = length / 2 or 0.5 w1 = -totalwidth / 2 + offset w2 = w1 + l v1 = Vector(-l2, w1, 0) v2 = Vector(l2, w1, 0) v3 = Vector(l2, w2, 0) v4 = Vector(-l2, w2, 0) base.append( Part.Face(Part.makePolygon([v1, v2, v3, v4, v1]))) offset += l else: l2 = length / 2 or 0.5 w2 = width / 2 or 0.5 v1 = Vector(-l2, -w2, 0) v2 = Vector(l2, -w2, 0) v3 = Vector(l2, w2, 0) v4 = Vector(-l2, w2, 0) base = Part.Face(Part.makePolygon([v1, v2, v3, v4, v1])) placement = FreeCAD.Placement() if base and placement: extrusion = normal.multiply(height) return (base, extrusion, placement) return None
def execute(self, obj): import Part # math #DraftGeomUtils output = "" toolLoad = obj.ToolController if toolLoad is None or toolLoad.ToolNumber == 0: FreeCAD.Console.PrintError( "No Tool Controller is selected. We need a tool to build a Path." ) #return else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = toolLoad.Proxy.getTool(toolLoad) if not tool or tool.Diameter == 0: FreeCAD.Console.PrintError( "No Tool found or diameter is zero. We need a tool to build a Path." ) return else: self.radius = tool.Diameter / 2 output += "(" + obj.Label + ")" if obj.UseComp: output += "(Compensated Tool Path. Diameter: " + str( self.radius * 2) + ")" else: output += "(Uncompensated Tool Path)" if obj.Base: holes = [] faces = [] for b in obj.Base: for sub in b[1]: shape = getattr(b[0].Shape, sub) if isinstance(shape, Part.Face): faces.append(shape) if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face holes += shape.Wires[1:] else: print( "found a base object which is not a face. Can't continue." ) return profileshape = Part.makeCompound(faces) profilewire = TechDraw.findShapeOutline(profileshape, 1, Vector(0, 0, 1)) if obj.processHoles: for wire in holes: edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) output += self._buildPathLibarea(obj, edgelist, True) if obj.processPerimeter: edgelist = profilewire.Edges edgelist = Part.__sortEdges__(edgelist) output += self._buildPathLibarea(obj, edgelist, False) else: #Try to build targets frorm the job base parentJob = PathUtils.findParentJob(obj) if parentJob is None: return baseobject = parentJob.Base if baseobject is None: return if hasattr(baseobject, "Proxy"): if isinstance(baseobject.Proxy, ArchPanel.PanelSheet): # process the sheet if obj.processPerimeter: shapes = baseobject.Proxy.getOutlines(baseobject, transform=True) for shape in shapes: for wire in shape.Wires: edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) PathLog.debug( "Processing panel perimeter. edges found: {}" .format(len(edgelist))) try: output += self._buildPathLibarea(obj, edgelist, isHole=False) except: FreeCAD.Console.PrintError( "Something unexpected happened. Unable to generate a contour path. Check project and tool config." ) shapes = baseobject.Proxy.getHoles(baseobject, transform=True) for shape in shapes: for wire in shape.Wires: drillable = PathUtils.isDrillable( baseobject.Proxy, wire) if (drillable and obj.processCircles) or ( not drillable and obj.processHoles): edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) try: output += self._buildPathLibarea( obj, edgelist, isHole=True) except: FreeCAD.Console.PrintError( "Something unexpected happened. Unable to generate a contour path. Check project and tool config." ) if obj.Active: path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False
def execute(self, obj): import Part # math #DraftGeomUtils output = "" toolLoad = PathUtils.getLastToolLoad(obj) # obj.ToolController = PathUtils.getToolControllers(obj) # toolLoad = PathUtils.getToolLoad(obj, obj.ToolController) if toolLoad is None or toolLoad.ToolNumber == 0: self.vertFeed = 100 self.horizFeed = 100 self.vertRapid = 100 self.horizRapid = 100 self.radius = 0.25 obj.ToolNumber = 0 obj.ToolDescription = "UNDEFINED" else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = PathUtils.getTool(obj, toolLoad.ToolNumber) if tool.Diameter == 0: self.radius = 0.25 else: self.radius = tool.Diameter / 2 obj.ToolNumber = toolLoad.ToolNumber obj.ToolDescription = toolLoad.Name if obj.UserLabel == "": obj.Label = obj.Name + " :" + obj.ToolDescription else: obj.Label = obj.UserLabel + " :" + obj.ToolDescription output += "(" + obj.Label + ")" if obj.Side != "On": output += "(Compensated Tool Path. Diameter: " + str( self.radius * 2) + ")" else: output += "(Uncompensated Tool Path)" if obj.Base: # hfaces = [] # vfaces = [] wires = [] for b in obj.Base: edgelist = [] for sub in b[1]: edgelist.append(getattr(b[0].Shape, sub)) wires.extend(findWires(edgelist)) for wire in wires: edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) output += self._buildPathLibarea(obj, edgelist) if obj.Active: path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False
def getObjectData(obj,wireframeMode=wireframeStyle): """returns the geometry data of an object as three.js snippet. wireframeMode can be multimaterial, faceloop or None""" result = "" wires = [] if obj.isDerivedFrom("Part::Feature"): fcmesh = obj.Shape.tessellate(0.1) result = "var geom = new THREE.Geometry();\n" # adding vertices data for i in range(len(fcmesh[0])): v = fcmesh[0][i] result += tab+"var v"+str(i)+" = new THREE.Vector3("+str(v.x)+","+str(v.y)+","+str(v.z)+");\n" result += tab+"console.log(geom.vertices)\n" for i in range(len(fcmesh[0])): result += tab+"geom.vertices.push(v"+str(i)+");\n" # adding facets data for f in fcmesh[1]: result += tab+"geom.faces.push( new THREE.Face3"+str(f)+" );\n" for f in obj.Shape.Faces: for w in f.Wires: wo = Part.Wire(Part.__sortEdges__(w.Edges)) wires.append(wo.discretize(QuasiDeflection=0.1)) elif obj.isDerivedFrom("Mesh::Feature"): mesh = obj.Mesh result = "var geom = new THREE.Geometry();\n" # adding vertices data for p in mesh.Points: v = p.Vector i = p.Index result += tab+"var v"+str(i)+" = new THREE.Vector3("+str(v.x)+","+str(v.y)+","+str(v.z)+");\n" result += tab+"console.log(geom.vertices)\n" for p in mesh.Points: result += tab+"geom.vertices.push(v"+str(p.Index)+");\n" # adding facets data for f in mesh.Facets: result += tab+"geom.faces.push( new THREE.Face3"+str(f.PointIndices)+" );\n" if result: # adding a base material if FreeCADGui: col = obj.ViewObject.ShapeColor rgb = Draft.getrgb(col,testbw=False) else: rgb = "#888888" # test color result += tab+"var basematerial = new THREE.MeshBasicMaterial( { color: 0x"+str(rgb)[1:]+" } );\n" #result += tab+"var basematerial = new THREE.MeshLambertMaterial( { color: 0x"+str(rgb)[1:]+" } );\n" if wireframeMode == "faceloop": # adding the mesh to the scene with a wireframe copy result += tab+"var mesh = new THREE.Mesh( geom, basematerial );\n" result += tab+"scene.add( mesh );\n" result += tab+"var linematerial = new THREE.LineBasicMaterial({linewidth: %d, color: 0x000000,});\n" % linewidth for w in wires: result += tab+"var wire = new THREE.Geometry();\n" for p in w: result += tab+"wire.vertices.push(new THREE.Vector3(" result += str(p.x)+", "+str(p.y)+", "+str(p.z)+"));\n" result += tab+"var line = new THREE.Line(wire, linematerial);\n" result += tab+"scene.add(line);\n" elif wireframeMode == "multimaterial": # adding a wireframe material result += tab+"var wireframe = new THREE.MeshBasicMaterial( { color: " result += "0x000000, wireframe: true, transparent: true } );\n" result += tab+"var material = [ basematerial, wireframe ];\n" result += tab+"var mesh = new THREE.SceneUtils.createMultiMaterialObject( geom, material );\n" result += tab+"scene.add( mesh );\n"+tab else: # adding the mesh to the scene with simple material result += tab+"var mesh = new THREE.Mesh( geom, basematerial );\n" result += tab+"scene.add( mesh );\n"+tab return result
def getRebarShapeSVG( rebar, view_direction: Union[FreeCAD.Vector, WorkingPlane.Plane] = FreeCAD.Vector(0, 0, 0), include_mark: bool = True, stirrup_extended_edge_offset: float = 2, rebar_stroke_width: float = 0.35, rebar_color_style: str = "shape color", include_dimensions: bool = True, rebar_dimension_units: str = "mm", rebar_length_dimension_precision: int = 0, include_units_in_dimension_label: bool = False, bent_angle_dimension_exclude_list: Union[Tuple[float, ...], List[float]] = ( 45, 90, 180, ), dimension_font_family: str = "DejaVu Sans", dimension_font_size: float = 2, helical_rebar_dimension_label_format: str = "%L,r=%R,pitch=%P", scale: float = 1, max_height: float = 0, max_width: float = 0, side_padding: float = 1, horizontal_shape: bool = False, ) -> ElementTree.Element: """Generate and return rebar shape svg. Parameters ---------- rebar: <ArchRebar._Rebar> or <rebar2.BaseRebar> Rebar to generate its shape svg. view_direction: FreeCAD.Vector or WorkingPlane.Plane, optional The view point direction for rebar shape. Default is FreeCAD.Vector(0, 0, 0) to automatically choose view_direction. include_mark: bool, optional If True, then rebar.Mark will be included in rebar shape svg. Default is True. stirrup_extended_edge_offset: float, optional The offset of extended end edges of stirrup, so that end edges of stirrup with 90 degree bent angle do not overlap with stirrup edges. Default is 2. rebar_stroke_width: float, optional The stroke-width of rebar in svg. Default is 0.35 rebar_color_style: {"shape color", "color_name", "hex_value_of_color"} The color style of rebar. "shape color" means select color of rebar shape. include_dimensions: bool, optional If True, then each rebar edge dimensions and bent angle dimensions will be included in rebar shape svg. rebar_dimension_units: str, optional The units to be used for rebar length dimensions. Default is "mm". rebar_length_dimension_precision: int, optional The number of decimals that should be shown for rebar length as dimension label. Set it to None to use user preferred unit precision from FreeCAD unit preferences. Default is 0 include_units_in_dimension_label: bool, optional If it is True, then rebar length units will be shown in dimension label. Default is False. bent_angle_dimension_exclude_list: list or tuple of float, optional The list of bent angles to not include their dimensions. Default is (45, 90, 180). dimension_font_family: str, optional The font-family of dimension text. Default is "DejaVu Sans". dimension_font_size: float, optional The font-size of dimension text. Default is 2 helical_rebar_dimension_label_format: str, optional The format of helical rebar dimension label. %L -> Length of helical rebar %R -> Helix radius of helical rebar %P -> Helix pitch of helical rebar Default is "%L,r=%R,pitch=%P". scale: float, optional The scale value to scale rebar svg. The scale parameter helps to scale down rebar_stroke_width and dimension_font_size to make them resolution independent. If max_height or max_width is set to non-zero value, then scale parameter will be ignored. Default is 1 max_height: float, optional The maximum height of rebar shape svg. Default is 0 to set rebar shape svg height based on scale parameter. max_width: float, optional The maximum width of rebar shape svg. Default is 0 to set rebar shape svg width based on scale parameter. side_padding: float, optional The padding on each side of rebar shape. Default is 1. horizontal_shape: bool, optional If True, then rebar shape will be made horizontal by rotating max length edge of rebar shape. Default is False. Returns ------- ElementTree.Element The generated rebar shape svg. """ if isinstance(view_direction, FreeCAD.Vector): if DraftVecUtils.isNull(view_direction): if (hasattr(rebar, "RebarShape") and rebar.RebarShape == "HelicalRebar"): view_direction = rebar.Base.Placement.Rotation.multVec( FreeCAD.Vector(0, -1, 0)) if hasattr(rebar, "Direction") and not DraftVecUtils.isNull( rebar.Direction): view_direction = FreeCAD.Vector(rebar.Direction) view_direction.normalize() else: view_direction = getRebarsSpanAxis(rebar) view_plane = getSVGPlaneFromAxis(view_direction) elif isinstance(view_direction, WorkingPlane.Plane): view_plane = view_direction else: FreeCAD.Console.PrintError( "Invalid view_direction type. Supported view_direction types: " "FreeCAD.Vector, WorkingPlane.Plane\n") return ElementTree.Element("g") if rebar_length_dimension_precision is None: # Get user preferred unit precision precision: int = FreeCAD.ParamGet( "User parameter:BaseApp/Preferences/Units").GetInt("Decimals") else: precision = abs(int(rebar_length_dimension_precision)) rebar_color = getRebarColor(rebar, rebar_color_style) # Create required svg elements svg = getSVGRootElement() rebar_shape_svg = ElementTree.Element("g", attrib={"id": str(rebar.Name)}) svg.append(rebar_shape_svg) rebar_edges_svg = ElementTree.Element("g") edge_dimension_svg = ElementTree.Element("g") rebar_shape_svg.extend([rebar_edges_svg, edge_dimension_svg]) # Get basewire and fillet_basewire (basewire with round edges) basewire = rebar.Base.Shape.Wires[0].copy() fillet_radius = rebar.Rounding * rebar.Diameter.Value if fillet_radius: fillet_basewire = DraftGeomUtils.filletWire(basewire, fillet_radius) else: fillet_basewire = basewire ( rebar_shape_min_x, rebar_shape_min_y, rebar_shape_max_x, rebar_shape_max_y, ) = getVertexesMinMaxXY(fillet_basewire.Vertexes, view_plane) # If rebar shape should be horizontal and its width is less than its # height, then we should rotate basewire to make rebar shape horizontal rebar_shape_rotation_angle = 0 if horizontal_shape: line_type_edges = [ edge for edge in basewire.Edges if DraftGeomUtils.geomType(edge) == "Line" ] if line_type_edges: max_length_edge = max(line_type_edges, key=lambda x: x.Length) rebar_shape_rotation_angle = math.degrees( DraftVecUtils.angle( max_length_edge.lastVertex().Point.sub( max_length_edge.firstVertex().Point), view_plane.u, view_plane.axis, )) elif (rebar_shape_max_x - rebar_shape_min_x) < (rebar_shape_max_y - rebar_shape_min_y): rebar_shape_rotation_angle = -90 basewire.rotate(basewire.CenterOfMass, view_plane.axis, rebar_shape_rotation_angle) fillet_radius = rebar.Rounding * rebar.Diameter.Value if fillet_radius: fillet_basewire = DraftGeomUtils.filletWire( basewire, fillet_radius) else: fillet_basewire = basewire ( rebar_shape_min_x, rebar_shape_min_y, rebar_shape_max_x, rebar_shape_max_y, ) = getVertexesMinMaxXY(fillet_basewire.Vertexes, view_plane) # Check if stirrup will be having extended edges separated apart if (hasattr(rebar, "RebarShape") and rebar.RebarShape == "Stirrup" and hasattr(rebar, "BentAngle") and rebar.BentAngle == 90): apply_stirrup_extended_edge_offset = True else: apply_stirrup_extended_edge_offset = False # Apply max_height and max_width of rebar shape svg And calculate scaling # factor rebar_shape_height = (rebar_shape_max_y - rebar_shape_min_y) or 1 rebar_shape_width = (rebar_shape_max_x - rebar_shape_min_x) or 1 h_scaling_factor = v_scaling_factor = scale if max_height: v_scaling_factor = ( max_height - dimension_font_size * ((2 if include_mark else 0) + (2 if include_dimensions else 0)) - 2 * side_padding - (stirrup_extended_edge_offset if apply_stirrup_extended_edge_offset and (round( getProjectionToSVGPlane( Part.__sortEdges__(basewire.Edges)[0].firstVertex().Point, view_plane, ).y) in (round(rebar_shape_min_y), round(rebar_shape_max_y))) else 0)) / rebar_shape_height if max_width: h_scaling_factor = ( max_width - dimension_font_size * (2 if include_dimensions else 0) - 2 * side_padding - (stirrup_extended_edge_offset if apply_stirrup_extended_edge_offset and (round( getProjectionToSVGPlane( Part.__sortEdges__(basewire.Edges)[0].firstVertex().Point, view_plane, ).x) in (round(rebar_shape_min_x), round(rebar_shape_max_x))) else 0)) / rebar_shape_width scale = min(h_scaling_factor, v_scaling_factor) svg_height = ( rebar_shape_height * scale + dimension_font_size * ((2 if include_mark else 0) + (2 if include_dimensions else 0)) + 2 * side_padding + (stirrup_extended_edge_offset if apply_stirrup_extended_edge_offset and (round( getProjectionToSVGPlane( Part.__sortEdges__(basewire.Edges)[0].firstVertex().Point, view_plane, ).y) in (round(rebar_shape_min_y), round(rebar_shape_max_y))) else 0)) svg_width = ( rebar_shape_width * scale + dimension_font_size * (2 if include_dimensions else 0) + 2 * side_padding + (stirrup_extended_edge_offset if apply_stirrup_extended_edge_offset and (round( getProjectionToSVGPlane( Part.__sortEdges__(basewire.Edges)[0].firstVertex().Point, view_plane, ).x) in (round(rebar_shape_min_x), round(rebar_shape_max_x))) else 0)) # Move (min_x, min_y) point in svg plane to (0, 0) so that entire basewire # should be visible in svg view box and apply required scaling translate_x = round( -(rebar_shape_min_x - (dimension_font_size if include_dimensions else 0) / scale - side_padding / scale - (stirrup_extended_edge_offset / scale if apply_stirrup_extended_edge_offset and (round( getProjectionToSVGPlane( Part.__sortEdges__(basewire.Edges)[0].firstVertex().Point, view_plane, ).x) == round(rebar_shape_min_x)) else 0))) translate_y = round( -(rebar_shape_min_y - ((2 if include_mark else 0) + (1 if include_dimensions else 0)) * dimension_font_size / scale - side_padding / scale - (stirrup_extended_edge_offset / scale if apply_stirrup_extended_edge_offset and (round( getProjectionToSVGPlane( Part.__sortEdges__(basewire.Edges)[0].firstVertex().Point, view_plane, ).y) == round(rebar_shape_min_y)) else 0))) rebar_shape_svg.set( "transform", "scale({}) translate({} {})".format(scale, translate_x, translate_y), ) svg.set("width", "{}mm".format(round(svg_width))) svg.set("height", "{}mm".format(round(svg_height))) svg.set("viewBox", "0 0 {} {}".format(round(svg_width), round(svg_height))) # Scale down rebar_stroke_width and dimension_font_size to make them # resolution independent rebar_stroke_width /= scale dimension_font_size /= scale # Include rebar.Mark in rebar shape svg if include_mark: if hasattr(rebar, "Mark"): mark = rebar.Mark elif hasattr(rebar, "MarkNumber"): mark = rebar.MarkNumber else: mark = "" rebar_shape_svg.append( getSVGTextElement( mark, rebar_shape_min_x, rebar_shape_min_y - (0.5 + bool(include_dimensions)) * dimension_font_size, dimension_font_family, 1.5 * dimension_font_size, )) if hasattr(rebar, "RebarShape") and rebar.RebarShape == "HelicalRebar": helical_rebar_shape_svg = Draft.getSVG( rebar, direction=view_plane, linewidth=rebar_stroke_width, fillstyle="none", color=rebar_color, ) if helical_rebar_shape_svg: helical_rebar_shape_svg_element = ElementTree.fromstring( "<g>{}</g>".format(helical_rebar_shape_svg)) rebar_edges_svg.append(helical_rebar_shape_svg_element) helical_rebar_center = getProjectionToSVGPlane( rebar.Base.Shape.CenterOfMass, view_plane) helical_rebar_shape_svg_element.set( "transform", "rotate({} {} {})".format( rebar_shape_rotation_angle, helical_rebar_center.x, helical_rebar_center.y, ), ) if include_dimensions: # Create rebar dimension svg top_mid_point = FreeCAD.Vector( (rebar_shape_min_x + rebar_shape_max_x) / 2, rebar_shape_min_y) helical_rebar_length = str( round( FreeCAD.Units.Quantity("{}mm".format( rebar.Base.Shape.Wires[0].Length)).getValueAs( rebar_dimension_units).Value, precision, )) helix_radius = str( round( rebar.Base.Radius.getValueAs(rebar_dimension_units).Value, precision, )) helix_pitch = str( round( rebar.Base.Pitch.getValueAs(rebar_dimension_units).Value, precision, )) if "." in helical_rebar_length: helical_rebar_length = helical_rebar_length.rstrip("0").rstrip( ".") if "." in helix_radius: helix_radius = helix_radius.rstrip("0").rstrip(".") if "." in helix_pitch: helix_pitch = helix_pitch.rstrip("0").rstrip(".") if include_units_in_dimension_label: helical_rebar_length += rebar_dimension_units helix_radius += rebar_dimension_units helix_pitch += rebar_dimension_units edge_dimension_svg.append( getSVGTextElement( helical_rebar_dimension_label_format.replace( "%L", helical_rebar_length).replace( "%R", helix_radius).replace("%P", helix_pitch), top_mid_point.x, top_mid_point.y - rebar_stroke_width * 2, dimension_font_family, dimension_font_size, "middle", )) else: if stirrup_extended_edge_offset and apply_stirrup_extended_edge_offset: basewire = getBasewireOfStirrupWithExtendedEdges( rebar, view_plane, stirrup_extended_edge_offset / scale) basewire.rotate( basewire.CenterOfMass, view_plane.axis, rebar_shape_rotation_angle, ) fillet_radius = rebar.Rounding * rebar.Diameter.Value if fillet_radius: fillet_basewire = DraftGeomUtils.filletWire( basewire, fillet_radius) else: fillet_basewire = basewire edges = Part.__sortEdges__(fillet_basewire.Edges) straight_edges = Part.__sortEdges__(rebar.Base.Shape.Wires[0].Edges) for edge in list(straight_edges): if DraftGeomUtils.geomType(edge) != "Line": straight_edges.remove(edge) current_straight_edge_index = 0 for edge_index, edge in enumerate(edges): if DraftGeomUtils.geomType(edge) == "Line": p1 = getProjectionToSVGPlane(edge.Vertexes[0].Point, view_plane) p2 = getProjectionToSVGPlane(edge.Vertexes[1].Point, view_plane) # Create Edge svg if round(p1.x) == round(p2.x) and round(p1.y) == round(p2.y): edge_svg = getPointSVG(p1, radius=2 * rebar_stroke_width, fill=rebar_color) else: edge_svg = getLineSVG(p1, p2, rebar_stroke_width, rebar_color) if include_dimensions: # Create edge dimension svg mid_point = FreeCAD.Vector((p1.x + p2.x) / 2, (p1.y + p2.y) / 2) dimension_rotation = (math.degrees( math.atan((p2.y - p1.y) / (p2.x - p1.x))) if round(p2.x) != round(p1.x) else -90) edge_length = str( round( FreeCAD.Units.Quantity("{}mm".format( straight_edges[current_straight_edge_index]. Length)).getValueAs( rebar_dimension_units).Value, precision, )) if "." in edge_length: edge_length = edge_length.rstrip("0").rstrip(".") if include_units_in_dimension_label: edge_length += rebar_dimension_units edge_dimension_svg.append( getSVGTextElement( edge_length, mid_point.x, mid_point.y - rebar_stroke_width * 2, dimension_font_family, dimension_font_size, "middle", )) edge_dimension_svg[-1].set( "transform", "rotate({} {} {})".format( dimension_rotation, round(mid_point.x), round(mid_point.y), ), ) current_straight_edge_index += 1 if (0 <= edge_index - 1 and DraftGeomUtils.geomType( edges[edge_index - 1]) == "Line"): radius = max(fillet_radius, dimension_font_size * 0.8) bent_angle_svg = getEdgesAngleSVG( edges[edge_index - 1], edge, radius, view_plane, dimension_font_family, dimension_font_size * 0.8, bent_angle_dimension_exclude_list, 0.2 / scale, ) edge_dimension_svg.append(bent_angle_svg) elif DraftGeomUtils.geomType(edge) == "Circle": p1 = getProjectionToSVGPlane(edge.Vertexes[0].Point, view_plane) p2 = getProjectionToSVGPlane(edge.Vertexes[1].Point, view_plane) if round(p1.x) == round(p2.x) or round(p1.y) == round(p2.y): edge_svg = getLineSVG(p1, p2, rebar_stroke_width, rebar_color) else: edge_svg = getRoundEdgeSVG(edge, view_plane, rebar_stroke_width, rebar_color) if include_dimensions: # Create bent angle svg if 0 <= edge_index - 1 and edge_index + 1 < len(edges): prev_edge = edges[edge_index - 1] next_edge = edges[edge_index + 1] if (DraftGeomUtils.geomType(prev_edge) == DraftGeomUtils.geomType(next_edge) == "Line"): radius = max(fillet_radius, dimension_font_size * 0.8) bent_angle_svg = getEdgesAngleSVG( prev_edge, next_edge, radius, view_plane, dimension_font_family, dimension_font_size * 0.8, bent_angle_dimension_exclude_list, 0.2 / scale, ) edge_dimension_svg.append(bent_angle_svg) else: edge_svg = ElementTree.Element("g") rebar_edges_svg.append(edge_svg) return svg
def execute(self, obj): if self.clone(obj): return import Part, math, DraftGeomUtils pl = obj.Placement #self.baseface = None base = None w = None if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.Solids: base = obj.Base.Shape #pl = obj.Base.Placement else: 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 = Part.__sortEdges__(w.Edges) l = len(edges) 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 i in range(l): self.calcEdgeGeometry(edges, i) for i in range(l): self.calcDraftEdges(i) for i in range(l): self.calcEave(i) for p in self.profilsDico: heights.append(p["height"]) obj.Heights = heights for i in range(l): self.getRoofPaneProject(i) profilCurrent = self.findProfil(i) midpoint = DraftGeomUtils.findMidpoint( profilCurrent["edge"]) ptsPaneProject = profilCurrent["points"] lp = len(ptsPaneProject) if lp != 0: ptsPaneProject.append(ptsPaneProject[0]) edgesWire = [] for p in range(lp): edge = Part.makeLine(ptsPaneProject[p], ptsPaneProject[p + 1]) edgesWire.append(edge) wire = Part.Wire(edgesWire) d = wire.BoundBox.DiagonalLength thicknessV = profilCurrent["thickness"] / (math.cos( math.radians(profilCurrent["angle"]))) overhangV = profilCurrent["overhang"] * math.tan( math.radians(profilCurrent["angle"])) if wire.isClosed(): f = Part.Face(wire) f = f.extrude( FreeCAD.Vector( 0, 0, profilCurrent["height"] + 1000000.0)) f.translate( FreeCAD.Vector(0.0, 0.0, -2 * overhangV)) ptsPaneProfil = [ FreeCAD.Vector(-profilCurrent["overhang"], -overhangV, 0.0), FreeCAD.Vector(profilCurrent["run"], profilCurrent["height"], 0.0), FreeCAD.Vector( profilCurrent["run"], profilCurrent["height"] + thicknessV, 0.0), FreeCAD.Vector(-profilCurrent["overhang"], -overhangV + thicknessV, 0.0) ] self.shps.append( self.createProfilShape(ptsPaneProfil, midpoint, profilCurrent["rot"], profilCurrent["vec"], profilCurrent["run"], d, f)) ## subVolume shape ptsSubVolumeProfil = [ FreeCAD.Vector(-profilCurrent["overhang"], -overhangV, 0.0), FreeCAD.Vector(profilCurrent["run"], profilCurrent["height"], 0.0), FreeCAD.Vector(profilCurrent["run"], profilCurrent["height"] + 900000.0, 0.0), FreeCAD.Vector(-profilCurrent["overhang"], profilCurrent["height"] + 900000.0, 0.0) ] self.subVolshps.append( self.createProfilShape(ptsSubVolumeProfil, midpoint, profilCurrent["rot"], profilCurrent["vec"], profilCurrent["run"], d, f)) ## 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 = self.shps.pop() for s in self.shps: base = base.fuse(s) base = self.processSubShapes(obj, base) self.applyShape(obj, base, pl, allownosolid=True) elif base: base = self.processSubShapes(obj, base) self.applyShape(obj, base, pl, allownosolid=True) else: FreeCAD.Console.PrintMessage( translate("Arch", "Unable to create a roof"))
def export(exportList, filename, colors=None, camera=None): """Exports objects to an html file""" global disableCompression, base, baseFloat data = {'camera': {}, 'file': {}, 'objects': []} if not FreeCADGui and not camera: camera = OfflineRenderingUtils.getCamera( FreeCAD.ActiveDocument.FileName) if camera: # REF: https://github.com/FreeCAD/FreeCAD/blob/master/src/Mod/Arch/OfflineRenderingUtils.py camnode = OfflineRenderingUtils.getCoinCamera(camera) cameraPosition = camnode.position.getValue().getValue() data['camera']['type'] = 'Orthographic' if 'PerspectiveCamera' in camera: data['camera']['type'] = 'Perspective' data['camera']['focalDistance'] = camnode.focalDistance.getValue() data['camera']['position_x'] = cameraPosition[0] data['camera']['position_y'] = cameraPosition[1] data['camera']['position_z'] = cameraPosition[2] else: v = FreeCADGui.ActiveDocument.ActiveView data['camera']['type'] = v.getCameraType() data['camera']['focalDistance'] = v.getCameraNode( ).focalDistance.getValue() data['camera']['position_x'] = v.viewPosition().Base.x data['camera']['position_y'] = v.viewPosition().Base.y data['camera']['position_z'] = v.viewPosition().Base.z # Take the objects out of groups objectslist = Draft.get_group_contents(exportList, walls=True, addgroups=False) # objectslist = Arch.pruneIncluded(objectslist) for obj in objectslist: # Pull all obj data before we dig down the links label = obj.Label color = '#cccccc' opacity = 1.0 if FreeCADGui: color = Draft.getrgb(obj.ViewObject.ShapeColor, testbw=False) opacity = int((100 - obj.ViewObject.Transparency) / 5) / 20 # 0>>1 with step of 0.05 elif colors: if label in colors: color = Draft.getrgb(colors[label], testbw=False) validObject = False if obj.isDerivedFrom('Mesh::Feature'): mesh = obj.Mesh validObject = True if obj.isDerivedFrom('Part::Feature'): objShape = obj.Shape validObject = True if obj.isDerivedFrom('App::Link'): linkPlacement = obj.LinkPlacement while True: # drill down to get to the actual obj if obj.isDerivedFrom("App::Link"): if obj.ViewObject.OverrideMaterial: color = Draft.getrgb( obj.ViewObject.ShapeMaterial.DiffuseColor, testbw=False) obj = obj.LinkedObject if hasattr(obj, "__len__"): FreeCAD.Console.PrintMessage( label + ": Sub-Links are Unsupported.\n") break elif obj.isDerivedFrom('Part::Feature'): objShape = obj.Shape.copy(False) objShape.Placement = linkPlacement validObject = True break elif obj.isDerivedFrom("Mesh::Feature"): mesh = obj.Mesh.copy() mesh.Placement = linkPlacement validObject = True break if not validObject: continue objdata = { 'name': label, 'color': color, 'opacity': opacity, 'verts': '', 'facets': '', 'wires': [], 'faceColors': [], 'facesToFacets': [], 'floats': [] } if obj.isDerivedFrom('Part::Feature'): deviation = 0.5 if FreeCADGui: deviation = obj.ViewObject.Deviation # obj.ViewObject.DiffuseColor is length=1 when all faces are the same color, length=len(faces) for when they're not if len(obj.ViewObject.DiffuseColor) == len(objShape.Faces): for fc in obj.ViewObject.DiffuseColor: objdata['faceColors'].append( Draft.getrgb(fc, testbw=False)) # get verts and facets for ENTIRE object shapeData = objShape.tessellate(deviation) mesh = Mesh.Mesh(shapeData) if len(objShape.Faces) > 1: # Map each Facet created by tessellate() to a Face so that it can be colored correctly using faceColors # This is done by matching the results of a tessellate() on EACH FACE to the overall tessellate stored in shapeData # if there is any error in matching these two then we display the whole object as one face and forgo the face colors for f in objShape.Faces: faceData = f.tessellate(deviation) found = True for fv in range(len( faceData[0])): # face verts. List of type Vector() found = False for sv in range(len(shapeData[0])): #shape verts if faceData[0][fv] == shapeData[0][ sv]: # do not use isEqual() here faceData[0][ fv] = sv # replace with the index of shapeData[0] found = True break if not found: break if not found: FreeCAD.Console.PrintMessage( "Facet to Face Mismatch.\n") objdata['facesToFacets'] = [] break # map each of the face facets to the shape facets and make a list of shape facet indices that belong to this face facetList = [] for ff in faceData[1]: # face facets found = False for sf in range(len(shapeData[1])): #shape facets if faceData[0][ff[0]] in shapeData[1][ sf] and faceData[0][ff[1]] in shapeData[1][ sf] and faceData[0][ ff[2]] in shapeData[1][sf]: facetList.append(sf) found = True break if not found: break if not found: FreeCAD.Console.PrintMessage("Facet List Mismatch.\n") objdata['facesToFacets'] = [] break objdata['facesToFacets'].append(baseEncode(facetList)) wires = [] # Add wires for f in objShape.Faces: for w in f.Wires: wo = Part.Wire(Part.__sortEdges__(w.Edges)) wire = [] for v in wo.discretize(QuasiDeflection=0.005): wire.append( '{:.5f}'.format(v.x) ) # use strings to avoid 0.00001 written as 1e-05 wire.append('{:.5f}'.format(v.y)) wire.append('{:.5f}'.format(v.z)) wires.append(wire) if not disableCompression: for w in range(len(wires)): for wv in range(len(wires[w])): found = False for f in range(len(objdata['floats'])): if objdata['floats'][f] == wires[w][wv]: wires[w][wv] = f found = True break if not found: objdata['floats'].append(wires[w][wv]) wires[w][wv] = len(objdata['floats']) - 1 wires[w] = baseEncode(wires[w]) objdata['wires'] = wires vIndex = {} verts = [] for p in range(len(mesh.Points)): vIndex[mesh.Points[p].Index] = p verts.append('{:.5f}'.format(mesh.Points[p].Vector.x)) verts.append('{:.5f}'.format(mesh.Points[p].Vector.y)) verts.append('{:.5f}'.format(mesh.Points[p].Vector.z)) # create floats list to compress verts and wires being written into the JS if not disableCompression: for v in range(len(verts)): found = False for f in range(len(objdata['floats'])): if objdata['floats'][f] == verts[v]: verts[v] = f found = True break if not found: objdata['floats'].append(verts[v]) verts[v] = len(objdata['floats']) - 1 objdata['verts'] = baseEncode(verts) facets = [] for f in mesh.Facets: for i in f.PointIndices: facets.append(vIndex[i]) objdata['facets'] = baseEncode(facets) # compress floats if not disableCompression: # use ratio of 7x base13 to 4x base90 because 13^7 ~ 90^4 fullstr = json.dumps(objdata['floats'], separators=(',', ':')) fullstr = fullstr.replace('[', '').replace(']', '').replace('"', '') floatStr = '' baseFloatCt = len(baseFloat) baseCt = len(base) for fs in range(0, len(fullstr), 7): # chunks of 7 chars, skip the first one str7 = fullstr[fs:(fs + 7)] quotient = 0 for s in range(len(str7)): quotient += baseFloat.find(str7[s]) * pow( baseFloatCt, (6 - s)) for v in range(4): floatStr += base[quotient % baseCt] quotient = int(quotient / baseCt) objdata['floats'] = floatStr data['objects'].append(objdata) html = getHTMLTemplate() html = html.replace('$pagetitle', FreeCAD.ActiveDocument.Label) version = FreeCAD.Version() html = html.replace('$version', version[0] + '.' + version[1] + '.' + version[2]) # Remove data compression in JS data['compressed'] = not disableCompression data['base'] = base data['baseFloat'] = baseFloat html = html.replace('$data', json.dumps(data, separators=(',', ':'))) # Shape Data if six.PY2: outfile = pythonopen(filename, "wb") else: outfile = pythonopen(filename, "w") outfile.write(html) outfile.close() FreeCAD.Console.PrintMessage( translate("Arch", "Successfully written") + ' ' + filename + "\n")
def execute(self,obj): if self.clone(obj): return if not obj.Base: return if not obj.Base.Shape: return if not obj.Base.Shape.Wires: return pl = obj.Placement if obj.Base.Shape.Solids: obj.Shape = obj.Base.Shape.copy() if not pl.isNull(): obj.Placement = obj.Shape.Placement.multiply(pl) else: if not obj.Profile: return if not obj.Profile.isDerivedFrom("Part::Part2DObject"): return if not obj.Profile.Shape: return if not obj.Profile.Shape.Wires: return if not obj.Profile.Shape.Faces: for w in obj.Profile.Shape.Wires: if not w.isClosed(): return import DraftGeomUtils, Part, math baseprofile = obj.Profile.Shape.copy() if hasattr(obj,"ProfilePlacement"): if not obj.ProfilePlacement.isNull(): baseprofile.Placement = obj.ProfilePlacement.multiply(baseprofile.Placement) if not baseprofile.Faces: f = [] for w in baseprofile.Wires: f.append(Part.Face(w)) if len(f) == 1: baseprofile = f[0] else: baseprofile = Part.makeCompound(f) shapes = [] normal = DraftGeomUtils.getNormal(obj.Base.Shape) #for wire in obj.Base.Shape.Wires: edges = obj.Base.Shape.Edges if hasattr(obj,"Edges"): if obj.Edges == "Vertical edges": rv = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(0,1,0)) edges = [e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]] elif obj.Edges == "Horizontal edges": rv = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(1,0,0)) edges = [e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]] elif obj.Edges == "Top Horizontal edges": rv = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(1,0,0)) edges = [e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]] edges = sorted(edges,key=lambda x: x.CenterOfMass.z,reverse=True) z = edges[0].CenterOfMass.z edges = [e for e in edges if abs(e.CenterOfMass.z-z) < 0.00001] elif obj.Edges == "Bottom Horizontal edges": rv = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(1,0,0)) edges = [e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]] edges = sorted(edges,key=lambda x: x.CenterOfMass.z) z = edges[0].CenterOfMass.z edges = [e for e in edges if abs(e.CenterOfMass.z-z) < 0.00001] for e in edges: #e = wire.Edges[0] bvec = DraftGeomUtils.vec(e) bpoint = e.Vertexes[0].Point profile = baseprofile.copy() #basepoint = profile.Placement.Base if hasattr(obj,"BasePoint"): edges = Part.__sortEdges__(profile.Edges) basepointliste = [profile.CenterOfMass] for edge in edges: basepointliste.append(DraftGeomUtils.findMidpoint(edge)) basepointliste.append(edge.Vertexes[-1].Point) try: basepoint = basepointliste[obj.BasePoint] except IndexError: FreeCAD.Console.PrintMessage(translate("Arch","Crossing point not found in profile.\n")) basepoint = basepointliste[0] else : basepoint = profile.CenterOfMass profile.translate(bpoint.sub(basepoint)) if obj.Align: axis = profile.Placement.Rotation.multVec(FreeCAD.Vector(0,0,1)) angle = bvec.getAngle(axis) if round(angle,Draft.precision()) != 0: if round(angle,Draft.precision()) != round(math.pi,Draft.precision()): rotaxis = axis.cross(bvec) profile.rotate(DraftVecUtils.tup(bpoint), DraftVecUtils.tup(rotaxis), math.degrees(angle)) if obj.Rotation: profile.rotate(DraftVecUtils.tup(bpoint), DraftVecUtils.tup(FreeCAD.Vector(bvec).normalize()), obj.Rotation) #profile = wire.makePipeShell([profile],True,False,2) TODO buggy profile = profile.extrude(bvec) if obj.Offset: if not DraftVecUtils.isNull(obj.Offset): profile.translate(obj.Offset) shapes.append(profile) if shapes: if hasattr(obj,"Fuse"): if obj.Fuse: if len(shapes) > 1: s = shapes[0].multiFuse(shapes[1:]) s = s.removeSplitter() obj.Shape = s obj.Placement = pl return obj.Shape = Part.makeCompound(shapes) obj.Placement = pl
def proceed(self): """Proceed with execution of the command after proper selection.""" if self.call: self.view.removeEventCallback("SoEvent", self.call) sel = Gui.Selection.getSelection() if len(sel) == 2: self.trimObjects(sel) self.finish() return self.obj = sel[0] self.ui.trimUi() self.linetrack = trackers.lineTracker() import DraftGeomUtils import Part if "Shape" not in self.obj.PropertiesList: return if "Placement" in self.obj.PropertiesList: self.placement = self.obj.Placement if len(self.obj.Shape.Faces) == 1: # simple extrude mode, the object itself is extruded self.extrudeMode = True self.ghost = [trackers.ghostTracker([self.obj])] self.normal = self.obj.Shape.Faces[0].normalAt(0.5, 0.5) for v in self.obj.Shape.Vertexes: self.ghost.append(trackers.lineTracker()) elif len(self.obj.Shape.Faces) > 1: # face extrude mode, a new object is created ss = Gui.Selection.getSelectionEx()[0] if len(ss.SubObjects) == 1: if ss.SubObjects[0].ShapeType == "Face": self.obj = self.doc.addObject("Part::Feature", "Face") self.obj.Shape = ss.SubObjects[0] self.extrudeMode = True self.ghost = [trackers.ghostTracker([self.obj])] self.normal = self.obj.Shape.Faces[0].normalAt(0.5, 0.5) for v in self.obj.Shape.Vertexes: self.ghost.append(trackers.lineTracker()) else: # normal wire trimex mode self.color = self.obj.ViewObject.LineColor self.width = self.obj.ViewObject.LineWidth # self.obj.ViewObject.Visibility = False self.obj.ViewObject.LineColor = (0.5, 0.5, 0.5) self.obj.ViewObject.LineWidth = 1 self.extrudeMode = False if self.obj.Shape.Wires: self.edges = self.obj.Shape.Wires[0].Edges self.edges = Part.__sortEdges__(self.edges) else: self.edges = self.obj.Shape.Edges self.ghost = [] lc = self.color sc = (lc[0], lc[1], lc[2]) sw = self.width for e in self.edges: if DraftGeomUtils.geomType(e) == "Line": self.ghost.append( trackers.lineTracker(scolor=sc, swidth=sw)) else: self.ghost.append(trackers.arcTracker(scolor=sc, swidth=sw)) if not self.ghost: self.finish() for g in self.ghost: g.on() self.activePoint = 0 self.nodes = [] self.shift = False self.alt = False self.force = None self.cv = None self.call = self.view.addEventCallback("SoEvent", self.action) _msg(translate("draft", "Pick distance"))
def execute(self, obj): import Part # math #DraftGeomUtils output = "" toolLoad = PathUtils.getLastToolLoad(obj) if toolLoad is None or toolLoad.ToolNumber == 0: self.vertFeed = 100 self.horizFeed = 100 self.radius = 0.25 obj.ToolNumber = 0 obj.ToolDescription = "UNDEFINED" else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value tool = PathUtils.getTool(obj, toolLoad.ToolNumber) if tool.Diameter == 0: self.radius = 0.25 else: self.radius = tool.Diameter / 2 obj.ToolNumber = toolLoad.ToolNumber obj.ToolDescription = toolLoad.Name if obj.UserLabel == "": obj.Label = obj.Name + " :" + obj.ToolDescription else: obj.Label = obj.UserLabel + " :" + obj.ToolDescription if obj.Base: hfaces = [] vfaces = [] wires = [] for b in obj.Base: for sub in b[1]: # we only consider the outer wire if this is a Face # Horizontal and vertical faces are handled differently shape = getattr(b[0].Shape, sub) if numpy.isclose(shape.normalAt(0, 0).z, 1): # horizontal face hfaces.append(shape) elif numpy.isclose(shape.normalAt(0, 0).z, 0): # vertical face vfaces.append(shape) else: FreeCAD.Console.PrintError( translate( "Path", "Face doesn't appear to be parallel or perpendicular to the XY plane. No path will be generated for: \n" )) FreeCAD.Console.PrintError(b[0].Name + "." + sub + "\n") for h in hfaces: wires.append(h.OuterWire) tempshell = Part.makeShell(vfaces) slices = tempshell.slice(FreeCAD.Base.Vector(0, 0, 1), tempshell.CenterOfMass.z) wires = wires + slices for wire in wires: if obj.Algorithm == "OCC Native": output += self._buildPathOCC(obj, wire) else: try: import area except: FreeCAD.Console.PrintError( translate( "Path", "libarea needs to be installed for this command to work.\n" )) return edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) output += self._buildPathLibarea(obj, edgelist) if obj.Active: path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False
def execute(self, obj): import Part # math #DraftGeomUtils output = "" toolLoad = PathUtils.getLastToolLoad(obj) if toolLoad is None or toolLoad.ToolNumber == 0: self.vertFeed = 100 self.horizFeed = 100 self.vertRapid = 100 self.horizRapid = 100 self.radius = 0.25 obj.ToolNumber = 0 obj.ToolDescription = "UNDEFINED" else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = PathUtils.getTool(obj, toolLoad.ToolNumber) if tool.Diameter == 0: self.radius = 0.25 else: self.radius = tool.Diameter / 2 obj.ToolNumber = toolLoad.ToolNumber obj.ToolDescription = toolLoad.Name if obj.UserLabel == "": obj.Label = obj.Name + " :" + obj.ToolDescription else: obj.Label = obj.UserLabel + " :" + obj.ToolDescription output += "(" + obj.Label + ")" if not obj.UseComp: output += "(Compensated Tool Path. Diameter: " + str( self.radius * 2) + ")" else: output += "(Uncompensated Tool Path)" parentJob = PathUtils.findParentJob(obj) if parentJob is None: return baseobject = parentJob.Base if baseobject is None: return print "base object: " + baseobject.Name contourwire = PathUtils.silhouette(baseobject) edgelist = contourwire.Edges edgelist = Part.__sortEdges__(edgelist) try: output += self._buildPathLibarea(obj, edgelist) except: FreeCAD.Console.PrintError( "Something unexpected happened. Unable to generate a contour path. Check project and tool config." ) if obj.Active: path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False
def getBasewireOfStirrupWithExtendedEdges( stirrup, view_plane: WorkingPlane.Plane, extension_offset: float) -> Part.Wire: """Returns stirrup base wire after adding extension_offset to stirrup extended edges, so that end edges of stirrup with 90 degree bent angle do not overlap with stirrup edges. Parameters ---------- stirrup: <ArchRebar._Rebar> The stirrup with 90 degree bent angle. view_plane: WorkingPlane.Plane The view plane from which stirrup shape is visible. extension_offset: float The distance to move extended end edges of stirrup apart. Returns ------- Part.Wire The generated stirrup base wire. """ basewire = stirrup.Base.Shape.Wires[0].copy() # This function is meant for stirrup with bent angle 90 degree if stirrup.BentAngle != 90: return basewire min_x, min_y, max_x, max_y = getVertexesMinMaxXY(basewire.Vertexes, view_plane) def getModifiedEndEdgePoints(end_edge, coincident_edge): p1 = getProjectionToSVGPlane(end_edge.firstVertex().Point, view_plane) p2 = getProjectionToSVGPlane(end_edge.lastVertex().Point, view_plane) p3 = getProjectionToSVGPlane(coincident_edge.firstVertex().Point, view_plane) p4 = getProjectionToSVGPlane(coincident_edge.lastVertex().Point, view_plane) # The extended edge is vertical and is left side of stirrup And # coincident edge is horizontal if (round(p1.x) == round(p2.x) == round(min_x)) and (round(p3.y) == round(p4.y)): mod_p1 = end_edge.firstVertex().Point.add( extension_offset * view_plane.u.negative().normalize()) mod_p2 = end_edge.lastVertex().Point.add( extension_offset * view_plane.u.negative().normalize()) # The extended edge is vertical and is right side of stirrup And # coincident edge is horizontal elif (round(p1.x) == round(p2.x) == round(max_x)) and (round(p3.y) == round(p4.y)): mod_p1 = end_edge.firstVertex().Point.add(extension_offset * view_plane.u.normalize()) mod_p2 = end_edge.lastVertex().Point.add(extension_offset * view_plane.u.normalize()) # The extended edge is horizontal and is top side of stirrup And # coincident edge is vertical elif (round(p1.y) == round(p2.y) == round(min_y)) and (round(p3.x) == round(p4.x)): mod_p1 = end_edge.firstVertex().Point.add( extension_offset * view_plane.v.negative().normalize()) mod_p2 = end_edge.lastVertex().Point.add( extension_offset * view_plane.v.negative().normalize()) # The extended edge is horizontal and is bottom side of stirrup And # coincident edge is vertical elif (round(p1.y) == round(p2.y) == round(max_y)) and (round(p3.x) == round(p4.x)): mod_p1 = end_edge.firstVertex().Point.add(extension_offset * view_plane.v.normalize()) mod_p2 = end_edge.lastVertex().Point.add(extension_offset * view_plane.v.normalize()) else: # Don't modify any point mod_p1 = end_edge.firstVertex().Point mod_p2 = end_edge.lastVertex().Point return mod_p1, mod_p2 edges = Part.__sortEdges__(basewire.Edges) # Modify one end edge point_1, point_2 = getModifiedEndEdgePoints(edges[0], edges[1]) edges[0] = DraftGeomUtils.edg(point_1, point_2) edges[1] = DraftGeomUtils.edg(point_2, edges[1].lastVertex().Point) # Modify second end edge extension_offset = -1 * extension_offset point_1, point_2 = getModifiedEndEdgePoints(edges[-1], edges[-2]) edges[-1] = DraftGeomUtils.edg(point_1, point_2) edges[-2] = DraftGeomUtils.edg(edges[-2].firstVertex().Point, point_1) return DraftGeomUtils.connect(edges)
def getPath(edges=[],wires=[],pathname=None): import Part,DraftGeomUtils svg = "<path " if pathname is None: svg += 'id="%s" ' % obj.Name elif pathname != "": svg += 'id="%s" ' % pathname svg += ' d="' if not wires: egroups = Part.sortEdges(edges) else: egroups = [] for w in wires: w1=w.copy() w1.fixWire() egroups.append(Part.__sortEdges__(w1.Edges)) for egroupindex, edges in enumerate(egroups): edata = "" vs=() #skipped for the first edge for edgeindex,e in enumerate(edges): previousvs = vs # vertexes of an edge (reversed if needed) vs = e.Vertexes if previousvs: if (vs[0].Point-previousvs[-1].Point).Length > 1e-6: vs.reverse() if edgeindex == 0: v = getProj(vs[0].Point, plane) edata += 'M '+ str(v.x) +' '+ str(v.y) + ' ' else: if (vs[0].Point-previousvs[-1].Point).Length > 1e-6: raise ValueError('edges not ordered') iscircle = DraftGeomUtils.geomType(e) == "Circle" isellipse = DraftGeomUtils.geomType(e) == "Ellipse" if iscircle or isellipse: import math if hasattr(FreeCAD,"DraftWorkingPlane"): drawing_plane_normal = FreeCAD.DraftWorkingPlane.axis else: drawing_plane_normal = FreeCAD.Vector(0,0,1) if plane: drawing_plane_normal = plane.axis c = e.Curve if round(c.Axis.getAngle(drawing_plane_normal),2) in [0,3.14]: occversion = Part.OCC_VERSION.split(".") done = False if (int(occversion[0]) >= 7) and (int(occversion[1]) >= 1): # if using occ >= 7.1, use HLR algorithm import Drawing snip = Drawing.projectToSVG(e,drawing_plane_normal) if snip: try: a = "A " + snip.split("path d=\"")[1].split("\"")[0].split("A")[1] except: pass else: edata += a done = True if not done: if len(e.Vertexes) == 1 and iscircle: #complete curve svg = getCircle(e) return svg elif len(e.Vertexes) == 1 and isellipse: #svg = getEllipse(e) #return svg endpoints = (getProj(c.value((c.LastParameter-\ c.FirstParameter)/2.0), plane), \ getProj(vs[-1].Point, plane)) else: endpoints = (getProj(vs[-1].Point), plane) # arc if iscircle: rx = ry = c.Radius rot = 0 else: #ellipse rx = c.MajorRadius ry = c.MinorRadius rot = math.degrees(c.AngleXU * (c.Axis * \ FreeCAD.Vector(0,0,1))) if rot > 90: rot -=180 if rot < -90: rot += 180 #be careful with the sweep flag flag_large_arc = (((e.ParameterRange[1] - \ e.ParameterRange[0]) / math.pi) % 2) > 1 #flag_sweep = (c.Axis * drawing_plane_normal >= 0) \ # == (e.LastParameter > e.FirstParameter) # == (e.Orientation == "Forward") # other method: check the direction of the angle between tangents t1 = e.tangentAt(e.FirstParameter) t2 = e.tangentAt(e.FirstParameter + (e.LastParameter-e.FirstParameter)/10) flag_sweep = (DraftVecUtils.angle(t1,t2,drawing_plane_normal) < 0) for v in endpoints: edata += 'A %s %s %s %s %s %s %s ' % \ (str(rx),str(ry),str(rot),\ str(int(flag_large_arc)),\ str(int(flag_sweep)),str(v.x),str(v.y)) else: edata += getDiscretized(e, plane) elif DraftGeomUtils.geomType(e) == "Line": v = getProj(vs[-1].Point, plane) edata += 'L '+ str(v.x) +' '+ str(v.y) + ' ' else: bspline=e.Curve.toBSpline(e.FirstParameter,e.LastParameter) if bspline.Degree > 3 or bspline.isRational(): try: bspline=bspline.approximateBSpline(0.05,50, 3,'C0') except RuntimeError: print("Debug: unable to approximate bspline") if bspline.Degree <= 3 and not bspline.isRational(): for bezierseg in bspline.toBezier(): if bezierseg.Degree>3: #should not happen raise AssertionError elif bezierseg.Degree==1: edata +='L ' elif bezierseg.Degree==2: edata +='Q ' elif bezierseg.Degree==3: edata +='C ' for pole in bezierseg.getPoles()[1:]: v = getProj(pole, plane) edata += str(v.x) +' '+ str(v.y) + ' ' else: print("Debug: one edge (hash ",e.hashCode(),\ ") has been discretized with parameter 0.1") for linepoint in bspline.discretize(0.1)[1:]: v = getProj(linepoint, plane) edata += 'L '+ str(v.x) +' '+ str(v.y) + ' ' if fill != 'none': edata += 'Z ' if edata in pathdata: # do not draw a path on another identical path return "" else: svg += edata pathdata.append(edata) svg += '" ' svg += 'stroke="' + stroke + '" ' svg += 'stroke-width="' + str(linewidth) + ' px" ' svg += 'style="stroke-width:'+ str(linewidth) svg += ';stroke-miterlimit:4' svg += ';stroke-dasharray:' + lstyle svg += ';fill:' + fill try: svg += ';fill-opacity:' + str(fill_opacity) except NameError: pass svg += ';fill-rule: evenodd "' svg += '/>\n' return svg
def execute(self, obj): debug("\n\nExecuting PipeShell\n") path = None profs = [] edges = _utils.getShape(obj, "Spine", "Edge") path = Part.Wire(Part.__sortEdges__(edges)) if path.isValid(): debug("Valid spine : %s"%path) if hasattr(obj, "Profiles"): profs = obj.Profiles if not (path and profs): return(None) debug("Creating PipeShell") # create the pipeShell object ps = Part.BRepOffsetAPI.MakePipeShell(path) ps.setMaxDegree(self.getprop(obj, "MaxDegree") or 3) ps.setMaxSegments(self.getprop(obj, "MaxSegments") or 32) t3 = self.getprop(obj, "Tol3d") or 1.0e-4 tb = self.getprop(obj, "TolBound") or 1.0e-4 ta = self.getprop(obj, "TolAng") or 1.0e-2 ps.setTolerance(t3, tb, ta) mode = self.getprop(obj, "Mode")# or "DiscreteTrihedron" if mode in ["Binormal","FixedTrihedron"]: direction = self.getprop(obj, "Direction") if not direction: direction = FreeCAD.Vector(0,0,1) obj.Direction = direction FreeCAD.Console.PrintError("\nWrong direction, defaulting to +Z\n") elif direction.Length < 1e-7: direction = FreeCAD.Vector(0,0,1) obj.Direction = direction FreeCAD.Console.PrintError("\nDirection has null length, defaulting to +Z\n") if mode == "Binormal": debug("Binormal mode (%r)"%direction) ps.setBiNormalMode(direction) elif mode == "FixedTrihedron": loc = self.getprop(obj, "Location") or FreeCAD.Vector(0,0,0) debug("FixedTrihedron mode (%r %r)"%(loc, direction)) ps.setTrihedronMode(loc, direction) elif mode == "Frenet": fre = self.getprop(obj, "Corrected") debug("Frenet mode (%r)"%fre) ps.setFrenetMode(fre) elif mode == "AuxiliarySpine": aux = self.getprop(obj, "Auxiliary") w = None if aux: if aux.Shape.Wires: w = aux.Shape.Wires[0] elif aux.Shape.Edges: w = Part.Wire(Part.__sortEdges__(aux.Shape.Edges)) if w: curv = self.getprop(obj, "EquiCurvi") or False cont = self.getprop(obj, "Contact") or "NoContact" n = self.getCode(cont) debug("AuxiliarySpine mode (%r %s)"%(curv,cont)) ps.setAuxiliarySpine(w,curv,n) else: FreeCAD.Console.PrintError("\nPlease set a valid Auxiliary Spine Object\n") elif mode == "ShapeSupport": sup = self.getprop(obj, "Support") sh = None if sup: sh = sup.Shape if sh: debug("ShapeSupport mode") ps.setSpineSupport(sh) else: FreeCAD.Console.PrintError("\nPlease set a valid Spine support Object\n") for p in profs: self.add(ps,p) if ps.isReady(): output = self.getprop(obj, "Output") solid = self.getprop(obj, "Solid") or False if (output == "Surface") or (not hasattr(ps,'simulate')): ps.build() if solid: ps.makeSolid() obj.Shape = ps.shape() else: shapes = ps.simulate(self.getprop(obj, "Samples") or 100) if output == "Lofted sections": obj.Shape = Part.makeLoft(shapes, solid, False, False, self.getprop(obj, "MaxDegree")) else: rails = self.getRails(shapes) c = Part.Compound(shapes + rails) obj.Shape = c else: FreeCAD.Console.PrintError("\nFailed to create shape\n")
def execute(self, obj): if self.clone(obj): return if not obj.Base: return if not obj.Base.Shape: return if not obj.Base.Shape.Wires: return pl = obj.Placement if obj.Base.Shape.Solids: obj.Shape = obj.Base.Shape.copy() if not pl.isNull(): obj.Placement = obj.Shape.Placement.multiply(pl) else: if not obj.Profile: return if not obj.Profile.Shape: return if obj.Profile.Shape.findPlane() is None: return if not obj.Profile.Shape.Wires: return if not obj.Profile.Shape.Faces: for w in obj.Profile.Shape.Wires: if not w.isClosed(): return import DraftGeomUtils, Part, math baseprofile = obj.Profile.Shape.copy() if hasattr(obj, "ProfilePlacement"): if not obj.ProfilePlacement.isNull(): baseprofile.Placement = obj.ProfilePlacement.multiply( baseprofile.Placement) if not baseprofile.Faces: f = [] for w in baseprofile.Wires: f.append(Part.Face(w)) if len(f) == 1: baseprofile = f[0] else: baseprofile = Part.makeCompound(f) shapes = [] normal = DraftGeomUtils.getNormal(obj.Base.Shape) edges = obj.Base.Shape.Edges if hasattr(obj, "Edges"): if obj.Edges == "Vertical edges": rv = obj.Base.Placement.Rotation.multVec( FreeCAD.Vector(0, 1, 0)) edges = [ e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)), 4) in [0, 3.1416] ] elif obj.Edges == "Horizontal edges": rv = obj.Base.Placement.Rotation.multVec( FreeCAD.Vector(1, 0, 0)) edges = [ e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)), 4) in [0, 3.1416] ] elif obj.Edges == "Top Horizontal edges": rv = obj.Base.Placement.Rotation.multVec( FreeCAD.Vector(1, 0, 0)) edges = [ e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)), 4) in [0, 3.1416] ] edges = sorted(edges, key=lambda x: x.CenterOfMass.z, reverse=True) z = edges[0].CenterOfMass.z edges = [ e for e in edges if abs(e.CenterOfMass.z - z) < 0.00001 ] elif obj.Edges == "Bottom Horizontal edges": rv = obj.Base.Placement.Rotation.multVec( FreeCAD.Vector(1, 0, 0)) edges = [ e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)), 4) in [0, 3.1416] ] edges = sorted(edges, key=lambda x: x.CenterOfMass.z) z = edges[0].CenterOfMass.z edges = [ e for e in edges if abs(e.CenterOfMass.z - z) < 0.00001 ] for e in edges: bvec = DraftGeomUtils.vec(e) bpoint = e.Vertexes[0].Point profile = baseprofile.copy() rot = None # New rotation. # Supplying FreeCAD.Rotation() with two parallel vectors and # a null vector may seem strange, but the function is perfectly # able to handle this. Its algorithm will use default axes in # such cases. if obj.Align: if normal is None: rot = FreeCAD.Rotation(FreeCAD.Vector(), bvec, bvec, "ZYX") else: rot = FreeCAD.Rotation(FreeCAD.Vector(), normal, bvec, "ZYX") profile.Placement.Rotation = rot if hasattr(obj, "BasePoint"): edges = Part.__sortEdges__(profile.Edges) basepointliste = [profile.Placement.Base] for edge in edges: basepointliste.append( DraftGeomUtils.findMidpoint(edge)) basepointliste.append(edge.Vertexes[-1].Point) try: basepoint = basepointliste[obj.BasePoint] except IndexError: FreeCAD.Console.PrintMessage( translate("Arch", "Crossing point not found in profile.") + "\n") basepoint = basepointliste[0] else: basepoint = profile.Placement.Base delta = bpoint.sub(basepoint) # Translation vector. if obj.Offset and (not DraftVecUtils.isNull(obj.Offset)): if rot is None: delta = delta + obj.Offset else: delta = delta + rot.multVec(obj.Offset) profile.translate(delta) if obj.Rotation: profile.rotate(bpoint, bvec, obj.Rotation) # profile = wire.makePipeShell([profile], True, False, 2) TODO buggy profile = profile.extrude(bvec) shapes.append(profile) if shapes: if hasattr(obj, "Fuse"): if obj.Fuse: if len(shapes) > 1: s = shapes[0].multiFuse(shapes[1:]) s = s.removeSplitter() obj.Shape = s obj.Placement = pl return obj.Shape = Part.makeCompound(shapes) obj.Placement = pl
def Activated(self): b = [] selection = FreeCADGui.Selection.getSelectionEx() if selection: if len(selection) == 4: base = FreeCAD.ActiveDocument.getObject( (selection[0].ObjectName)) b = base.WingPanels _rootRib = FreeCAD.ActiveDocument.getObject( (selection[1].ObjectName)) _path = FreeCAD.ActiveDocument.getObject( (selection[2].ObjectName)) base.WingEdges.append(_path) _envelope = FreeCAD.ActiveDocument.getObject( (selection[3].ObjectName)) base.WingEdges.append(_envelope) _leadingedge = FreeCAD.ActiveDocument.getObject( (selection[3].ObjectName)) # A netoyer en doublon wingsketch = FreeCAD.ActiveDocument.getObject( (selection[3].ObjectName)) # Separate leadInEdge & trailingEdge edges = Part.sortEdges( wingsketch.Shape.Edges ) # Separate, #edges=Part.sortEdges(wingsketch.Shape.Edges) # deprecated ? paths = Part.__sortEdges__(_path.Shape.Edges) leadInEdges = edges[0] #id the leading edge trailingEdges = edges[1] #id the trailing edge FreeCAD.Console.PrintMessage("Edges number : " + str(len(edges)) + "\n") if len(edges) != 2: FreeCAD.Console.PrintMessage("Edges must be 2 and not " + str(len(edges)) + "\n") return nbOfPanels = len(leadInEdges) FreeCAD.Console.PrintMessage( "-------------------- Wing Panel --------------------" + "\n") FreeCAD.Console.PrintMessage(" Rib :" + str(_rootRib.Label) + "\n") FreeCAD.Console.PrintMessage(" Wing :" + str(base.Label) + "\n") FreeCAD.Console.PrintMessage(" Path :" + str(_path.Label) + "\n") FreeCAD.Console.PrintMessage(" envelope :" + str(_envelope.Label) + "\n") FreeCAD.Console.PrintMessage(" envelope placement:" + str(_envelope.Placement) + "\n") FreeCAD.Console.PrintMessage(" Number of Panels :" + str(nbOfPanels) + "\n") pmin = 0 pmax = 0 for i in range(0, nbOfPanels): # for each panel pmin = 0 #pmax pmax = leadInEdges[i].Length param = leadInEdges[i].getParameterByLength(pmin) param2 = leadInEdges[i].getParameterByLength(pmax) direction = leadInEdges[i].tangentAt(param) posvec = leadInEdges[i].valueAt(param) posvec2 = leadInEdges[i].valueAt(param2) #normal = CurvedShapes.getNormal(obj.Base) #rotaxis = normal.cross(direction) #angle = math.degrees(normal.getAngle(direction)) bbox = leadInEdges[i].BoundBox bbox2 = trailingEdges[i].BoundBox FreeCAD.Console.PrintMessage(" Panel n° " + str(i) + " ------------------------\n") FreeCAD.Console.PrintMessage(" leadInEdges id :" + str(leadInEdges[i]) + "\n") FreeCAD.Console.PrintMessage(" leadInEdges Length :" + str(leadInEdges[i].Length) + "\n") FreeCAD.Console.PrintMessage(" trailingEdges id :" + str(trailingEdges[i]) + "\n") FreeCAD.Console.PrintMessage(" trailingEdges Length :" + str(trailingEdges[i].Length) + "\n") FreeCAD.Console.PrintMessage(" direction :" + str(direction) + "\n") FreeCAD.Console.PrintMessage(" pmin : " + str(pmin) + "\n") FreeCAD.Console.PrintMessage(" Param : " + str(param) + "\n") FreeCAD.Console.PrintMessage(" Position : " + str(posvec) + "\n") FreeCAD.Console.PrintMessage(" Position2 : " + str(posvec2) + "\n") FreeCAD.Console.PrintMessage( " BoundBox leadInEdges : " + str(bbox) + "\n") FreeCAD.Console.PrintMessage( " BoundBox trailingEdges : " + str(bbox2) + "\n") FreeCADGui.activateWorkbench("DraftWorkbench") plane = WorkingPlane.plane() FreeCAD.DraftWorkingPlane = plane #workplane = WorkingPlane.plane() workplane = FreeCAD.DraftWorkingPlane v1 = FreeCAD.Vector( 0, 1, 0).normalize() #paths[i].tangentAt(param).normalize() v2 = FreeCAD.Vector(0, 0, 1).normalize() #workplane.alignToPointAndAxis(v1, v2, 0) #FreeCAD.DraftWorkingPlane.alignToPointAndAxis(v1, v2, 0) #FreeCADGui.Snapper.toggleGrid() FreeCAD.Console.PrintMessage(" V1 : " + str(v1) + "\n") FreeCAD.Console.PrintMessage(" V2 : " + str(v2) + "\n") # workplane.alignToPointAndAxis( v1, v2, 0) #FreeCADGui.Snapper.toggleGrid() FreeCADGui.activeDocument().activeView( ).setCameraOrientation(_path.Placement.Rotation) #paths[i]. FreeCAD.Console.PrintMessage(" pathline : " + str(paths[i]) + "\n") #pathline=Part.Line(paths[i].Geometry) myObj0 = Draft.makeSketch(paths[i], autoconstraints=True) #myObj1=Part.Line(paths[i].Content) myObj0.Label = "path" + str(i) vec = _envelope.Placement.Rotation FreeCADGui.activeDocument().activeView( ).setCameraOrientation(vec) #(0,0,0,1)) myObj1 = Draft.makeSketch(leadInEdges[i], name="leadInEdges" + str(i), autoconstraints=True) #myObj1=Part.Line() myObj1.Label = "leadInEdges" + str(i) FreeCADGui.activeDocument().activeView( ).setCameraOrientation(vec) myObj2 = Draft.makeSketch(trailingEdges[i], autoconstraints=True) myObj2.Label = "trailingEdge" + str(i) obj = FreeCAD.ActiveDocument.addObject( "Part::FeaturePython", "WingPanel" + str(i)) WingPanel(obj, _rootRib, myObj0, _envelope, myObj1, myObj2, 200, 100, 100, 0, 0) #WingPanel(obj,_rootRib,_path,_envelope,myObj1,myObj2,200,100,100,0,0) #WingPanel(obj,_rootRib,_path,_envelope,leadInEdges[i],trailingEdges[i],200,100,100,0,0) #WingPanel(obj,_rootRib,_path,leadInEdges[i],trailingEdges[i],200,100,100,0,0) ViewProviderPanel(obj.ViewObject) b.append(obj) FreeCAD.ActiveDocument.recompute() else: #---------------------création des nervures temporaires #_rootRib=FreeCAD.ActiveDocument.addObject("Part::FeaturePython","RibRoot_") #WingRib(_rootRib,"/Users/fredericnivoix/Library/Preferences/FreeCAD/Mod/AirPlaneDesign/wingribprofil/naca/naca2412.dat",False,0,200,0,0,0,0,0,0) #ViewProviderWingRib(_rootRib.ViewObject) #_tipRib=FreeCAD.ActiveDocument.addObject("Part::FeaturePython","RibTip_") #WingRib(_tipRib,"/Users/fredericnivoix/Library/Preferences/FreeCAD/Mod/AirPlaneDesign/wingribprofil/naca/naca2412.dat",False,0,200,0,500,0,0,0,0) #ViewProviderWingRib(_tipRib.ViewObject) #---------- obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "WingPanel") WingPanel(obj, None, None, None, None, None, 200, 100, 100, 0, 0) ViewProviderPanel(obj.ViewObject) if selection: #selection==None : try: #b=base.WingPanels #b.append(obj) base.WingPanels = b except: print("The selection is not a wing") FreeCAD.Gui.activeDocument().activeView().viewAxonometric() FreeCAD.Gui.SendMsgToActiveView("ViewFit")
def getExtrusionData(self,obj): """returns (shape,extrusion vector,placement) or None""" import Part,DraftGeomUtils data = ArchComponent.Component.getExtrusionData(self,obj) if data: if not isinstance(data[0],list): # multifuses not considered here return data length = obj.Length.Value width = obj.Width.Value height = obj.Height.Value if not height: for p in obj.InList: if Draft.getType(p) in ["Floor","BuildingPart"]: if p.Height.Value: height = p.Height.Value if not height: return None if obj.Normal == Vector(0,0,0): normal = Vector(0,0,1) else: normal = Vector(obj.Normal) base = None placement = None self.basewires = None # build wall layers layers = [] if hasattr(obj,"Material"): if obj.Material: if hasattr(obj.Material,"Materials"): varwidth = 0 restwidth = width - sum(obj.Material.Thicknesses) if restwidth > 0: varwidth = [t for t in obj.Material.Thicknesses if t == 0] if varwidth: varwidth = restwidth/len(varwidth) for t in obj.Material.Thicknesses: if t: layers.append(t) elif varwidth: layers.append(varwidth) if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape: if obj.Base.Shape.Solids: return None elif obj.Face > 0: if len(obj.Base.Shape.Faces) >= obj.Face: face = obj.Base.Shape.Faces[obj.Face-1] # this wall is based on a specific face of its base object if obj.Normal != Vector(0,0,0): normal = face.normalAt(0,0) if normal.getAngle(Vector(0,0,1)) > math.pi/4: normal.multiply(width) base = face.extrude(normal) if obj.Align == "Center": base.translate(normal.negative().multiply(0.5)) elif obj.Align == "Right": base.translate(normal.negative()) else: normal.multiply(height) base = face.extrude(normal) base,placement = self.rebase(base) return (base,normal,placement) elif obj.Base.Shape.Faces: if not DraftGeomUtils.isCoplanar(obj.Base.Shape.Faces): return None else: base,placement = self.rebase(obj.Base.Shape) elif len(obj.Base.Shape.Edges) == 1: self.basewires = [Part.Wire(obj.Base.Shape.Edges)] else: # self.basewires = obj.Base.Shape.Wires self.basewires = [] for cluster in Part.getSortedClusters(obj.Base.Shape.Edges): for c in Part.sortEdges(cluster): self.basewires.append(Part.Wire(c)) if self.basewires and width: if (len(self.basewires) == 1) and layers: self.basewires = [self.basewires[0] for l in layers] layeroffset = 0 baseface = None for i,wire in enumerate(self.basewires): e = wire.Edges[0] if isinstance(e.Curve,Part.Circle): dvec = e.Vertexes[0].Point.sub(e.Curve.Center) else: dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal) if not DraftVecUtils.isNull(dvec): dvec.normalize() sh = None if obj.Align == "Left": off = obj.Offset.Value if layers: off = off+layeroffset dvec.multiply(layers[i]) layeroffset += layers[i] else: dvec.multiply(width) if off: dvec2 = DraftVecUtils.scaleTo(dvec,off) wire = DraftGeomUtils.offsetWire(wire,dvec2) w2 = DraftGeomUtils.offsetWire(wire,dvec) w1 = Part.Wire(Part.__sortEdges__(wire.Edges)) sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Right": dvec = dvec.negative() off = obj.Offset.Value if layers: off = off+layeroffset dvec.multiply(layers[i]) layeroffset += layers[i] else: dvec.multiply(width) if off: dvec2 = DraftVecUtils.scaleTo(dvec,off) wire = DraftGeomUtils.offsetWire(wire,dvec2) w2 = DraftGeomUtils.offsetWire(wire,dvec) w1 = Part.Wire(Part.__sortEdges__(wire.Edges)) sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Center": if layers: off = width/2-layeroffset d1 = Vector(dvec).multiply(off) w1 = DraftGeomUtils.offsetWire(wire,d1) layeroffset += layers[i] off = width/2-layeroffset d1 = Vector(dvec).multiply(off) w2 = DraftGeomUtils.offsetWire(wire,d1) else: dvec.multiply(width/2) w1 = DraftGeomUtils.offsetWire(wire,dvec) dvec = dvec.negative() w2 = DraftGeomUtils.offsetWire(wire,dvec) sh = DraftGeomUtils.bind(w1,w2) if sh: sh.fix(0.1,0,1) # fixes self-intersecting wires f = Part.Face(sh) if baseface: if layers: baseface.append(f) else: baseface = baseface.fuse(f) # baseface = baseface.removeSplitter() s = DraftGeomUtils.removeSplitter(baseface) if s: baseface = s else: if layers: baseface = [f] else: baseface = f if baseface: base,placement = self.rebase(baseface) else: if layers: totalwidth = sum(layers) offset = 0 base = [] for l in layers: l2 = length/2 or 0.5 w1 = -totalwidth/2 + offset w2 = w1 + l v1 = Vector(-l2,w1,0) v2 = Vector(l2,w1,0) v3 = Vector(l2,w2,0) v4 = Vector(-l2,w2,0) base.append(Part.Face(Part.makePolygon([v1,v2,v3,v4,v1]))) offset += l else: l2 = length/2 or 0.5 w2 = width/2 or 0.5 v1 = Vector(-l2,-w2,0) v2 = Vector(l2,-w2,0) v3 = Vector(l2,w2,0) v4 = Vector(-l2,w2,0) base = Part.Face(Part.makePolygon([v1,v2,v3,v4,v1])) placement = FreeCAD.Placement() if base and placement: extrusion = normal.multiply(height) if placement.Rotation.Angle > 0: extrusion = placement.inverse().Rotation.multVec(extrusion) return (base,extrusion,placement) return None
def getProfiles(self, obj, noplacement=False): "Returns the base profile(s) of this component, if applicable" wires = [] n, l, w, h = self.getDefaultValues(obj) if obj.Base: if obj.Base.isDerivedFrom("Part::Extrusion"): if obj.Base.Base: base = obj.Base.Base.Shape.copy() if noplacement: base.Placement = FreeCAD.Placement() return [base] elif obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape: base = obj.Base.Shape.copy() if noplacement: base.Placement = FreeCAD.Placement() if not base.Solids: if base.Faces: import DraftGeomUtils if not DraftGeomUtils.isCoplanar(base.Faces): return [] return [base] basewires = [] if not base.Wires: if len(base.Edges) == 1: import Part basewires = [Part.Wire(base.Edges)] else: basewires = base.Wires if basewires: import DraftGeomUtils, DraftVecUtils, Part for wire in basewires: e = wire.Edges[0] if isinstance(e.Curve, Part.Circle): dvec = e.Vertexes[0].Point.sub( e.Curve.Center) else: dvec = DraftGeomUtils.vec( wire.Edges[0]).cross(n) if not DraftVecUtils.isNull(dvec): dvec.normalize() sh = None if hasattr(obj, "Align"): if obj.Align == "Left": dvec.multiply(w) if hasattr(obj, "Offset"): if obj.Offset.Value: dvec2 = DraftVecUtils.scaleTo( dvec, obj.Offset.Value) wire = DraftGeomUtils.offsetWire( wire, dvec2) w2 = DraftGeomUtils.offsetWire( wire, dvec) w1 = Part.Wire( Part.__sortEdges__(wire.Edges)) sh = DraftGeomUtils.bind(w1, w2) elif obj.Align == "Right": dvec.multiply(w) dvec = dvec.negative() if hasattr(obj, "Offset"): if obj.Offset.Value: dvec2 = DraftVecUtils.scaleTo( dvec, obj.Offset.Value) wire = DraftGeomUtils.offsetWire( wire, dvec2) w2 = DraftGeomUtils.offsetWire( wire, dvec) w1 = Part.Wire( Part.__sortEdges__(wire.Edges)) sh = DraftGeomUtils.bind(w1, w2) elif obj.Align == "Center": dvec.multiply(w / 2) w1 = DraftGeomUtils.offsetWire( wire, dvec) dvec = dvec.negative() w2 = DraftGeomUtils.offsetWire( wire, dvec) sh = DraftGeomUtils.bind(w1, w2) if sh: wires.append(sh) else: wires.append(wire) elif Draft.getType(obj) in ["Wall", "Structure"]: if (Draft.getType(obj) == "Structure") and (l > h): if noplacement: h2 = h / 2 or 0.5 w2 = w / 2 or 0.5 v1 = Vector(-h2, -w2, 0) v2 = Vector(h2, -w2, 0) v3 = Vector(h2, w2, 0) v4 = Vector(-h2, w2, 0) else: h2 = h / 2 or 0.5 w2 = w / 2 or 0.5 v1 = Vector(0, -w2, -h2) v2 = Vector(0, -w2, h2) v3 = Vector(0, w2, h2) v4 = Vector(0, w2, -h2) else: l2 = l / 2 or 0.5 w2 = w / 2 or 0.5 v1 = Vector(-l2, -w2, 0) v2 = Vector(l2, -w2, 0) v3 = Vector(l2, w2, 0) v4 = Vector(-l2, w2, 0) import Part base = Part.makePolygon([v1, v2, v3, v4, v1]) return [base] return wires
def execute(self,obj): if self.clone(obj): return import Part, math, DraftGeomUtils pl = obj.Placement #self.baseface = None base = None w = None if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.Solids: base = obj.Base.Shape #pl = obj.Base.Placement else: 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 = Part.__sortEdges__(w.Edges) l = len(edges) 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 i in range(l): self.calcEdgeGeometry(edges, i) for i in range(l): self.calcDraftEdges(i) for i in range(l): self.calcEave(i) for p in self.profilsDico: heights.append(p["height"]) obj.Heights = heights for i in range(l): self.getRoofPaneProject(i) profilCurrent = self.findProfil(i) midpoint = DraftGeomUtils.findMidpoint(profilCurrent["edge"]) ptsPaneProject = profilCurrent["points"] lp = len(ptsPaneProject) if lp != 0: ptsPaneProject.append(ptsPaneProject[0]) edgesWire = [] for p in range(lp): edge = Part.makeLine(ptsPaneProject[p],ptsPaneProject[p+1]) edgesWire.append(edge) wire = Part.Wire(edgesWire) d = wire.BoundBox.DiagonalLength thicknessV = profilCurrent["thickness"]/(math.cos(math.radians(profilCurrent["angle"]))) overhangV = profilCurrent["overhang"]*math.tan(math.radians(profilCurrent["angle"])) if wire.isClosed(): f = Part.Face(wire) f = f.extrude(FreeCAD.Vector(0,0,profilCurrent["height"]+1000000.0)) f.translate(FreeCAD.Vector(0.0,0.0,-2*overhangV)) ptsPaneProfil=[FreeCAD.Vector(-profilCurrent["overhang"],-overhangV,0.0),FreeCAD.Vector(profilCurrent["run"],profilCurrent["height"],0.0),FreeCAD.Vector(profilCurrent["run"],profilCurrent["height"]+thicknessV,0.0),FreeCAD.Vector(-profilCurrent["overhang"],-overhangV+thicknessV,0.0)] self.shps.append(self.createProfilShape(ptsPaneProfil, midpoint, profilCurrent["rot"], profilCurrent["vec"], profilCurrent["run"], d, f)) ## subVolume shape ptsSubVolumeProfil=[FreeCAD.Vector(-profilCurrent["overhang"],-overhangV,0.0),FreeCAD.Vector(profilCurrent["run"],profilCurrent["height"],0.0),FreeCAD.Vector(profilCurrent["run"],profilCurrent["height"]+900000.0,0.0),FreeCAD.Vector(-profilCurrent["overhang"],profilCurrent["height"]+900000.0,0.0)] self.subVolshps.append(self.createProfilShape(ptsSubVolumeProfil, midpoint, profilCurrent["rot"], profilCurrent["vec"], profilCurrent["run"], d, f)) ## 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 = self.shps.pop() for s in self.shps : base = base.fuse(s) base = self.processSubShapes(obj,base) self.applyShape(obj,base,pl,allownosolid=True) elif base : base = self.processSubShapes(obj,base) self.applyShape(obj,base,pl,allownosolid=True) else: FreeCAD.Console.PrintMessage(translate("Arch","Unable to create a roof"))
def getPath(edges=[], wires=[], pathname=None): svg = "<path " if pathname is None: svg += 'id="%s" ' % obj.Name elif pathname != "": svg += 'id="%s" ' % pathname svg += ' d="' if not wires: egroups = Part.sortEdges(edges) else: egroups = [] first = True for w in wires: w1 = w.copy() if first: first = False else: # invert further wires to create holes w1 = DraftGeomUtils.invert(w1) w1.fixWire() egroups.append(Part.__sortEdges__(w1.Edges)) for egroupindex, edges in enumerate(egroups): edata = "" vs = () #skipped for the first edge for edgeindex, e in enumerate(edges): previousvs = vs # vertexes of an edge (reversed if needed) vs = e.Vertexes if previousvs: if (vs[0].Point - previousvs[-1].Point).Length > 1e-6: vs.reverse() if edgeindex == 0: v = getProj(vs[0].Point, plane) edata += 'M ' + str(v.x) + ' ' + str(v.y) + ' ' else: if (vs[0].Point - previousvs[-1].Point).Length > 1e-6: raise ValueError('edges not ordered') iscircle = DraftGeomUtils.geomType(e) == "Circle" isellipse = DraftGeomUtils.geomType(e) == "Ellipse" if iscircle or isellipse: import math if hasattr(FreeCAD, "DraftWorkingPlane"): drawing_plane_normal = FreeCAD.DraftWorkingPlane.axis else: drawing_plane_normal = FreeCAD.Vector(0, 0, 1) if plane: drawing_plane_normal = plane.axis c = e.Curve if round(c.Axis.getAngle(drawing_plane_normal), 2) in [0, 3.14]: occversion = Part.OCC_VERSION.split(".") done = False if (int(occversion[0]) >= 7) and (int(occversion[1]) >= 1): # if using occ >= 7.1, use HLR algorithm import Drawing snip = Drawing.projectToSVG( e, drawing_plane_normal) if snip: try: a = "A " + snip.split("path d=\"")[ 1].split("\"")[0].split("A")[1] except: pass else: edata += a done = True if not done: if len(e.Vertexes ) == 1 and iscircle: #complete curve svg = getCircle(e) return svg elif len(e.Vertexes) == 1 and isellipse: #svg = getEllipse(e) #return svg endpoints = [ getProj( c.value((c.LastParameter - c.FirstParameter) / 2.0), plane), getProj(vs[-1].Point, plane) ] else: endpoints = [getProj(vs[-1].Point, plane)] # arc if iscircle: rx = ry = c.Radius rot = 0 else: #ellipse rx = c.MajorRadius ry = c.MinorRadius rot = math.degrees(c.AngleXU * (c.Axis * \ FreeCAD.Vector(0,0,1))) if rot > 90: rot -= 180 if rot < -90: rot += 180 #be careful with the sweep flag flag_large_arc = (((e.ParameterRange[1] - \ e.ParameterRange[0]) / math.pi) % 2) > 1 #flag_sweep = (c.Axis * drawing_plane_normal >= 0) \ # == (e.LastParameter > e.FirstParameter) # == (e.Orientation == "Forward") # other method: check the direction of the angle between tangents t1 = e.tangentAt(e.FirstParameter) t2 = e.tangentAt( e.FirstParameter + (e.LastParameter - e.FirstParameter) / 10) flag_sweep = (DraftVecUtils.angle( t1, t2, drawing_plane_normal) < 0) for v in endpoints: edata += 'A %s %s %s %s %s %s %s ' % \ (str(rx),str(ry),str(rot),\ str(int(flag_large_arc)),\ str(int(flag_sweep)),str(v.x),str(v.y)) else: edata += getDiscretized(e, plane) elif DraftGeomUtils.geomType(e) == "Line": v = getProj(vs[-1].Point, plane) edata += 'L ' + str(v.x) + ' ' + str(v.y) + ' ' else: bspline = e.Curve.toBSpline(e.FirstParameter, e.LastParameter) if bspline.Degree > 3 or bspline.isRational(): try: bspline = bspline.approximateBSpline( 0.05, 50, 3, 'C0') except RuntimeError: print("Debug: unable to approximate bspline") if bspline.Degree <= 3 and not bspline.isRational(): for bezierseg in bspline.toBezier(): if bezierseg.Degree > 3: #should not happen raise AssertionError elif bezierseg.Degree == 1: edata += 'L ' elif bezierseg.Degree == 2: edata += 'Q ' elif bezierseg.Degree == 3: edata += 'C ' for pole in bezierseg.getPoles()[1:]: v = getProj(pole, plane) edata += str(v.x) + ' ' + str(v.y) + ' ' else: print("Debug: one edge (hash ",e.hashCode(),\ ") has been discretized with parameter 0.1") for linepoint in bspline.discretize(0.1)[1:]: v = getProj(linepoint, plane) edata += 'L ' + str(v.x) + ' ' + str(v.y) + ' ' if fill != 'none': edata += 'Z ' if edata in pathdata: # do not draw a path on another identical path return "" else: svg += edata pathdata.append(edata) svg += '" ' svg += 'stroke="' + stroke + '" ' svg += 'stroke-width="' + str(linewidth) + ' px" ' svg += 'style="stroke-width:' + str(linewidth) svg += ';stroke-miterlimit:4' svg += ';stroke-dasharray:' + lstyle svg += ';fill:' + fill try: svg += ';fill-opacity:' + str(fill_opacity) except NameError: pass svg += ';fill-rule: evenodd "' svg += '/>\n' return svg
def SortPath(wire, Side, radius, clockwise, firstedge=None, SegLen=0.5): '''SortPath(wire,Side,radius,clockwise,firstedge=None,SegLen =0.5) Sorts the wire and reverses it, if needed. Splits arcs over 180 degrees in two. Returns the reordered offset of the wire. ''' if firstedge: edgelist = wire.Edges[:] if wire.isClosed(): elindex = None n = 0 for e in edgelist: if isSameEdge(e, firstedge): # FreeCAD.Console.PrintMessage('found first edge\n') elindex = n n = n + 1 l1 = edgelist[:elindex] l2 = edgelist[elindex:] newedgelist = l2 + l1 if clockwise: newedgelist.reverse() last = newedgelist.pop(-1) newedgelist.insert(0, last) preoffset = [] for e in newedgelist: if clockwise: r = reverseEdge(e) preoffset.append(r) else: preoffset.append(e) sortedpreoff = Part.__sortEdges__(preoffset) wire = Part.Wire(sortedpreoff) #wire = findWires(sortedpreoff)[0] else: sortedpreoff = Part.__sortEdges__(edgelist) wire = Part.Wire(sortedpreoff) #wire = findWires(sortedpreoff)[0] edgelist = [] for e in wire.Edges: if geomType(e) == "Circle": arclist = filterArcs(e) for a in arclist: edgelist.append(a) elif geomType(e) == "Line": edgelist.append(e) elif geomType(e) == "BSplineCurve" or \ geomType(e) == "BezierCurve" or \ geomType(e) == "Ellipse": edgelist.append(Part.Wire(curvetowire(e, (SegLen)))) #newwire = Part.Wire(edgelist) sortededges = Part.__sortEdges__(edgelist) newwire = findWires(sortededges)[0] print "newwire is clockwise: " + str(is_clockwise(newwire)) if is_clockwise(newwire) is not clockwise: newwire.reverse() print "newwire is clockwise: " + str(is_clockwise(newwire)) if Side == 'Left': # we use the OCC offset feature offset = newwire.makeOffset(radius) # tool is outside line elif Side == 'Right': offset = newwire.makeOffset(-radius) # tool is inside line else: if wire.isClosed(): offset = newwire.makeOffset(0.0) else: offset = newwire print "offset wire is clockwise: " + str(is_clockwise(offset)) offset.reverse() print "offset wire is clockwise: " + str(is_clockwise(offset)) return offset
def makeRoof(baseobj=None, facenr=0, angles=[ 45., ], run=[], idrel=[ 0, ], thickness=[ 50., ], overhang=[ 100., ], name="Roof"): '''makeRoof(baseobj,[facenr],[angle],[name]) : Makes a roof based on a closed wire or an object. You can provide a list of angles, run, idrel, thickness, overhang for each edges in the wire to define the roof shape. The default for angle is 45 and the list is automatically complete to match with number of edges in the wire. If the base object is a solid the roof take the shape.''' import Part obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", name) obj.Label = translate("Arch", name) w = None _Roof(obj) if FreeCAD.GuiUp: _ViewProviderRoof(obj.ViewObject) if baseobj: obj.Base = baseobj if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.Solids: if FreeCAD.GuiUp: obj.Base.ViewObject.hide() else: if (obj.Base.Shape.Faces and obj.Face): w = obj.Base.Shape.Faces[obj.Face - 1].Wires[0] if FreeCAD.GuiUp: obj.Base.ViewObject.hide() elif obj.Base.Shape.Wires: w = obj.Base.Shape.Wires[0] if FreeCAD.GuiUp: obj.Base.ViewObject.hide() if w: if w.isClosed(): if FreeCAD.GuiUp: obj.Base.ViewObject.hide() edges = Part.__sortEdges__(w.Edges) l = len(edges) la = len(angles) alist = angles for i in range(l - la): alist.append(angles[0]) obj.Angles = alist lr = len(run) rlist = run for i in range(l - lr): #rlist.append(w.Edges[i].Length/2.) rlist.append(250.) obj.Runs = rlist lidrel = len(idrel) rellist = idrel for i in range(l - lidrel): rellist.append(0) obj.IdRel = rellist lthick = len(thickness) tlist = thickness for i in range(l - lthick): tlist.append(thickness[0]) obj.Thickness = tlist lover = len(overhang) olist = overhang for i in range(l - lover): olist.append(overhang[0]) obj.Overhang = olist obj.Face = facenr return obj
def SortPath(wire, Side, radius, clockwise, firstedge=None, SegLen=0.5): '''SortPath(wire,Side,radius,clockwise,firstedge=None,SegLen =0.5) Sorts the wire and reverses it, if needed. Splits arcs over 180 degrees in two. Returns the reordered offset of the wire. ''' if firstedge: edgelist = wire.Edges[:] if wire.isClosed(): elindex = None n = 0 for e in edgelist: if isSameEdge(e, firstedge): # FreeCAD.Console.PrintMessage('found first edge\n') elindex = n n = n + 1 l1 = edgelist[:elindex] l2 = edgelist[elindex:] newedgelist = l2 + l1 if clockwise: newedgelist.reverse() last = newedgelist.pop(-1) newedgelist.insert(0, last) preoffset = [] for e in newedgelist: if clockwise: r = reverseEdge(e) preoffset.append(r) else: preoffset.append(e) sortedpreoff = Part.__sortEdges__(preoffset) wire = Part.Wire(sortedpreoff) else: sortedpreoff = Part.__sortEdges__(edgelist) wire = Part.Wire(sortedpreoff) edgelist = [] for e in wire.Edges: if geomType(e) == "Circle": arclist = filterArcs(e) for a in arclist: edgelist.append(a) elif geomType(e) == "Line": edgelist.append(e) elif geomType(e) == "BSplineCurve" or \ geomType(e) == "BezierCurve" or \ geomType(e) == "Ellipse": edgelist.append(Part.Wire(curvetowire(e, (SegLen)))) newwire = Part.Wire(edgelist) if Side == 'Left': # we use the OCC offset feature offset = newwire.makeOffset(radius) #tool is outside line elif Side == 'Right': offset = newwire.makeOffset(-radius) #tool is inside line else: if wire.isClosed(): offset = newwire.makeOffset(0.0) else: offset = newwire return offset
def getProfiles(self,obj,noplacement=False): "Returns the base profile(s) of this component, if applicable" wires = [] n,l,w,h = self.getDefaultValues(obj) if obj.Base: if obj.Base.isDerivedFrom("Part::Extrusion"): if obj.Base.Base: base = obj.Base.Base.Shape.copy() if noplacement: base.Placement = FreeCAD.Placement() return [base] elif obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape: base = obj.Base.Shape.copy() if noplacement: base.Placement = FreeCAD.Placement() if not base.Solids: if base.Faces: import DraftGeomUtils if not DraftGeomUtils.isCoplanar(base.Faces): return [] return [base] basewires = [] if not base.Wires: if len(base.Edges) == 1: import Part basewires = [Part.Wire(base.Edges)] else: basewires = base.Wires if basewires: import DraftGeomUtils,DraftVecUtils,Part for wire in basewires: e = wire.Edges[0] if isinstance(e.Curve,Part.Circle): dvec = e.Vertexes[0].Point.sub(e.Curve.Center) else: dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(n) if not DraftVecUtils.isNull(dvec): dvec.normalize() sh = None if hasattr(obj,"Align"): if obj.Align == "Left": dvec.multiply(w) if hasattr(obj,"Offset"): if obj.Offset.Value: dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset.Value) wire = DraftGeomUtils.offsetWire(wire,dvec2) w2 = DraftGeomUtils.offsetWire(wire,dvec) w1 = Part.Wire(Part.__sortEdges__(wire.Edges)) sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Right": dvec.multiply(w) dvec = dvec.negative() if hasattr(obj,"Offset"): if obj.Offset.Value: dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset.Value) wire = DraftGeomUtils.offsetWire(wire,dvec2) w2 = DraftGeomUtils.offsetWire(wire,dvec) w1 = Part.Wire(Part.__sortEdges__(wire.Edges)) sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Center": dvec.multiply(w/2) w1 = DraftGeomUtils.offsetWire(wire,dvec) dvec = dvec.negative() w2 = DraftGeomUtils.offsetWire(wire,dvec) sh = DraftGeomUtils.bind(w1,w2) if sh: wires.append(sh) else: wires.append(wire) elif Draft.getType(obj) in ["Wall","Structure"]: if (Draft.getType(obj) == "Structure") and (l > h): if noplacement: h2 = h/2 or 0.5 w2 = w/2 or 0.5 v1 = Vector(-h2,-w2,0) v2 = Vector(h2,-w2,0) v3 = Vector(h2,w2,0) v4 = Vector(-h2,w2,0) else: h2 = h/2 or 0.5 w2 = w/2 or 0.5 v1 = Vector(0,-w2,-h2) v2 = Vector(0,-w2,h2) v3 = Vector(0,w2,h2) v4 = Vector(0,w2,-h2) else: l2 = l/2 or 0.5 w2 = w/2 or 0.5 v1 = Vector(-l2,-w2,0) v2 = Vector(l2,-w2,0) v3 = Vector(l2,w2,0) v4 = Vector(-l2,w2,0) import Part base = Part.makePolygon([v1,v2,v3,v4,v1]) return [base] return wires
def getObjectData(obj, wireframeMode=wireframeStyle, color=None): """returns the geometry data of an object as three.js snippet. wireframeMode can be multimaterial, faceloop, or None""" result = "" wires = [] if hasattr(obj, 'Shape'): fcmesh = obj.Shape.tessellate(0.1) result = "var geom = new THREE.Geometry();\n" # adding vertices data for i in range(len(fcmesh[0])): v = fcmesh[0][i] result += tab + "var v" + str(i) + " = new THREE.Vector3(" + str( v.x) + "," + str(v.y) + "," + str(v.z) + ");\n" result += tab + "console.log(geom.vertices)\n" for i in range(len(fcmesh[0])): result += tab + "geom.vertices.push(v" + str(i) + ");\n" # adding facets data for f in fcmesh[1]: result += tab + "geom.faces.push( new THREE.Face3" + str( f).replace("L", "") + " );\n" for f in obj.Shape.Faces: for w in f.Wires: wo = Part.Wire(Part.__sortEdges__(w.Edges)) wires.append(wo.discretize(QuasiDeflection=0.1)) elif obj.isDerivedFrom("Mesh::Feature"): mesh = obj.Mesh result = "var geom = new THREE.Geometry();\n" # adding vertices data for p in mesh.Points: v = p.Vector i = p.Index result += tab + "var v" + str(i) + " = new THREE.Vector3(" + str( v.x) + "," + str(v.y) + "," + str(v.z) + ");\n" result += tab + "console.log(geom.vertices)\n" for p in mesh.Points: result += tab + "geom.vertices.push(v" + str(p.Index) + ");\n" # adding facets data for f in mesh.Facets: pointIndices = tuple([int(i) for i in f.PointIndices]) result += tab + "geom.faces.push( new THREE.Face3" + str( pointIndices).replace("L", "") + " );\n" if result: # adding a base material if color: rgb = Draft.getrgb(color, testbw=False) elif FreeCADGui: col = obj.ViewObject.ShapeColor rgb = Draft.getrgb(col, testbw=False) else: rgb = "#888888" # test color result += tab + "var basematerial = new THREE.MeshBasicMaterial( { color: 0x" + str( rgb)[1:] + " } );\n" #result += tab+"var basematerial = new THREE.MeshLambertMaterial( { color: 0x"+str(rgb)[1:]+" } );\n" if wireframeMode == "faceloop": # adding the mesh to the scene with a wireframe copy result += tab + "var mesh = new THREE.Mesh( geom, basematerial );\n" result += tab + "scene.add( mesh );\n" result += tab + "var linematerial = new THREE.LineBasicMaterial({linewidth: %d, color: 0x000000,});\n" % linewidth for w in wires: result += tab + "var wire = new THREE.Geometry();\n" for p in w: result += tab + "wire.vertices.push(new THREE.Vector3(" result += str(p.x) + ", " + str(p.y) + ", " + str( p.z) + "));\n" result += tab + "var line = new THREE.Line(wire, linematerial);\n" result += tab + "scene.add(line);\n" elif wireframeMode == "multimaterial": # adding a wireframe material result += tab + "var wireframe = new THREE.MeshBasicMaterial( { color: " result += "0x000000, wireframe: true, transparent: true } );\n" result += tab + "var material = [ basematerial, wireframe ];\n" result += tab + "var mesh = new THREE.SceneUtils.createMultiMaterialObject( geom, material );\n" result += tab + "scene.add( mesh );\n" + tab else: # adding the mesh to the scene with simple material result += tab + "var mesh = new THREE.Mesh( geom, basematerial );\n" result += tab + "scene.add( mesh );\n" + tab return result
def execute(self, obj): if not obj.Active: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False return #Tool may have changed. Refresh data toolLoad = PathUtils.getLastToolLoad(obj) if toolLoad is None or toolLoad.ToolNumber == 0: self.vertFeed = 100 self.horizFeed = 100 self.vertRapid = 100 self.horiRrapid = 100 self.radius = 0.25 obj.ToolNumber = 0 obj.ToolDescription = "UNDEFINED" else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = PathUtils.getTool(obj, toolLoad.ToolNumber) if tool.Diameter == 0: self.radius = 0.25 else: self.radius = tool.Diameter / 2 obj.ToolNumber = toolLoad.ToolNumber obj.ToolDescription = toolLoad.Name #Build preliminary comments output = "" output += "(" + obj.Label + ")" if obj.UserLabel == "": obj.Label = obj.Name + " :" + obj.ToolDescription else: obj.Label = obj.UserLabel + " :" + obj.ToolDescription #Facing is done either against base objects if obj.Base: faces = [] for b in obj.Base: for sub in b[1]: shape = getattr(b[0].Shape, sub) if isinstance(shape, Part.Face): faces.append(shape) else: print('falling out') return planeshape = Part.makeCompound(faces) #If no base object, do planing of top surface of entire model else: parentJob = PathUtils.findParentJob(obj) if parentJob is None: return baseobject = parentJob.Base if baseobject is None: return planeshape = baseobject.Shape #if user wants the boundbox, calculate that if obj.BoundaryShape == 'Boundbox': bb = planeshape.BoundBox bbperim = Part.makeBox(bb.XLength, bb.YLength, 1, Vector(bb.XMin, bb.YMin, bb.ZMin), Vector(0, 0, 1)) contourwire = TechDraw.findShapeOutline(bbperim, 1, Vector(0, 0, 1)) else: contourwire = TechDraw.findShapeOutline(planeshape, 1, Vector(0, 0, 1)) edgelist = contourwire.Edges edgelist = Part.__sortEdges__(edgelist) #use libarea to build the pattern a = area.Area() c = PathScripts.PathKurveUtils.makeAreaCurve(edgelist, 'CW') a.append(c) a.Reorder() output += self.buildpathlibarea(obj, a) path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True
def makeAreaCurve(edges, direction, startpt=None, endpt=None): curveobj = area.Curve() cleanededges = Part.__sortEdges__(PathUtils.cleanedges(edges, 0.01)) # for e in cleanededges: # print str(e.valueAt(e.FirstParameter)) + "," + # str(e.valueAt(e.LastParameter)) edgelist = [] if len(cleanededges) == 1: # user selected a single edge. edgelist = cleanededges else: # edgelist = [] #Multiple edges. Need to sequence the vetexes. # First get the first segment oriented correctly. # We first compare the last parameter of the first segment to see if it # matches either end of the second segment. If not, it must need # flipping. if cleanededges[0].valueAt(cleanededges[0].LastParameter) in [cleanededges[1].valueAt(cleanededges[1].FirstParameter), cleanededges[1].valueAt(cleanededges[1].LastParameter)]: edge0 = cleanededges[0] else: edge0 = PathUtils.reverseEdge(cleanededges[0]) edgelist.append(edge0) # Now iterate the rest of the edges matching the last parameter of the # previous segment. for edge in cleanededges[1:]: if edge.valueAt(edge.FirstParameter) == edgelist[-1].valueAt(edgelist[-1].LastParameter): nextedge = edge else: nextedge = PathUtils.reverseEdge(edge) edgelist.append(nextedge) # print "makeareacurve 87: " + "area.Point(" + # str(edgelist[0].Vertexes[0].X) + ", " + # str(edgelist[0].Vertexes[0].Y)+")" curveobj.append(area.Point(edgelist[0].Vertexes[ 0].X, edgelist[0].Vertexes[0].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 curveobj.IsClockwise() and direction == 'CCW': curveobj.Reverse() elif not curveobj.IsClockwise() and direction == 'CW': curveobj.Reverse() return curveobj
def getWire(self): return (Part.Wire(Part.__sortEdges__(self.getEdges())))
def getIndices(shape, offset): "returns a list with 2 lists: vertices and face indexes, offsetted with the given amount" vlist = [] elist = [] flist = [] curves = None for e in shape.Edges: try: if not isinstance(e.Curve, Part.Line): if not curves: curves = shape.tessellate(1) FreeCAD.Console.PrintWarning( translate( "Arch", "Found a shape containing curves, triangulating\n") ) break except: # unimplemented curve type curves = shape.tessellate(1) FreeCAD.Console.PrintWarning( translate("Arch", "Found a shape containing curves, triangulating\n")) break if curves: for v in curves[0]: vlist.append(" " + str(round(v.x, p)) + " " + str(round(v.y, p)) + " " + str(round(v.z, p))) for f in curves[1]: fi = "" for vi in f: fi += " " + str(vi + offset) flist.append(fi) else: for v in shape.Vertexes: vlist.append(" " + str(round(v.X, p)) + " " + str(round(v.Y, p)) + " " + str(round(v.Z, p))) if not shape.Faces: for e in shape.Edges: if DraftGeomUtils.geomType(e) == "Line": ei = " " + str( findVert(e.Vertexes[0], shape.Vertexes) + offset) ei += " " + str( findVert(e.Vertexes[-1], shape.Vertexes) + offset) elist.append(ei) for f in shape.Faces: if len(f.Wires) > 1: # if we have holes, we triangulate tris = f.tessellate(1) for fdata in tris[1]: fi = "" for vi in fdata: vdata = Part.Vertex(tris[0][vi]) fi += " " + str( findVert(vdata, shape.Vertexes) + offset) flist.append(fi) else: fi = "" # OCC vertices are unsorted. We need to sort in the right order... edges = Part.__sortEdges__(f.OuterWire.Edges) #print edges for e in edges: #print e.Vertexes[0].Point,e.Vertexes[1].Point v = e.Vertexes[0] ind = findVert(v, shape.Vertexes) if ind == None: return None, None, None fi += " " + str(ind + offset) flist.append(fi) return vlist, elist, flist
def execute(self, obj): import Part # math #DraftGeomUtils output = "" toolLoad = PathUtils.getLastToolLoad(obj) # obj.ToolController = PathUtils.getToolControllers(obj) # toolLoad = PathUtils.getToolLoad(obj, obj.ToolController) if toolLoad is None or toolLoad.ToolNumber == 0: self.vertFeed = 100 self.horizFeed = 100 self.vertRapid = 100 self.horizRapid = 100 self.radius = 0.25 obj.ToolNumber = 0 obj.ToolDescription = "UNDEFINED" else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = PathUtils.getTool(obj, toolLoad.ToolNumber) if tool.Diameter == 0: self.radius = 0.25 else: self.radius = tool.Diameter/2 obj.ToolNumber = toolLoad.ToolNumber obj.ToolDescription = toolLoad.Name if obj.UserLabel == "": obj.Label = obj.Name + " :" + obj.ToolDescription else: obj.Label = obj.UserLabel + " :" + obj.ToolDescription output += "(" + obj.Label + ")" if obj.Side != "On": output += "(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")" else: output += "(Uncompensated Tool Path)" if obj.Base: # hfaces = [] # vfaces = [] wires = [] for b in obj.Base: edgelist = [] for sub in b[1]: edgelist.append(getattr(b[0].Shape, sub)) wires.extend(findWires(edgelist)) for wire in wires: edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) output += self._buildPathLibarea(obj, edgelist) if obj.Active: path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False
def getExtrusionData(self,obj): """returns (shape,extrusion vector,placement) or None""" import Part,DraftGeomUtils data = ArchComponent.Component.getExtrusionData(self,obj) if data: if not isinstance(data[0],list): # multifuses not considered here return data length = obj.Length.Value width = obj.Width.Value height = obj.Height.Value if not height: for p in obj.InList: if Draft.getType(p) == "Floor": if p.Height.Value: height = p.Height.Value if obj.Normal == Vector(0,0,0): normal = Vector(0,0,1) else: normal = Vector(obj.Normal) base = None placement = None basewires = None if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape: if obj.Base.Shape.Solids: return None elif obj.Face > 0: if len(obj.Base.Shape.Faces) >= obj.Face: face = obj.Base.Shape.Faces[obj.Face-1] # this wall is based on a specific face of its base object normal = face.normalAt(0,0) if normal.getAngle(Vector(0,0,1)) > math.pi/4: normal.multiply(width) base = face.extrude(normal) if obj.Align == "Center": base.translate(normal.negative().multiply(0.5)) elif obj.Align == "Right": base.translate(normal.negative()) else: normal.multiply(height) base = face.extrude(normal) base,placement = self.rebase(base) return (base,normal,placement) elif obj.Base.Shape.Faces: if not DraftGeomUtils.isCoplanar(obj.Base.Shape.Faces): return None else: base,placement = self.rebase(obj.Base.Shape) elif obj.Base.Shape.Wires: basewires = obj.Base.Shape.Wires elif len(obj.Base.Shape.Edges) == 1: basewires = [Part.Wire(obj.Base.Shape.Edges)] if basewires and width: baseface = None for wire in basewires: e = wire.Edges[0] if isinstance(e.Curve,Part.Circle): dvec = e.Vertexes[0].Point.sub(e.Curve.Center) else: dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal) if not DraftVecUtils.isNull(dvec): dvec.normalize() sh = None if obj.Align == "Left": dvec.multiply(width) if obj.Offset.Value: dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset.Value) wire = DraftGeomUtils.offsetWire(wire,dvec2) w2 = DraftGeomUtils.offsetWire(wire,dvec) w1 = Part.Wire(Part.__sortEdges__(wire.Edges)) sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Right": dvec.multiply(width) dvec = dvec.negative() if obj.Offset.Value: dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset.Value) wire = DraftGeomUtils.offsetWire(wire,dvec2) w2 = DraftGeomUtils.offsetWire(wire,dvec) w1 = Part.Wire(Part.__sortEdges__(wire.Edges)) sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Center": dvec.multiply(width/2) w1 = DraftGeomUtils.offsetWire(wire,dvec) dvec = dvec.negative() w2 = DraftGeomUtils.offsetWire(wire,dvec) sh = DraftGeomUtils.bind(w1,w2) if sh: sh.fix(0.1,0,1) # fixes self-intersecting wires f = Part.Face(sh) if baseface: baseface = baseface.fuse(f) else: baseface = f if baseface: base,placement = self.rebase(baseface) else: l2 = length/2 or 0.5 w2 = width/2 or 0.5 v1 = Vector(-l2,-w2,0) v2 = Vector(l2,-w2,0) v3 = Vector(l2,w2,0) v4 = Vector(-l2,w2,0) base = Part.Face(Part.makePolygon([v1,v2,v3,v4,v1])) placement = FreeCAD.Placement() if base and placement: extrusion = normal.multiply(height) return (base,extrusion,placement) return None
def execute(self, obj): if self.clone(obj): return pl = obj.Placement #self.baseface = None self.flip = False if hasattr(obj, "Flip"): if obj.Flip: self.flip = True base = None baseWire = None if obj.Base: if hasattr(obj.Base, "Shape"): if obj.Base.Shape.Solids: base = obj.Base.Shape #pl = obj.Base.Placement else: if (obj.Base.Shape.Faces and obj.Face): baseWire = obj.Base.Shape.Faces[obj.Face - 1].Wires[0] elif obj.Base.Shape.Wires: baseWire = obj.Base.Shape.Wires[0] if baseWire: if baseWire.isClosed(): self.profilsDico = [] self.shps = [] self.subVolShps = [] heights = [] edges = Part.__sortEdges__(baseWire.Edges) if self.flip: edges = self.flipEdges(edges) ln = len(edges) obj.Angles = adjust_list_len(obj.Angles, ln, obj.Angles[0]) obj.Runs = adjust_list_len(obj.Runs, ln, obj.Runs[0]) obj.IdRel = adjust_list_len(obj.IdRel, ln, obj.IdRel[0]) obj.Thickness = adjust_list_len(obj.Thickness, ln, obj.Thickness[0]) obj.Overhang = adjust_list_len(obj.Overhang, ln, obj.Overhang[0]) for i in range(ln): self.makeRoofProfilsDic(i, obj.Angles[i], obj.Runs[i], obj.IdRel[i], obj.Overhang[i], obj.Thickness[i]) for i in range(ln): self.calcEdgeGeometry(i, edges[i]) for i in range(ln): self.calcApex( i, ln) # after calcEdgeGeometry as it uses vec data for i in range(ln): self.calcMissingData( i, ln ) # after calcApex so it can use recalculated heights for i in range(ln): self.calcDraftEdges(i) for i in range(ln): self.calcEave(i) for profil in self.profilsDico: heights.append(profil["height"]) obj.Heights = heights for i in range(ln): self.getRoofPaneProject(i) profilCurr = self.profilsDico[i] ptsPaneProject = profilCurr["points"] if len(ptsPaneProject) == 0: continue face = face_from_points(ptsPaneProject) if face: diag = face.BoundBox.DiagonalLength midpoint = DraftGeomUtils.findMidpoint( profilCurr["edge"]) thicknessV = profilCurr["thickness"] / (math.cos( math.radians(profilCurr["angle"]))) overhangV = profilCurr["overhang"] * math.tan( math.radians(profilCurr["angle"])) sol = face.extrude( Vector(0.0, 0.0, profilCurr["height"] + 1000000.0)) sol.translate(Vector(0.0, 0.0, -2.0 * overhangV)) ## baseVolume shape ptsPaneProfil = [ Vector(-profilCurr["overhang"], -overhangV, 0.0), Vector(profilCurr["run"], profilCurr["height"], 0.0), Vector(profilCurr["run"], profilCurr["height"] + thicknessV, 0.0), Vector(-profilCurr["overhang"], -overhangV + thicknessV, 0.0) ] self.shps.append( self.createProfilShape(ptsPaneProfil, midpoint, profilCurr["rot"], profilCurr["vec"], profilCurr["run"], diag, sol)) ## subVolume shape ptsSubVolProfil = [ Vector(-profilCurr["overhang"], -overhangV, 0.0), Vector(profilCurr["run"], profilCurr["height"], 0.0), Vector(profilCurr["run"], profilCurr["height"] + 900000.0, 0.0), Vector(-profilCurr["overhang"], profilCurr["height"] + 900000.0, 0.0) ] self.subVolShps.append( self.createProfilShape(ptsSubVolProfil, midpoint, profilCurr["rot"], profilCurr["vec"], profilCurr["run"], diag, sol)) if len( self.shps ) == 0: # occurs if all segments have angle=90 or run=0. # create a flat roof using the eavePtLst outline: ptsPaneProject = [] for i in range(ln): ptsPaneProject.append( self.profilsDico[i]["eavePtLst"][0]) face = face_from_points(ptsPaneProject) if face: thk = max( 1.0, self.profilsDico[0]["thickness"] ) # FreeCAD will crash when extruding with a null vector here self.shps = [face.extrude(Vector(0.0, 0.0, thk))] self.subVolShps = [ face.extrude(Vector(0.0, 0.0, 1000000.0)) ] ## baseVolume base = self.shps.pop() for s in self.shps: base = base.fuse(s) base = self.processSubShapes(obj, base, pl) self.applyShape(obj, base, pl, allownosolid=True) ## 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 elif base: base = self.processSubShapes(obj, base, pl) self.applyShape(obj, base, pl, allownosolid=True) else: FreeCAD.Console.PrintMessage( translate("Arch", "Unable to create a roof"))
def offsetOpenWire(wx, dist, sym, normal): """Offsets an open wire returning a face""" resultFace = None try: if sym: logging.debug('open wire sym...') if isWireSingleArcOrCircle(wx): logging.debug('...Wire is a single arc') ex = wx.Edges[0] #construct outside offset of arc as an edge, and list of edges c1 = Part.Circle() c1.Center = ex.centerOfCurvatureAt(ex.FirstParameter) c1.Axis = ex.Curve.Axis c1.Radius = ex.Curve.Radius + dist.Value / 2 ax1 = Part.Arc(c1, ex.FirstParameter, ex.LastParameter) baseEdge = ax1.toShape() base = Part.Wire([baseEdge]) #construct inside offset of arc c2 = Part.Circle() c2.Center = ex.centerOfCurvatureAt(ex.FirstParameter) c2.Axis = ex.Curve.Axis c2.Radius = ex.Curve.Radius - dist.Value / 2 ax2 = Part.Arc(c2, ex.FirstParameter, ex.LastParameter) offEdge = ax2.toShape() offset = Part.Wire([offEdge]) #get the connector points p1 = baseEdge.firstVertex().Point p2 = baseEdge.lastVertex().Point p3 = offEdge.lastVertex().Point p4 = offEdge.firstVertex().Point else: base = wx.makeOffset2D(-dist / 2, fill=False, openResult=True, intersection=True, join=2) offset = wx.makeOffset2D(dist / 2, fill=False, openResult=True, intersection=True, join=2) logging.debug('getting sorting baseEdges...') baseEdges = Part.__sortEdges__(base.Edges) logging.debug('getting sorting offset edges...') offEdges = Part.__sortEdges__(offset.Edges) p1 = baseEdges[0].Vertexes[0].Point p2 = baseEdges[len(baseEdges) - 1].Vertexes[1].Point p3 = offEdges[len(offEdges) - 1].Vertexes[1].Point p4 = offEdges[0].Vertexes[0].Point else: logging.debug('...open wire non-sym') if isWireSingleArcOrCircle(wx): logging.debug('...Wire is a single arc') ex = wx.Edges[0] base = wx c2 = Part.Circle() c2.Center = ex.centerOfCurvatureAt(0.0) c2.Axis = ex.Curve.Axis c2.Radius = ex.Curve.Radius + dist.Value ax = Part.Arc(c2, ex.FirstParameter, ex.LastParameter) offEdge = ax.toShape() offset = Part.Wire([offEdge]) p1 = ex.firstVertex().Point p2 = ex.lastVertex().Point p3 = offEdge.lastVertex().Point p4 = offEdge.firstVertex().Point else: resultFace = wx.makeOffset2D(dist, fill=True, openResult=True, intersection=True, join=2) #in the case of a straight line wire, makeOffset2D will fail. In that case construct the shape except: traceback.print_exc() logging.debug('-->exception caught') wireEdges = Part.__sortEdges__(wx.Edges) p1 = wireEdges[0].Vertexes[0].Point p2 = wireEdges[len(wireEdges) - 1].Vertexes[1].Point vWire = p2 - p1 vWire.normalize() offdir = normal.cross(vWire) offdir.multiply(dist) if sym: p1 = p1 - offdir * 0.5 p2 = p2 - offdir * 0.5 p4 = p1 + offdir p3 = p2 + offdir base = Part.makeLine(p1, p2) offset = Part.makeLine(p3, p4) if resultFace is None: logging.debug('building face...') end1 = Part.makeLine(p2, p3) end2 = Part.makeLine(p4, p1) bndyEdges = base.Edges + [end1] + offset.Edges + [end2] bndyEdges = Part.__sortEdges__(bndyEdges) faceWire = Part.Wire(bndyEdges) resultFace = Part.Face(faceWire) return resultFace
def makeRoof(baseobj=None,facenr=0, angles=[45.,], run = [], idrel = [0,],thickness = [50.,], overhang=[100.,], name="Roof"): '''makeRoof(baseobj,[facenr],[angle],[name]) : Makes a roof based on a closed wire or an object. You can provide a list of angles, run, idrel, thickness, overhang for each edges in the wire to define the roof shape. The default for angle is 45 and the list is automatically complete to match with number of edges in the wire. If the base object is a solid the roof take the shape.''' import Part obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name) obj.Label = translate("Arch",name) w = None _Roof(obj) if FreeCAD.GuiUp: _ViewProviderRoof(obj.ViewObject) if baseobj: obj.Base = baseobj if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.Solids: if FreeCAD.GuiUp: obj.Base.ViewObject.hide() else: if (obj.Base.Shape.Faces and obj.Face): w = obj.Base.Shape.Faces[obj.Face-1].Wires[0] if FreeCAD.GuiUp: obj.Base.ViewObject.hide() elif obj.Base.Shape.Wires: w = obj.Base.Shape.Wires[0] if FreeCAD.GuiUp: obj.Base.ViewObject.hide() if w: if w.isClosed(): if FreeCAD.GuiUp: obj.Base.ViewObject.hide() edges = Part.__sortEdges__(w.Edges) l = len(edges) la = len(angles) alist = angles for i in range(l-la): alist.append(angles[0]) obj.Angles=alist lr = len(run) rlist = run for i in range(l-lr): #rlist.append(w.Edges[i].Length/2.) rlist.append(250.) obj.Runs = rlist lidrel = len(idrel) rellist = idrel for i in range(l-lidrel): rellist.append(0) obj.IdRel = rellist lthick = len(thickness) tlist = thickness for i in range(l-lthick): tlist.append(thickness[0]) obj.Thickness = tlist lover = len(overhang) olist = overhang for i in range(l-lover): olist.append(overhang[0]) obj.Overhang = olist obj.Face = facenr return obj
centre = FreeCAD.Vector(0, 0, 0) pos = obj.Placement.Base newplace = FreeCAD.Placement(pos, rot, centre) obj.Placement = newplace App.getDocument('TOBERA').recompute() ##################### CARAS ENTRADA y SALIDA ############ Part.Face( Part.Wire(Part.__sortEdges__([ App.ActiveDocument.TOBERA.Shape.Edge1, ]))) App.ActiveDocument.addObject('Part::Feature', 'SALIDA').Shape = _ ###################### MALLADO ##################### __doc__ = FreeCAD.getDocument("TOBERA") __mesh__ = __doc__.addObject("Mesh::Feature", "tobera_mesh") __mesh__.Mesh = MeshPart.meshFromShape(Shape=__doc__.getObject("TOBERA").Shape, MaxLength=m_tobera) __mesh__.Label = "tobera_mesh"
def execute(self, obj): import Part # math #DraftGeomUtils output = "" toolLoad = PathUtils.getLastToolLoad(obj) if toolLoad is None or toolLoad.ToolNumber == 0: self.vertFeed = 100 self.horizFeed = 100 self.radius = 0.25 obj.ToolNumber = 0 obj.ToolDescription = "UNDEFINED" else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value tool = PathUtils.getTool(obj, toolLoad.ToolNumber) if tool.Diameter == 0: self.radius = 0.25 else: self.radius = tool.Diameter/2 obj.ToolNumber = toolLoad.ToolNumber obj.ToolDescription = toolLoad.Name if obj.UserLabel == "": obj.Label = obj.Name + " (" + obj.ToolDescription + ")" else: obj.Label = obj.UserLabel + " (" + obj.ToolDescription + ")" if obj.Base: hfaces = [] vfaces = [] wires = [] for b in obj.Base: for sub in b[1]: # we only consider the outer wire if this is a Face # Horizontal and vertical faces are handled differently shape = getattr(b[0].Shape, sub) if numpy.isclose(shape.normalAt(0, 0).z, 1): # horizontal face hfaces.append(shape) elif numpy.isclose(shape.normalAt(0, 0).z, 0): # vertical face vfaces.append(shape) else: FreeCAD.Console.PrintError(translate("Path", "Face doesn't appear to be parallel or perpendicular to the XY plane. No path will be generated for: \n")) FreeCAD.Console.PrintError(b[0].Name + "." + sub + "\n") for h in hfaces: wires.append(h.OuterWire) tempshell = Part.makeShell(vfaces) slices = tempshell.slice(FreeCAD.Base.Vector(0, 0, 1), tempshell.CenterOfMass.z ) wires = wires + slices for wire in wires: if obj.Algorithm == "OCC Native": output += self._buildPathOCC(obj, wire) else: try: import area except: FreeCAD.Console.PrintError(translate("Path", "libarea needs to be installed for this command to work.\n")) return edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) output += self._buildPathLibarea(obj, edgelist) if obj.Active: path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False
def Myarray2NurbsD3(arr,label="MyWall",degree=3): pstb=np.array(arr).swapaxes(0,1) pst2=np.concatenate([pstb[7:-1],pstb[1:7]]) psta=pst2.swapaxes(1,0) # ptsa=np.array(arr) try: NbVPoles,NbUPoles,_t1 =psta.shape except: return (Part.Shape(),Part.Shape()) # bs=Part.BSplineSurface() # bs.interpolate(psta) pst=psta FreeCAD.shoe_pst=pst # bs.setVPeriodic() pst[:,:,1] *= -1 psta=pst # die flaeche bs=createBS(pst) # try: fa=App.ActiveDocument.curveA # except: fa=App.ActiveDocument.addObject('Part::Spline','curveA') # # fa.Shape=bs.toShape() color=(random.random(),random.random(),random.random()) #- kann qwg # for i,pps in enumerate(psta): # if i == 0 : continue # bc=Part.BSplineCurve() # bc.interpolate(pps) # App.ActiveDocument.Ribs.OutList[i].Shape=bc.toShape() # App.ActiveDocument.Ribs.OutList[i].ViewObject.LineColor=color # # for i,pps in enumerate(psta.swapaxes(0,1)): # bc=Part.BSplineCurve() # bc.interpolate(pps[2:]) # App.ActiveDocument.Meridians.OutList[i].Shape=bc.toShape() # App.ActiveDocument.Meridians.OutList[i].ViewObject.LineColor=color if 1: sf2=bs.copy() sf2.setVPeriodic() uks=sf2.getUKnots() sf2.segment(uks[1],1,0,1) sh2=sf2.toShape() uks=bs.getUKnots() bs.segment(uks[1],1,0,1) sh=bs.toShape() vcp=False try: sp=App.ActiveDocument.Poles vcp=sp.ViewObject.ControlPoints except: sp=App.ActiveDocument.addObject("Part::Spline","Poles") sp.Shape=sh2 sp.ViewObject.ControlPoints=vcp #sp.ViewObject.hide() try: fa=bs.uIso(0) sha1 = Part.Wire(fa.toShape()) sha = Part.Face(sha1) fb=bs.uIso(1) shb1 = Part.Wire(fb.toShape()) shb = Part.Face(shb1) sol=Part.Solid(Part.Shell([sha.Face1,shb.Face1,sh.Face1])) except: try: sha=Part.makeFilledFace(Part.__sortEdges__([App.ActiveDocument.Poles.Shape.Edge3, ])) shb=Part.makeFilledFace(Part.__sortEdges__([App.ActiveDocument.Poles.Shape.Edge1, ])) sol=Part.Solid(Part.Shell([sha.Face1,shb.Face1,sh.Face1])) except: sol=sh return (sol,bs)