def areaOpShapes(self, obj): '''areaOpShapes(obj) ... returns envelope for all base shapes or wires for Arch.Panels.''' if obj.UseComp: self.commandlist.append(Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: self.commandlist.append(Path.Command("(Uncompensated Tool Path)")) shapes = [] if obj.Base: # The user has selected subobjects from the base. Process each. 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: FreeCAD.Console.PrintWarning("found a base object which is not a face. Can't continue.") return for wire in holes: f = Part.makeFace(wire, 'Part::FaceMakerSimple') drillable = PathUtils.isDrillable(self.baseobject.Shape, wire) if (drillable and obj.processCircles) or (not drillable and obj.processHoles): env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=f, depthparams=self.depthparams) shapes.append((env, True)) if len(faces) > 0: profileshape = Part.makeCompound(faces) if obj.processPerimeter: env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=profileshape, depthparams=self.depthparams) shapes.append((env, False)) else: # Try to build targets from the job base if hasattr(self.baseobject, "Proxy"): if isinstance(self.baseobject.Proxy, ArchPanel.PanelSheet): # process the sheet if obj.processCircles or obj.processHoles: for shape in self.baseobject.Proxy.getHoles(self.baseobject, transform=True): for wire in shape.Wires: drillable = PathUtils.isDrillable(self.baseobject.Proxy, wire) if (drillable and obj.processCircles) or (not drillable and obj.processHoles): f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=f, depthparams=self.depthparams) shapes.append((env, True)) if obj.processPerimeter: for shape in self.baseobject.Proxy.getOutlines(self.baseobject, transform=True): for wire in shape.Wires: f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=f, depthparams=self.depthparams) shapes.append((env, False)) PathLog.debug("%d shapes" % len(shapes)) return shapes
def circle_hollow(params,document): od = params['D'] t = params['t'] l = params['l'] name = params['name'] id = od - t outer = Part.Wire(Part.makeCircle(0.5*od)) inner = Part.Wire(Part.makeCircle(0.5*id)) face = Part.makeFace([outer, inner], "Part::FaceMakerBullseye") if params['arch']: part = Arch.makeStructure(name=name) prof = document.addObject("Part::Feature","Profile") prof.Shape = face part.Base = prof part.Height = l else: part = document.addObject("Part::Feature","BOLTS_part") part.Label = name beam = face.extrude(Vector(0,0,l)) part.Shape = beam
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... returns envelope for all wires formed by the base edges.''' PathLog.track() if obj.UseComp: self.commandlist.append(Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: self.commandlist.append(Path.Command("(Uncompensated Tool Path)")) shapes = [] if obj.Base: basewires = [] for b in obj.Base: edgelist = [] for sub in b[1]: edgelist.append(getattr(b[0].Shape, sub)) basewires.append((b[0], findWires(edgelist))) for base,wires in basewires: for wire in wires: f = Part.makeFace(wire, 'Part::FaceMakerSimple') # shift the compound to the bottom of the base object for # proper sectioning zShift = b[0].Shape.BoundBox.ZMin - f.BoundBox.ZMin newPlace = FreeCAD.Placement(FreeCAD.Vector(0, 0, zShift), f.Placement.Rotation) f.Placement = newPlace env = PathUtils.getEnvelope(base.Shape, subshape=f, depthparams=self.depthparams) shapes.append((env, False)) return shapes
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... return shapes representing the solids to be removed.''' PathLog.track() if obj.Base: PathLog.debug("base items exist. Processing...") removalshapes = [] for b in obj.Base: PathLog.debug("Base item: {}".format(b)) for sub in b[1]: if "Face" in sub: shape = Part.makeCompound([getattr(b[0].Shape, sub)]) else: edges = [getattr(b[0].Shape, sub) for sub in b[1]] shape = Part.makeFace(edges, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=shape, depthparams=self.depthparams) obj.removalshape = env.cut(self.baseobject.Shape) removalshapes.append((obj.removalshape, False)) else: # process the job base object as a whole PathLog.debug("processing the whole job base object") env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=None, depthparams=self.depthparams) obj.removalshape = env.cut(self.baseobject.Shape) removalshapes = [(obj.removalshape, False)] return removalshapes
def smBase(thk=2.0, length=10.0, radius=1.0, Side="Inside", midplane=False, reverse=False, MainObject=None): WireList = MainObject.Shape.Wires[0] mat = MainObject.getGlobalPlacement() normal = mat.multVec(FreeCAD.Vector(0, 0, 1)) #print(sketch_normal) if WireList.isClosed(): sketch_face = Part.makeFace(MainObject.Shape.Wires, "Part::FaceMakerBullseye") wallSolid = sketch_face.extrude(sketch_face.normalAt(0, 0) * thk) else: if len(WireList.Edges) > 1: if midplane: WireList.translate(normal * length / 2.0) wire_extr = WireList.extrude(normal * -length) elif reverse: wire_extr = WireList.extrude(normal * length) else: wire_extr = WireList.extrude(normal * -length) #Part.show(wire_extr,"wire_extr") if Side == "Middle": wire_extr = wire_extr.makeOffsetShape(-thk / 2.0, 0.0, fill=False, join=2) elif Side == "Outside": wire_extr = wire_extr.makeOffsetShape(-thk, 0.0, fill=False, join=2) #Part.show(wire_extr,"wire_extr") filleted_extr = wire_extr.makeFillet((radius + thk / 2.0), wire_extr.Edges) #Part.show(filleted_extr,"filleted_extr") offset_extr = filleted_extr.makeOffsetShape(-thk / 2.0, 0.0, fill=False) #Part.show(offset_extr,"offset_extr") wallSolid = filleted_extr.makeOffsetShape(thk, 0.0, fill=True) #Part.show(wallSolid,"wallSolid") else: if MainObject.TypeId == 'Sketcher::SketchObject': sketch_face = MainObject.Shape.Wires[0].extrude(normal * -length) #Part.show(sketch_face) wallSolid = sketch_face.extrude( sketch_face.Faces[0].normalAt(0, 0) * -thk) Gui.ActiveDocument.getObject(MainObject.Name).Visibility = False return wallSolid
def execute(self, slopedPlanes): '''execute(self, slopedPlanes) Builds the shape of the slopedPlanes object.''' # print('execute') sketch = slopedPlanes.Base shape = sketch.Shape.copy() shape.Placement = P() self.declareSlopedPlanes(slopedPlanes) # print(self.OnChanged, self.slopeList) if self.OnChanged and self.slopeList: # print('A ', self.OnChanged) faceList = self.reProcessFaces(slopedPlanes) pyFaceListNew = self.Pyth else: # print('B ', self.OnChanged) face = Part.makeFace(shape.Wires, slopedPlanes.FaceMaker) fList = face.Faces faceList, pyFaceListNew = self.processFaces(slopedPlanes, fList) self.Pyth = pyFaceListNew # print('pyFaceListNew ', pyFaceListNew) self.OnChanged = False endShape =\ self.makeShells(slopedPlanes, pyFaceListNew) if slopedPlanes.Group: # print('Group') endShape = self.groupping(slopedPlanes, endShape) if slopedPlanes.Thickness: # print('Thickness') endShape = self.fattening(slopedPlanes, faceList, endShape) if not slopedPlanes.Complement: endShape.complement() endShape.removeInternalWires(True) if slopedPlanes.Solid: endShape = Part.makeSolid(endShape) # print(endShape.Placement) slopedPlanes.Shape = endShape
def sweep_wire(self, w, solid=False): faces = [] for e in w.Edges: faces.append(self.sweep_edge(e, solid)) shell = Part.Shell(faces) shell.sewShape() if solid: cyl = Part.makeCylinder(self.max_radius * 2, self.nb_of_turns * self.lead) cyl.Placement = self._placement.multiply( FreeCAD.Placement(FreeCAD.Vector(), FreeCAD.Vector(1, 0, 0), -90)) common = cyl.common(shell) cut_faces = common.Faces new_edges = [] for e1 in common.Edges: found = False for e2 in shell.Edges: if nurbs_tools.is_same(e1.Curve, e2.Curve, tol=1e-7, full=False): found = True #print("found similar edges") continue if not found: new_edges.append(e1) #print(len(Part.sortEdges(new_edges))) el1, el2 = Part.sortEdges(new_edges)[0:2] f1 = Part.makeFace(Part.Wire(el1), 'Part::FaceMakerSimple') f2 = Part.makeFace(Part.Wire(el2), 'Part::FaceMakerSimple') cut_faces.extend([f1, f2]) try: shell = Part.Shell(cut_faces) shell.sewShape() return Part.Solid(shell) except Part.OCCError: print("Failed to create solid") return Part.Compound(cut_faces) return shell
def smBase(thk=2.0, length=10.0, radius=1.0, Side="Inside", MainObject=None): WireList = MainObject.Shape.Wires[0] #print(sketch_normal) if WireList.isClosed(): sketch_face = Part.makeFace(MainObject.Shape.Wires, "Part::FaceMakerBullseye") wallSolid = sketch_face.extrude(sketch_face.normalAt(0, 0) * thk) else: if len(WireList.Edges) > 1: if Side == "Inside": wire = WireList.makeOffset2D(thk / 2.0, openResult=True, join=2) elif Side == "Outside": wire = WireList.makeOffset2D(-thk / 2.0, openResult=True, join=2) else: wire = WireList #Part.show(wire) filletedWire = DraftGeomUtils.filletWire(wire, (radius + thk / 2)) #Part.show(filletedWire) offsetwire = filletedWire.makeOffset2D(thk / 2.0, openResult=True) #Part.show(offsetwire) sketch_face = offsetwire.makeOffset2D(thk, openResult=True, fill=True) #Part.show(sketch_face) Edge_Dir = sketch_face.normalAt(0, 0) offsetSolid = offsetwire.extrude(Edge_Dir * length) CutList = [] for x in offsetSolid.Faces: if issubclass(type(x.Surface), Part.Plane): offsetSolid = x.extrude(x.normalAt(0, 0) * -thk) CutList.append(offsetSolid) #Part.show(offsetSolid) wallSolid = sketch_face.extrude(Edge_Dir * length) offsetSolids = CutList[0].multiFuse(CutList[1:]) wallSolid = wallSolid.fuse(offsetSolids) else: if MainObject.TypeId == 'Sketcher::SketchObject': mat = MainObject.getGlobalPlacement() normal = mat.multVec(FreeCAD.Vector(0, 0, 1)) sketch_face = MainObject.Shape.Wires[0].extrude(normal * -length) #Part.show(sketch_face) wallSolid = sketch_face.extrude( sketch_face.Faces[0].normalAt(0, 0) * -thk) Gui.ActiveDocument.getObject(MainObject.Name).Visibility = False return wallSolid
def smBase(thk=2.0, length=10.0, radius=1.0, Side="Inside", midplane=False, reverse=False, MainObject=None): # To Get sketch normal WireList = MainObject.Shape.Wires[0] mat = MainObject.getGlobalPlacement().Rotation normal = (mat.multVec(FreeCAD.Vector(0, 0, 1))).normalize() #print([mat, normal]) if WireList.isClosed(): # If Cosed sketch is there, make a face & extrude it sketch_face = Part.makeFace(MainObject.Shape.Wires, "Part::FaceMakerBullseye") wallSolid = sketch_face.extrude(sketch_face.normalAt(0, 0) * thk) else: filleted_extr = modifiedWire(WireList, radius, thk, length, normal, Side, 1.0) #Part.show(filleted_extr,"filleted_extr") dist = WireList.Vertexes[0].Point.distanceToPlane( FreeCAD.Vector(0, 0, 0), normal) #print(dist) slice_wire = filleted_extr.slice(normal, dist) #print(slice_wire) #Part.show(slice_wire[0],"slice_wire") traj = slice_wire[0] #Part.show(traj,"traj") if midplane: traj.translate(normal * -length / 2.0) elif reverse: traj.translate(normal * -length) traj_extr = traj.extrude(normal * length) #Part.show(traj_extr,"traj_extr") solidlist = [] for face in traj_extr.Faces: solid = face.makeOffsetShape(thk, 0.0, fill=True) solidlist.append(solid) if len(solidlist) > 1: wallSolid = solidlist[0].multiFuse(solidlist[1:]) else: wallSolid = solidlist[0] #Part.show(wallSolid,"wallSolid") #Part.show(wallSolid,"wallSolid") return wallSolid
def makeFace(rib): if len(rib.Wires) == 1: wire = rib.Wires[0] else: wire = Part.Wire(rib.Edges) if wire.isClosed(): try: return Part.makeFace(wire, "Part::FaceMakerSimple") except: FreeCAD.Console.PrintError( "Cannot make face from Base shape. Cannot draw solid\n") else: FreeCAD.Console.PrintError( "Base shape is not closed. Cannot draw solid\n") return None
def execute(self, obj): debug("\n* paramVector : execute *\n") if not hasattr(obj,"Origin"): v0 = FreeCAD.Vector(0,0,0) else: v0 = obj.Origin if not hasattr(obj,"Direction"): v1 = FreeCAD.Vector(0,0,-10) else: v1 = obj.Direction.normalize().multiply(10) v2 = v0.add(v1) line = Part.Edge(Part.LineSegment(v0,v2)) cone = Part.makeCone(1,0,3,v2,v1,360) circle = Part.makeCircle(10,v0,v1.negative()) face = Part.makeFace(circle,"Part::FaceMakerSimple") comp = Part.Compound([line,cone,face]) obj.Shape = comp obj.ViewObject.Transparency = 50
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... return envelope over the job's Base.Shape or all Arch.Panel shapes.''' if obj.UseComp: self.commandlist.append(Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: self.commandlist.append(Path.Command("(Uncompensated Tool Path)")) isPanel = False if hasattr(self.baseobject, "Proxy"): if isinstance(self.baseobject.Proxy, ArchPanel.PanelSheet): # process the sheet isPanel = True self.baseobject.Proxy.execute(self.baseobject) shapes = self.baseobject.Proxy.getOutlines(self.baseobject, transform=True) for shape in shapes: f = Part.makeFace([shape], 'Part::FaceMakerSimple') thickness = self.baseobject.Group[0].Source.Thickness return [(f.extrude(FreeCAD.Vector(0, 0, thickness)), False)] if hasattr(self.baseobject, "Shape") and not isPanel: return [(PathUtils.getEnvelope(partshape=self.baseobject.Shape, subshape=None, depthparams=self.depthparams), False)]
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... returns envelope for all wires formed by the base edges.''' PathLog.track() if obj.UseComp: self.commandlist.append( Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: self.commandlist.append(Path.Command("(Uncompensated Tool Path)")) shapes = [] if obj.Base: basewires = [] zMin = None for b in obj.Base: edgelist = [] for sub in b[1]: edgelist.append(getattr(b[0].Shape, sub)) basewires.append((b[0], findWires(edgelist))) if zMin is None or b[0].Shape.BoundBox.ZMin < zMin: zMin = b[0].Shape.BoundBox.ZMin for base, wires in basewires: for wire in wires: f = Part.makeFace(wire, 'Part::FaceMakerSimple') # shift the compound to the bottom of the base object for # proper sectioning zShift = zMin - f.BoundBox.ZMin newPlace = FreeCAD.Placement(FreeCAD.Vector(0, 0, zShift), f.Placement.Rotation) f.Placement = newPlace env = PathUtils.getEnvelope(base.Shape, subshape=f, depthparams=self.depthparams) shapes.append((env, False)) return shapes
def smBase(thk = 2.0, length = 10.0, radius = 1.0, Side = "Inside", midplane = False, reverse = False, MainObject = None): # To Get sketch normal WireList = MainObject.Shape.Wires[0] mat = MainObject.getGlobalPlacement().Rotation normal = (mat.multVec(FreeCAD.Vector(0,0,1))).normalize() #print([mat, normal]) if WireList.isClosed() : # If Cosed sketch is there, make a face & extrude it sketch_face = Part.makeFace(MainObject.Shape.Wires,"Part::FaceMakerBullseye") wallSolid = sketch_face.extrude(sketch_face.normalAt(0,0) * thk) else : # If sketch is one type, make a face by extruding & offset it to correct position if midplane : WireList.translate(normal * length/2.0) wire_extr = WireList.extrude(normal * -length) elif reverse: wire_extr = WireList.extrude(normal * length) else : wire_extr = WireList.extrude(normal * -length) #Part.show(wire_extr,"wire_extr") if Side == "Inside" : wire_extr = wire_extr.makeOffsetShape(-thk/2.0, 0.0, fill = False, join = 2) elif Side == "Outside" : wire_extr = wire_extr.makeOffsetShape(thk/2.0, 0.0, fill = False, join = 2) #Part.show(wire_extr,"wire_extr") if len(WireList.Edges) > 1 : filleted_extr = wire_extr.makeFillet((radius + thk / 2.0), wire_extr.Edges) #Part.show(filleted_extr,"filleted_extr") else : filleted_extr = wire_extr #Part.show(filleted_extr,"filleted_extr") offset_extr = filleted_extr.makeOffsetShape(-thk/2.0, 0.0, fill = False) #Part.show(offset_extr,"offset_extr") wallSolid = offset_extr.makeOffsetShape(thk, 0.0, fill = True) #Part.show(wallSolid,"wallSolid") #Part.show(wallSolid,"wallSolid") return wallSolid
def setup(doc=None, solvertype="ccxtools"): # init FreeCAD document if doc is None: doc = init_doc() # explanation object # just keep the following line and change text string in get_explanation method manager.add_explanation_obj( doc, get_explanation(manager.get_header(get_information()))) # geometric object v1 = vec(-200, -100, 0) v2 = vec(200, -100, 0) v3 = vec(200, 100, 0) v4 = vec(-200, 100, 0) l1 = ln(v1, v2) l2 = ln(v2, v3) l3 = ln(v3, v4) l4 = ln(v4, v1) v5 = vec(0, 0, 0) c1 = ci(50, v5) face = Part.makeFace([Part.Wire([l1, l2, l3, l4]), c1], "Part::FaceMakerBullseye") geom_obj = doc.addObject("Part::Feature", "Hole_Plate") geom_obj.Shape = face.extrude(vec(0, 0, 10)) doc.recompute() if FreeCAD.GuiUp: geom_obj.ViewObject.Document.activeView().viewAxonometric() geom_obj.ViewObject.Document.activeView().fitAll() # analysis analysis = ObjectsFem.makeAnalysis(doc, "Analysis") # solver if solvertype == "calculix": solver_obj = ObjectsFem.makeSolverCalculix(doc, "SolverCalculiX") elif solvertype == "ccxtools": solver_obj = ObjectsFem.makeSolverCalculixCcxTools( doc, "CalculiXccxTools") solver_obj.WorkingDir = u"" else: FreeCAD.Console.PrintWarning( "Not known or not supported solver type: {}. " "No solver object was created.\n".format(solvertype)) if solvertype == "calculix" or solvertype == "ccxtools": solver_obj.SplitInputWriter = False solver_obj.AnalysisType = "static" solver_obj.GeometricalNonlinearity = "linear" solver_obj.ThermoMechSteadyState = False solver_obj.MatrixSolverType = "default" solver_obj.IterationsControlParameterTimeUse = False solver_obj.GeometricalNonlinearity = 'nonlinear' solver_obj.MaterialNonlinearity = 'nonlinear' analysis.addObject(solver_obj) # linear material material_obj = ObjectsFem.makeMaterialSolid(doc, "Material_lin") matprop = material_obj.Material matprop["Name"] = "CalculiX-Steel" matprop["YoungsModulus"] = "210000 MPa" matprop["PoissonRatio"] = "0.30" material_obj.Material = matprop analysis.addObject(material_obj) # nonlinear material name_nlm = "Material_nonlin" nonlinear_mat = ObjectsFem.makeMaterialMechanicalNonlinear( doc, material_obj, name_nlm) nonlinear_mat.YieldPoint1 = '240.0, 0.0' nonlinear_mat.YieldPoint2 = '270.0, 0.025' analysis.addObject(nonlinear_mat) # check solver attributes, Nonlinearity needs to be set to nonlinear # constraint fixed con_fixed = ObjectsFem.makeConstraintFixed(doc, "ConstraintFixed") con_fixed.References = [(geom_obj, "Face4")] analysis.addObject(con_fixed) # pressure constraint con_pressure = ObjectsFem.makeConstraintPressure(doc, "ConstraintPressure") con_pressure.References = [(geom_obj, "Face2")] con_pressure.Pressure = 130.0 con_pressure.Reversed = True analysis.addObject(con_pressure) # mesh from .meshes.mesh_platewithhole_tetra10 import create_nodes, create_elements fem_mesh = Fem.FemMesh() control = create_nodes(fem_mesh) if not control: FreeCAD.Console.PrintError("Error on creating nodes.\n") control = create_elements(fem_mesh) if not control: FreeCAD.Console.PrintError("Error on creating elements.\n") femmesh_obj = analysis.addObject( ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Part = geom_obj femmesh_obj.SecondOrderLinear = False doc.recompute() return doc
def getExtrusionData(self,obj): """returns (shape,extrusion vector,placement) or None""" if hasattr(obj,"IfcRole"): role = obj.IfcRole else: role = obj.Role 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 normal = None if not height: for p in obj.InList: if Draft.getType(p) in ["Floor","BuildingPart"]: if p.Height.Value: height = p.Height.Value base = None placement = None if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape: if obj.Base.Shape.Solids: return None elif obj.Base.Shape.Faces: if not DraftGeomUtils.isCoplanar(obj.Base.Shape.Faces): return None else: base,placement = self.rebase(obj.Base.Shape) normal = obj.Base.Shape.Faces[0].normalAt(0,0) normal = placement.inverse().Rotation.multVec(normal) elif obj.Base.Shape.Wires: baseface = None if hasattr(obj,"FaceMaker"): if obj.FaceMaker != "None": try: baseface = Part.makeFace(obj.Base.Shape.Wires,"Part::FaceMaker"+str(obj.FaceMaker)) except: FreeCAD.Console.PrintError(translate("Arch","Facemaker returned an error")+"\n") return None if len(baseface.Faces) > 1: baseface = baseface.Faces[0] normal = baseface.normalAt(0,0) if not baseface: for w in obj.Base.Shape.Wires: if not w.isClosed(): p0 = w.OrderedVertexes[0].Point p1 = w.OrderedVertexes[-1].Point if p0 != p1: e = Part.Line(p0,p1).toShape() w.add(e) w.fix(0.1,0,1) # fixes self-intersecting wires f = Part.Face(w) if baseface: baseface = baseface.fuse(f) else: baseface = f normal = f.normalAt(0,0) base,placement = self.rebase(baseface) normal = placement.inverse().Rotation.multVec(normal) elif (len(obj.Base.Shape.Edges) == 1) and (len(obj.Base.Shape.Vertexes) == 1): # closed edge w = Part.Wire(obj.Base.Shape.Edges[0]) baseface = Part.Face(w) base,placement = self.rebase(baseface) elif length and width and height: if (length > height) and (role != "Slab"): h2 = height/2 or 0.5 w2 = width/2 or 0.5 v1 = Vector(0,-w2,-h2) v4 = Vector(0,-w2,h2) v3 = Vector(0,w2,h2) v2 = Vector(0,w2,-h2) 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) import Part baseface = Part.Face(Part.makePolygon([v1,v2,v3,v4,v1])) base,placement = self.rebase(baseface) if base and placement: if obj.Normal.Length: normal = Vector(obj.Normal) normal = placement.inverse().Rotation.multVec(normal) if not normal: normal = Vector(0,0,1) if not normal.Length: normal = Vector(0,0,1) extrusion = normal if (length > height) and (role != "Slab"): if length: extrusion = normal.multiply(length) else: if height: extrusion = normal.multiply(height) return (base,extrusion,placement) return None
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 normal = None if not height: for p in obj.InList: if Draft.getType(p) == "Floor": if p.Height.Value: height = p.Height.Value base = None placement = None if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape: if obj.Base.Shape.Solids: return None elif obj.Base.Shape.Faces: if not DraftGeomUtils.isCoplanar(obj.Base.Shape.Faces): return None else: base,placement = self.rebase(obj.Base.Shape) normal = obj.Base.Shape.Faces[0].normalAt(0,0) elif obj.Base.Shape.Wires: baseface = None if hasattr(obj,"FaceMaker"): if obj.FaceMaker != "None": try: baseface = Part.makeFace(obj.Base.Shape.Wires,"Part::FaceMaker"+str(obj.FaceMaker)) except: FreeCAD.Console.PrintError(translate("Arch","Facemaker returned an error")+"\n") return None if len(baseface.Faces) > 1: baseface = baseface.Faces[0] normal = baseface.normalAt(0,0) if not baseface: for w in obj.Base.Shape.Wires: w.fix(0.1,0,1) # fixes self-intersecting wires f = Part.Face(w) if baseface: baseface = baseface.fuse(f) else: baseface = f normal = f.normalAt(0,0) base,placement = self.rebase(baseface) elif (len(obj.Base.Shape.Edges) == 1) and (len(obj.Base.Shape.Vertexes) == 1): # closed edge w = Part.Wire(obj.Base.Shape.Edges[0]) baseface = Part.Face(w) base,placement = self.rebase(baseface) elif length and width and height: if (length > height) and (obj.Role != "Slab"): h2 = height/2 or 0.5 w2 = width/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 = 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) import Part baseface = Part.Face(Part.makePolygon([v1,v2,v3,v4,v1])) base,placement = self.rebase(baseface) if base and placement: if obj.Normal == Vector(0,0,0): if not normal: normal = Vector(0,0,1) else: normal = Vector(obj.Normal) if (length > height) and (obj.Role != "Slab"): extrusion = normal.multiply(length) else: extrusion = normal.multiply(height) return (base,extrusion,placement) return None
def execute(self, obj, getsim=False): commandlist = [] sim = None if not obj.Active: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False return parentJob = PathUtils.findParentJob(obj) if parentJob is None: return baseobject = parentJob.Base if baseobject is None: return self.depthparams = depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=0.0, final_depth=obj.FinalDepth.Value, user_depths=None) 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 commandlist.append(Path.Command("(" + obj.Label + ")")) if obj.UseComp: commandlist.append( Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: commandlist.append(Path.Command("(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: f = Part.makeFace(wire, 'Part::FaceMakerSimple') # shift the compound to the bottom of the base object for # proper sectioning zShift = b[0].Shape.BoundBox.ZMin - f.BoundBox.ZMin newPlace = FreeCAD.Placement(FreeCAD.Vector(0, 0, zShift), f.Placement.Rotation) f.Placement = newPlace env = PathUtils.getEnvelope(baseobject.Shape, subshape=f, depthparams=self.depthparams) try: (pp, sim) = self._buildPathArea(obj, baseobject=env, start=obj.StartPoint, getsim=getsim) commandlist.extend(pp.Commands) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError( "Something unexpected happened. Unable to generate a contour path. Check project and tool config." ) # Let's finish by rapid to clearance...just for safety commandlist.append(Path.Command("G0", {"Z": obj.ClearanceHeight.Value})) path = Path.Path(commandlist) obj.Path = path obj.ViewObject.Visibility = True return sim
def rectangle_hollow(params,document): h = params['h'] b = params['b'] t = params['t'] l = params['l'] name = params['name'] ## Definition in EN standard ri=1.0*t ro=1.5*t # outer rectangle, going clockwise Vor1 = Vector((b/2),(h/2-ro),0) Vor2 = Vector((b/2),(-h/2+ro),0) Vor3 = Vector((b/2-ro),(-h/2),0) Vor4 = Vector((-b/2+ro),-h/2,0) Vor5 = Vector(-b/2,(-h/2+ro),0) Vor6 = Vector(-b/2,(h/2-ro),0) Vor7 = Vector((-b/2+ro),(h/2),0) Vor8 = Vector((b/2-ro),(h/2),0) Lor1 = makeLine(Vor1,Vor2) Lor2 = makeLine(Vor3,Vor4) Lor3 = makeLine(Vor5,Vor6) Lor4 = makeLine(Vor7,Vor8) # outer radius, going clockwise Voc1 = Vector((b/2-ro),(-h/2+ro),0) Voc2 = Vector((-b/2+ro),(-h/2+ro),0) Voc3 = Vector((-b/2+ro),(h/2-ro),0) Voc4= Vector((b/2-ro),(h/2-ro),0) normal = Vector(0,0,1) Coc1 = makeCircle(ro,Voc1,normal,270, 0) Coc2 = makeCircle(ro,Voc2,normal,180,270) Coc3 = makeCircle(ro,Voc3,normal, 90,180) Coc4 = makeCircle(ro,Voc4,normal, 0, 90) # inner rectangle, going clockwise Vir1 = Vector((b/2-t),(h/2-t-ri),0) Vir2 = Vector((b/2-t),(-h/2+t+ri),0) Vir3 = Vector((b/2-t-ri),(-h/2+t),0) Vir4 = Vector((-b/2+t+ri),(-h/2+t),0) Vir5 = Vector((-b/2+t),(-h/2+t+ri),0) Vir6 = Vector((-b/2+t),(h/2-t-ri),0) Vir7 = Vector((-b/2+t+ri),(h/2-t),0) Vir8 = Vector((b/2-t-ri),(h/2-t),0) Lir1 = makeLine(Vir1,Vir2) Lir2 = makeLine(Vir3,Vir4) Lir3 = makeLine(Vir5,Vir6) Lir4 = makeLine(Vir7,Vir8) # inner radius, going clockwise Vic1 = Vector((b/2-t-ri),(-h/2+t+ri),0) Vic2 = Vector((-b/2+t+ri),(-h/2+t+ri),0) Vic3 = Vector((-b/2+t+ri),(h/2-t-ri),0) Vic4= Vector((b/2-t-ri),(h/2-t-ri),0) normal = Vector(0,0,1) Cic1 = makeCircle(ri,Vic1,normal,270, 0) Cic2 = makeCircle(ri,Vic2,normal,180,270) Cic3 = makeCircle(ri,Vic3,normal, 90,180) Cic4 = makeCircle(ri,Vic4,normal, 0, 90) # putting the segments together, make wires, make faces, extrude them and cut them Wo = Part.Wire([Lor1,Coc1,Lor2,Coc2,Lor3,Coc3,Lor4,Coc4,]) Wi = Part.Wire([Lir1,Cic1,Lir2,Cic2,Lir3,Cic3,Lir4,Cic4,]) face = Part.makeFace([Wo, Wi], "Part::FaceMakerBullseye") if params['arch']: part = Arch.makeStructure(name=name) prof = document.addObject("Part::Feature","Profile") prof.Shape = face part.Base = prof part.Height = l else: part = document.addObject("Part::Feature","BOLTS_part") part.Label = name beam = face.extrude(Vector(0,0,l)) part.Shape = beam
def rectangle_hollow(params, document): h = params["h"] b = params["b"] t = params["t"] le = params["l"] name = params["name"] # Definition in EN standard ri = 1.0 * t ro = 1.5 * t # outer rectangle, going clockwise Vor1 = Vector((b / 2), (h / 2 - ro), 0) Vor2 = Vector((b / 2), (-h / 2 + ro), 0) Vor3 = Vector((b / 2 - ro), (-h / 2), 0) Vor4 = Vector((-b / 2 + ro), -h / 2, 0) Vor5 = Vector(-b / 2, (-h / 2 + ro), 0) Vor6 = Vector(-b / 2, (h / 2 - ro), 0) Vor7 = Vector((-b / 2 + ro), (h / 2), 0) Vor8 = Vector((b / 2 - ro), (h / 2), 0) Lor1 = makeLine(Vor1, Vor2) Lor2 = makeLine(Vor3, Vor4) Lor3 = makeLine(Vor5, Vor6) Lor4 = makeLine(Vor7, Vor8) # outer radius, going clockwise Voc1 = Vector((b / 2 - ro), (-h / 2 + ro), 0) Voc2 = Vector((-b / 2 + ro), (-h / 2 + ro), 0) Voc3 = Vector((-b / 2 + ro), (h / 2 - ro), 0) Voc4 = Vector((b / 2 - ro), (h / 2 - ro), 0) normal = Vector(0, 0, 1) Coc1 = makeCircle(ro, Voc1, normal, 270, 0) Coc2 = makeCircle(ro, Voc2, normal, 180, 270) Coc3 = makeCircle(ro, Voc3, normal, 90, 180) Coc4 = makeCircle(ro, Voc4, normal, 0, 90) # inner rectangle, going clockwise Vir1 = Vector((b / 2 - t), (h / 2 - t - ri), 0) Vir2 = Vector((b / 2 - t), (-h / 2 + t + ri), 0) Vir3 = Vector((b / 2 - t - ri), (-h / 2 + t), 0) Vir4 = Vector((-b / 2 + t + ri), (-h / 2 + t), 0) Vir5 = Vector((-b / 2 + t), (-h / 2 + t + ri), 0) Vir6 = Vector((-b / 2 + t), (h / 2 - t - ri), 0) Vir7 = Vector((-b / 2 + t + ri), (h / 2 - t), 0) Vir8 = Vector((b / 2 - t - ri), (h / 2 - t), 0) Lir1 = makeLine(Vir1, Vir2) Lir2 = makeLine(Vir3, Vir4) Lir3 = makeLine(Vir5, Vir6) Lir4 = makeLine(Vir7, Vir8) # inner radius, going clockwise Vic1 = Vector((b / 2 - t - ri), (-h / 2 + t + ri), 0) Vic2 = Vector((-b / 2 + t + ri), (-h / 2 + t + ri), 0) Vic3 = Vector((-b / 2 + t + ri), (h / 2 - t - ri), 0) Vic4 = Vector((b / 2 - t - ri), (h / 2 - t - ri), 0) normal = Vector(0, 0, 1) Cic1 = makeCircle(ri, Vic1, normal, 270, 0) Cic2 = makeCircle(ri, Vic2, normal, 180, 270) Cic3 = makeCircle(ri, Vic3, normal, 90, 180) Cic4 = makeCircle(ri, Vic4, normal, 0, 90) # putting the segments together, make wires, make faces, extrude them and cut them Wo = Part.Wire([ Lor1, Coc1, Lor2, Coc2, Lor3, Coc3, Lor4, Coc4, ]) Wi = Part.Wire([ Lir1, Cic1, Lir2, Cic2, Lir3, Cic3, Lir4, Cic4, ]) face = Part.makeFace([Wo, Wi], "Part::FaceMakerBullseye") if params["arch"]: from ArchStructure import makeStructure part = makeStructure(name=name) prof = document.addObject("Part::Feature", "Profile") prof.Shape = face part.Base = prof part.Height = le else: part = document.addObject("Part::Feature", "BOLTS_part") part.Label = name beam = face.extrude(Vector(0, 0, le)) part.Shape = beam
def get_elebase_sh(corner_min, size, baseheight, tm): from FreeCAD import Vector as vec from MeshPart import meshFromShape from Part import makeLine # scaled place on origin place_for_mesh = FreeCAD.Vector( -corner_min.x - size[0], -corner_min.y - size[1], 0.00) # SRTM data resolution is 30 m = 30'000 mm in the usa # rest of the world is 90 m = 90'000 mm # it makes no sense to use values smaller than 90'000 mm pt_distance = 100000 say(corner_min) # y is huge!, but this is ok! say(size) # base area surface mesh with heights # Version new pn1 = vec( 0, 0, 0 ) pn2 = vec( pn1.x + size[0] * 2, pn1.y, 0 ) pn3 = vec( pn1.x + size[0] * 2, pn1.y + size[1] * 2, 0 ) pn4 = vec( pn1.x, pn1.y + size[1] * 2, 0 ) ln1 = makeLine(pn1, pn2) ln2 = makeLine(pn2, pn3) ln3 = makeLine(pn3, pn4) ln4 = makeLine(pn4, pn1) wi = Part.Wire([ln1, ln2, ln3, ln4]) fa = Part.makeFace([wi], "Part::FaceMakerSimple") msh = meshFromShape(fa, LocalLength=pt_distance) # move to corner_min to retrieve the heights msh.translate( corner_min.x, corner_min.y, 0, ) # move mesh points z-koord for pt_msh in msh.Points: # say(pt_msh.Index) # say(pt_msh.Vector) pt_tm = tm.toGeographic(pt_msh.Vector.x, pt_msh.Vector.y) height = get_height_single(pt_tm[0], pt_tm[1]) # mm # say(height) pt_msh.move(FreeCAD.Vector(0, 0, height)) # move mesh back centered on origin msh.translate( -corner_min.x - size[0], -corner_min.y - size[1], -baseheight, ) # create Shape from Mesh sh = Part.Shape() sh.makeShapeFromMesh(msh.Topology, 0.1) return sh
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... return top face''' # Facing is done either against base objects holeShape = None if obj.Base: PathLog.debug("obj.Base: {}".format(obj.Base)) faces = [] holes = [] holeEnvs = [] oneBase = [obj.Base[0][0], True] sub0 = getattr(obj.Base[0][0].Shape, obj.Base[0][1][0]) minHeight = sub0.BoundBox.ZMax 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 shape.BoundBox.ZMin < minHeight: minHeight = shape.BoundBox.ZMin if oneBase[0] is not b[0]: oneBase[1] = False if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face for wire in shape.Wires[1:]: if obj.ExcludeRaisedAreas is True: ip = self.isPocket(b[0], shape, wire) if ip is False: holes.append((b[0].Shape, wire)) else: holes.append((b[0].Shape, wire)) else: PathLog.error('The base subobject, "{}," is not a face. Ignoring "{}."'.format(sub, sub)) if obj.ExcludeRaisedAreas is True and len(holes) > 0: for shape, wire in holes: f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope(shape, subshape=f, depthparams=self.depthparams) holeEnvs.append(env) holeShape = Part.makeCompound(holeEnvs) PathLog.debug("Working on a collection of faces {}".format(faces)) planeshape = Part.makeCompound(faces) # If no base object, do planing of top surface of entire model else: planeshape = Part.makeCompound([base.Shape for base in self.model]) PathLog.debug("Working on a shape {}".format(obj.Label)) # Find the correct shape depending on Boundary shape. PathLog.debug("Boundary Shape: {}".format(obj.BoundaryShape)) bb = planeshape.BoundBox if obj.BoundaryShape == 'Boundbox': bbperim = Part.makeBox(bb.XLength, bb.YLength, 1, FreeCAD.Vector(bb.XMin, bb.YMin, bb.ZMin), FreeCAD.Vector(0, 0, 1)) env = PathUtils.getEnvelope(partshape=bbperim, depthparams=self.depthparams) if obj.ExcludeRaisedAreas is True and oneBase[1] is True: includedFaces = self.getAllIncludedFaces(oneBase[0], env, faceZ=minHeight) if len(includedFaces) > 0: includedShape = Part.makeCompound(includedFaces) includedEnv = PathUtils.getEnvelope(oneBase[0].Shape, subshape=includedShape, depthparams=self.depthparams) env = env.cut(includedEnv) elif obj.BoundaryShape == 'Stock': stock = PathUtils.findParentJob(obj).Stock.Shape env = stock if obj.ExcludeRaisedAreas is True and oneBase[1] is True: includedFaces = self.getAllIncludedFaces(oneBase[0], stock, faceZ=minHeight) if len(includedFaces) > 0: stockEnv = PathUtils.getEnvelope(partshape=stock, depthparams=self.depthparams) includedShape = Part.makeCompound(includedFaces) includedEnv = PathUtils.getEnvelope(oneBase[0].Shape, subshape=includedShape, depthparams=self.depthparams) env = stockEnv.cut(includedEnv) else: env = PathUtils.getEnvelope(partshape=planeshape, depthparams=self.depthparams) if holeShape is not None: PathLog.info("Processing holes...") holeEnv = PathUtils.getEnvelope(partshape=holeShape, depthparams=self.depthparams) newEnv = env.cut(holeEnv) return [(newEnv, False)] else: return [(env, False)]
def smBend(bendR = 1.0, bendA = 90.0, miterA1 = 0.0,miterA2 = 0.0, BendType = "Material Outside", flipped = False, unfold = False, offset = 0.0, extLen = 10.0, gap1 = 0.0, gap2 = 0.0, reliefType = "Rectangle", reliefW = 0.8, reliefD = 1.0, extend1 = 0.0, extend2 = 0.0, kfactor = 0.45, ReliefFactor = 0.7, UseReliefFactor = False, selFaceNames = '', MainObject = None, automiter = True, sketch = None ): # if sketch is as wall sketches = False if sketch : if sketch.Shape.Wires[0].isClosed() : sketches = True else : pass if not(sketches) : miterA1List1, miterA2List1, gap1List1, gap2List1, reliefDList1, wallsolid_common_list1 = smMiter(bendR = bendR, bendA = bendA, miterA1 = miterA1, miterA2 = miterA2, flipped = flipped, extLen = extLen, gap1 = gap1, sign = 1.0, offset = offset, gap2 = gap2, reliefD = reliefD, selFaceNames = selFaceNames, automiter = automiter, MainObject = MainObject) bendAflip = (bendA - 180) miterA1List2, miterA2List2, gap1List2, gap2List2, reliefDList2, wallsolid_common_list2 = smMiter(bendR = bendR, bendA = bendAflip, miterA1 = miterA1, miterA2 = miterA2, flipped = flipped, extLen = extLen, gap1 = gap1, sign = -1.0, offset = offset, gap2 = gap2, reliefD = reliefD, selFaceNames = selFaceNames, automiter = automiter, MainObject = MainObject) miterA1List = [x if a > b else y for x, y, a, b in zip(miterA1List1, miterA1List2, wallsolid_common_list1, wallsolid_common_list2)] miterA2List = [x if a > b else y for x, y, a, b in zip(miterA2List1, miterA2List2, wallsolid_common_list1, wallsolid_common_list2)] gap1List = [max(x,y) for x, y in zip(gap1List1, gap1List2)] gap2List = [max(x,y) for x, y in zip(gap2List1, gap2List2)] reliefDList = [min(x , y) for x, y in zip(reliefDList1, reliefDList2)] else : miterA1List, miterA2List, gap1List, gap2List, reliefDList = ( [0.0],[0.0],[gap1],[gap2],[reliefD]) thk_faceList = [] resultSolid = MainObject for i, selFaceName in enumerate(selFaceNames): selItem = MainObject.getElement(selFaceName) selFace = smFace(selItem, MainObject) selFace = smModifiedFace(selFace, resultSolid) gap1, gap2 = (gap1List[i], gap2List[i]) reliefD = reliefDList[i] # find the narrow edge thk = 999999.0 for edge in selFace.Edges: if abs( edge.Length ) < thk: thk = abs( edge.Length ) thkEdge = edge # Add as offset to set any distance if UseReliefFactor : reliefW = thk * ReliefFactor reliefD = thk * ReliefFactor # Add Relief factor if BendType == "Material Outside" : offset = 0.0 inside = False elif BendType == "Material Inside" : offset = -(thk + bendR) inside = True elif BendType == "Thickness Outside" : offset = -bendR inside = True elif BendType == "Offset" : if offset < 0.0 : inside = True else : inside = False # find a length edge = revolve axis direction p0 = thkEdge.valueAt(thkEdge.FirstParameter) for lenEdge in selFace.Edges: p1 = lenEdge.valueAt(lenEdge.FirstParameter) p2 = lenEdge.valueAt(lenEdge.LastParameter) if lenEdge.isSame(thkEdge): continue if (p1 - p0).Length < smEpsilon: revAxisV = p2 - p1 break if (p2 - p0).Length < smEpsilon: revAxisV = p1 - p2 break # find the large face connected with selected face list2 = resultSolid.ancestorsOfType(lenEdge, Part.Face) for Cface in list2 : if not(Cface.isSame(selFace)) : break # Produce Offset Edge if offset > 0.0 : lenEdge.translate(selFace.normalAt(0,0) * offset) # main Length Edge MlenEdge = lenEdge leng = MlenEdge.Length revAxisV.normalize() thkDir = Cface.normalAt(0,0) * -1 FaceDir = selFace.normalAt(0,0) # Get correct size inside face if inside : e1 = MlenEdge.copy() e1.translate(FaceDir * offset) EdgeShape = e1.common(Cface) lenEdge = EdgeShape.Edges[0] Noffset1 = abs((MlenEdge.valueAt(MlenEdge.FirstParameter)-lenEdge.valueAt(lenEdge.FirstParameter)).Length) Noffset2 = abs((MlenEdge.valueAt(MlenEdge.LastParameter)-lenEdge.valueAt(lenEdge.LastParameter)).Length) # if sketch is as wall sketches = False if sketch : if sketch.Shape.Wires[0].isClosed() : sketches = True else : pass if sketches : sketch_face = Part.makeFace(sketch.Shape.Wires, "Part::FaceMakerBullseye") sketch_face.translate(thkDir * -thk ) if inside : sketch_face.translate(FaceDir * offset ) sketch_Shape = lenEdge.common(sketch_face) sketch_Edge = sketch_Shape.Edges[0] gap1 = (lenEdge.valueAt(lenEdge.FirstParameter) - sketch_Edge.valueAt(sketch_Edge.FirstParameter)).Length gap2 = (lenEdge.valueAt(lenEdge.LastParameter) - sketch_Edge.valueAt(sketch_Edge.LastParameter)).Length # Get angles of adjacent face Agap1 = 0.0 Agap2 = 0.0 if inside : AngleList =[] if MlenEdge.Vertexes[0].Orientation == "Reversed" : vertex1 = MlenEdge.Vertexes[0] vertex0 = MlenEdge.Vertexes[1] else : vertex0 = MlenEdge.Vertexes[0] vertex1 = MlenEdge.Vertexes[1] Edgelist = Cface.ancestorsOfType(vertex0, Part.Edge) for ed in Edgelist : if not(MlenEdge.isSame(ed)): #Part.show(ed) if abs((MlenEdge.valueAt(MlenEdge.FirstParameter)- ed.valueAt(ed.LastParameter)).Length) < smEpsilon: lineDir = ed.valueAt(ed.LastParameter)- ed.valueAt(ed.FirstParameter) edgeDir = MlenEdge.valueAt(MlenEdge.FirstParameter) - MlenEdge.valueAt(MlenEdge.LastParameter) angle1 = edgeDir.getAngle(lineDir) angle = math.degrees(angle1) #print("1",angle) AngleList.append(angle) elif abs((MlenEdge.valueAt(MlenEdge.FirstParameter) - ed.valueAt(ed.FirstParameter)).Length) < smEpsilon: lineDir = ed.valueAt(ed.FirstParameter)- ed.valueAt(ed.LastParameter) edgeDir = MlenEdge.valueAt(MlenEdge.FirstParameter) - MlenEdge.valueAt(MlenEdge.LastParameter) angle1 = edgeDir.getAngle(lineDir) angle = math.degrees(angle1) #print("2",angle) AngleList.append(angle) Edgelist = Cface.ancestorsOfType(vertex1, Part.Edge) for ed in Edgelist : if not(MlenEdge.isSame(ed)): if abs((MlenEdge.valueAt(MlenEdge.LastParameter)- ed.valueAt(ed.FirstParameter)).Length) < smEpsilon: lineDir = ed.valueAt(ed.FirstParameter)- ed.valueAt(ed.LastParameter) edgeDir = MlenEdge.valueAt(MlenEdge.LastParameter) - MlenEdge.valueAt(MlenEdge.FirstParameter) angle1 = edgeDir.getAngle(lineDir) angle = math.degrees(angle1) #print("1",angle) AngleList.append(angle) elif abs((MlenEdge.valueAt(MlenEdge.LastParameter) - ed.valueAt(ed.LastParameter)).Length) < smEpsilon: lineDir = ed.valueAt(ed.LastParameter)- ed.valueAt(ed.FirstParameter) edgeDir = MlenEdge.valueAt(MlenEdge.LastParameter) - MlenEdge.valueAt(MlenEdge.FirstParameter) angle1 = edgeDir.getAngle(lineDir) angle = math.degrees(angle1) #print("2",angle) AngleList.append(angle) if AngleList : if AngleList[0] > 90.01 and gap1 == 0.0 : Agap1 = reliefW if AngleList[1] > 90.01 and gap2 == 0.0 : Agap2 = reliefW #make sure the direction verctor is correct in respect to the normal if (thkDir.cross(revAxisV).normalize() - FaceDir).Length < smEpsilon: revAxisV = revAxisV * -1 reliefDn = reliefD if inside : reliefDn = reliefD + abs(offset) # CutSolids list for collecting Solids CutSolids = [] # remove relief if needed if reliefD > 0.0 : if reliefW > 0.0 and ( gap1 > 0.0 or Agap1 > 0.0 ): reliefFace1 = smMakeReliefFace(MlenEdge, FaceDir* -1, gap1-reliefW, reliefW, reliefDn, reliefType) reliefSolid1 = reliefFace1.extrude(thkDir * thk) #Part.show(reliefSolid1) CutSolids.append(reliefSolid1) if reliefW > 0.0 and ( gap2 > 0.0 or Agap2 > 0.0 ): reliefFace2 = smMakeReliefFace(MlenEdge, FaceDir* -1, leng-gap2, reliefW, reliefDn, reliefType) reliefSolid2 = reliefFace2.extrude(thkDir * thk) #Part.show(reliefSolid2) CutSolids.append(reliefSolid2) # restrict angle if (bendA < 0): bendA = -bendA flipped = not flipped if not(flipped): revAxisP = lenEdge.valueAt(lenEdge.FirstParameter) + thkDir * (bendR + thk) revAxisV = revAxisV * -1 else: revAxisP = lenEdge.valueAt(lenEdge.FirstParameter) + thkDir * -bendR # remove bend face if present if inside : if gap1 == 0.0 or (reliefD == 0.0 and gap1 == 0.1) : Edgelist = selFace.ancestorsOfType(vertex0, Part.Edge) for ed in Edgelist : if not(MlenEdge.isSame(ed)): list1 = resultSolid.ancestorsOfType(ed, Part.Face) for Rface in list1 : if Rface.Area != selFace.Area and issubclass(type(Rface.Surface),Part.Plane) : for edge in Rface.Edges: if issubclass(type(edge.Curve),Part.Circle): RfaceE = Rface.extrude(Rface.normalAt(0,0) * -Noffset1 ) CutSolids.append(RfaceE) break if gap2 == 0.0 or (reliefD == 0.0 and gap2 == 0.1) : Edgelist = selFace.ancestorsOfType(vertex1, Part.Edge) for ed in Edgelist : if not(MlenEdge.isSame(ed)): list1 = resultSolid.ancestorsOfType(ed, Part.Face) for Rface in list1 : if Rface.Area != selFace.Area and issubclass(type(Rface.Surface),Part.Plane) : for edge in Rface.Edges: if issubclass(type(edge.Curve),Part.Circle): RfaceE = Rface.extrude(Rface.normalAt(0,0) * -Noffset2 ) CutSolids.append(RfaceE) break if reliefD == 0.0 and ( gap1 == 0.1 or gap2 == 0.1 ) : CutFace = smMakeFace(MlenEdge, thkDir, thk, 0, 0) else : CutFace = smMakeFace(MlenEdge, thkDir, thk, gap1, gap2) CutSolid = CutFace.extrude(FaceDir * offset ) CfaceSolid = Cface.extrude(thkDir * thk) CutSolid = CutSolid.common(CfaceSolid) CutSolids.append(CutSolid) # Produce Main Solid for Inside Bends if CutSolids : if len(CutSolids) == 1 : resultSolid = resultSolid.cut(CutSolids[0]) else : Solid = CutSolids[0].multiFuse(CutSolids[1:]) Solid.removeSplitter() #Part.show(Solid) resultSolid = resultSolid.cut(Solid) # Produce Offset Solid if offset > 0.0 : # create wall offset_face = smMakeFace(lenEdge, FaceDir, -offset) OffsetSolid = offset_face.extrude(thkDir * thk) resultSolid = resultSolid.fuse(OffsetSolid) #wallSolid = None if sketches : Wall_face = Part.makeFace(sketch.Shape.Wires, "Part::FaceMakerBullseye") if inside : Wall_face.translate(FaceDir * offset ) FaceAxisP = sketch_Edge.valueAt(sketch_Edge.FirstParameter) + thkDir * thk FaceAxisV = sketch_Edge.valueAt(sketch_Edge.FirstParameter) - sketch_Edge.valueAt(sketch_Edge.LastParameter) Wall_face.rotate(FaceAxisP, FaceAxisV, -90.0) wallSolid = Wall_face.extrude(thkDir * -thk) #Part.show(wallSolid) wallSolid.rotate(revAxisP, revAxisV, bendA) elif extLen > 0.0 : # create wall Wall_face = smMakeFace(lenEdge, FaceDir, extLen, gap1-extend1, gap2-extend2, miterA1List[i], miterA2List[i]) wallSolid = Wall_face.extrude(thkDir * thk) #Part.show(wallSolid) wallSolid.rotate(revAxisP, revAxisV, bendA) #Part.show(wallSolid.Faces[2]) thk_faceList.append(wallSolid.Faces[2]) # Produce bend Solid if not(unfold) : if bendA > 0.0 : # create bend # narrow the wall if we have gaps revFace = smMakeFace(lenEdge, thkDir, thk, gap1, gap2) if revFace.normalAt(0,0) != FaceDir : revFace.reverse() bendSolid = revFace.revolve(revAxisP, revAxisV, bendA) #Part.show(bendSolid) resultSolid = resultSolid.fuse(bendSolid) if wallSolid : resultSolid = resultSolid.fuse(wallSolid) # Produce unfold Solid else : if bendA > 0.0 : # create bend unfoldLength = ( bendR + kfactor * thk ) * bendA * math.pi / 180.0 # narrow the wall if we have gaps unfoldFace = smMakeFace(lenEdge, thkDir, thk, gap1, gap2) if unfoldFace.normalAt(0,0) != FaceDir : unfoldFace.reverse() unfoldSolid = unfoldFace.extrude(FaceDir * unfoldLength) #Part.show(unfoldSolid) resultSolid = resultSolid.fuse(unfoldSolid) if extLen > 0.0 : wallSolid.rotate(revAxisP, revAxisV, -bendA) #Part.show(wallSolid) wallSolid.translate(FaceDir * unfoldLength) resultSolid = resultSolid.fuse(wallSolid) #Gui.ActiveDocument.getObject(MainObject.Name).Visibility = False #if sketch : #Gui.ActiveDocument.getObject(sketch.Name).Visibility = False return resultSolid, thk_faceList
def doPlane(self, direction, pyWire, geom, firstParam, lastParam, scale, closed): '''doPlane(self, direction, pyWire, geom, firstParam, lastParam, scale, closed)''' # print '# doPlane' # print 'scale ', scale size = _Py.size width = size length = 2 * size # print 'size ', size # print 'width ', width # print 'length ', length leftScale = self.leftWidth * scale rightScale = self.rightWidth * scale upScale = self.length * scale # print 'leftScale ', leftScale # print 'rightScale ', rightScale # print 'upScale ', upScale if not upScale: # print 'up' upScale = 2 * size * scale if scale > 1: if self.leftWidth < width: # print 'left' leftScale = width * scale if self.rightWidth < width: # print 'right' rightScale = width * scale if self.length < length: # print 'length' upScale = length * scale # print 'leftScale ', leftScale # print 'rightScale ', rightScale # print 'upScale ', upScale # print 'firstParam ', firstParam # print 'lastParam ', lastParam if isinstance(geom, (Part.LineSegment, Part.ArcOfParabola)): # print 'a' startParam = firstParam - leftScale endParam = lastParam + rightScale elif isinstance(geom, (Part.ArcOfHyperbola)): # print 'b' startParam = firstParam endParam = lastParam elif isinstance(geom, (Part.ArcOfCircle, Part.ArcOfEllipse)): # print 'c' rear = self.rear if rear: # print 'reflex' if len(rear) == 1: # print 'c1' pyReflex = self.reflexedList[0] if rear[0] == pyReflex.rear[0]: # print 'c11' startParam = firstParam endParam = startParam + 2 * pi else: # print 'c12' startParam = lastParam endParam = startParam - 2 * pi else: # print 'c2' startParam = (2 * pi - (lastParam - firstParam)) / 2 + lastParam endParam = startParam + 2 * pi else: # print 'no reflex' dist = abs(lastParam - firstParam) # print 'dist ', dist if dist >= pi: # print '2pi o more' startParam = firstParam endParam = lastParam else: # print 'less 2pi' center = (lastParam - firstParam) / 2 + firstParam # print 'center ', center startParam = center - pi / 2 endParam = center + pi / 2 elif isinstance(geom, Part.BSplineCurve): # print 'd' pass # print 'startParam ', startParam # print 'endParam ', endParam extendGeom = self.makeGeom(geom, startParam, endParam) # print 'extendGeom ', extendGeom extendShape = extendGeom.toShape() if self.sweepCurve and not\ FreeCAD.ActiveDocument.getObject(self.sweepCurve).Shape.isNull(): # print 'A' angle = self.angle sweepSketch = FreeCAD.ActiveDocument.getObject(self.sweepCurve) wire = sweepSketch.Shape.copy() wire.Placement = FreeCAD.Placement() try: constraint = degrees(sweepSketch.Constraints[3].Value) except IndexError: constraint = 45 angleConstraint = constraint ang = angle - angleConstraint wire.rotate(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, 0, 1), ang) geomShape = self.geomShape ffPoint = geomShape.firstVertex(True).Point llPoint = geomShape.lastVertex(True).Point if ffPoint == llPoint: # print 'a' edge = _Py.slopedPlanes.Shape.Edges[1] aa = ffPoint bb = edge.firstVertex(True).Point direction = bb.sub(aa) else: # print 'b' direction = llPoint.sub(ffPoint) aa = direction.getAngle(FreeCAD.Vector(1, 0, 0)) + pi / 2 if ffPoint.y > llPoint.y: aa = aa + pi rotation = FreeCAD.Rotation() rotation.Axis = FreeCAD.Vector(1, 0, 0) rotation.Angle = pi / 2 wire.Placement.Rotation =\ rotation.multiply(wire.Placement.Rotation) if ffPoint == llPoint: # print 'aa' point = geom.Location numWire = self.numWire angleXU = geom.AngleXU # print 'angleXU ', angleXU rotation = FreeCAD.Rotation() rotation.Axis = FreeCAD.Vector(0, 0, 1) if numWire == 0: rotation.Angle = pi + angleXU else: rotation.Angle = angleXU wire.Placement.Rotation =\ rotation.multiply(wire.Placement.Rotation) wire.Placement.Base = ffPoint edge = wire.Edges[0] # print 'edge ', edge.Curve # print edge.firstVertex(True).Point # print edge.lastVertex(True).Point plane = edge.revolve(point, FreeCAD.Vector(0, 0, 1)) # print plane # print plane.Area if _Py.reverse: # print 'negative' plane = plane.mirror(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, 0, -1)) if isinstance(geom, Part.ArcOfEllipse): # print 'ellipse' major = geom.MajorRadius minor = geom.MinorRadius matrix = FreeCAD.Matrix() coef = minor / major matrix.scale(FreeCAD.Vector(1, coef, 1)) plane.translate(-1 * point) plane.rotate(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, 0, 1), -1 * degrees(angleXU)) plane = plane.transformGeometry(matrix) plane.rotate(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, 0, 1), degrees(angleXU)) plane.translate(point) plane = plane.Faces[0] else: # print 'bb' rotation = FreeCAD.Rotation() rotation.Axis = _Py.normal rotation.Angle = aa wire.Placement.Rotation =\ rotation.multiply(wire.Placement.Rotation) wire.Placement.Base = ffPoint extendShape = Part.Wire(extendShape) plane = wire.makePipeShell([extendShape]) else: # print 'B' if closed: # print 'B1' angle = self.angle # print 'angle ', angle point = geom.Location # print 'point ', point length = self.length # print 'length ', length # print 'geom' if isinstance(geom, Part.ArcOfEllipse): # print 'ellipse' major = geom.MajorRadius minor = geom.MinorRadius radius = major else: # print 'circle' radius = geom.Radius # print 'radius ', radius angle = abs(angle) % 360 # print 'angle ', angle if angle == 0: # print 'B11' slopedPlanes = _Py.slopedPlanes faceMaker = slopedPlanes.FaceMaker if pyWire.numWire == 0: plane = Part.makeFace(geom.toShape(), faceMaker) else: rr = radius + length circle = Part.makeCircle(rr) circle.translate(point) plane = Part.makeFace([extendShape, circle], faceMaker) elif angle == 90: # print 'B12' plane = Part.makeCylinder(radius, length, point) elif angle == 180: # print 'B13' slopedPlanes = _Py.slopedPlanes faceMaker = slopedPlanes.FaceMaker if pyWire.numWire > 0: # print 'B131' plane = Part.makeFace(extendShape, faceMaker) plane.translate(point) else: # print 'B132' rr = radius + length circle = Part.makeCircle(rr) circle.translate(point) plane = Part.makeFace([extendShape, circle], faceMaker) elif angle > 90: # print 'B14' radiusBottom = radius ang = angle - 90 # print 'ang ', ang if pyWire.numWire == 0: # print 'B141' radiusTop = radiusBottom + length * sin(radians(ang)) else: # print 'B142' ll = radius / cos(radians(ang)) # print 'll ', ll if ll <= length: radiusTop = 0 else: radiusTop = radiusBottom - length * sin(radians(ang)) height = length * cos(radians(ang)) # print 'radiusBottom ', radiusBottom # print 'radiusTop ', radiusTop # print 'height ', height plane = Part.makeCone(radiusBottom, radiusTop, height, point) # print plane.Placement else: # print 'B15' radiusBottom = radius ll = radius / cos(radians(angle)) # print 'll ', ll if ll <= length: # print 'B151' if pyWire.numWire == 0: # print 'B1511' height = radius * tan(radians(angle)) radiusTop = 0 else: # print 'B1512' height = length * sin(radians(angle)) radiusTop = radiusBottom + length * cos(radians(angle)) else: # print 'B152' if pyWire.numWire == 0: # print 'B1521' height = length * sin(radians(angle)) radiusTop = radiusBottom - length * cos(radians(angle)) else: # print 'B1522' height = radius * tan(radians(angle)) radiusTop = radiusBottom + length * cos(radians(angle)) # print 'radiusBottom ', radiusBottom # print 'radiusTop ', radiusTop # print 'height ', height plane = Part.makeCone(radiusBottom, radiusTop, height, point) # print plane.Placement if isinstance(geom, Part.ArcOfEllipse): # print 'ellipse' matrix = FreeCAD.Matrix() coef = minor / major matrix.scale(FreeCAD.Vector(1, coef, 1)) plane.translate(-1 * point) plane = plane.transformGeometry(matrix) plane.translate(point) if self.angle < 0 and _Py.reverse: pass elif self.angle < 0 or _Py.reverse: # print 'negative' plane = plane.mirror(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, 0, -1)) plane = plane.Faces[0] # print plane.Placement angleXU = geom.AngleXU # print 'angleXU ', angleXU plane.rotate(point, FreeCAD.Vector(0, 0, 1), degrees(angleXU)) # print plane.Placement else: # print 'B2' plane = extendShape.extrude(direction * upScale) return plane
def setup(doc=None, solvertype="ccxtools"): """ Nonlinear material example, plate with hole. https://forum.freecadweb.org/viewtopic.php?f=24&t=31997&start=30 https://forum.freecadweb.org/viewtopic.php?t=33974&start=90 https://forum.freecadweb.org/viewtopic.php?t=35893 plate: 400x200x10 mm hole: diameter 100 mm (half cross section) load: 130 MPa tension linear material: Steel, E = 210000 MPa, my = 0.3 nonlinear material: '240.0, 0.0' to '270.0, 0.025' TODO nonlinear material: give more information, use values from harry TODO compare results with example from HarryvL """ if doc is None: doc = init_doc() # part import Part from FreeCAD import Vector as vec from Part import makeLine as ln from Part import makeCircle as ci v1 = vec(-200, -100, 0) v2 = vec(200, -100, 0) v3 = vec(200, 100, 0) v4 = vec(-200, 100, 0) l1 = ln(v1, v2) l2 = ln(v2, v3) l3 = ln(v3, v4) l4 = ln(v4, v1) v5 = vec(0, 0, 0) c1 = ci(50, v5) face = Part.makeFace([Part.Wire([l1, l2, l3, l4]), c1], "Part::FaceMakerBullseye") partfem = doc.addObject("Part::Feature", "Hole_Plate") partfem.Shape = face.extrude(vec(0, 0, 10)) doc.recompute() if FreeCAD.GuiUp: import FreeCADGui FreeCADGui.ActiveDocument.activeView().viewAxonometric() FreeCADGui.SendMsgToActiveView("ViewFit") # analysis analysis = ObjectsFem.makeAnalysis(doc, "Analysis") # solver if solvertype == "calculix": solver = analysis.addObject( ObjectsFem.makeSolverCalculix(doc, "SolverCalculiX"))[0] elif solvertype == "ccxtools": solver = analysis.addObject( ObjectsFem.makeSolverCalculixCcxTools(doc, "CalculiXccxTools"))[0] solver.WorkingDir = u"" if solvertype == "calculix" or solvertype == "ccxtools": solver.SplitInputWriter = False solver.AnalysisType = "static" solver.GeometricalNonlinearity = "linear" solver.ThermoMechSteadyState = False solver.MatrixSolverType = "default" solver.IterationsControlParameterTimeUse = False solver.GeometricalNonlinearity = 'nonlinear' solver.MaterialNonlinearity = 'nonlinear' # linear material matprop = {} matprop["Name"] = "CalculiX-Steel" matprop["YoungsModulus"] = "210000 MPa" matprop["PoissonRatio"] = "0.30" matprop["Density"] = "7900 kg/m^3" material = analysis.addObject( ObjectsFem.makeMaterialSolid(doc, "Material_lin"))[0] material.Material = matprop # nonlinear material nonlinear_material = analysis.addObject( ObjectsFem.makeMaterialMechanicalNonlinear(doc, material, "Material_nonlin"))[0] nonlinear_material.YieldPoint1 = '240.0, 0.0' nonlinear_material.YieldPoint2 = '270.0, 0.025' # check solver attributes, Nonlinearity needs to be set to nonlinear # fixed_constraint fixed_constraint = analysis.addObject( ObjectsFem.makeConstraintFixed(doc, "ConstraintFixed"))[0] fixed_constraint.References = [(partfem, "Face4")] # force constraint pressure_constraint = doc.Analysis.addObject( ObjectsFem.makeConstraintPressure(doc, "ConstraintPressure"))[0] pressure_constraint.References = [(partfem, "Face2")] pressure_constraint.Pressure = 130.0 pressure_constraint.Reversed = True # mesh from .meshes.mesh_platewithhole_tetra10 import create_nodes, create_elements fem_mesh = Fem.FemMesh() control = create_nodes(fem_mesh) if not control: FreeCAD.Console.PrintError("Error on creating nodes.\n") control = create_elements(fem_mesh) if not control: FreeCAD.Console.PrintError("Error on creating elements.\n") femmesh_obj = analysis.addObject( doc.addObject("Fem::FemMeshObject", mesh_name))[0] femmesh_obj.FemMesh = fem_mesh doc.recompute() return doc
def execute(self, obj): "creates the panel shape" if self.clone(obj): return import Part, DraftGeomUtils # base tests if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.isNull(): return elif obj.Base.isDerivedFrom("Mesh::Feature"): if not obj.Base.Mesh.isSolid(): return else: if obj.Length.Value: length = obj.Length.Value else: return if obj.Width.Value: width = obj.Width.Value else: return if obj.Thickness.Value: thickness = obj.Thickness.Value else: if not obj.Base: return elif obj.Base.isDerivedFrom("Part::Feature"): if not obj.Base.Shape.Solids: return # creating base shape pl = obj.Placement base = None normal = None if hasattr(obj, "Normal"): if obj.Normal.Length > 0: normal = Vector(obj.Normal) normal.normalize() normal.multiply(thickness) baseprofile = None if obj.Base: base = obj.Base.Shape.copy() if not base.Solids: p = FreeCAD.Placement(obj.Base.Placement) if base.Faces: baseprofile = base if not normal: normal = baseprofile.Faces[0].normalAt( 0, 0).multiply(thickness) base = base.extrude(normal) elif base.Wires: fm = False if hasattr(obj, "FaceMaker"): if obj.FaceMaker != "None": try: base = Part.makeFace( base.Wires, "Part::FaceMaker" + str(obj.FaceMaker)) fm = True except: FreeCAD.Console.PrintError( translate("Arch", "Facemaker returned an error") + "\n") return if not fm: closed = True for w in base.Wires: if not w.isClosed(): closed = False if closed: baseprofile = ArchCommands.makeFace(base.Wires) if not normal: normal = baseprofile.normalAt( 0, 0).multiply(thickness) base = baseprofile.extrude(normal) elif obj.Base.isDerivedFrom("Mesh::Feature"): if obj.Base.Mesh.isSolid(): if obj.Base.Mesh.countComponents() == 1: sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh) if sh.isClosed() and sh.isValid() and sh.Solids: base = sh else: if not normal: normal = Vector(0, 0, 1).multiply(thickness) 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.makePolygon([v1, v2, v3, v4, v1]) baseprofile = Part.Face(base) base = baseprofile.extrude(normal) if hasattr(obj, "Area"): if baseprofile: obj.Area = baseprofile.Area if hasattr(obj, "WaveLength"): if baseprofile and obj.WaveLength.Value and obj.WaveHeight.Value: # corrugated element bb = baseprofile.BoundBox bb.enlarge(bb.DiagonalLength) p1 = Vector(bb.getPoint(0).x, bb.getPoint(0).y, bb.Center.z) if obj.WaveType == "Curved": p2 = p1.add( Vector(obj.WaveLength.Value / 2, 0, obj.WaveHeight.Value)) p3 = p2.add( Vector(obj.WaveLength.Value / 2, 0, -obj.WaveHeight.Value)) e1 = Part.Arc(p1, p2, p3).toShape() p4 = p3.add( Vector(obj.WaveLength.Value / 2, 0, -obj.WaveHeight.Value)) p5 = p4.add( Vector(obj.WaveLength.Value / 2, 0, obj.WaveHeight.Value)) e2 = Part.Arc(p3, p4, p5).toShape() else: if obj.WaveHeight.Value < obj.WaveLength.Value: p2 = p1.add( Vector(obj.WaveHeight.Value, 0, obj.WaveHeight.Value)) p3 = p2.add( Vector( obj.WaveLength.Value - 2 * obj.WaveHeight.Value, 0, 0)) p4 = p3.add( Vector(obj.WaveHeight.Value, 0, -obj.WaveHeight.Value)) e1 = Part.makePolygon([p1, p2, p3, p4]) p5 = p4.add( Vector(obj.WaveHeight.Value, 0, -obj.WaveHeight.Value)) p6 = p5.add( Vector( obj.WaveLength.Value - 2 * obj.WaveHeight.Value, 0, 0)) p7 = p6.add( Vector(obj.WaveHeight.Value, 0, obj.WaveHeight.Value)) e2 = Part.makePolygon([p4, p5, p6, p7]) else: p2 = p1.add( Vector(obj.WaveLength.Value / 2, 0, obj.WaveHeight.Value)) p3 = p2.add( Vector(obj.WaveLength.Value / 2, 0, -obj.WaveHeight.Value)) e1 = Part.makePolygon([p1, p2, p3]) p4 = p3.add( Vector(obj.WaveLength.Value / 2, 0, -obj.WaveHeight.Value)) p5 = p4.add( Vector(obj.WaveLength.Value / 2, 0, obj.WaveHeight.Value)) e2 = Part.makePolygon([p3, p4, p5]) edges = [e1, e2] for i in range(int(bb.XLength / (obj.WaveLength.Value * 2))): e1 = e1.copy() e1.translate(Vector(obj.WaveLength.Value * 2, 0, 0)) e2 = e2.copy() e2.translate(Vector(obj.WaveLength.Value * 2, 0, 0)) edges.extend([e1, e2]) basewire = Part.Wire(edges) baseface = basewire.extrude(Vector(0, bb.YLength, 0)) base = baseface.extrude(Vector(0, 0, thickness)) rot = FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), normal) base.rotate(bb.Center, rot.Axis, math.degrees(rot.Angle)) if obj.WaveDirection.Value: base.rotate(bb.Center, normal, obj.WaveDirection.Value) n1 = normal.negative().normalize().multiply( obj.WaveHeight.Value * 2) self.vol = baseprofile.copy() self.vol.translate(n1) self.vol = self.vol.extrude(n1.negative().multiply(2)) base = self.vol.common(base) base = base.removeSplitter() if not base: FreeCAD.Console.PrintError( transpate("Arch", "Error computing shape of ") + obj.Label + "\n") return False if base and (obj.Sheets > 1) and normal and thickness: bases = [base] for i in range(1, obj.Sheets): n = FreeCAD.Vector(normal).normalize().multiply(i * thickness) b = base.copy() b.translate(n) bases.append(b) base = Part.makeCompound(bases) if base and normal and hasattr(obj, "Offset"): if obj.Offset.Value: v = DraftVecUtils.scaleTo(normal, obj.Offset.Value) base.translate(v) # process subshapes base = self.processSubShapes(obj, base, pl) # applying if base: if not base.isNull(): if base.isValid() and base.Solids: if base.Volume < 0: base.reverse() if base.Volume < 0: FreeCAD.Console.PrintError( translate("Arch", "Couldn't compute a shape")) return base = base.removeSplitter() obj.Shape = base if not pl.isNull(): obj.Placement = pl
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... return shapes representing the solids to be removed.''' PathLog.track() subObjTups = [] removalshapes = [] if obj.Base: PathLog.debug("base items exist. Processing... ") for base in obj.Base: PathLog.debug("obj.Base item: {}".format(base)) # Check if all subs are faces allSubsFaceType = True Faces = [] for sub in base[1]: if "Face" in sub: face = getattr(base[0].Shape, sub) Faces.append(face) subObjTups.append((sub, face)) else: allSubsFaceType = False break if len(Faces) == 0: allSubsFaceType = False if allSubsFaceType is True and obj.HandleMultipleFeatures == 'Collectively': if obj.OpFinalDepth == obj.FinalDepth: (fzmin, fzmax) = self.getMinMaxOfFaces(Faces) obj.FinalDepth.Value = fzmin finish_step = obj.FinishDepth.Value if hasattr( obj, "FinishDepth") else 0.0 self.depthparams = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=fzmin, user_depths=None) PathLog.info( "Updated obj.FinalDepth.Value and self.depthparams to zmin: {}" .format(fzmin)) if obj.AdaptivePocketStart is True or obj.AdaptivePocketFinish is True: pocketTup = self.calculateAdaptivePocket( obj, base, subObjTups) if pocketTup is not False: removalshapes.append( pocketTup ) # (shape, isHole, sub, angle, axis, strDep, finDep) else: strDep = obj.StartDepth.Value finDep = obj.FinalDepth.Value shape = Part.makeCompound(Faces) env = PathUtils.getEnvelope( base[0].Shape, subshape=shape, depthparams=self.depthparams) obj.removalshape = env.cut(base[0].Shape) obj.removalshape.tessellate(0.1) # (shape, isHole, sub, angle, axis, strDep, finDep) removalshapes.append( (obj.removalshape, False, '3DPocket', 0.0, 'X', strDep, finDep)) else: for sub in base[1]: if "Face" in sub: shape = Part.makeCompound( [getattr(base[0].Shape, sub)]) else: edges = [ getattr(base[0].Shape, sub) for sub in base[1] ] shape = Part.makeFace(edges, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope( base[0].Shape, subshape=shape, depthparams=self.depthparams) obj.removalshape = env.cut(base[0].Shape) obj.removalshape.tessellate(0.1) removalshapes.append((obj.removalshape, False)) else: # process the job base object as a whole PathLog.debug("processing the whole job base object") strDep = obj.StartDepth.Value finDep = obj.FinalDepth.Value recomputeDepthparams = False for base in self.model: if obj.OpFinalDepth == obj.FinalDepth: if base.Shape.BoundBox.ZMin < obj.FinalDepth.Value: obj.FinalDepth.Value = base.Shape.BoundBox.ZMin finDep = base.Shape.BoundBox.ZMin recomputeDepthparams = True PathLog.info( "Updated obj.FinalDepth.Value to {}".format( finDep)) if obj.OpStartDepth == obj.StartDepth: if base.Shape.BoundBox.ZMax > obj.StartDepth.Value: obj.StartDepth.Value = base.Shape.BoundBox.ZMax finDep = base.Shape.BoundBox.ZMax recomputeDepthparams = True PathLog.info( "Updated obj.StartDepth.Value to {}".format( strDep)) if recomputeDepthparams is True: finish_step = obj.FinishDepth.Value if hasattr( obj, "FinishDepth") else 0.0 self.depthparams = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=obj.FinalDepth.Value, user_depths=None) recomputeDepthparams = False if obj.ProcessStockArea is True: job = PathUtils.findParentJob(obj) finish_step = obj.FinishDepth.Value if hasattr( obj, "FinishDepth") else 0.0 depthparams = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=base.Shape.BoundBox.ZMin, user_depths=None) stockEnvShape = PathUtils.getEnvelope( job.Stock.Shape, subshape=None, depthparams=depthparams) obj.removalshape = stockEnvShape.cut(base.Shape) obj.removalshape.tessellate(0.1) else: env = PathUtils.getEnvelope(base.Shape, subshape=None, depthparams=self.depthparams) obj.removalshape = env.cut(base.Shape) obj.removalshape.tessellate(0.1) removalshapes.append((obj.removalshape, False, '3DPocket', 0.0, 'X', strDep, finDep)) return removalshapes
def execute(self, obj, getsim=False): import Part if not obj.Active: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False return self.depthparams = depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=0.0, final_depth=obj.FinalDepth.Value, user_depths=None) commandlist = [] 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 commandlist.append(Path.Command("(" + obj.Label + ")")) if obj.UseComp: commandlist.append(Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: commandlist.append(Path.Command("(Uncompensated Tool Path)")) parentJob = PathUtils.findParentJob(obj) if parentJob is None: return baseobject = parentJob.Base if baseobject is None: return if obj.Base: # The user has selected subobjects from the base. Process each. 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: FreeCAD.Console.PrintWarning("found a base object which is not a face. Can't continue.") return for wire in holes: f = Part.makeFace(wire, 'Part::FaceMakerSimple') drillable = PathUtils.isDrillable(baseobject.Shape, wire) if (drillable and obj.processCircles) or (not drillable and obj.processHoles): env = PathUtils.getEnvelope(baseobject.Shape, subshape=f, depthparams=self.depthparams) try: (pp, sim) = self._buildPathArea(obj, baseobject=env, isHole=True, start=None, getsim=getsim) commandlist.extend(pp.Commands) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") if len(faces) > 0: profileshape = Part.makeCompound(faces) if obj.processPerimeter: env = PathUtils.getEnvelope(baseobject.Shape, subshape=profileshape, depthparams=self.depthparams) try: (pp, sim) = self._buildPathArea(obj, baseobject=env, start=None, getsim=getsim) commandlist.extend(pp.Commands) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") else: # Try to build targets from the job base 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: f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope(baseobject.Shape, subshape=f, depthparams=self.depthparams) try: (pp, sim) = self._buildPathArea(obj, baseobject=env, isHole=False, start=None, getsim=getsim) commandlist.extend(pp.Commands) except Exception as e: FreeCAD.Console.PrintError(e) 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): f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope(baseobject.Shape, subshape=f, depthparams=self.depthparams) try: (pp, sim) = self._buildPathArea(obj, baseobject=env, isHole=True, start=None, getsim=getsim) commandlist.extend(pp.Commands) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") # Let's finish by rapid to clearance...just for safety commandlist.append(Path.Command("G0", {"Z": obj.ClearanceHeight.Value})) path = Path.Path(commandlist) obj.Path = path
def smSketchOnSheetMetal(kfactor = 0.5, sketch = '', flipped = False, selFaceNames = '', MainObject = None): resultSolid = MainObject.Shape.copy() selElement = resultSolid.getElement(selFaceNames[0]) LargeFace = smFace(selElement, resultSolid) sketch_face = Part.makeFace(sketch.Shape.Wires,"Part::FaceMakerBullseye") #To get thk of sheet, top face normal thk = smthk(resultSolid, LargeFace) #print(thk) #To get top face normal, flatsolid solidlist = [] normal = LargeFace.normalAt(0,0) #To check face direction coeff = normal.dot(sketch_face.Faces[0].normalAt(0,0)) if coeff < 0 : sketch_face.reverse() Flatface = sketch_face.common(LargeFace) BalanceFaces = sketch_face.cut(Flatface) #Part.show(BalanceFace,"BalanceFace") Flatsolid = Flatface.extrude(normal * -thk) #Part.show(Flatsolid,"Flatsolid") solidlist.append(Flatsolid) if BalanceFaces.Faces : for BalanceFace in BalanceFaces.Faces : #Part.show(BalanceFace,"BalanceFace") TopFace = LargeFace #Part.show(TopFace,"TopFace") #flipped = False while BalanceFace.Faces : BendEdge = smGetEdge(BalanceFace, TopFace) #Part.show(BendEdge,"BendEdge") facelist = resultSolid.ancestorsOfType(BendEdge, Part.Face) #To get bend radius, bend angle for cylface in facelist : if issubclass(type(cylface.Surface),Part.Cylinder) : break if not(issubclass(type(cylface.Surface),Part.Cylinder)) : break #Part.show(cylface,"cylface") for planeface in facelist : if issubclass(type(planeface.Surface),Part.Plane) : break #Part.show(planeface,"planeface") normal = planeface.normalAt(0,0) revAxisV = cylface.Surface.Axis revAxisP = cylface.Surface.Center bendA = bendAngle(cylface, revAxisP) #print([bendA, revAxisV, revAxisP, cylface.Orientation]) #To check bend direction offsetface = cylface.makeOffsetShape(-thk, 0.0, fill = False) #Part.show(offsetface,"offsetface") if offsetface.Area < cylface.Area : bendR = cylface.Surface.Radius - thk flipped = True else : bendR = cylface.Surface.Radius flipped = False #To arrive unfold Length, neturalRadius unfoldLength = ( bendR + kfactor * thk ) * abs(bendA) * math.pi / 180.0 neturalRadius = ( bendR + kfactor * thk ) #print([unfoldLength,neturalRadius]) #To get faceNormal, bend face faceNormal = normal.cross(revAxisV).normalize() #print(faceNormal) if bendR < cylface.Surface.Radius : offsetSolid = cylface.makeOffsetShape(bendR/2.0, 0.0, fill = True) else: offsetSolid = cylface.makeOffsetShape(-bendR/2.0, 0.0, fill = True) #Part.show(offsetSolid,"offsetSolid") tool = BendEdge.copy() FaceArea = tool.extrude(faceNormal * -unfoldLength ) #Part.show(FaceArea,"FaceArea") #Part.show(BalanceFace,"BalanceFace") SolidFace = offsetSolid.common(FaceArea) #Part.show(BendSolidFace,"BendSolidFace") if not(SolidFace.Faces): faceNormal = faceNormal * -1 FaceArea = tool.extrude(faceNormal * -unfoldLength ) BendSolidFace = BalanceFace.common(FaceArea) #Part.show(FaceArea,"FaceArea") #Part.show(BendSolidFace,"BendSolidFace") #print([bendR, bendA, revAxisV, revAxisP, normal, flipped, BendSolidFace.Faces[0].normalAt(0,0)]) bendsolid = SheetMetalBendSolid.BendSolid(BendSolidFace.Faces[0], BendEdge, bendR, thk, neturalRadius, revAxisV, flipped) #Part.show(bendsolid,"bendsolid") solidlist.append(bendsolid) if flipped == True: bendA = -bendA if not(SolidFace.Faces): revAxisV = revAxisV * -1 sketch_face = BalanceFace.cut(BendSolidFace) sketch_face.translate(faceNormal * unfoldLength) #Part.show(sketch_face,"sketch_face") sketch_face.rotate(revAxisP, -revAxisV, bendA) #Part.show(sketch_face,"Rsketch_face") TopFace = smCutFace(sketch_face, resultSolid) #Part.show(TopFace,"TopFace") #To get top face normal, flatsolid normal = TopFace.normalAt(0,0) Flatface = sketch_face.common(TopFace) BalanceFace = sketch_face.cut(Flatface) #Part.show(BalanceFace,"BalanceFace") Flatsolid = Flatface.extrude(normal * -thk) #Part.show(Flatsolid,"Flatsolid") solidlist.append(Flatsolid) #To get relief Solid fused if len(solidlist) > 1 : SMSolid = solidlist[0].multiFuse(solidlist[1:]) #Part.show(SMSolid,"SMSolid") SMSolid = SMSolid.removeSplitter() else : SMSolid = solidlist[0] #Part.show(SMSolid,"SMSolid") resultSolid = resultSolid.cut(SMSolid) Gui.ActiveDocument.getObject(MainObject.Name).Visibility = False Gui.ActiveDocument.getObject(sketch.Name).Visibility = False return resultSolid
def getExtrusionData(self,obj): """returns (shape,extrusion vector,placement) or None""" import Part,DraftGeomUtils data = ArchComponent.Component.getExtrusionData(self,obj) if data: return data length = obj.Length.Value width = obj.Width.Value height = obj.Height.Value normal = None if not height: for p in obj.InList: if Draft.getType(p) == "Floor": if p.Height.Value: height = p.Height.Value base = None placement = None if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape: if obj.Base.Shape.Solids: return None elif obj.Base.Shape.Faces: if not DraftGeomUtils.isCoplanar(obj.Base.Shape.Faces): return None else: base,placement = self.rebase(obj.Base.Shape) normal = obj.Base.Shape.Faces[0].normalAt(0,0) elif obj.Base.Shape.Wires: baseface = None if hasattr(obj,"FaceMaker"): if obj.FaceMaker != "None": try: baseface = Part.makeFace(obj.Base.Shape.Wires,"Part::FaceMaker"+str(obj.FaceMaker)) except: FreeCAD.Console.PrintError(translate("Arch","Facemaker returned an error")+"\n") return None if len(baseface.Faces) > 1: baseface = baseface.Faces[0] normal = baseface.normalAt(0,0) if not baseface: for w in obj.Base.Shape.Wires: w.fix(0.1,0,1) # fixes self-intersecting wires f = Part.Face(w) if baseface: baseface = baseface.fuse(f) else: baseface = f normal = f.normalAt(0,0) base,placement = self.rebase(baseface) elif (len(obj.Base.Shape.Edges) == 1) and (len(obj.Base.Shape.Vertexes) == 1): # closed edge w = Part.Wire(obj.Base.Shape.Edges[0]) baseface = Part.Face(w) base,placement = self.rebase(baseface) elif length and width and height: if (length > height) and (obj.Role != "Slab"): h2 = height/2 or 0.5 w2 = width/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 = 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) import Part baseface = Part.Face(Part.makePolygon([v1,v2,v3,v4,v1])) base,placement = self.rebase(baseface) if base and placement: if obj.Normal == Vector(0,0,0): if not normal: normal = Vector(0,0,1) else: normal = Vector(obj.Normal) if (length > height) and (obj.Role != "Slab"): extrusion = normal.multiply(length) else: extrusion = normal.multiply(height) return (base,extrusion,placement) return None
def setup(doc=None, solvertype="ccxtools"): # setup model if doc is None: doc = init_doc() # geometry objects v1 = vec(-200, -100, 0) v2 = vec(200, -100, 0) v3 = vec(200, 100, 0) v4 = vec(-200, 100, 0) l1 = ln(v1, v2) l2 = ln(v2, v3) l3 = ln(v3, v4) l4 = ln(v4, v1) v5 = vec(0, 0, 0) c1 = ci(50, v5) face = Part.makeFace([Part.Wire([l1, l2, l3, l4]), c1], "Part::FaceMakerBullseye") geom_obj = doc.addObject("Part::Feature", "Hole_Plate") geom_obj.Shape = face.extrude(vec(0, 0, 10)) doc.recompute() if FreeCAD.GuiUp: geom_obj.ViewObject.Document.activeView().viewAxonometric() geom_obj.ViewObject.Document.activeView().fitAll() # analysis analysis = ObjectsFem.makeAnalysis(doc, "Analysis") # solver if solvertype == "calculix": solver = analysis.addObject( ObjectsFem.makeSolverCalculix(doc, "SolverCalculiX"))[0] elif solvertype == "ccxtools": solver = analysis.addObject( ObjectsFem.makeSolverCalculixCcxTools(doc, "CalculiXccxTools"))[0] solver.WorkingDir = u"" if solvertype == "calculix" or solvertype == "ccxtools": solver.SplitInputWriter = False solver.AnalysisType = "static" solver.GeometricalNonlinearity = "linear" solver.ThermoMechSteadyState = False solver.MatrixSolverType = "default" solver.IterationsControlParameterTimeUse = False solver.GeometricalNonlinearity = 'nonlinear' solver.MaterialNonlinearity = 'nonlinear' # linear material matprop = {} matprop["Name"] = "CalculiX-Steel" matprop["YoungsModulus"] = "210000 MPa" matprop["PoissonRatio"] = "0.30" matprop["Density"] = "7900 kg/m^3" material = analysis.addObject( ObjectsFem.makeMaterialSolid(doc, "Material_lin"))[0] material.Material = matprop # nonlinear material nonlinear_material = analysis.addObject( ObjectsFem.makeMaterialMechanicalNonlinear(doc, material, "Material_nonlin"))[0] nonlinear_material.YieldPoint1 = '240.0, 0.0' nonlinear_material.YieldPoint2 = '270.0, 0.025' # check solver attributes, Nonlinearity needs to be set to nonlinear # fixed_constraint fixed_constraint = analysis.addObject( ObjectsFem.makeConstraintFixed(doc, "ConstraintFixed"))[0] fixed_constraint.References = [(geom_obj, "Face4")] # force constraint pressure_constraint = doc.Analysis.addObject( ObjectsFem.makeConstraintPressure(doc, "ConstraintPressure"))[0] pressure_constraint.References = [(geom_obj, "Face2")] pressure_constraint.Pressure = 130.0 pressure_constraint.Reversed = True # mesh from .meshes.mesh_platewithhole_tetra10 import create_nodes, create_elements fem_mesh = Fem.FemMesh() control = create_nodes(fem_mesh) if not control: FreeCAD.Console.PrintError("Error on creating nodes.\n") control = create_elements(fem_mesh) if not control: FreeCAD.Console.PrintError("Error on creating elements.\n") femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, mesh_name))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Part = geom_obj femmesh_obj.SecondOrderLinear = False doc.recompute() return doc
def makeFace(self, fp): if fp.Face and len(fp.Shape.Wires) > 0: face = Part.makeFace(fp.Shape.Wires, "Part::FaceMakerSimple") fp.Shape = face
def smBend(bendR = 1.0, bendA = 90.0, miterA1 = 0.0,miterA2 = 0.0, BendType = "Material Outside", flipped = False, unfold = False, offset = 0.0, extLen = 10.0, gap1 = 0.0, gap2 = 0.0, reliefType = "Rectangle", reliefW = 0.8, reliefD = 1.0, extend1 = 0.0, extend2 = 0.0, kfactor = 0.45, ReliefFactor = 0.7, UseReliefFactor = False, selFaceNames = '', MainObject = None, automiter = True, sketch = None ): # if sketch is as wall sketches = False if sketch : if sketch.Shape.Wires[0].isClosed() : sketches = True else : pass if not(sketches) : miterA1List1, miterA2List1, gap1List1, gap2List1, reliefDList1, wallsolid_common_list1 = smMiter(bendR = bendR, bendA = bendA, miterA1 = miterA1, miterA2 = miterA2, flipped = flipped, extLen = extLen, gap1 = gap1, sign = 1.0, offset = offset, gap2 = gap2, reliefD = reliefD, selFaceNames = selFaceNames, automiter = automiter, MainObject = MainObject) bendAflip = (bendA - 180) miterA1List2, miterA2List2, gap1List2, gap2List2, reliefDList2, wallsolid_common_list2 = smMiter(bendR = bendR, bendA = bendAflip, miterA1 = miterA1, miterA2 = miterA2, flipped = flipped, extLen = extLen, gap1 = gap1, sign = -1.0, offset = offset, gap2 = gap2, reliefD = reliefD, selFaceNames = selFaceNames, automiter = automiter, MainObject = MainObject) miterA1List = [x if a > b else y for x, y, a, b in zip(miterA1List1, miterA1List2, wallsolid_common_list1, wallsolid_common_list2)] miterA2List = [x if a > b else y for x, y, a, b in zip(miterA2List1, miterA2List2, wallsolid_common_list1, wallsolid_common_list2)] gap1List = [x + y for x, y in zip(gap1List1, gap1List2)] gap2List = [x + y for x, y in zip(gap2List1, gap2List2)] reliefDList = [min(x , y) for x, y in zip(reliefDList1, reliefDList2)] else : miterA1List, miterA2List, gap1List, gap2List, reliefDList = ( [0.0],[0.0],[gap1],[gap2],[reliefD]) thk_faceList = [] resultSolid = MainObject for i, selFaceName in enumerate(selFaceNames): selItem = MainObject.getElement(selFaceName) selFace = smFace(selItem, MainObject) selFace = smModifiedFace(selFace, resultSolid) gap1, gap2 = (gap1List[i], gap2List[i]) reliefD = reliefDList[i] # find the narrow edge thk = 999999.0 for edge in selFace.Edges: if abs( edge.Length ) < thk: thk = abs( edge.Length ) thkEdge = edge # Add as offset to set any distance if UseReliefFactor : reliefW = thk * ReliefFactor reliefD = thk * ReliefFactor # Add Relief factor if BendType == "Material Outside" : offset = 0.0 inside = False elif BendType == "Material Inside" : offset = -(thk + bendR) inside = True elif BendType == "Thickness Outside" : offset = -bendR inside = True elif BendType == "Offset" : if offset < 0.0 : inside = True else : inside = False # find a length edge = revolve axis direction p0 = thkEdge.valueAt(thkEdge.FirstParameter) for lenEdge in selFace.Edges: p1 = lenEdge.valueAt(lenEdge.FirstParameter) p2 = lenEdge.valueAt(lenEdge.LastParameter) if lenEdge.isSame(thkEdge): continue if (p1 - p0).Length < smEpsilon: revAxisV = p2 - p1 break if (p2 - p0).Length < smEpsilon: revAxisV = p1 - p2 break # find the large face connected with selected face list2 = resultSolid.ancestorsOfType(lenEdge, Part.Face) for Cface in list2 : if not(Cface.isSame(selFace)) : break # Produce Offset Edge if offset > 0.0 : lenEdge.translate(selFace.normalAt(0,0) * offset) # main Length Edge MlenEdge = lenEdge leng = MlenEdge.Length revAxisV.normalize() thkDir = Cface.normalAt(0,0) * -1 FaceDir = selFace.normalAt(0,0) # Get correct size inside face if inside : e1 = MlenEdge.copy() e1.translate(FaceDir * offset) EdgeShape = e1.common(Cface) lenEdge = EdgeShape.Edges[0] Noffset1 = abs((MlenEdge.valueAt(MlenEdge.FirstParameter)-lenEdge.valueAt(lenEdge.FirstParameter)).Length) Noffset2 = abs((MlenEdge.valueAt(MlenEdge.LastParameter)-lenEdge.valueAt(lenEdge.LastParameter)).Length) # if sketch is as wall sketches = False if sketch : if sketch.Shape.Wires[0].isClosed() : sketches = True else : pass if sketches : sketch_face = Part.makeFace(sketch.Shape.Wires, "Part::FaceMakerBullseye") sketch_face.translate(thkDir * -thk ) if inside : sketch_face.translate(FaceDir * offset ) sketch_Shape = lenEdge.common(sketch_face) sketch_Edge = sketch_Shape.Edges[0] gap1 = (lenEdge.valueAt(lenEdge.FirstParameter) - sketch_Edge.valueAt(sketch_Edge.FirstParameter)).Length gap2 = (lenEdge.valueAt(lenEdge.LastParameter) - sketch_Edge.valueAt(sketch_Edge.LastParameter)).Length # Get angles of adjcent face Agap1 = 0.0 Agap2 = 0.0 if inside : AngleList =[] if MlenEdge.Vertexes[0].Orientation == "Reversed" : vertex1 = MlenEdge.Vertexes[0] vertex0 = MlenEdge.Vertexes[1] else : vertex0 = MlenEdge.Vertexes[0] vertex1 = MlenEdge.Vertexes[1] Edgelist = Cface.ancestorsOfType(vertex0, Part.Edge) for ed in Edgelist : if not(MlenEdge.isSame(ed)): #Part.show(ed) if abs((MlenEdge.valueAt(MlenEdge.FirstParameter)- ed.valueAt(ed.LastParameter)).Length) < smEpsilon: lineDir = ed.valueAt(ed.LastParameter)- ed.valueAt(ed.FirstParameter) edgeDir = MlenEdge.valueAt(MlenEdge.FirstParameter) - MlenEdge.valueAt(MlenEdge.LastParameter) angle1 = edgeDir.getAngle(lineDir) angle = math.degrees(angle1) #print("1",angle) AngleList.append(angle) elif abs((MlenEdge.valueAt(MlenEdge.FirstParameter) - ed.valueAt(ed.FirstParameter)).Length) < smEpsilon: lineDir = ed.valueAt(ed.FirstParameter)- ed.valueAt(ed.LastParameter) edgeDir = MlenEdge.valueAt(MlenEdge.FirstParameter) - MlenEdge.valueAt(MlenEdge.LastParameter) angle1 = edgeDir.getAngle(lineDir) angle = math.degrees(angle1) #print("2",angle) AngleList.append(angle) Edgelist = Cface.ancestorsOfType(vertex1, Part.Edge) for ed in Edgelist : if not(MlenEdge.isSame(ed)): if abs((MlenEdge.valueAt(MlenEdge.LastParameter)- ed.valueAt(ed.FirstParameter)).Length) < smEpsilon: lineDir = ed.valueAt(ed.FirstParameter)- ed.valueAt(ed.LastParameter) edgeDir = MlenEdge.valueAt(MlenEdge.LastParameter) - MlenEdge.valueAt(MlenEdge.FirstParameter) angle1 = edgeDir.getAngle(lineDir) angle = math.degrees(angle1) #print("1",angle) AngleList.append(angle) elif abs((MlenEdge.valueAt(MlenEdge.LastParameter) - ed.valueAt(ed.LastParameter)).Length) < smEpsilon: lineDir = ed.valueAt(ed.LastParameter)- ed.valueAt(ed.FirstParameter) edgeDir = MlenEdge.valueAt(MlenEdge.LastParameter) - MlenEdge.valueAt(MlenEdge.FirstParameter) angle1 = edgeDir.getAngle(lineDir) angle = math.degrees(angle1) #print("2",angle) AngleList.append(angle) if AngleList : if AngleList[0] > 90.01 and gap1 == 0.0 : Agap1 = reliefW if AngleList[1] > 90.01 and gap2 == 0.0 : Agap2 = reliefW #make sure the direction verctor is correct in respect to the normal if (thkDir.cross(revAxisV).normalize() - FaceDir).Length < smEpsilon: revAxisV = revAxisV * -1 reliefDn = reliefD if inside : reliefDn = reliefD + abs(offset) # CutSolids list for collecting Solids CutSolids = [] # remove relief if needed if reliefD > 0.0 : if reliefW > 0.0 and ( gap1 > 0.0 or Agap1 > 0.0 ): reliefFace1 = smMakeReliefFace(MlenEdge, FaceDir* -1, gap1-reliefW, reliefW, reliefDn, reliefType) reliefSolid1 = reliefFace1.extrude(thkDir * thk) #Part.show(reliefSolid1) CutSolids.append(reliefSolid1) if reliefW > 0.0 and ( gap2 > 0.0 or Agap2 > 0.0 ): reliefFace2 = smMakeReliefFace(MlenEdge, FaceDir* -1, leng-gap2, reliefW, reliefDn, reliefType) reliefSolid2 = reliefFace2.extrude(thkDir * thk) #Part.show(reliefSolid2) CutSolids.append(reliefSolid2) # restrict angle if (bendA < 0): bendA = -bendA flipped = not flipped if not(flipped): revAxisP = lenEdge.valueAt(lenEdge.FirstParameter) + thkDir * (bendR + thk) revAxisV = revAxisV * -1 else: revAxisP = lenEdge.valueAt(lenEdge.FirstParameter) + thkDir * -bendR # remove bend face if present if inside : if gap1 == 0.0 or (reliefD == 0.0 and gap1 == 0.1) : Edgelist = selFace.ancestorsOfType(vertex0, Part.Edge) for ed in Edgelist : if not(MlenEdge.isSame(ed)): list1 = resultSolid.ancestorsOfType(ed, Part.Face) for Rface in list1 : if Rface.Area != selFace.Area and issubclass(type(Rface.Surface),Part.Plane) : for edge in Rface.Edges: if issubclass(type(edge.Curve),Part.Circle): RfaceE = Rface.extrude(Rface.normalAt(0,0) * -Noffset1 ) CutSolids.append(RfaceE) break if gap2 == 0.0 or (reliefD == 0.0 and gap2 == 0.1) : Edgelist = selFace.ancestorsOfType(vertex1, Part.Edge) for ed in Edgelist : if not(MlenEdge.isSame(ed)): list1 = resultSolid.ancestorsOfType(ed, Part.Face) for Rface in list1 : if Rface.Area != selFace.Area and issubclass(type(Rface.Surface),Part.Plane) : for edge in Rface.Edges: if issubclass(type(edge.Curve),Part.Circle): RfaceE = Rface.extrude(Rface.normalAt(0,0) * -Noffset2 ) CutSolids.append(RfaceE) break if reliefD == 0.0 and ( gap1 == 0.1 or gap2 == 0.1 ) : CutFace = smMakeFace(MlenEdge, thkDir, thk, 0, 0) else : CutFace = smMakeFace(MlenEdge, thkDir, thk, gap1, gap2) CutSolid = CutFace.extrude(FaceDir * offset ) CfaceSolid = Cface.extrude(thkDir * thk) CutSolid = CutSolid.common(CfaceSolid) CutSolids.append(CutSolid) # Produce Main Solid for Inside Bends if CutSolids : if len(CutSolids) == 1 : resultSolid = resultSolid.cut(CutSolids[0]) else : Solid = CutSolids[0].multiFuse(CutSolids[1:]) Solid.removeSplitter() #Part.show(Solid) resultSolid = resultSolid.cut(Solid) # Produce Offset Solid if offset > 0.0 : # create wall offset_face = smMakeFace(lenEdge, FaceDir, -offset) OffsetSolid = offset_face.extrude(thkDir * thk) resultSolid = resultSolid.fuse(OffsetSolid) #wallSolid = None if sketches : Wall_face = Part.makeFace(sketch.Shape.Wires, "Part::FaceMakerBullseye") if inside : Wall_face.translate(FaceDir * offset ) FaceAxisP = sketch_Edge.valueAt(sketch_Edge.FirstParameter) + thkDir * thk FaceAxisV = sketch_Edge.valueAt(sketch_Edge.FirstParameter) - sketch_Edge.valueAt(sketch_Edge.LastParameter) Wall_face.rotate(FaceAxisP, FaceAxisV, -90.0) wallSolid = Wall_face.extrude(thkDir * -thk) #Part.show(wallSolid) wallSolid.rotate(revAxisP, revAxisV, bendA) elif extLen > 0.0 : # create wall Wall_face = smMakeFace(lenEdge, FaceDir, extLen, gap1-extend1, gap2-extend2, miterA1List[i], miterA2List[i]) wallSolid = Wall_face.extrude(thkDir * thk) #Part.show(wallSolid) wallSolid.rotate(revAxisP, revAxisV, bendA) #Part.show(wallSolid.Faces[2]) thk_faceList.append(wallSolid.Faces[2]) # Produce bend Solid if not(unfold) : if bendA > 0.0 : # create bend # narrow the wall if we have gaps revFace = smMakeFace(lenEdge, thkDir, thk, gap1, gap2) if revFace.normalAt(0,0) != FaceDir : revFace.reverse() bendSolid = revFace.revolve(revAxisP, revAxisV, bendA) #Part.show(bendSolid) resultSolid = resultSolid.fuse(bendSolid) if wallSolid : resultSolid = resultSolid.fuse(wallSolid) # Produce unfold Solid else : if bendA > 0.0 : # create bend unfoldLength = ( bendR + kfactor * thk ) * bendA * math.pi / 180.0 # narrow the wall if we have gaps unfoldFace = smMakeFace(lenEdge, thkDir, thk, gap1, gap2) if unfoldFace.normalAt(0,0) != FaceDir : unfoldFace.reverse() unfoldSolid = unfoldFace.extrude(FaceDir * unfoldLength) #Part.show(unfoldSolid) resultSolid = resultSolid.fuse(unfoldSolid) if extLen > 0.0 : wallSolid.rotate(revAxisP, revAxisV, -bendA) #Part.show(wallSolid) wallSolid.translate(FaceDir * unfoldLength) resultSolid = resultSolid.fuse(wallSolid) #Gui.ActiveDocument.getObject(MainObject.Name).Visibility = False #if sketch : #Gui.ActiveDocument.getObject(sketch.Name).Visibility = False return resultSolid, thk_faceList
def execute(self, obj, getsim=False): PathLog.track() self.endVector = None if not obj.Active: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False return commandlist = [] toolLoad = obj.ToolController self.depthparams = depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=0.0, final_depth=obj.FinalDepth.Value, user_depths=None) 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 commandlist.append(Path.Command("(" + obj.Label + ")")) if obj.UseComp: commandlist.append( Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: commandlist.append(Path.Command("(Uncompensated Tool Path)")) parentJob = PathUtils.findParentJob(obj) if parentJob is None: return baseobject = parentJob.Base if baseobject is None: return # Let's always start by rapid to clearance...just for safety commandlist.append(Path.Command("G0", {"Z": obj.ClearanceHeight.Value})) isPanel = False if hasattr(baseobject, "Proxy"): if isinstance(baseobject.Proxy, ArchPanel.PanelSheet): # process the sheet isPanel = True baseobject.Proxy.execute(baseobject) shapes = baseobject.Proxy.getOutlines(baseobject, transform=True) for shape in shapes: f = Part.makeFace([shape], 'Part::FaceMakerSimple') thickness = baseobject.Group[0].Source.Thickness contourshape = f.extrude(FreeCAD.Vector(0, 0, thickness)) try: (pp, sim) = self._buildPathArea(obj, contourshape, start=obj.StartPoint, getsim=getsim) commandlist.extend(pp.Commands) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError( "Something unexpected happened. Unable to generate a contour path. Check project and tool config." ) if hasattr(baseobject, "Shape") and not isPanel: #bb = baseobject.Shape.BoundBox env = PathUtils.getEnvelope(partshape=baseobject.Shape, subshape=None, depthparams=self.depthparams) try: (pp, sim) = self._buildPathArea(obj, env, start=obj.StartPoint, getsim=getsim) commandlist.extend(pp.Commands) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError( "Something unexpected happened. Unable to generate a contour path. Check project and tool config." ) # Let's finish by rapid to clearance...just for safety commandlist.append(Path.Command("G0", {"Z": obj.ClearanceHeight.Value})) path = Path.Path(commandlist) obj.Path = path #obj.ViewObject.Visibility = True return sim
def makeFaceDXF(): global copper_diffuse, silks_diffuse global use_LinkGroups, use_AppPart doc = FreeCAD.ActiveDocument if doc is None: FreeCAD.newDocument() doc = FreeCAD.ActiveDocument docG = FreeCADGui.ActiveDocument Filter = "" last_pcb_path = "" pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp") last_pcb_path = pg.GetString("last_pcb_path") fn, Filter = PySide.QtGui.QFileDialog.getOpenFileNames( None, "Open File...", make_unicode(last_pcb_path), "*.dxf") for fname in fn: path, name = os.path.split(fname) filename = os.path.splitext(name)[0] #importDXF.open(os.path.join(dirname,filename)) if len(fname) > 0: #importDXF.open(fname) last_pcb_path = os.path.dirname(fname) pg = FreeCAD.ParamGet( "User parameter:BaseApp/Preferences/Mod/kicadStepUp") pg.SetString("last_pcb_path", make_string(last_pcb_path)) # py3 .decode("utf-8") pg = FreeCAD.ParamGet( "User parameter:BaseApp/Preferences/Mod/kicadStepUpGui") pcb_color_pos = pg.GetInt('pcb_color') #print(pcb_color_pos) if pcb_color_pos == 9: silks_diffuse = (0.18, 0.18, 0.18) #slick black else: silks_diffuse = ( 0.98, 0.92, 0.84 ) # #antique white # white (0.906,0.906,0.910) doc = FreeCAD.ActiveDocument objects = [] say("loading... ") t = time.time() if doc is not None: for o in doc.Objects: objects.append(o.Name) importDXF.insert(fname, doc.Name) else: importDXF.open(fname) FreeCADGui.SendMsgToActiveView("ViewFit") timeP = time.time() - t say("loading time = " + str(timeP) + "s") edges = [] sorted_edges = [] w = [] for o in doc.Objects: if o.Name not in str(objects): if hasattr(o, 'Shape'): w1 = Part.Wire(Part.__sortEdges__(o.Shape.Edges)) w.append(w1) #print (w) f = Part.makeFace(w, 'Part::FaceMakerBullseye') for o in doc.Objects: if o.Name not in str(objects): doc.removeObject(o.Name) if 'Silk' in filename: layerName = 'Silks' else: layerName = 'Tracks' if 'F.' in filename or 'F_' in filename: layerName = 'top' + layerName if 'B.' in filename or 'B_' in filename: layerName = 'bot' + layerName doc.addObject('Part::Feature', layerName).Shape = f newShape = doc.ActiveObject botOffset = 1.6 if 'Silk' in layerName: docG.getObject(newShape.Name).ShapeColor = silks_diffuse else: docG.getObject( newShape.Name ).ShapeColor = brass_diffuse #copper_diffuse #(0.78,0.56,0.11) if len(doc.getObjectsByLabel('Pcb')) > 0: newShape.Placement = doc.getObjectsByLabel('Pcb')[0].Placement #botTracks.Placement = doc.Pcb.Placement if len(doc.getObjectsByLabel('Board_Geoms')) > 0: if use_AppPart and not use_LinkGroups: doc.getObject('Board_Geoms').addObject(newShape) elif use_LinkGroups: doc.getObject('Board_Geoms').ViewObject.dropObject( newShape, None, '', []) if hasattr(doc.getObjectsByLabel('Pcb')[0], 'Shape'): botOffset = doc.getObjectsByLabel( 'Pcb')[0].Shape.BoundBox.ZLength else: botOffset = doc.getObjectsByLabel( 'Pcb')[0].OutList[1].Shape.BoundBox.ZLength #elif 'bot' in layerName: # newShape.Placement.Base.z-=1.6 if 'top' in layerName: newShape.Placement.Base.z += 0.07 if 'bot' in layerName: newShape.Placement.Base.z -= botOffset + 0.07 timeD = time.time() - t - timeP say("displaying time = " + str(timeD) + "s") FreeCADGui.SendMsgToActiveView("ViewFit") docG.activeView().viewAxonometric()
def smExtrude(extLength=10.0, gap1=0.0, gap2=0.0, substraction=False, offset=0.02, refine=True, sketch='', selFaceNames='', selObject=''): finalShape = selObject for selFaceName in selFaceNames: selItem = selObject.getElement(selFaceName) selFace = smFace(selItem, selObject) # find the narrow edge thk = 999999.0 for edge in selFace.Edges: if abs(edge.Length) < thk: thk = abs(edge.Length) thkEdge = edge # find a length edge = revolve axis direction p0 = thkEdge.valueAt(thkEdge.FirstParameter) for lenEdge in selFace.Edges: p1 = lenEdge.valueAt(lenEdge.FirstParameter) p2 = lenEdge.valueAt(lenEdge.LastParameter) if lenEdge.isSame(thkEdge): continue if (p1 - p0).Length < smEpsilon: revAxisV = p2 - p1 break if (p2 - p0).Length < smEpsilon: revAxisV = p1 - p2 break # find the large face connected with selected face list2 = selObject.ancestorsOfType(lenEdge, Part.Face) for Cface in list2: if not (Cface.isSame(selFace)): break #Part.show(Cface, "Cface") # Main Length Edge, Extrusion direction MlenEdge = lenEdge # leng = MlenEdge.Length revAxisV.normalize() thkDir = Cface.normalAt(0, 0) * -1 FaceDir = selFace.normalAt(0, 0) # if sketch is as wall sketches = False if sketch: if sketch.Shape.Wires[0].isClosed(): sketches = True else: pass # Split solid Based on Top Face into two solid Topface_Solid = Cface.Wires[0].extrude(Cface.normalAt(0, 0) * -thk) #Part.show(Topface_Solid,"Topface_Solid") SplitSolids = BOPTools.SplitAPI.slice(finalShape, Topface_Solid.Faces, "Standard", 0.0) #Part.show(SplitSolids,"SplitSolids") for SplitSolid in SplitSolids.Solids: check_face = SplitSolid.common(Cface) if check_face.Faces: SplitSolid1 = SplitSolid break #Part.show(SplitSolid1,"SplitSolid1") for SplitSolid in SplitSolids.Solids: if not (SplitSolid.isSame(SplitSolid1)): SplitSolid2 = SplitSolid break #Part.show(SplitSolid2, "SplitSolid2") # Make solid from sketch, if sketch is present solidlist = [] if sketches: Wall_face = Part.makeFace(sketch.Shape.Wires, "Part::FaceMakerBullseye") check_face = Wall_face.common(Cface) if not (check_face.Faces): thkDir = thkDir * -1 wallSolid = Wall_face.extrude(thkDir * thk) #Part.show(wallSolid, "wallSolid") solidlist.append(wallSolid) # To find Overlapping Solid, non thickness side Face that touch Overlapping Solid overlap_solid = wallSolid.common(SplitSolid2) #Part.show(overlap_solid, "overlap_solid") substract_face = smTouchFace(wallSolid, SplitSolid2, thk) #Part.show(substract_face, "substract_face") # To get solids that aligned/normal to touching face overlap_solidlist = smgetSubface(substract_face, overlap_solid, lenEdge, thk) # Substract solid from Initial Solid if substraction: for solid in overlap_solidlist: CutSolid = solid.makeOffsetShape(offset, 0.0, fill=False, join=2) #Part.show(CutSolid, "CutSolid") finalShape = finalShape.cut(CutSolid) #Part.show(finalShape,"finalShape") elif extLength > 0.0: # create wall, if edge or face selected Wall_face = smMakeFace(lenEdge, FaceDir, extLength, gap1, gap2, op='SMW') wallSolid = Wall_face.extrude(thkDir * thk) #Part.show(wallSolid,"wallSolid") solidlist.append(wallSolid) # Fuse All solid created to Split solid if len(solidlist) > 0: resultSolid = SplitSolid1.fuse(solidlist[0]) if refine: resultSolid = resultSolid.removeSplitter() #Part.show(resultSolid,"resultSolid") # Merge final list finalShape = finalShape.cut(resultSolid) #Part.show(finalShape,"finalShape") finalShape = finalShape.fuse(resultSolid) #Part.show(finalShape,"finalShape") return finalShape
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... returns envelope for all base shapes or wires for Arch.Panels.''' PathLog.track() if obj.UseComp: self.commandlist.append( Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: self.commandlist.append(Path.Command("(Uncompensated Tool Path)")) shapes = [] self.profileshape = [] # pylint: disable=attribute-defined-outside-init baseSubsTuples = [] subCount = 0 allTuples = [] if obj.Base: # The user has selected subobjects from the base. Process each. if obj.EnableRotation != 'Off': for p in range(0, len(obj.Base)): (base, subsList) = obj.Base[p] for sub in subsList: subCount += 1 shape = getattr(base.Shape, sub) if isinstance(shape, Part.Face): rtn = False (norm, surf) = self.getFaceNormAndSurf(shape) (rtn, angle, axis, praInfo) = self.faceRotationAnalysis( obj, norm, surf) # pylint: disable=unused-variable if rtn is True: (clnBase, angle, clnStock, tag) = self.applyRotationalAnalysis( obj, base, angle, axis, subCount) # Verify faces are correctly oriented - InverseAngle might be necessary faceIA = getattr(clnBase.Shape, sub) (norm, surf) = self.getFaceNormAndSurf(faceIA) (rtn, praAngle, praAxis, praInfo) = self.faceRotationAnalysis( obj, norm, surf) # pylint: disable=unused-variable if rtn is True: PathLog.error( translate( "Path", "Face appears misaligned after initial rotation." )) if obj.AttemptInverseAngle is True and obj.InverseAngle is False: (clnBase, clnStock, angle) = self.applyInverseAngle( obj, clnBase, clnStock, axis, angle) else: msg = translate( "Path", "Consider toggling the 'InverseAngle' property and recomputing." ) PathLog.error(msg) else: PathLog.debug( "Face appears to be oriented correctly." ) tup = clnBase, sub, tag, angle, axis, clnStock else: if self.warnDisabledAxis(obj, axis) is False: PathLog.debug( str(sub) + ": No rotation used") axis = 'X' angle = 0.0 tag = base.Name + '_' + axis + str( angle).replace('.', '_') stock = PathUtils.findParentJob(obj).Stock tup = base, sub, tag, angle, axis, stock allTuples.append(tup) if subCount > 1: msg = translate('Path', "Multiple faces in Base Geometry.") + " " msg += translate( 'Path', "Depth settings will be applied to all faces.") PathLog.warning(msg) (Tags, Grps) = self.sortTuplesByIndex( allTuples, 2) # return (TagList, GroupList) subList = [] for o in range(0, len(Tags)): subList = [] for (base, sub, tag, angle, axis, stock) in Grps[o]: subList.append(sub) pair = base, subList, angle, axis, stock baseSubsTuples.append(pair) # Efor else: PathLog.debug( translate("Path", "EnableRotation property is 'Off'.")) stock = PathUtils.findParentJob(obj).Stock for (base, subList) in obj.Base: baseSubsTuples.append((base, subList, 0.0, 'X', stock)) # for base in obj.Base: finish_step = obj.FinishDepth.Value if hasattr( obj, "FinishDepth") else 0.0 for (base, subsList, angle, axis, stock) in baseSubsTuples: holes = [] faces = [] faceDepths = [] startDepths = [] for sub in subsList: shape = getattr(base.Shape, sub) if isinstance(shape, Part.Face): faces.append(shape) if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face for wire in shape.Wires[1:]: holes.append((base.Shape, wire)) # Add face depth to list faceDepths.append(shape.BoundBox.ZMin) else: ignoreSub = base.Name + '.' + sub msg = translate( 'Path', "Found a selected object which is not a face. Ignoring: {}" .format(ignoreSub)) PathLog.error(msg) FreeCAD.Console.PrintWarning(msg) # Set initial Start and Final Depths and recalculate depthparams finDep = obj.FinalDepth.Value strDep = obj.StartDepth.Value if strDep > stock.Shape.BoundBox.ZMax: strDep = stock.Shape.BoundBox.ZMax startDepths.append(strDep) self.depthparams = self._customDepthParams(obj, strDep, finDep) for shape, wire in holes: f = Part.makeFace(wire, 'Part::FaceMakerSimple') drillable = PathUtils.isDrillable(shape, wire) if (drillable and obj.processCircles) or (not drillable and obj.processHoles): env = PathUtils.getEnvelope( shape, subshape=f, depthparams=self.depthparams) tup = env, True, 'pathProfileFaces', angle, axis, strDep, finDep shapes.append(tup) if len(faces) > 0: profileshape = Part.makeCompound(faces) self.profileshape.append(profileshape) if obj.processPerimeter: if obj.HandleMultipleFeatures == 'Collectively': custDepthparams = self.depthparams if obj.LimitDepthToFace is True and obj.EnableRotation != 'Off': if profileshape.BoundBox.ZMin > obj.FinalDepth.Value: finDep = profileshape.BoundBox.ZMin custDepthparams = self._customDepthParams( obj, strDep, finDep - 0.5) # only an envelope try: env = PathUtils.getEnvelope( base.Shape, subshape=profileshape, depthparams=custDepthparams) except Exception: # pylint: disable=broad-except # PathUtils.getEnvelope() failed to return an object. PathLog.error( translate( 'Path', 'Unable to create path for face(s).')) else: tup = env, False, 'pathProfileFaces', angle, axis, strDep, finDep shapes.append(tup) elif obj.HandleMultipleFeatures == 'Individually': for shape in faces: profShape = Part.makeCompound([shape]) finalDep = obj.FinalDepth.Value custDepthparams = self.depthparams if obj.Side == 'Inside': if finalDep < shape.BoundBox.ZMin: # Recalculate depthparams finalDep = shape.BoundBox.ZMin custDepthparams = self._customDepthParams( obj, strDep, finalDep - 0.5) env = PathUtils.getEnvelope( base.Shape, subshape=profShape, depthparams=custDepthparams) tup = env, False, 'pathProfileFaces', angle, axis, strDep, finalDep shapes.append(tup) # Lower high Start Depth to top of Stock startDepth = max(startDepths) if obj.StartDepth.Value > startDepth: obj.StartDepth.Value = startDepth else: # Try to build targets from the job base if 1 == len(self.model): if hasattr(self.model[0], "Proxy"): PathLog.info("hasattr() Proxy") if isinstance(self.model[0].Proxy, ArchPanel.PanelSheet): # process the sheet if obj.processCircles or obj.processHoles: for shape in self.model[0].Proxy.getHoles( self.model[0], transform=True): for wire in shape.Wires: drillable = PathUtils.isDrillable( self.model[0].Proxy, wire) if (drillable and obj.processCircles) or ( not drillable and obj.processHoles): f = Part.makeFace( wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope( self.model[0].Shape, subshape=f, depthparams=self.depthparams) tup = env, True, 'pathProfileFaces', 0.0, 'X', obj.StartDepth.Value, obj.FinalDepth.Value shapes.append(tup) if obj.processPerimeter: for shape in self.model[0].Proxy.getOutlines( self.model[0], transform=True): for wire in shape.Wires: f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope( self.model[0].Shape, subshape=f, depthparams=self.depthparams) tup = env, False, 'pathProfileFaces', 0.0, 'X', obj.StartDepth.Value, obj.FinalDepth.Value shapes.append(tup) self.removalshapes = shapes # pylint: disable=attribute-defined-outside-init PathLog.debug("%d shapes" % len(shapes)) return shapes
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... returns envelope for all base shapes or wires for Arch.Panels.''' PathLog.track() PathLog.debug("----- areaOpShapes() in PathProfileFaces.py") if obj.UseComp: self.commandlist.append( Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: self.commandlist.append(Path.Command("(Uncompensated Tool Path)")) shapes = [] self.profileshape = [] finalDepths = [] baseSubsTuples = [] subCount = 0 allTuples = [] if obj.Base: # The user has selected subobjects from the base. Process each. if obj.EnableRotation != 'Off': for p in range(0, len(obj.Base)): (base, subsList) = obj.Base[p] for sub in subsList: subCount += 1 shape = getattr(base.Shape, sub) if isinstance(shape, Part.Face): rtn = False (norm, surf) = self.getFaceNormAndSurf(shape) (rtn, angle, axis, praInfo) = self.faceRotationAnalysis( obj, norm, surf) if rtn is True: (clnBase, angle, clnStock, tag) = self.applyRotationalAnalysis( obj, base, angle, axis, subCount) # Verify faces are correctly oriented - InverseAngle might be necessary faceIA = getattr(clnBase.Shape, sub) (norm, surf) = self.getFaceNormAndSurf(faceIA) (rtn, praAngle, praAxis, praInfo) = self.faceRotationAnalysis( obj, norm, surf) if rtn is True: PathLog.error( translate( "Path", "Face appears misaligned after initial rotation." )) if obj.AttemptInverseAngle is True and obj.InverseAngle is False: (clnBase, clnStock, angle) = self.applyInverseAngle( obj, clnBase, clnStock, axis, angle) else: msg = translate( "Path", "Consider toggling the 'InverseAngle' property and recomputing." ) PathLog.error(msg) # title = translate("Path", 'Rotation Warning') # self.guiMessage(title, msg, False) else: PathLog.debug( "Face appears to be oriented correctly." ) tup = clnBase, sub, tag, angle, axis, clnStock else: if self.warnDisabledAxis(obj, axis) is False: PathLog.debug( str(sub) + ": No rotation used") axis = 'X' angle = 0.0 tag = base.Name + '_' + axis + str( angle).replace('.', '_') stock = PathUtils.findParentJob(obj).Stock tup = base, sub, tag, angle, axis, stock # Eif allTuples.append(tup) # Eif # Efor # Efor if subCount > 1: msg = translate('Path', "Multiple faces in Base Geometry.") + " " msg += translate( 'Path', "Depth settings will be applied to all faces.") PathLog.warning(msg) # title = translate("Path", "Depth Warning") # self.guiMessage(title, msg) (Tags, Grps) = self.sortTuplesByIndex( allTuples, 2) # return (TagList, GroupList) subList = [] for o in range(0, len(Tags)): subList = [] for (base, sub, tag, angle, axis, stock) in Grps[o]: subList.append(sub) pair = base, subList, angle, axis, stock baseSubsTuples.append(pair) # Efor else: PathLog.info( translate("Path", "EnableRotation property is 'Off'.")) stock = PathUtils.findParentJob(obj).Stock for (base, subList) in obj.Base: baseSubsTuples.append((base, subList, 0.0, 'X', stock)) # for base in obj.Base: for (base, subsList, angle, axis, stock) in baseSubsTuples: holes = [] faces = [] for sub in subsList: shape = getattr(base.Shape, sub) if isinstance(shape, Part.Face): faces.append(shape) if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face for wire in shape.Wires[1:]: holes.append((base.Shape, wire)) else: ignoreSub = base.Name + '.' + sub msg = translate( 'Path', "Found a selected object which is not a face. Ignoring: {}" .format(ignoreSub)) PathLog.error(msg) FreeCAD.Console.PrintWarning(msg) # return for shape, wire in holes: f = Part.makeFace(wire, 'Part::FaceMakerSimple') drillable = PathUtils.isDrillable(shape, wire) if (drillable and obj.processCircles) or (not drillable and obj.processHoles): PathLog.track() # Recalculate depthparams (strDep, finDep) = self.calculateStartFinalDepths( obj, shape, stock) finalDepths.append(finDep) PathLog.debug( "Adjusted face depths strDep: {}, and finDep: {}". format(self.strDep, self.finDep)) finish_step = obj.FinishDepth.Value if hasattr( obj, "FinishDepth") else 0.0 self.depthparams = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=strDep, # obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=finDep, # obj.FinalDepth.Value, user_depths=None) env = PathUtils.getEnvelope( shape, subshape=f, depthparams=self.depthparams) # shapes.append((env, True)) tup = env, True, 'pathProfileFaces', angle, axis, strDep, finDep shapes.append(tup) if len(faces) > 0: profileshape = Part.makeCompound(faces) self.profileshape.append(profileshape) if obj.processPerimeter: PathLog.track() if profileshape: # Recalculate depthparams (strDep, finDep) = self.calculateStartFinalDepths( obj, profileshape, stock) finalDepths.append(finDep) PathLog.debug( "Adjusted face depths strDep: {}, and finDep: {}". format(self.strDep, self.finDep)) finish_step = obj.FinishDepth.Value if hasattr( obj, "FinishDepth") else 0.0 self.depthparams = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=strDep, # obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=finDep, # obj.FinalDepth.Value, user_depths=None) else: strDep = obj.StartDepth.Value finDep = obj.FinalDepth.Value try: env = PathUtils.getEnvelope( base.Shape, subshape=profileshape, depthparams=self.depthparams) except Exception: # PathUtils.getEnvelope() failed to return an object. PathLog.error( translate('Path', 'Unable to create path for face(s).')) else: # shapes.append((env, False)) tup = env, False, 'pathProfileFaces', angle, axis, strDep, finDep shapes.append(tup) else: for shape in faces: # Recalculate depthparams (strDep, finDep) = self.calculateStartFinalDepths( obj, shape, stock) finalDepths.append(finDep) finish_step = obj.FinishDepth.Value if hasattr( obj, "FinishDepth") else 0.0 self.depthparams = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=strDep, # obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=finDep, # obj.FinalDepth.Value, user_depths=None) env = PathUtils.getEnvelope( base.Shape, subshape=shape, depthparams=self.depthparams) tup = env, False, 'pathProfileFaces', angle, axis, strDep, finDep shapes.append(tup) # Eif # adjust FinalDepth as needed finalDepth = min(finalDepths) if obj.FinalDepth.Value < finalDepth: obj.FinalDepth.Value = finalDepth else: # Try to build targets from the job base if 1 == len(self.model) and hasattr(self.model[0], "Proxy"): if isinstance(self.model[0].Proxy, ArchPanel.PanelSheet): # process the sheet if obj.processCircles or obj.processHoles: for shape in self.model[0].Proxy.getHoles( self.model[0], transform=True): for wire in shape.Wires: drillable = PathUtils.isDrillable( self.model[0].Proxy, wire) if (drillable and obj.processCircles) or ( not drillable and obj.processHoles): f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope( self.model[0].Shape, subshape=f, depthparams=self.depthparams) # shapes.append((env, True)) tup = env, True, 'pathProfileFaces', 0.0, 'X', obj.StartDepth.Value, obj.FinalDepth.Value shapes.append(tup) if obj.processPerimeter: for shape in self.model[0].Proxy.getOutlines( self.model[0], transform=True): for wire in shape.Wires: f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope( self.model[0].Shape, subshape=f, depthparams=self.depthparams) # shapes.append((env, False)) tup = env, False, 'pathProfileFaces', 0.0, 'X', obj.StartDepth.Value, obj.FinalDepth.Value shapes.append(tup) self.removalshapes = shapes PathLog.debug("%d shapes" % len(shapes)) return shapes
def execute(self,obj): "creates the panel shape" if self.clone(obj): return import Part, DraftGeomUtils # base tests if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.isNull(): return elif obj.Base.isDerivedFrom("Mesh::Feature"): if not obj.Base.Mesh.isSolid(): return else: if obj.Length.Value: length = obj.Length.Value else: return if obj.Width.Value: width = obj.Width.Value else: return if obj.Thickness.Value: thickness = obj.Thickness.Value else: if not obj.Base: return elif obj.Base.isDerivedFrom("Part::Feature"): if not obj.Base.Shape.Solids: return # creating base shape pl = obj.Placement base = None normal = None if hasattr(obj,"Normal"): if obj.Normal.Length > 0: normal = Vector(obj.Normal) normal.normalize() normal.multiply(thickness) baseprofile = None if obj.Base: base = obj.Base.Shape.copy() if not base.Solids: p = FreeCAD.Placement(obj.Base.Placement) if base.Faces: baseprofile = base if not normal: normal = baseprofile.Faces[0].normalAt(0,0).multiply(thickness) base = base.extrude(normal) elif base.Wires: fm = False if hasattr(obj,"FaceMaker"): if obj.FaceMaker != "None": try: base = Part.makeFace(base.Wires,"Part::FaceMaker"+str(obj.FaceMaker)) fm = True except: FreeCAD.Console.PrintError(translate("Arch","Facemaker returned an error")+"\n") return if not fm: closed = True for w in base.Wires: if not w.isClosed(): closed = False if closed: baseprofile = ArchCommands.makeFace(base.Wires) if not normal: normal = baseprofile.normalAt(0,0).multiply(thickness) base = baseprofile.extrude(normal) elif obj.Base.isDerivedFrom("Mesh::Feature"): if obj.Base.Mesh.isSolid(): if obj.Base.Mesh.countComponents() == 1: sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh) if sh.isClosed() and sh.isValid() and sh.Solids: base = sh else: if not normal: normal = Vector(0,0,1).multiply(thickness) 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.makePolygon([v1,v2,v3,v4,v1]) baseprofile = Part.Face(base) base = baseprofile.extrude(normal) if hasattr(obj,"Area"): if baseprofile: obj.Area = baseprofile.Area if hasattr(obj,"WaveLength"): if baseprofile and obj.WaveLength.Value and obj.WaveHeight.Value: # corrugated element bb = baseprofile.BoundBox bb.enlarge(bb.DiagonalLength) p1 = Vector(bb.getPoint(0).x,bb.getPoint(0).y,bb.Center.z) if obj.WaveType == "Curved": p2 = p1.add(Vector(obj.WaveLength.Value/2,0,obj.WaveHeight.Value)) p3 = p2.add(Vector(obj.WaveLength.Value/2,0,-obj.WaveHeight.Value)) e1 = Part.Arc(p1,p2,p3).toShape() p4 = p3.add(Vector(obj.WaveLength.Value/2,0,-obj.WaveHeight.Value)) p5 = p4.add(Vector(obj.WaveLength.Value/2,0,obj.WaveHeight.Value)) e2 = Part.Arc(p3,p4,p5).toShape() else: if obj.WaveHeight.Value < obj.WaveLength.Value: p2 = p1.add(Vector(obj.WaveHeight.Value,0,obj.WaveHeight.Value)) p3 = p2.add(Vector(obj.WaveLength.Value-2*obj.WaveHeight.Value,0,0)) p4 = p3.add(Vector(obj.WaveHeight.Value,0,-obj.WaveHeight.Value)) e1 = Part.makePolygon([p1,p2,p3,p4]) p5 = p4.add(Vector(obj.WaveHeight.Value,0,-obj.WaveHeight.Value)) p6 = p5.add(Vector(obj.WaveLength.Value-2*obj.WaveHeight.Value,0,0)) p7 = p6.add(Vector(obj.WaveHeight.Value,0,obj.WaveHeight.Value)) e2 = Part.makePolygon([p4,p5,p6,p7]) else: p2 = p1.add(Vector(obj.WaveLength.Value/2,0,obj.WaveHeight.Value)) p3 = p2.add(Vector(obj.WaveLength.Value/2,0,-obj.WaveHeight.Value)) e1 = Part.makePolygon([p1,p2,p3]) p4 = p3.add(Vector(obj.WaveLength.Value/2,0,-obj.WaveHeight.Value)) p5 = p4.add(Vector(obj.WaveLength.Value/2,0,obj.WaveHeight.Value)) e2 = Part.makePolygon([p3,p4,p5]) edges = [e1,e2] for i in range(int(bb.XLength/(obj.WaveLength.Value*2))): e1 = e1.copy() e1.translate(Vector(obj.WaveLength.Value*2,0,0)) e2 = e2.copy() e2.translate(Vector(obj.WaveLength.Value*2,0,0)) edges.extend([e1,e2]) basewire = Part.Wire(edges) baseface = basewire.extrude(Vector(0,bb.YLength,0)) base = baseface.extrude(Vector(0,0,thickness)) rot = FreeCAD.Rotation(FreeCAD.Vector(0,0,1),normal) base.rotate(bb.Center,rot.Axis,math.degrees(rot.Angle)) if obj.WaveDirection.Value: base.rotate(bb.Center,normal,obj.WaveDirection.Value) n1 = normal.negative().normalize().multiply(obj.WaveHeight.Value*2) self.vol = baseprofile.copy() self.vol.translate(n1) self.vol = self.vol.extrude(n1.negative().multiply(2)) base = self.vol.common(base) base = base.removeSplitter() if not base: FreeCAD.Console.PrintError(transpate("Arch","Error computing shape of ")+obj.Label+"\n") return False if base and (obj.Sheets > 1) and normal and thickness: bases = [base] for i in range(1,obj.Sheets): n = FreeCAD.Vector(normal).normalize().multiply(i*thickness) b = base.copy() b.translate(n) bases.append(b) base = Part.makeCompound(bases) if base and normal and hasattr(obj,"Offset"): if obj.Offset.Value: v = DraftVecUtils.scaleTo(normal,obj.Offset.Value) base.translate(v) # process subshapes base = self.processSubShapes(obj,base,pl) # applying if base: if not base.isNull(): if base.isValid() and base.Solids: if base.Volume < 0: base.reverse() if base.Volume < 0: FreeCAD.Console.PrintError(translate("Arch","Couldn't compute a shape")) return base = base.removeSplitter() obj.Shape = base if not pl.isNull(): obj.Placement = pl