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): #print("TimberMachiningCut Start Execute") face = obj.Face faceObject = face[0] faceNumber = int(face[1][0][4:]) - 1 face = faceObject.Shape.Faces[faceNumber] structure = obj.Structure cutVolume = ArchCommands.getCutVolume(face, structure.Shape) machining = cutVolume[2].common(beam.Shape) obj.Shape = machining
def previewCutVolume(self, i): cutVolume = ArchCommands.getCutVolume(FreeCADGui.Selection.getSelectionEx()[1].SubObjects[0], FreeCADGui.Selection.getSelectionEx()[0].Object.Shape) FreeCAD.ActiveDocument.removeObject(self.previewObj.Name) self.previewObj = FreeCAD.ActiveDocument.addObject("Part::Feature", "PreviewCutVolume") self.previewObj.ViewObject.ShapeColor = (1.00,0.00,0.00) self.previewObj.ViewObject.Transparency = 75 if i == 1: cutVolume = cutVolume[1] else: cutVolume = cutVolume[2] if cutVolume: self.previewObj.Shape = cutVolume
def cutComponentwithPlane(archObject, cutPlane, sideFace): """cut object from a plan define by a face, Behind = 0 , front = 1""" cutVolume = ArchCommands.getCutVolume(cutPlane, archObject.Object.Shape) if sideFace == 0: cutVolume = cutVolume[2] else: cutVolume = cutVolume[1] if cutVolume: obj = FreeCAD.ActiveDocument.addObject("Part::Feature", "CutVolume") obj.Shape = cutVolume # add substraction component to Arch object return ArchCommands.removeComponents(obj,archObject.Object)
def getArea(self,obj): "returns the horizontal area at the center of the space" import Part,DraftGeomUtils try: pl = Part.makePlane(1,1) sh = obj.Shape.copy() cutplane,v1,v2 = ArchCommands.getCutVolume(pl,sh) e = sh.section(cutplane) e = DraftGeomUtils.sortEdges(e.Edges) w = Part.Wire(e) f = Part.Face(w) return round(f.Area,Draft.getParam("dimPrecision",6)) except: return 0
def getArea(self,obj): "returns the horizontal area at the center of the space" import Part,DraftGeomUtils 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 = DraftGeomUtils.sortEdges(e.Edges) w = Part.Wire(e) f = Part.Face(w) return f.Area except: return 0
def cutComponentwithPlane(archObject, cutPlane, sideFace): """cut object from a plan define by a face, Behind = 0 , front = 1""" cutVolume = ArchCommands.getCutVolume(cutPlane, archObject.Object.Shape) if sideFace == 0: cutVolume = cutVolume[2] else: cutVolume = cutVolume[1] if cutVolume: obj = FreeCAD.ActiveDocument.addObject("Part::Feature", "CutVolume") obj.Shape = cutVolume obj.ViewObject.ShapeColor = (1.00, 0.00, 0.00) obj.ViewObject.Transparency = 75 if "Additions" in archObject.Object.PropertiesList: return ArchCommands.removeComponents(obj, archObject.Object) else: cutObj = FreeCAD.ActiveDocument.addObject("Part::Cut", "CutPlane") cutObj.Base = archObject.Object cutObj.Tool = obj return cutObj
def getCutShapes(objs, section, showHidden): import Part, DraftGeomUtils shapes = [] hshapes = [] sshapes = [] for o in objs: if o.isDerivedFrom("Part::Feature"): if o.Shape.isNull(): pass elif section.OnlySolids: if o.Shape.isValid(): shapes.extend(o.Shape.Solids) else: print section.Label, ": Skipping invalid object:", o.Label else: shapes.append(o.Shape) cutface, cutvolume, invcutvolume = ArchCommands.getCutVolume( section.Shape.copy(), shapes) if cutvolume: nsh = [] for sh in shapes: for sol in sh.Solids: if sol.Volume < 0: sol.reverse() c = sol.cut(cutvolume) s = sol.section(cutface) try: wires = DraftGeomUtils.findWires(s.Edges) for w in wires: f = Part.Face(w) sshapes.append(f) #s = Part.Wire(s.Edges) #s = Part.Face(s) except Part.OCCError: #print "ArchDrawingView: unable to get a face" sshapes.append(s) nsh.extend(c.Solids) #sshapes.append(s) if showHidden: c = sol.cut(invcutvolume) hshapes.append(c) shapes = nsh return shapes, hshapes, sshapes, cutface, cutvolume, invcutvolume
def cut(self, cutplane, hidden=False): "Cuts through the shapes with a given cut plane and builds section faces" if DEBUG: print("\n\n======> Starting cut\n\n") if self.iscut: return if not self.shapes: if DEBUG: print("No objects to make sections") else: fill = (1.0, 1.0, 1.0, 1.0) shps = [] for sh in self.shapes: shps.append(sh[0]) cutface, cutvolume, invcutvolume = ArchCommands.getCutVolume( cutplane, shps) if cutface and cutvolume: shapes = [] faces = [] sections = [] for sh in self.shapes: for sol in sh[0].Solids: c = sol.cut(cutvolume) shapes.append([c] + sh[1:]) for f in c.Faces: faces.append([f] + sh[1:]) #print("iscoplanar:",f.Vertexes[0].Point,f.normalAt(0,0),cutface.Vertexes[0].Point,cutface.normalAt(0,0)) if DraftGeomUtils.isCoplanar([f, cutface]): print("COPLANAR") sections.append([f, fill]) if hidden: c = sol.cut(invcutvolume) self.hiddenEdges.extend(c.Edges) self.shapes = shapes self.faces = faces self.sections = sections if DEBUG: print("Built ", len(self.sections), " sections, ", len(self.faces), " faces retained") self.iscut = True self.oriented = False self.trimmed = False self.sorted = False self.joined = False if DEBUG: print("\n\n======> Finished cut\n\n")
def cutComponentwithPlane(archObject, cutPlane, sideFace): """cut object from a plan define by a face, Behind = 0 , front = 1""" cutVolume = ArchCommands.getCutVolume(cutPlane, archObject.Object.Shape) if sideFace == 0: cutVolume = cutVolume[2] else: cutVolume = cutVolume[1] if cutVolume: obj = FreeCAD.ActiveDocument.addObject("Part::Feature", str(translate("Arch","CutVolume"))) obj.Shape = cutVolume obj.ViewObject.ShapeColor = (1.00,0.00,0.00) obj.ViewObject.Transparency = 75 if "Additions" in archObject.Object.PropertiesList: return ArchCommands.removeComponents(obj,archObject.Object) else: cutObj = FreeCAD.ActiveDocument.addObject("Part::Cut", str(translate("Arch","CutPlane"))) cutObj.Base = archObject.Object cutObj.Tool = obj return cutObj
def getCutShapes(objs,section,showHidden): import Part,DraftGeomUtils shapes = [] hshapes = [] sshapes = [] for o in objs: if o.isDerivedFrom("Part::Feature"): if o.Shape.isNull(): pass elif section.OnlySolids: if o.Shape.isValid(): shapes.extend(o.Shape.Solids) else: print(section.Label,": Skipping invalid object:",o.Label) else: shapes.append(o.Shape) cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(section.Shape.copy(),shapes) if cutvolume: nsh = [] for sh in shapes: for sol in sh.Solids: if sol.Volume < 0: sol.reverse() c = sol.cut(cutvolume) s = sol.section(cutface) try: wires = DraftGeomUtils.findWires(s.Edges) for w in wires: f = Part.Face(w) sshapes.append(f) #s = Part.Wire(s.Edges) #s = Part.Face(s) except Part.OCCError: #print "ArchDrawingView: unable to get a face" sshapes.append(s) nsh.extend(c.Solids) #sshapes.append(s) if showHidden: c = sol.cut(invcutvolume) hshapes.append(c) shapes = nsh return shapes,hshapes,sshapes,cutface,cutvolume,invcutvolume
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 cut(self,cutplane,hidden=False): "Cuts through the shapes with a given cut plane and builds section faces" if DEBUG: print "\n\n======> Starting cut\n\n" if self.iscut: return if not self.shapes: if DEBUG: print "No objects to make sections" else: fill = (1.0,1.0,1.0,1.0) shps = [] for sh in self.shapes: shps.append(sh[0]) cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(cutplane,shps) if cutface and cutvolume: shapes = [] faces = [] sections = [] for sh in self.shapes: for sol in sh[0].Solids: c = sol.cut(cutvolume) shapes.append([c]+sh[1:]) for f in c.Faces: faces.append([f]+sh[1:]) print "iscoplanar:",f.Vertexes[0].Point,f.normalAt(0,0),cutface.Vertexes[0].Point,cutface.normalAt(0,0) if DraftGeomUtils.isCoplanar([f,cutface]): print "COPLANAR" sections.append([f,fill]) if hidden: c = sol.cut(invcutvolume) self.hiddenEdges.extend(c.Edges) self.shapes = shapes self.faces = faces self.sections = sections if DEBUG: print "Built ",len(self.sections)," sections, ", len(self.faces), " faces retained" self.iscut = True self.oriented = False self.trimmed = False self.sorted = False self.joined = False if DEBUG: print "\n\n======> Finished cut\n\n"
def execute(self, obj): tol = 1 # tolerance for alignment. This is only visual, we can keep it low... ptol = 0.001 # tolerance for coincident points import math, Part, DraftGeomUtils, ArchCommands if len(obj.Pipes) < 2: return if len(obj.Pipes) > 3: FreeCAD.Console.PrintWarning( translate("Arch", "Only the 3 first wires will be connected") + "\n") if obj.Radius.Value == 0: return wires = [] order = [] for o in obj.Pipes: wires.append(o.Proxy.getWire(o)) if wires[0].Vertexes[0].Point.sub( wires[1].Vertexes[0].Point).Length <= ptol: order = ["start", "start"] point = wires[0].Vertexes[0].Point elif wires[0].Vertexes[0].Point.sub( wires[1].Vertexes[-1].Point).Length <= ptol: order = ["start", "end"] point = wires[0].Vertexes[0].Point elif wires[0].Vertexes[-1].Point.sub( wires[1].Vertexes[-1].Point).Length <= ptol: order = ["end", "end"] point = wires[0].Vertexes[-1].Point elif wires[0].Vertexes[-1].Point.sub( wires[1].Vertexes[0].Point).Length <= ptol: order = ["end", "start"] point = wires[0].Vertexes[-1].Point else: FreeCAD.Console.PrintError( translate("Arch", "Common vertex not found") + "\n") return if order[0] == "start": v1 = wires[0].Vertexes[1].Point.sub( wires[0].Vertexes[0].Point).normalize() else: v1 = wires[0].Vertexes[-2].Point.sub( wires[0].Vertexes[-1].Point).normalize() if order[1] == "start": v2 = wires[1].Vertexes[1].Point.sub( wires[1].Vertexes[0].Point).normalize() else: v2 = wires[1].Vertexes[-2].Point.sub( wires[1].Vertexes[-1].Point).normalize() p = obj.Pipes[0].Proxy.getProfile(obj.Pipes[0]) p = Part.Face(p) if len(obj.Pipes) == 2: if obj.ConnectorType != "Corner": obj.ConnectorType = "Corner" if round(v1.getAngle(v2), tol) in [0, round(math.pi, tol)]: FreeCAD.Console.PrintError( translate("Arch", "Pipes are already aligned") + "\n") return normal = v2.cross(v1) offset = math.tan(math.pi / 2 - v1.getAngle(v2) / 2) * obj.Radius.Value v1.multiply(offset) v2.multiply(offset) self.setOffset(obj.Pipes[0], order[0], offset) self.setOffset(obj.Pipes[1], order[1], offset) # find center perp = v1.cross(normal).normalize() perp.multiply(obj.Radius.Value) center = point.add(v1).add(perp) # move and rotate the profile to the first point delta = point.add(v1) - p.CenterOfMass p.translate(delta) vp = DraftGeomUtils.getNormal(p) rot = FreeCAD.Rotation(vp, v1) p.rotate(p.CenterOfMass, rot.Axis, math.degrees(rot.Angle)) sh = p.revolve(center, normal, math.degrees(math.pi - v1.getAngle(v2))) #sh = Part.makeCompound([sh]+[Part.Vertex(point),Part.Vertex(point.add(v1)),Part.Vertex(center),Part.Vertex(point.add(v2))]) else: if obj.ConnectorType != "Tee": obj.ConnectorType = "Tee" if wires[2].Vertexes[0].Point == point: order.append("start") elif wires[0].Vertexes[-1].Point == point: order.append("end") else: FreeCAD.Console.PrintError( translate("Arch", "Common vertex not found") + "\n") if order[2] == "start": v3 = wires[2].Vertexes[1].Point.sub( wires[2].Vertexes[0].Point).normalize() else: v3 = wires[2].Vertexes[-2].Point.sub( wires[2].Vertexes[-1].Point).normalize() if round(v1.getAngle(v2), tol) in [0, round(math.pi, tol)]: pair = [v1, v2, v3] elif round(v1.getAngle(v3), tol) in [0, round(math.pi, tol)]: pair = [v1, v3, v2] elif round(v2.getAngle(v3), tol) in [0, round(math.pi, tol)]: pair = [v2, v3, v1] else: FreeCAD.Console.PrintError( translate("Arch", "At least 2 pipes must align") + "\n") return offset = obj.Radius.Value v1.multiply(offset) v2.multiply(offset) v3.multiply(offset) self.setOffset(obj.Pipes[0], order[0], offset) self.setOffset(obj.Pipes[1], order[1], offset) self.setOffset(obj.Pipes[2], order[2], offset) normal = pair[0].cross(pair[2]) # move and rotate the profile to the first point delta = point.add(pair[0]) - p.CenterOfMass p.translate(delta) vp = DraftGeomUtils.getNormal(p) rot = FreeCAD.Rotation(vp, pair[0]) p.rotate(p.CenterOfMass, rot.Axis, math.degrees(rot.Angle)) t1 = p.extrude(pair[1].multiply(2)) # move and rotate the profile to the second point delta = point.add(pair[2]) - p.CenterOfMass p.translate(delta) vp = DraftGeomUtils.getNormal(p) rot = FreeCAD.Rotation(vp, pair[2]) p.rotate(p.CenterOfMass, rot.Axis, math.degrees(rot.Angle)) t2 = p.extrude(pair[2].negative().multiply(2)) # create a cut plane cp = Part.makePolygon( [point, point.add(pair[0]), point.add(normal), point]) cp = Part.Face(cp) if cp.normalAt(0, 0).getAngle(pair[2]) < math.pi / 2: cp.reverse() cf, cv, invcv = ArchCommands.getCutVolume(cp, t2) t2 = t2.cut(cv) sh = t1.fuse(t2) obj.Shape = sh
def updateSVG(self, obj,join=False): "encapsulates a svg fragment into a transformation node" import Part, DraftGeomUtils if hasattr(obj,"Source"): if obj.Source: if obj.Source.Objects: objs = Draft.getGroupContents(obj.Source.Objects) objs = Draft.removeHidden(objs) svg = '' # generating SVG linewidth = obj.LineWidth/obj.Scale if obj.RenderingMode == "Solid": # render using the Arch Vector Renderer import ArchVRM render = ArchVRM.Renderer() render.setWorkingPlane(obj.Source.Placement) render.addObjects(Draft.getGroupContents(objs,walls=True)) render.cut(obj.Source.Shape) svg += render.getViewSVG(linewidth=linewidth) svg += render.getSectionSVG(linewidth=linewidth*2) # print render.info() else: # render using the Drawing module import Drawing, Part shapes = [] p = FreeCAD.Placement(obj.Source.Placement) direction = p.Rotation.multVec(FreeCAD.Vector(0,0,1)) for o in objs: if o.isDerivedFrom("Part::Feature"): shapes.extend(o.Shape.Solids) cutface,cutvolume = ArchCommands.getCutVolume(obj.Source.Shape.copy(),shapes) if cutvolume: nsh = [] for sh in shapes: for sol in sh.Solids: c = sol.cut(cutvolume) nsh.append(c) shapes = nsh base = Part.makeCompound(shapes) #if shapes: # base = shapes.pop().copy() #for sh in shapes: # try: # base = base.fuse(sh) # except: # print "unable to fuse, passing..." svgf = Drawing.projectToSVG(base,direction) if svgf: svgf = svgf.replace('stroke-width="0.35"','stroke-width="' + str(linewidth) + 'px"') svgf = svgf.replace('stroke-width="1"','stroke-width="' + str(linewidth) + 'px"') svgf = svgf.replace('stroke-width:0.01','stroke-width:' + str(linewidth) + 'px') svg += svgf result = '' result += '<g id="' + obj.Name + '"' result += ' transform="' result += 'rotate('+str(obj.Rotation)+','+str(obj.X)+','+str(obj.Y)+') ' result += 'translate('+str(obj.X)+','+str(obj.Y)+') ' result += 'scale('+str(obj.Scale)+','+str(-obj.Scale)+')' result += '">\n' result += svg result += '</g>\n' # print "complete node:",result return result return ''
def getShape(self, obj): "computes a shape from a base shape and/or bounday faces" import Part shape = None faces = [] #print "starting compute" # 1: if we have a base shape, we use it if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.Solids: shape = obj.Base.Shape.Solids[0].copy() shape = shape.removeSplitter() # 2: if not, add all bounding boxes of considered objects and build a first shape if shape: #print "got shape from base object" bb = shape.BoundBox else: bb = None for b in obj.Boundaries: if b[0].isDerivedFrom("Part::Feature"): if not bb: bb = b[0].Shape.BoundBox else: bb.add(b[0].Shape.BoundBox) if not bb: return shape = Part.makeBox(bb.XLength, bb.YLength, bb.ZLength, FreeCAD.Vector(bb.XMin, bb.YMin, bb.ZMin)) #print "created shape from boundbox" # 3: identifing boundary faces goodfaces = [] for b in obj.Boundaries: if b[0].isDerivedFrom("Part::Feature"): if "Face" in b[1]: fn = int(b[1][4:]) - 1 faces.append(b[0].Shape.Faces[fn]) #print "adding face ",fn," of object ",b[0].Name #print "total: ", len(faces), " faces" # 4: get cutvolumes from faces cutvolumes = [] for f in faces: f = f.copy() f.reverse() cutface, cutvolume, invcutvolume = ArchCommands.getCutVolume( f, shape) if cutvolume: #print "generated 1 cutvolume" cutvolumes.append(cutvolume.copy()) #Part.show(cutvolume) for v in cutvolumes: #print "cutting" shape = shape.cut(v) # 5: get the final shape if shape: if shape.Solids: #print "setting objects shape" shape = shape.Solids[0] obj.Shape = shape return print "Arch: error computing space boundary"
def getShape(self,obj): "computes a shape from a base shape and/or bounday faces" import Part shape = None faces = [] pl = obj.Placement #print("starting compute") # 1: if we have a base shape, we use it if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.Solids: shape = obj.Base.Shape.copy() shape = shape.removeSplitter() # 2: if not, add all bounding boxes of considered objects and build a first shape if shape: #print("got shape from base object") bb = shape.BoundBox else: bb = None for b in obj.Boundaries: if b[0].isDerivedFrom("Part::Feature"): if not bb: bb = b[0].Shape.BoundBox else: bb.add(b[0].Shape.BoundBox) if not bb: return shape = Part.makeBox(bb.XLength,bb.YLength,bb.ZLength,FreeCAD.Vector(bb.XMin,bb.YMin,bb.ZMin)) #print("created shape from boundbox") # 3: identifying boundary faces goodfaces = [] for b in obj.Boundaries: if b[0].isDerivedFrom("Part::Feature"): for sub in b[1]: if "Face" in sub: fn = int(sub[4:])-1 faces.append(b[0].Shape.Faces[fn]) #print("adding face ",fn," of object ",b[0].Name) #print("total: ", len(faces), " faces") # 4: get cutvolumes from faces cutvolumes = [] for f in faces: f = f.copy() f.reverse() cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(f,shape) if cutvolume: #print("generated 1 cutvolume") cutvolumes.append(cutvolume.copy()) #Part.show(cutvolume) for v in cutvolumes: #print("cutting") shape = shape.cut(v) # 5: get the final shape if shape: if shape.Solids: #print("setting objects shape") shape = shape.Solids[0] obj.Shape = shape #pl = pl.multiply(obj.Placement) obj.Placement = pl if hasattr(obj.Area,"Value"): a = self.getArea(obj) if obj.Area.Value != a: obj.Area = a return print("Arch: error computing space boundary")
def execute(self,obj): tol = 1 # tolerance for alignment. This is only visual, we can keep it low... ptol = 0.001 # tolerance for coincident points import math,Part,DraftGeomUtils,ArchCommands if len(obj.Pipes) < 2: return if len(obj.Pipes) > 3: FreeCAD.Console.PrintWarning(translate("Arch","Only the 3 first wires will be connected")+"\n") if obj.Radius.Value == 0: return wires = [] order = [] for o in obj.Pipes: wires.append(o.Proxy.getWire(o)) if wires[0].Vertexes[0].Point.sub(wires[1].Vertexes[0].Point).Length <= ptol: order = ["start","start"] point = wires[0].Vertexes[0].Point elif wires[0].Vertexes[0].Point.sub(wires[1].Vertexes[-1].Point).Length <= ptol: order = ["start","end"] point = wires[0].Vertexes[0].Point elif wires[0].Vertexes[-1].Point.sub(wires[1].Vertexes[-1].Point).Length <= ptol: order = ["end","end"] point = wires[0].Vertexes[-1].Point elif wires[0].Vertexes[-1].Point.sub(wires[1].Vertexes[0].Point).Length <= ptol: order = ["end","start"] point = wires[0].Vertexes[-1].Point else: FreeCAD.Console.PrintError(translate("Arch","Common vertex not found")+"\n") return if order[0] == "start": v1 = wires[0].Vertexes[1].Point.sub(wires[0].Vertexes[0].Point).normalize() else: v1 = wires[0].Vertexes[-2].Point.sub(wires[0].Vertexes[-1].Point).normalize() if order[1] == "start": v2 = wires[1].Vertexes[1].Point.sub(wires[1].Vertexes[0].Point).normalize() else: v2 = wires[1].Vertexes[-2].Point.sub(wires[1].Vertexes[-1].Point).normalize() p = obj.Pipes[0].Proxy.getProfile(obj.Pipes[0]) p = Part.Face(p) if len(obj.Pipes) == 2: if obj.ConnectorType != "Corner": obj.ConnectorType = "Corner" if round(v1.getAngle(v2),tol) in [0,round(math.pi,tol)]: FreeCAD.Console.PrintError(translate("Arch","Pipes are already aligned")+"\n") return normal = v2.cross(v1) offset = math.tan(math.pi/2-v1.getAngle(v2)/2)*obj.Radius.Value v1.multiply(offset) v2.multiply(offset) self.setOffset(obj.Pipes[0],order[0],offset) self.setOffset(obj.Pipes[1],order[1],offset) # find center perp = v1.cross(normal).normalize() perp.multiply(obj.Radius.Value) center = point.add(v1).add(perp) # move and rotate the profile to the first point delta = point.add(v1)-p.CenterOfMass p.translate(delta) vp = DraftGeomUtils.getNormal(p) rot = FreeCAD.Rotation(vp,v1) p.rotate(p.CenterOfMass,rot.Axis,math.degrees(rot.Angle)) sh = p.revolve(center,normal,math.degrees(math.pi-v1.getAngle(v2))) #sh = Part.makeCompound([sh]+[Part.Vertex(point),Part.Vertex(point.add(v1)),Part.Vertex(center),Part.Vertex(point.add(v2))]) else: if obj.ConnectorType != "Tee": obj.ConnectorType = "Tee" if wires[2].Vertexes[0].Point == point: order.append("start") elif wires[0].Vertexes[-1].Point == point: order.append("end") else: FreeCAD.Console.PrintError(translate("Arch","Common vertex not found")+"\n") if order[2] == "start": v3 = wires[2].Vertexes[1].Point.sub(wires[2].Vertexes[0].Point).normalize() else: v3 = wires[2].Vertexes[-2].Point.sub(wires[2].Vertexes[-1].Point).normalize() if round(v1.getAngle(v2),tol) in [0,round(math.pi,tol)]: pair = [v1,v2,v3] elif round(v1.getAngle(v3),tol) in [0,round(math.pi,tol)]: pair = [v1,v3,v2] elif round(v2.getAngle(v3),tol) in [0,round(math.pi,tol)]: pair = [v2,v3,v1] else: FreeCAD.Console.PrintError(translate("Arch","At least 2 pipes must aligned")+"\n") return offset = obj.Radius.Value v1.multiply(offset) v2.multiply(offset) v3.multiply(offset) self.setOffset(obj.Pipes[0],order[0],offset) self.setOffset(obj.Pipes[1],order[1],offset) self.setOffset(obj.Pipes[2],order[2],offset) normal = pair[0].cross(pair[2]) # move and rotate the profile to the first point delta = point.add(pair[0])-p.CenterOfMass p.translate(delta) vp = DraftGeomUtils.getNormal(p) rot = FreeCAD.Rotation(vp,pair[0]) p.rotate(p.CenterOfMass,rot.Axis,math.degrees(rot.Angle)) t1 = p.extrude(pair[1].multiply(2)) # move and rotate the profile to the second point delta = point.add(pair[2])-p.CenterOfMass p.translate(delta) vp = DraftGeomUtils.getNormal(p) rot = FreeCAD.Rotation(vp,pair[2]) p.rotate(p.CenterOfMass,rot.Axis,math.degrees(rot.Angle)) t2 = p.extrude(pair[2].negative().multiply(2)) # create a cut plane cp = Part.makePolygon([point,point.add(pair[0]),point.add(normal),point]) cp = Part.Face(cp) if cp.normalAt(0,0).getAngle(pair[2]) < math.pi/2: cp.reverse() cf, cv, invcv = ArchCommands.getCutVolume(cp,t2) t2 = t2.cut(cv) sh = t1.fuse(t2) obj.Shape = sh
def getCutShapes(objs, section, showHidden, groupSshapesByObject=False): import Part, DraftGeomUtils shapes = [] hshapes = [] sshapes = [] objectShapes = [] objectSshapes = [] for o in objs: if o.isDerivedFrom("Part::Feature"): if o.Shape.isNull(): pass elif section.OnlySolids: if o.Shape.isValid(): solids = [] solids.extend(o.Shape.Solids) shapes.extend(solids) objectShapes.append((o, solids)) else: print(section.Label, ": Skipping invalid object:", o.Label) else: shapes.append(o.Shape) objectShapes.append((o, [o.Shape])) cutface, cutvolume, invcutvolume = ArchCommands.getCutVolume( section.Shape.copy(), shapes) if cutvolume: for o, shapeList in objectShapes: tmpSshapes = [] for sh in shapeList: for sol in sh.Solids: if sol.Volume < 0: sol.reverse() c = sol.cut(cutvolume) s = sol.section(cutface) try: wires = DraftGeomUtils.findWires(s.Edges) for w in wires: f = Part.Face(w) tmpSshapes.append(f) #s = Part.Wire(s.Edges) #s = Part.Face(s) except Part.OCCError: #print "ArchDrawingView: unable to get a face" tmpSshapes.append(s) shapes.extend(c.Solids) #sshapes.append(s) if showHidden: c = sol.cut(invcutvolume) hshapes.append(c) if len(tmpSshapes) > 0: sshapes.extend(tmpSshapes) if groupSshapesByObject: objectSshapes.append((o, tmpSshapes)) if groupSshapesByObject: return shapes, hshapes, sshapes, cutface, cutvolume, invcutvolume, objectSshapes else: return shapes, hshapes, sshapes, cutface, cutvolume, invcutvolume
def onChanged(self, obj, prop): if prop in ["Source", "RenderingMode", "ShowCut"]: import Part, DraftGeomUtils if hasattr(obj, "Source"): if obj.Source: if obj.Source.Objects: objs = Draft.getGroupContents(obj.Source.Objects, walls=True, addgroups=True) objs = Draft.removeHidden(objs) # separate spaces self.spaces = [] os = [] for o in objs: if Draft.getType(o) == "Space": self.spaces.append(o) else: os.append(o) objs = os self.svg = '' fillpattern = '<pattern id="sectionfill" patternUnits="userSpaceOnUse" patternTransform="matrix(5,0,0,5,0,0)"' fillpattern += ' x="0" y="0" width="10" height="10">' fillpattern += '<g>' fillpattern += '<rect width="10" height="10" style="stroke:none; fill:#ffffff" /><path style="stroke:#000000; stroke-width:1" d="M0,0 l10,10" /></g></pattern>' # generating SVG if obj.RenderingMode == "Solid": # render using the Arch Vector Renderer import ArchVRM, WorkingPlane wp = WorkingPlane.plane() wp.setFromPlacement(obj.Source.Placement) #wp.inverse() render = ArchVRM.Renderer() render.setWorkingPlane(wp) render.addObjects(objs) if hasattr(obj, "ShowCut"): render.cut(obj.Source.Shape, obj.ShowCut) else: render.cut(obj.Source.Shape) self.svg += '<g transform="scale(1,-1)">\n' self.svg += render.getViewSVG( linewidth="LWPlaceholder") self.svg += fillpattern self.svg += render.getSectionSVG( linewidth="SWPlaceholder", fillpattern="sectionfill") if hasattr(obj, "ShowCut"): if obj.ShowCut: self.svg += render.getHiddenSVG( linewidth="LWPlaceholder") self.svg += '</g>\n' # print render.info() else: # render using the Drawing module import Drawing, Part shapes = [] hshapes = [] sshapes = [] p = FreeCAD.Placement(obj.Source.Placement) self.direction = p.Rotation.multVec( FreeCAD.Vector(0, 0, 1)) for o in objs: if o.isDerivedFrom("Part::Feature"): if o.Shape.isNull(): pass #FreeCAD.Console.PrintWarning(translate("Arch","Skipping empty object: ")+o.Name) elif o.Shape.isValid(): if hasattr(obj.Source, "OnlySolids"): if obj.Source.OnlySolids: shapes.extend(o.Shape.Solids) else: shapes.append(o.Shape) else: shapes.extend(o.Shape.Solids) else: FreeCAD.Console.PrintWarning( translate( "Arch", "Skipping invalid object: ") + o.Name) cutface, cutvolume, invcutvolume = ArchCommands.getCutVolume( obj.Source.Shape.copy(), shapes) if cutvolume: nsh = [] for sh in shapes: for sol in sh.Solids: if sol.Volume < 0: sol.reverse() c = sol.cut(cutvolume) s = sol.section(cutface) try: wires = DraftGeomUtils.findWires( s.Edges) for w in wires: f = Part.Face(w) sshapes.append(f) #s = Part.Wire(s.Edges) #s = Part.Face(s) except Part.OCCError: #print "ArchDrawingView: unable to get a face" sshapes.append(s) nsh.extend(c.Solids) #sshapes.append(s) if hasattr(obj, "ShowCut"): if obj.ShowCut: c = sol.cut(invcutvolume) hshapes.append(c) shapes = nsh if shapes: self.shapes = shapes self.baseshape = Part.makeCompound(shapes) svgf = Drawing.projectToSVG( self.baseshape, self.direction) if svgf: svgf = svgf.replace( 'stroke-width="0.35"', 'stroke-width="LWPlaceholder"') svgf = svgf.replace( 'stroke-width="1"', 'stroke-width="LWPlaceholder"') svgf = svgf.replace( 'stroke-width:0.01', 'stroke-width:LWPlaceholder') self.svg += svgf if hshapes: hshapes = Part.makeCompound(hshapes) self.hiddenshape = hshapes svgh = Drawing.projectToSVG( hshapes, self.direction) if svgh: svgh = svgh.replace( 'stroke-width="0.35"', 'stroke-width="LWPlaceholder"') svgh = svgh.replace( 'stroke-width="1"', 'stroke-width="LWPlaceholder"') svgh = svgh.replace( 'stroke-width:0.01', 'stroke-width:LWPlaceholder') svgh = svgh.replace( 'fill="none"', 'fill="none"\nstroke-dasharray="DAPlaceholder"' ) self.svg += svgh if sshapes: svgs = "" if hasattr(obj, "ShowFill"): if obj.ShowFill: svgs += fillpattern svgs += '<g transform="rotate(180)">\n' for s in sshapes: if s.Edges: f = Draft.getSVG( s, direction=self.direction. negative(), linewidth=0, fillstyle="sectionfill", color=(0, 0, 0)) svgs += f svgs += "</g>\n" sshapes = Part.makeCompound(sshapes) self.sectionshape = sshapes svgs += Drawing.projectToSVG( sshapes, self.direction) if svgs: svgs = svgs.replace( 'stroke-width="0.35"', 'stroke-width="SWPlaceholder"') svgs = svgs.replace( 'stroke-width="1"', 'stroke-width="SWPlaceholder"') svgs = svgs.replace( 'stroke-width:0.01', 'stroke-width:SWPlaceholder') svgs = svgs.replace( 'stroke-width="0.35 px"', 'stroke-width="SWPlaceholder"') svgs = svgs.replace( 'stroke-width:0.35', 'stroke-width:SWPlaceholder') self.svg += svgs
def getSVG(section,allOn=False,renderMode="Wireframe",showHidden=False,showFill=False,scale=1,linewidth=1,fontsize=1): """getSVG(section,[allOn,renderMode,showHidden,showFill,scale,linewidth,fontsize]) : returns an SVG fragment from an Arch section plane. If allOn is True, all cut objects are shown, regardless if they are visible or not. renderMode can be Wireframe (default) or Solid to use the Arch solid renderer. If showHidden is True, the hidden geometry above the section plane is shown in dashed line. If showFill is True, the cut areas get filled with a pattern""" if not section.Objects: return import DraftGeomUtils p = FreeCAD.Placement(section.Placement) direction = p.Rotation.multVec(FreeCAD.Vector(0,0,1)) objs = Draft.getGroupContents(section.Objects,walls=True,addgroups=True) if not allOn: objs = Draft.removeHidden(objs) # separate spaces spaces = [] nonspaces = [] for o in objs: if Draft.getType(o) == "Space": spaces.append(o) else: nonspaces.append(o) objs = nonspaces svg = '' fillpattern = '<pattern id="sectionfill" patternUnits="userSpaceOnUse" patternTransform="matrix(5,0,0,5,0,0)"' fillpattern += ' x="0" y="0" width="10" height="10">' fillpattern += '<g>' fillpattern += '<rect width="10" height="10" style="stroke:none; fill:#ffffff" /><path style="stroke:#000000; stroke-width:1" d="M0,0 l10,10" /></g></pattern>' # generating SVG if renderMode == "Solid": # render using the Arch Vector Renderer import ArchVRM, WorkingPlane wp = WorkingPlane.plane() wp.setFromPlacement(section.Placement) #wp.inverse() render = ArchVRM.Renderer() render.setWorkingPlane(wp) render.addObjects(objs) if showHidden: render.cut(section.Shape,showHidden) else: render.cut(section.Shape) svg += '<g transform="scale(1,-1)">\n' svg += render.getViewSVG(linewidth="LWPlaceholder") svg += fillpattern svg += render.getSectionSVG(linewidth="SWPlaceholder",fillpattern="sectionfill") if showHidden: svg += render.getHiddenSVG(linewidth="LWPlaceholder") svg += '</g>\n' # print render.info() else: # render using the Drawing module import Drawing, Part shapes = [] hshapes = [] sshapes = [] for o in objs: if o.isDerivedFrom("Part::Feature"): if o.Shape.isNull(): pass elif o.Shape.isValid(): if section.OnlySolids: shapes.extend(o.Shape.Solids) else: shapes.append(o.Shape) else: print section.Label,": Skipping invalid object:",o.Label cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(section.Shape.copy(),shapes) if cutvolume: nsh = [] for sh in shapes: for sol in sh.Solids: if sol.Volume < 0: sol.reverse() c = sol.cut(cutvolume) s = sol.section(cutface) try: wires = DraftGeomUtils.findWires(s.Edges) for w in wires: f = Part.Face(w) sshapes.append(f) #s = Part.Wire(s.Edges) #s = Part.Face(s) except Part.OCCError: #print "ArchDrawingView: unable to get a face" sshapes.append(s) nsh.extend(c.Solids) #sshapes.append(s) if showHidden: c = sol.cut(invcutvolume) hshapes.append(c) shapes = nsh if shapes: baseshape = Part.makeCompound(shapes) svgf = Drawing.projectToSVG(baseshape,direction) if svgf: svgf = svgf.replace('stroke-width="0.35"','stroke-width="LWPlaceholder"') svgf = svgf.replace('stroke-width="1"','stroke-width="LWPlaceholder"') svgf = svgf.replace('stroke-width:0.01','stroke-width:LWPlaceholder') svg += svgf if hshapes: hshapes = Part.makeCompound(hshapes) svgh = Drawing.projectToSVG(hshapes,direction) if svgh: svgh = svgh.replace('stroke-width="0.35"','stroke-width="LWPlaceholder"') svgh = svgh.replace('stroke-width="1"','stroke-width="LWPlaceholder"') svgh = svgh.replace('stroke-width:0.01','stroke-width:LWPlaceholder') svgh = svgh.replace('fill="none"','fill="none"\nstroke-dasharray="DAPlaceholder"') svg += svgh if sshapes: svgs = "" if showFill: svgs += fillpattern svgs += '<g transform="rotate(180)">\n' for s in sshapes: if s.Edges: f = Draft.getSVG(s,direction=direction.negative(),linewidth=0,fillstyle="sectionfill",color=(0,0,0)) svgs += f svgs += "</g>\n" sshapes = Part.makeCompound(sshapes) svgs += Drawing.projectToSVG(sshapes,direction) if svgs: svgs = svgs.replace('stroke-width="0.35"','stroke-width="SWPlaceholder"') svgs = svgs.replace('stroke-width="1"','stroke-width="SWPlaceholder"') svgs = svgs.replace('stroke-width:0.01','stroke-width:SWPlaceholder') svgs = svgs.replace('stroke-width="0.35 px"','stroke-width="SWPlaceholder"') svgs = svgs.replace('stroke-width:0.35','stroke-width:SWPlaceholder') svg += svgs linewidth = linewidth/scale st = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("CutLineThickness",2) da = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetString("archHiddenPattern","30,10") da = da.replace(" ","") svg = svg.replace('LWPlaceholder', str(linewidth) + 'px') svg = svg.replace('SWPlaceholder', str(linewidth*st) + 'px') svg = svg.replace('DAPlaceholder', str(da)) if spaces and round(direction.getAngle(FreeCAD.Vector(0,0,1)),Draft.precision()) in [0,round(math.pi,Draft.precision())]: svg += '<g transform="scale(1,-1)">' for s in spaces: svg += Draft.getSVG(s,scale=scale,fontsize=fontsize,direction=direction) svg += '</g>' # print "complete node:",svg return svg
def getCutShapes(objs,section,showHidden,groupSshapesByObject=False): import Part,DraftGeomUtils shapes = [] hshapes = [] sshapes = [] objectShapes = [] objectSshapes = [] for o in objs: if o.isDerivedFrom("Part::Feature"): if o.Shape.isNull(): pass elif section.OnlySolids: if o.Shape.isValid(): solids = [] solids.extend(o.Shape.Solids) shapes.extend(solids) objectShapes.append((o, solids)) else: print(section.Label,": Skipping invalid object:",o.Label) else: shapes.append(o.Shape) objectShapes.append((o, [o.Shape])) clip = False if hasattr(section, "Clip"): clip = section.Clip cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(section.Shape.copy(),shapes,clip) shapes =[] if cutvolume: for o, shapeList in objectShapes: tmpSshapes = [] for sh in shapeList: for sol in sh.Solids: if sol.Volume < 0: sol.reverse() c = sol.cut(cutvolume) s = sol.section(cutface) try: wires = DraftGeomUtils.findWires(s.Edges) for w in wires: f = Part.Face(w) tmpSshapes.append(f) #s = Part.Wire(s.Edges) #s = Part.Face(s) except Part.OCCError: #print "ArchDrawingView: unable to get a face" tmpSshapes.append(s) shapes.extend(c.Solids) #sshapes.append(s) if showHidden: c = sol.cut(invcutvolume) hshapes.append(c) if len(tmpSshapes) > 0: sshapes.extend(tmpSshapes) if groupSshapesByObject: objectSshapes.append((o, tmpSshapes)) if groupSshapesByObject: return shapes,hshapes,sshapes,cutface,cutvolume,invcutvolume,objectSshapes else: return shapes,hshapes,sshapes,cutface,cutvolume,invcutvolume
def buildSVG(self, obj,join=False): "creates a svg representation" import Part, DraftGeomUtils if hasattr(obj,"Source"): if obj.Source: if obj.Source.Objects: objs = Draft.getGroupContents(obj.Source.Objects,walls=True) objs = Draft.removeHidden(objs) self.svg = '' # generating SVG if obj.RenderingMode == "Solid": # render using the Arch Vector Renderer import ArchVRM render = ArchVRM.Renderer() render.setWorkingPlane(obj.Source.Placement) render.addObjects(objs) if hasattr(obj,"ShowCut"): render.cut(obj.Source.Shape,obj.ShowCut) else: render.cut(obj.Source.Shape) self.svg += render.getViewSVG(linewidth="LWPlaceholder") self.svg += render.getSectionSVG(linewidth="SWPLaceholder") if hasattr(obj,"ShowCut"): if obj.ShowCut: self.svg += render.getHiddenSVG(linewidth="LWPlaceholder") # print render.info() else: # render using the Drawing module import Drawing, Part shapes = [] hshapes = [] sshapes = [] p = FreeCAD.Placement(obj.Source.Placement) self.direction = p.Rotation.multVec(FreeCAD.Vector(0,0,1)) for o in objs: if o.isDerivedFrom("Part::Feature"): if o.Shape.isNull(): pass #FreeCAD.Console.PrintWarning(translate("Arch","Skipping empty object: ")+o.Name) elif o.Shape.isValid(): shapes.extend(o.Shape.Solids) else: FreeCAD.Console.PrintWarning(translate("Arch","Skipping invalid object: ")+o.Name) cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(obj.Source.Shape.copy(),shapes) if cutvolume: nsh = [] for sh in shapes: for sol in sh.Solids: if sol.Volume < 0: sol.reverse() c = sol.cut(cutvolume) s = sol.section(cutface) nsh.extend(c.Solids) sshapes.append(s) if hasattr(obj,"ShowCut"): if obj.ShowCut: c = sol.cut(invcutvolume) hshapes.append(c) shapes = nsh if shapes: self.shapes = shapes self.baseshape = Part.makeCompound(shapes) svgf = Drawing.projectToSVG(self.baseshape,self.direction) if svgf: svgf = svgf.replace('stroke-width="0.35"','stroke-width="LWPlaceholder"') svgf = svgf.replace('stroke-width="1"','stroke-width="LWPlaceholder"') svgf = svgf.replace('stroke-width:0.01','stroke-width:LWPlaceholder') self.svg += svgf if hshapes: hshapes = Part.makeCompound(hshapes) svgh = Drawing.projectToSVG(hshapes,self.direction) if svgh: svgh = svgh.replace('stroke-width="0.35"','stroke-width="LWPlaceholder"') svgh = svgh.replace('stroke-width="1"','stroke-width="LWPlaceholder"') svgh = svgh.replace('stroke-width:0.01','stroke-width:LWPlaceholder') svgh = svgh.replace('fill="none"','fill="none"\nstroke-dasharray="0.09,0.05"') self.svg += svgh if sshapes: edges = [] for s in sshapes: edges.extend(s.Edges) wires = DraftGeomUtils.findWires(edges) faces = [] for w in wires: if (w.ShapeType == "Wire") and w.isClosed(): faces.append(Part.Face(w)) sshapes = Part.makeCompound(faces) svgs = Drawing.projectToSVG(sshapes,self.direction) if svgs: svgs = svgs.replace('stroke-width="0.35"','stroke-width="SWPlaceholder"') svgs = svgs.replace('stroke-width="1"','stroke-width="SWPlaceholder"') svgs = svgs.replace('stroke-width:0.01','stroke-width:SWPlaceholder') self.svg += svgs
def getShape(self,obj): "computes a shape from a base shape and/or bounday faces" import Part shape = None faces = [] #print "starting compute" # 1: if we have a base shape, we use it if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.Solids: shape = obj.Base.Shape.Solids[0].copy() # 2: if not, add all bounding boxes of considered objects and build a first shape if shape: #print "got shape from base object" bb = shape.BoundBox else: bb = None for b in obj.Boundaries: if b[0].isDerivedFrom("Part::Feature"): if not bb: bb = b[0].Shape.BoundBox else: bb.add(b[0].Shape.BoundBox) if not bb: return shape = Part.makeBox(bb.XLength,bb.YLength,bb.ZLength,FreeCAD.Vector(bb.XMin,bb.YMin,bb.ZMin)) #print "created shape from boundbox" # 3: identifing boundary faces goodfaces = [] for b in obj.Boundaries: if b[0].isDerivedFrom("Part::Feature"): if "Face" in b[1]: fn = int(b[1][4:])-1 faces.append(b[0].Shape.Faces[fn]) #print "adding face ",fn," of object ",b[0].Name #print "total: ", len(faces), " faces" # 4: get cutvolumes from faces cutvolumes = [] for f in faces: f = f.copy() f.reverse() cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(f,shape) if cutvolume: #print "generated 1 cutvolume" cutvolumes.append(cutvolume.copy()) #Part.show(cutvolume) for v in cutvolumes: #print "cutting" shape = shape.cut(v) # 5: get the final shape if shape: if shape.Solids: #print "setting objects shape" shape = shape.Solids[0] obj.Shape = shape return print "Arch: error computing space boundary"
def getShape(self, obj): "computes a shape from a base shape and/or boundary faces" import Part shape = None faces = [] pl = obj.Placement #print("starting compute") # 1: if we have a base shape, we use it if obj.Base: if hasattr(obj.Base, 'Shape'): if obj.Base.Shape.Solids: shape = obj.Base.Shape.copy() shape = shape.removeSplitter() # 2: if not, add all bounding boxes of considered objects and build a first shape if shape: #print("got shape from base object") bb = shape.BoundBox else: bb = None for b in obj.Boundaries: if hasattr(b[0], 'Shape'): if not bb: bb = b[0].Shape.BoundBox else: bb.add(b[0].Shape.BoundBox) if not bb: # compute area even if we are not calculating the shape if obj.Shape and obj.Shape.Solids: if hasattr(obj.Area, "Value"): a = self.getArea(obj) if obj.Area.Value != a: obj.Area = a return shape = Part.makeBox(bb.XLength, bb.YLength, bb.ZLength, FreeCAD.Vector(bb.XMin, bb.YMin, bb.ZMin)) #print("created shape from boundbox") # 3: identifying boundary faces goodfaces = [] for b in obj.Boundaries: if hasattr(b[0], 'Shape'): for sub in b[1]: if "Face" in sub: fn = int(sub[4:]) - 1 faces.append(b[0].Shape.Faces[fn]) #print("adding face ",fn," of object ",b[0].Name) #print("total: ", len(faces), " faces") # 4: get cutvolumes from faces cutvolumes = [] for f in faces: f = f.copy() f.reverse() cutface, cutvolume, invcutvolume = ArchCommands.getCutVolume( f, shape) if cutvolume: #print("generated 1 cutvolume") cutvolumes.append(cutvolume.copy()) #Part.show(cutvolume) for v in cutvolumes: #print("cutting") shape = shape.cut(v) # 5: get the final shape if shape: if shape.Solids: #print("setting objects shape") shape = shape.Solids[0] self.applyShape(obj, shape, pl) if hasattr(obj.Area, "Value"): a = self.getArea(obj) if obj.Area.Value != a: obj.Area = a return print("Arch: error computing space boundary for", obj.Label)
def onChanged(self, obj, prop): if prop in ["Source","RenderingMode","ShowCut"]: import Part, DraftGeomUtils if hasattr(obj,"Source"): if obj.Source: if obj.Source.Objects: objs = Draft.getGroupContents(obj.Source.Objects,walls=True) objs = Draft.removeHidden(objs) # separate spaces self.spaces = [] os = [] for o in objs: if Draft.getType(o) == "Space": self.spaces.append(o) else: os.append(o) objs = os self.svg = '' fillpattern = '<pattern id="sectionfill" patternUnits="userSpaceOnUse" patternTransform="matrix(5,0,0,5,0,0)"' fillpattern += ' x="0" y="0" width="10" height="10">' fillpattern += '<g>' fillpattern += '<rect width="10" height="10" style="stroke:none; fill:#ffffff" /><path style="stroke:#000000; stroke-width:1" d="M0,0 l10,10" /></g></pattern>' # generating SVG if obj.RenderingMode == "Solid": # render using the Arch Vector Renderer import ArchVRM, WorkingPlane wp = WorkingPlane.plane() wp.setFromPlacement(obj.Source.Placement) wp.inverse() render = ArchVRM.Renderer() render.setWorkingPlane(wp) render.addObjects(objs) if hasattr(obj,"ShowCut"): render.cut(obj.Source.Shape,obj.ShowCut) else: render.cut(obj.Source.Shape) self.svg += render.getViewSVG(linewidth="LWPlaceholder") self.svg += fillpattern self.svg += render.getSectionSVG(linewidth="SWPlaceholder",fillpattern="sectionfill") if hasattr(obj,"ShowCut"): if obj.ShowCut: self.svg += render.getHiddenSVG(linewidth="LWPlaceholder") # print render.info() else: # render using the Drawing module import Drawing, Part shapes = [] hshapes = [] sshapes = [] p = FreeCAD.Placement(obj.Source.Placement) self.direction = p.Rotation.multVec(FreeCAD.Vector(0,0,1)) for o in objs: if o.isDerivedFrom("Part::Feature"): if o.Shape.isNull(): pass #FreeCAD.Console.PrintWarning(translate("Arch","Skipping empty object: ")+o.Name) elif o.Shape.isValid(): if hasattr(obj.Source,"OnlySolids"): if obj.Source.OnlySolids: shapes.extend(o.Shape.Solids) else: shapes.append(o.Shape) else: shapes.extend(o.Shape.Solids) else: FreeCAD.Console.PrintWarning(translate("Arch","Skipping invalid object: ")+o.Name) cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(obj.Source.Shape.copy(),shapes) if cutvolume: nsh = [] for sh in shapes: for sol in sh.Solids: if sol.Volume < 0: sol.reverse() c = sol.cut(cutvolume) s = sol.section(cutface) try: wires = DraftGeomUtils.findWires(s.Edges) for w in wires: f = Part.Face(w) sshapes.append(f) #s = Part.Wire(s.Edges) #s = Part.Face(s) except Part.OCCError: #print "ArchDrawingView: unable to get a face" sshapes.append(s) nsh.extend(c.Solids) #sshapes.append(s) if hasattr(obj,"ShowCut"): if obj.ShowCut: c = sol.cut(invcutvolume) hshapes.append(c) shapes = nsh if shapes: self.shapes = shapes self.baseshape = Part.makeCompound(shapes) svgf = Drawing.projectToSVG(self.baseshape,self.direction) if svgf: svgf = svgf.replace('stroke-width="0.35"','stroke-width="LWPlaceholder"') svgf = svgf.replace('stroke-width="1"','stroke-width="LWPlaceholder"') svgf = svgf.replace('stroke-width:0.01','stroke-width:LWPlaceholder') self.svg += svgf if hshapes: hshapes = Part.makeCompound(hshapes) self.hiddenshape = hshapes svgh = Drawing.projectToSVG(hshapes,self.direction) if svgh: svgh = svgh.replace('stroke-width="0.35"','stroke-width="LWPlaceholder"') svgh = svgh.replace('stroke-width="1"','stroke-width="LWPlaceholder"') svgh = svgh.replace('stroke-width:0.01','stroke-width:LWPlaceholder') svgh = svgh.replace('fill="none"','fill="none"\nstroke-dasharray="DAPlaceholder"') self.svg += svgh if sshapes: svgs = "" if hasattr(obj,"ShowFill"): if obj.ShowFill: svgs += fillpattern svgs += '<g transform="rotate(180)">\n' for s in sshapes: if s.Edges: f = Draft.getSVG(s,direction=self.direction.negative(),linewidth=0,fillstyle="sectionfill",color=(0,0,0)) svgs += f svgs += "</g>\n" sshapes = Part.makeCompound(sshapes) self.sectionshape = sshapes svgs += Drawing.projectToSVG(sshapes,self.direction) if svgs: svgs = svgs.replace('stroke-width="0.35"','stroke-width="SWPlaceholder"') svgs = svgs.replace('stroke-width="1"','stroke-width="SWPlaceholder"') svgs = svgs.replace('stroke-width:0.01','stroke-width:SWPlaceholder') svgs = svgs.replace('stroke-width="0.35 px"','stroke-width="SWPlaceholder"') svgs = svgs.replace('stroke-width:0.35','stroke-width:SWPlaceholder') self.svg += svgs
def getSVG(section, allOn=False, renderMode="Wireframe", showHidden=False, showFill=False, scale=1, linewidth=1, fontsize=1): """getSVG(section,[allOn,renderMode,showHidden,showFill,scale,linewidth,fontsize]) : returns an SVG fragment from an Arch section plane. If allOn is True, all cut objects are shown, regardless if they are visible or not. renderMode can be Wireframe (default) or Solid to use the Arch solid renderer. If showHidden is True, the hidden geometry above the section plane is shown in dashed line. If showFill is True, the cut areas get filled with a pattern""" if not section.Objects: return import DraftGeomUtils p = FreeCAD.Placement(section.Placement) direction = p.Rotation.multVec(FreeCAD.Vector(0, 0, 1)) objs = Draft.getGroupContents(section.Objects, walls=True, addgroups=True) if not allOn: objs = Draft.removeHidden(objs) # separate spaces spaces = [] nonspaces = [] for o in objs: if Draft.getType(o) == "Space": spaces.append(o) else: nonspaces.append(o) objs = nonspaces svg = '' fillpattern = '<pattern id="sectionfill" patternUnits="userSpaceOnUse" patternTransform="matrix(5,0,0,5,0,0)"' fillpattern += ' x="0" y="0" width="10" height="10">' fillpattern += '<g>' fillpattern += '<rect width="10" height="10" style="stroke:none; fill:#ffffff" /><path style="stroke:#000000; stroke-width:1" d="M0,0 l10,10" /></g></pattern>' # generating SVG if renderMode == "Solid": # render using the Arch Vector Renderer import ArchVRM, WorkingPlane wp = WorkingPlane.plane() wp.setFromPlacement(section.Placement) #wp.inverse() render = ArchVRM.Renderer() render.setWorkingPlane(wp) render.addObjects(objs) if showHidden: render.cut(section.Shape, showHidden) else: render.cut(section.Shape) svg += '<g transform="scale(1,-1)">\n' svg += render.getViewSVG(linewidth="LWPlaceholder") svg += fillpattern svg += render.getSectionSVG(linewidth="SWPlaceholder", fillpattern="sectionfill") if showHidden: svg += render.getHiddenSVG(linewidth="LWPlaceholder") svg += '</g>\n' # print render.info() else: # render using the Drawing module import Drawing, Part shapes = [] hshapes = [] sshapes = [] for o in objs: if o.isDerivedFrom("Part::Feature"): if o.Shape.isNull(): pass elif o.Shape.isValid(): if section.OnlySolids: shapes.extend(o.Shape.Solids) else: shapes.append(o.Shape) else: print section.Label, ": Skipping invalid object:", o.Label cutface, cutvolume, invcutvolume = ArchCommands.getCutVolume( section.Shape.copy(), shapes) if cutvolume: nsh = [] for sh in shapes: for sol in sh.Solids: if sol.Volume < 0: sol.reverse() c = sol.cut(cutvolume) s = sol.section(cutface) try: wires = DraftGeomUtils.findWires(s.Edges) for w in wires: f = Part.Face(w) sshapes.append(f) #s = Part.Wire(s.Edges) #s = Part.Face(s) except Part.OCCError: #print "ArchDrawingView: unable to get a face" sshapes.append(s) nsh.extend(c.Solids) #sshapes.append(s) if showHidden: c = sol.cut(invcutvolume) hshapes.append(c) shapes = nsh if shapes: baseshape = Part.makeCompound(shapes) svgf = Drawing.projectToSVG(baseshape, direction) if svgf: svgf = svgf.replace('stroke-width="0.35"', 'stroke-width="LWPlaceholder"') svgf = svgf.replace('stroke-width="1"', 'stroke-width="LWPlaceholder"') svgf = svgf.replace('stroke-width:0.01', 'stroke-width:LWPlaceholder') svg += svgf if hshapes: hshapes = Part.makeCompound(hshapes) svgh = Drawing.projectToSVG(hshapes, direction) if svgh: svgh = svgh.replace('stroke-width="0.35"', 'stroke-width="LWPlaceholder"') svgh = svgh.replace('stroke-width="1"', 'stroke-width="LWPlaceholder"') svgh = svgh.replace('stroke-width:0.01', 'stroke-width:LWPlaceholder') svgh = svgh.replace( 'fill="none"', 'fill="none"\nstroke-dasharray="DAPlaceholder"') svg += svgh if sshapes: svgs = "" if showFill: svgs += fillpattern svgs += '<g transform="rotate(180)">\n' for s in sshapes: if s.Edges: f = Draft.getSVG(s, direction=direction.negative(), linewidth=0, fillstyle="sectionfill", color=(0, 0, 0)) svgs += f svgs += "</g>\n" sshapes = Part.makeCompound(sshapes) svgs += Drawing.projectToSVG(sshapes, direction) if svgs: svgs = svgs.replace('stroke-width="0.35"', 'stroke-width="SWPlaceholder"') svgs = svgs.replace('stroke-width="1"', 'stroke-width="SWPlaceholder"') svgs = svgs.replace('stroke-width:0.01', 'stroke-width:SWPlaceholder') svgs = svgs.replace('stroke-width="0.35 px"', 'stroke-width="SWPlaceholder"') svgs = svgs.replace('stroke-width:0.35', 'stroke-width:SWPlaceholder') svg += svgs linewidth = linewidth / scale st = FreeCAD.ParamGet( "User parameter:BaseApp/Preferences/Mod/Arch").GetFloat( "CutLineThickness", 2) da = FreeCAD.ParamGet( "User parameter:BaseApp/Preferences/Mod/Arch").GetString( "archHiddenPattern", "30,10") da = da.replace(" ", "") svg = svg.replace('LWPlaceholder', str(linewidth) + 'px') svg = svg.replace('SWPlaceholder', str(linewidth * st) + 'px') svg = svg.replace('DAPlaceholder', str(da)) if spaces and round( direction.getAngle(FreeCAD.Vector(0, 0, 1)), Draft.precision()) in [0, round(math.pi, Draft.precision())]: svg += '<g transform="scale(1,-1)">' for s in spaces: svg += Draft.getSVG(s, scale=scale, fontsize=fontsize, direction=direction) svg += '</g>' # print "complete node:",svg return svg