def execute(self, obj): # please, don't override. Override derivedExecute instead. plms = self.derivedExecute(obj) if plms is not None: if plms == "suppress": return obj.NumElements = len(plms) shapes = [] markerSize = obj.MarkerSize if markerSize < DistConfusion: markerSize = getMarkerSizeEstimate(plms) marker = lattice2Markers.getPlacementMarker( scale=markerSize, markerID=obj.MarkerShape) bExposing = False if obj.ExposePlacement: if len(plms) == 1: bExposing = True else: lattice2Executer.warning( obj, "Multiple placements are being fed, can't expose placements. Placement property will be forced to zero." ) obj.Placement = App.Placement() if bExposing: obj.Shape = shallowCopy(marker) obj.Placement = plms[0] else: for plm in plms: sh = shallowCopy(marker) sh.Placement = plm shapes.append(sh) if len(shapes) == 0: obj.Shape = lattice2Markers.getNullShapeShape(markerSize) raise ValueError('Lattice object is null') sh = Part.makeCompound(shapes) sh.Placement = obj.Placement obj.Shape = sh if obj.isLattice == 'Auto-Off': obj.isLattice = 'Auto-On' else: # DerivedExecute didn't return anything. Thus we assume it # has assigned the shape, and thus we don't do anything. # Moreover, we assume that it is no longer a lattice object, so: if obj.isLattice == 'Auto-On': obj.isLattice = 'Auto-Off' if obj.ExposePlacement: if obj.Shape.ShapeType == "Compound": children = obj.Shape.childShapes() if len(children) == 1: obj.Placement = children[0].Placement obj.Shape = children[0] else: obj.Placement = App.Placement() else: #nothing to do - FreeCAD will take care to make obj.Placement and obj.Shape.Placement synchronized. pass return
def __init__(self, obj, label, node1, node2): x = node1.position_X y = node1.position_Y z = node1.position_Z obj.addExtension("App::GroupExtensionPython", self) #Create scripted object: obj.addProperty("App::PropertyString","label","In line joint","label",1).label = label obj.addProperty("App::PropertyString","joint","In line joint","joint",1).joint = 'prismatic' obj.addProperty("App::PropertyString","node 1","In line joint","node 1",1).node_1 = node1.label obj.addProperty("App::PropertyString","node 2","In line joint","node 2",1).node_2 = node2.label #Absolute position at the node 1 position, only for animation, not for MBDyn sumulation: obj.addProperty("App::PropertyDistance","position X","Initial absolute position","position X",1).position_X = x obj.addProperty("App::PropertyDistance","position Y","Initial absolute position","position Y",1).position_Y = y obj.addProperty("App::PropertyDistance","position Z","Initial absolute position","position Z",1).position_Z = z obj.addProperty("App::PropertyString","animate","Animation","animate").animate = 'false' obj.addProperty("App::PropertyString","frame","Animation","frame").frame = 'local' obj.addProperty("App::PropertyString","structural dummy","Animation","structural dummy").structural_dummy = '2' obj.addProperty("App::PropertyString","force vector multiplier","Animation","force vector multiplier").force_vector_multiplier = '1' obj.Proxy = self length = FreeCAD.ActiveDocument.getObjectsByLabel("x: structural: " + node1.label)[0].Length.Value # Calculate the body characteristic length. Will be used to size the arrows that represent the node. p1 = FreeCAD.Vector(0, 0, 0) #Add x vector of the coordinate system: p2 = FreeCAD.Vector(length, 0, 0) l = Draft.makeLine(p1, p2) l.Label = 'x: joint: '+ label l.ViewObject.LineColor = (1.00,0.00,0.00) l.ViewObject.PointColor = (1.00,0.00,0.00) l.Placement=FreeCAD.Placement(FreeCAD.Vector(x,y,z), FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0), FreeCAD.Vector(0,0,0)) l.ViewObject.EndArrow = True l.ViewObject.ArrowType = u"Arrow" l.ViewObject.LineWidth = 1.00 l.ViewObject.PointSize = 1.00 l.ViewObject.ArrowSize = str(length/15)+' mm' l.ViewObject.Selectable = False #Add y vector of the coordinate system: p2 = FreeCAD.Vector(0, length, 0) l = Draft.makeLine(p1, p2) l.Label = 'y: joint: '+ label l.ViewObject.LineColor = (0.00,1.00,0.00) l.ViewObject.PointColor = (0.00,1.00,0.00) l.Placement=FreeCAD.Placement(FreeCAD.Vector(x,y,z), FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0), FreeCAD.Vector(0,0,0)) l.ViewObject.EndArrow = True l.ViewObject.ArrowType = u"Arrow" l.ViewObject.LineWidth = 1.00 l.ViewObject.PointSize = 1.00 l.ViewObject.ArrowSize = str(length/15)+' mm' l.ViewObject.Selectable = False #Add z vector of the coordinate system: p2 = FreeCAD.Vector(0, 0, length) l = Draft.makeLine(p1, p2) l.Label = 'z: joint: '+ label l.ViewObject.ArrowType = u"Arrow" l.ViewObject.LineColor = (0.00,0.00,1.00) l.ViewObject.PointColor = (0.00,0.00,1.00) l.Placement=FreeCAD.Placement(FreeCAD.Vector(x,y,z), FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0), FreeCAD.Vector(0,0,0)) l.ViewObject.EndArrow = True l.ViewObject.LineWidth = 1.00 l.ViewObject.PointSize = 1.00 l.ViewObject.ArrowSize = str(length/15)+' mm' l.ViewObject.Selectable = False #Add the vector to visualize reaction forces Llength = FreeCAD.Units.Quantity(FreeCAD.ActiveDocument.getObjectsByLabel("X")[0].End[0]/4,FreeCAD.Units.Unit('mm')) p1 = FreeCAD.Vector(x, y, z) p2 = FreeCAD.Vector(x+Llength, y+Llength, z+Llength) d = Draft.makeLine(p1, p2) d.ViewObject.LineColor = (1.00,0.00,0.00) d.ViewObject.PointColor = (1.00,0.00,0.00) d.ViewObject.LineWidth = 1.00 d.ViewObject.PointSize = 1.00 d.ViewObject.EndArrow = True d.ViewObject.ArrowType = u"Arrow" d.ViewObject.ArrowSize = str(Llength/75)#+' mm' d.ViewObject.Selectable = False d.Label = "jf: "+ label FreeCAD.ActiveDocument.recompute()
def updateData(self, obj, prop): if hasattr(self,"arc"): from pivy import coin import Part, DraftGeomUtils import DraftGui arcsegs = 24 # calculate the arc data if DraftVecUtils.isNull(obj.Normal): norm = App.Vector(0,0,1) else: norm = obj.Normal radius = (obj.Dimline.sub(obj.Center)).Length self.circle = Part.makeCircle(radius,obj.Center,norm,obj.FirstAngle.Value,obj.LastAngle.Value) self.p2 = self.circle.Vertexes[0].Point self.p3 = self.circle.Vertexes[-1].Point mp = DraftGeomUtils.findMidpoint(self.circle.Edges[0]) ray = mp.sub(obj.Center) # set text value if obj.LastAngle.Value > obj.FirstAngle.Value: a = obj.LastAngle.Value - obj.FirstAngle.Value else: a = (360 - obj.FirstAngle.Value) + obj.LastAngle.Value su = True if hasattr(obj.ViewObject,"ShowUnit"): su = obj.ViewObject.ShowUnit if hasattr(obj.ViewObject,"Decimals"): self.string = DraftGui.displayExternal(a,obj.ViewObject.Decimals,'Angle',su) else: self.string = DraftGui.displayExternal(a,None,'Angle',su) if obj.ViewObject.Override: self.string = obj.ViewObject.Override.replace("$dim",\ self.string) self.text.string = self.text3d.string = utils.string_encode_coin(self.string) # check display mode try: m = obj.ViewObject.DisplayMode except: # swallow all exceptions here since it always fails on first run (Displaymode enum no set yet) m = ["2D","3D"][utils.get_param("dimstyle",0)] # set the arc if m == "3D": # calculate the spacing of the text spacing = (len(self.string)*obj.ViewObject.FontSize.Value)/8.0 pts1 = [] cut = None pts2 = [] for i in range(arcsegs+1): p = self.circle.valueAt(self.circle.FirstParameter+((self.circle.LastParameter-self.circle.FirstParameter)/arcsegs)*i) if (p.sub(mp)).Length <= spacing: if cut is None: cut = i else: if cut is None: pts1.append([p.x,p.y,p.z]) else: pts2.append([p.x,p.y,p.z]) self.coords.point.setValues(pts1+pts2) i1 = len(pts1) i2 = i1+len(pts2) self.arc.coordIndex.setValues(0,len(pts1)+len(pts2)+1,list(range(len(pts1)))+[-1]+list(range(i1,i2))) if (len(pts1) >= 3) and (len(pts2) >= 3): self.circle1 = Part.Arc(App.Vector(pts1[0][0],pts1[0][1],pts1[0][2]),App.Vector(pts1[1][0],pts1[1][1],pts1[1][2]),App.Vector(pts1[-1][0],pts1[-1][1],pts1[-1][2])).toShape() self.circle2 = Part.Arc(App.Vector(pts2[0][0],pts2[0][1],pts2[0][2]),App.Vector(pts2[1][0],pts2[1][1],pts2[1][2]),App.Vector(pts2[-1][0],pts2[-1][1],pts2[-1][2])).toShape() else: pts = [] for i in range(arcsegs+1): p = self.circle.valueAt(self.circle.FirstParameter+((self.circle.LastParameter-self.circle.FirstParameter)/arcsegs)*i) pts.append([p.x,p.y,p.z]) self.coords.point.setValues(pts) self.arc.coordIndex.setValues(0,arcsegs+1,list(range(arcsegs+1))) # set the arrow coords and rotation self.trans1.translation.setValue((self.p2.x,self.p2.y,self.p2.z)) self.coord1.point.setValue((self.p2.x,self.p2.y,self.p2.z)) self.trans2.translation.setValue((self.p3.x,self.p3.y,self.p3.z)) self.coord2.point.setValue((self.p3.x,self.p3.y,self.p3.z)) # calculate small chords to make arrows look better arrowlength = 4*obj.ViewObject.ArrowSize.Value u1 = (self.circle.valueAt(self.circle.FirstParameter+arrowlength)).sub(self.circle.valueAt(self.circle.FirstParameter)).normalize() u2 = (self.circle.valueAt(self.circle.LastParameter)).sub(self.circle.valueAt(self.circle.LastParameter-arrowlength)).normalize() if hasattr(obj.ViewObject,"FlipArrows"): if obj.ViewObject.FlipArrows: u1 = u1.negative() u2 = u2.negative() w2 = self.circle.Curve.Axis w1 = w2.negative() v1 = w1.cross(u1) v2 = w2.cross(u2) q1 = App.Placement(DraftVecUtils.getPlaneRotation(u1,v1,w1)).Rotation.Q q2 = App.Placement(DraftVecUtils.getPlaneRotation(u2,v2,w2)).Rotation.Q self.trans1.rotation.setValue((q1[0],q1[1],q1[2],q1[3])) self.trans2.rotation.setValue((q2[0],q2[1],q2[2],q2[3])) # setting text pos & rot self.tbase = mp if hasattr(obj.ViewObject,"TextPosition"): if not DraftVecUtils.isNull(obj.ViewObject.TextPosition): self.tbase = obj.ViewObject.TextPosition u3 = ray.cross(norm).normalize() v3 = norm.cross(u3) r = App.Placement(DraftVecUtils.getPlaneRotation(u3,v3,norm)).Rotation offset = r.multVec(App.Vector(0,1,0)) if hasattr(obj.ViewObject,"TextSpacing"): offset = DraftVecUtils.scaleTo(offset,obj.ViewObject.TextSpacing.Value) else: offset = DraftVecUtils.scaleTo(offset,0.05) if m == "3D": offset = offset.negative() self.tbase = self.tbase.add(offset) q = r.Q self.textpos.translation.setValue([self.tbase.x,self.tbase.y,self.tbase.z]) self.textpos.rotation = coin.SbRotation(q[0],q[1],q[2],q[3]) # set the angle property if round(obj.Angle,utils.precision()) != round(a,utils.precision()): obj.Angle = a
def addtofreecad(self, doc=None, fcpar=None): def center(obj, x, y, z): obj.Placement = FreeCAD.Placement(\ FreeCAD.Vector(-x/2.0,-y/2.0,-z/2.0),\ FreeCAD.Rotation(0,0,0,1)) import FreeCAD, Part if not doc: doc = FreeCAD.newDocument() namel = self.name.lower() multifeature = { 'union': "Part::MultiFuse", 'imp_union': "Part::MultiFuse", 'intersection': "Part::MultiCommon" } if namel in multifeature: if len(self.children) > 1: obj = doc.addObject(multifeature[namel], namel) subobjs = [ child.addtofreecad(doc, obj) for child in self.children ] obj.Shapes = subobjs for subobj in subobjs: subobj.ViewObject.hide() elif len(self.children) == 1: obj = self.children[0].addtofreecad(doc, fcpar or True) else: obj = fcpar elif namel == 'difference': if len(self.children) == 1: obj = self.children[0].addtofreecad(doc, fcpar or True) else: obj = doc.addObject("Part::Cut", namel) base = self.children[0].addtofreecad(doc, obj) if len(self.children) == 2: tool = self.children[1].addtofreecad(doc, obj) else: tool = Node(name='imp_union',\ children=self.children[1:]).addtofreecad(doc,obj) obj.Base = base obj.Tool = tool base.ViewObject.hide() tool.ViewObject.hide() elif namel == 'cube': obj = doc.addObject('Part::Box', namel) x, y, z = self.arguments['size'] obj.Length = x obj.Width = y obj.Height = z if self.arguments['center']: center(obj, x, y, z) elif namel == 'sphere': obj = doc.addObject("Part::Sphere", namel) obj.Radius = self.arguments['r'] elif namel == 'cylinder': h = self.arguments['h'] r1, r2 = self.arguments['r1'], self.arguments['r2'] if '$fn' in self.arguments and self.arguments['$fn'] > 2 \ and self.arguments['$fn']<=Node.fnmin: # polygonal if r1 == r2: # prismatic obj = doc.addObject("Part::Prism", "prism") obj.Polygon = int(self.arguments['$fn']) obj.Length = r1 obj.Height = h if self.arguments['center']: center(obj, 0, 0, h) base.ViewObject.hide() elif True: #use Frustum Feature with makeRuledSurface obj = doc.addObject("Part::FeaturePython", 'frustum') Frustum(obj, r1, r2, int(self.arguments['$fn']), h) ViewProviderTree(obj.ViewObject) if self.arguments['center']: center(obj, 0, 0, h) else: #Use Part::Loft and GetWire Feature obj = doc.addObject('Part::Loft', 'frustum') import Draft p1 = Draft.makePolygon(int(self.arguments['$fn']), r1) p2 = Draft.makePolygon(int(self.arguments['$fn']), r2) if self.arguments['center']: p1.Placement = FreeCAD.Placement(\ FreeCAD.Vector(0.0,0.0,-h/2.0),FreeCAD.Rotation()) p2.Placement = FreeCAD.Placement(\ FreeCAD.Vector(0.0,0.0,h/2.0),FreeCAD.Rotation()) else: p2.Placement = FreeCAD.Placement(\ FreeCAD.Vector(0.0,0.0,h),FreeCAD.Rotation()) w1 = doc.addObject("Part::FeaturePython", 'polygonwire1') w2 = doc.addObject("Part::FeaturePython", 'polygonwire2') GetWire(w1, p1) GetWire(w2, p2) ViewProviderTree(w1.ViewObject) ViewProviderTree(w2.ViewObject) obj.Sections = [w1, w2] obj.Solid = True obj.Ruled = True p1.ViewObject.hide() p2.ViewObject.hide() w1.ViewObject.hide() w2.ViewObject.hide() else: if r1 == r2: obj = doc.addObject("Part::Cylinder", namel) obj.Height = h obj.Radius = r1 else: obj = doc.addObject("Part::Cone", 'cone') obj.Height = h obj.Radius1, obj.Radius2 = r1, r2 if self.arguments['center']: center(obj, 0, 0, h) elif namel == 'polyhedron': obj = doc.addObject("Part::Feature", namel) points = self.arguments['points'] faces = self.arguments['triangles'] shell=Part.Shell([Part.Face(Part.makePolygon(\ [tuple(points[pointindex]) for pointindex in \ (face+face[0:1])])) for face in faces]) # obj.Shape=Part.Solid(shell).removeSplitter() solid = Part.Solid(shell).removeSplitter() if solid.Volume < 0: # solid.complement() solid.reverse() obj.Shape = solid #.removeSplitter() elif namel == 'polygon': obj = doc.addObject("Part::Feature", namel) points = self.arguments['points'] paths = self.arguments.get('paths') if not paths: faces = [ Part.Face( Part.makePolygon([(x, y, 0) for x, y in points + points[0:1]])) ] else: faces= [Part.Face(Part.makePolygon([(points[pointindex][0],points[pointindex][1],0) for \ pointindex in (path+path[0:1])])) for path in paths] obj.Shape = subtractfaces(faces) elif namel == 'square': obj = doc.addObject("Part::Plane", namel) x, y = self.arguments['size'] obj.Length = x obj.Width = y if self.arguments['center']: center(obj, x, y, 0) elif namel == 'circle': r = self.arguments['r'] import Draft if '$fn' in self.arguments and self.arguments['$fn'] != 0 \ and self.arguments['$fn']<=Node.fnmin: obj = Draft.makePolygon(int(self.arguments['$fn']), r) else: obj = Draft.makeCircle(r) # create a Face #obj = doc.addObject("Part::Circle",namel);obj.Radius = r elif namel == 'color': if len(self.children) == 1: obj = self.children[0].addtofreecad(doc, fcpar or True) else: obj = Node(name='imp_union',\ children=self.children).addtofreecad(doc,fcpar or True) obj.ViewObject.ShapeColor = tuple( [float(p) for p in self.arguments[:3]]) #RGB transp = 100 - int(math.floor(100 * self.arguments[3])) #Alpha obj.ViewObject.Transparency = transp elif namel == 'multmatrix': assert (len(self.children) > 0) m1l = [round(f, 12) for f in sum(self.arguments, []) ] #Thats the original matrix m1 = FreeCAD.Matrix(*tuple(m1l)) #Thats the original matrix if isspecialorthogonalpython(fcsubmatrix( m1)): #a Placement can represent the transformation if len(self.children) == 1: obj = self.children[0].addtofreecad(doc, fcpar or True) else: obj = Node(name='imp_union',\ children=self.children).addtofreecad(doc,fcpar or True) #FreeCAD.Console.PrintMessage('obj %s\nmat %s/n' % (obj.Placement,m1)) obj.Placement = FreeCAD.Placement(m1).multiply(obj.Placement) else: #we need to apply the matrix transformation to the Shape using a custom PythonFeature obj = doc.addObject("Part::FeaturePython", namel) if len(self.children) == 1: child = self.children[0].addtofreecad(doc, obj) else: child = Node(name='imp_union',\ children=self.children).addtofreecad(doc,obj) MatrixTransform( obj, m1, child) #This object is not mutable from the GUI ViewProviderTree(obj.ViewObject) #elif namel == 'import': pass #Custom Feature elif namel == 'linear_extrude': height = self.arguments['height'] twist = self.arguments.get('twist') if not twist: obj = doc.addObject("Part::Extrusion", namel) else: #twist obj = doc.addObject("Part::FeaturePython", 'twist_extrude') if len(self.children) == 0: base = Node('import', self.arguments).addtofreecad(doc, obj) elif len(self.children) == 1: base = self.children[0].addtofreecad(doc, obj) else: base = Node(name='imp_union',\ children=self.children).addtofreecad(doc,obj) if False and base.isDerivedFrom('Part::MultiFuse'): #does not solve all the problems newobj = doc.addObject("Part::FeaturePython", 'refine') RefineShape(newobj, base) ViewProviderTree(newobj.ViewObject) base.ViewObject.hide() base = newobj if not twist: obj.Base = base obj.Dir = (0, 0, height) else: #twist Twist(obj, base, height, -twist) ViewProviderTree(obj.ViewObject) if self.arguments['center']: center(obj, 0, 0, height) base.ViewObject.hide() elif namel == 'rotate_extrude': obj = doc.addObject("Part::Revolution", namel) if len(self.children) == 0: base = Node('import', self.arguments).addtofreecad(doc, obj) elif len(self.children) == 1: base = self.children[0].addtofreecad(doc, obj) else: base = Node(name='imp_union',\ children=self.children).addtofreecad(doc,obj) if False and base.isDerivedFrom('Part::MultiFuse'): #creates 'Axe and meridian are confused' Errors newobj = doc.addObject("Part::FeaturePython", 'refine') RefineShape(newobj, base) ViewProviderTree(newobj.ViewObject) base.ViewObject.hide() base = newobj obj.Source = base obj.Axis = (0.00, 1.00, 0.00) obj.Base = (0.00, 0.00, 0.00) obj.Angle = 360.00 base.ViewObject.hide() obj.Placement = FreeCAD.Placement(FreeCAD.Vector(), FreeCAD.Rotation(0, 0, 90)) elif namel == 'projection': if self.arguments['cut']: planename = 'xy_plane_used_for_project_cut' obj = doc.addObject('Part::MultiCommon', 'projection_cut') plane = doc.getObject(planename) if not plane: plane = doc.addObject("Part::Plane", planename) plane.Length = Node.planedim * 2 plane.Width = Node.planedim * 2 plane.Placement = FreeCAD.Placement(FreeCAD.Vector(\ -Node.planedim,-Node.planedim,0),FreeCAD.Rotation(0,0,0,1)) #plane.ViewObject.hide() subobjs = [ child.addtofreecad(doc, obj) for child in self.children ] subobjs.append(plane) obj.Shapes = subobjs for subobj in subobjs: subobj.ViewObject.hide() else: #Do a proper projection raise (NotImplementedError) elif namel == 'import': filename = self.arguments.get('file') scale = self.arguments.get('scale') origin = self.arguments.get('origin') if filename: import os docname = os.path.split(filename)[1] objname, extension = docname.split('.', 1) if not os.path.isabs(filename): try: global lastimportpath filename = os.path.join(lastimportpath, filename) except: raise #no path given # Check for a mesh fileformat support by the Mesh mddule if extension.lower() in reverseimporttypes()['Mesh']: import Mesh mesh1 = doc.getObject(objname) #reuse imported object if not mesh1: Mesh.insert(filename) mesh1 = doc.getObject(objname) mesh1.ViewObject.hide() sh = Part.Shape() sh.makeShapeFromMesh(mesh1.Mesh.Topology, 0.1) solid = Part.Solid(sh) obj = doc.addObject("Part::FeaturePython", 'import_%s_%s' % (extension, objname)) #obj=doc.addObject('Part::Feature',) ImportObject( obj, mesh1) #This object is not mutable from the GUI ViewProviderTree(obj.ViewObject) solid = solid.removeSplitter() if solid.Volume < 0: #sh.reverse() #sh = sh.copy() solid.complement() obj.Shape = solid #.removeSplitter() elif extension in ['dxf']: layera = self.arguments.get('layer') featname = 'import_dxf_%s_%s' % (objname, layera) # reusing an allready imported object does not work if the #shape in not yet calculated import importDXF global dxfcache layers = dxfcache.get(id(doc), []) if layers: try: groupobj = [ go for go in layers if (not layera) or go.Label == layera ] except: groupobj = None else: groupobj = None if not groupobj: groupname = objname layers = importDXF.processdxf( doc, filename) or importDXF.layers dxfcache[id(doc)] = layers[:] for l in layers: for o in l.Group: o.ViewObject.hide() l.ViewObject.hide() groupobj = [ go for go in layers if (not layera) or go.Label == layera ] edges = [] for shapeobj in groupobj[0].Group: edges.extend(shapeobj.Shape.Edges) try: f = edgestofaces(edges) except: FreeCAD.Console.PrintError(\ 'processing of dxf import faild\nPlease rework \'%s\' manualy\n' % layera) f = Part.Shape() #empty Shape obj = doc.addObject("Part::FeaturePython", 'import_dxf_%s_%s' % (objname, layera)) #obj=doc.addObject('Part::Feature',) ImportObject( obj, groupobj[0]) #This object is not mutable from the GUI ViewProviderTree(obj.ViewObject) obj.Shape = f else: FreeCAD.Console.ErrorMessage(\ 'Filetype of %s not supported\n' % (filename)) raise (NotImplementedError) if obj: #handle origin and scale if scale is not None and scale != 1: if origin is not None and any([c != 0 for c in origin]): raise (NotImplementedError ) # order of transformations unkown child = obj m1 = FreeCAD.Matrix() m1.scale(scale, scale, scale) obj = doc.addObject("Part::FeaturePython", 'scale_import') MatrixTransform( obj, m1, child) #This object is not mutable from the GUI ViewProviderTree(obj.ViewObject) elif origin is not None and any([c != 0 for c in origin]): placement = FreeCAD.Placement( FreeCAD.Vector(*[-c for c in origin]), FreeCAD.Rotation()) obj.Placement = placement.multiply(obj.Placement) else: FreeCAD.Console.ErrorMessage('Import of %s failed\n' % (filename)) elif namel == 'minkowski': childrennames = [child.name.lower() for child in self.children] if len(self.children) == 2 and \ childrennames.count('cube')==1 and \ (childrennames.count('sphere') + \ childrennames.count('cylinder')) == 1: if self.children[0].name.lower() == 'cube': cube = self.children[0] roundobj = self.children[1] elif self.children[1].name.lower() == 'cube': cube = self.children[1] roundobj = self.children[0] roundobjname = roundobj.name.lower() issphere = roundobjname == 'sphere' cubeobj = doc.addObject('Part::Box', 'roundedcube') x, y, z = cube.arguments['size'] r=roundobj.arguments.get('r') or \ roundobj.arguments.get('r1') cubeobj.Length = x + 2 * r cubeobj.Width = y + 2 * r cubeobj.Height = z + 2 * r * issphere obj = doc.addObject("Part::Fillet", "%s_%s" % (namel, roundobjname)) obj.Base = cubeobj cubeobj.ViewObject.hide() if issphere: obj.Edges = [(i, r, r) for i in range(1, 13)] else: #cylinder obj.Edges = [(i, r, r) for i in [1, 3, 5, 7]] if cube.arguments['center']: center(cubeobj, x + 2 * r, y + 2 * r, z + 2 * r * issphere) else: #htandle a rotated cylinder #OffsetShape raise (NotImplementedError) elif childrennames.count('sphere') == 1: sphereindex = childrennames.index('sphere') sphere = self.children[sphereindex] offset = sphere.arguments['r'] nonsphere=self.children[0:sphereindex]+\ self.sphere[sphereindex+1:] obj = doc.addObject("Part::FeaturePython", 'Offset') if len(nonsphere) == 1: child = nonsphere[0].addtofreecad(doc, obj) else: child = Node(name='imp_union',\ children=nonsphere).addtofreecad(doc,obj) OffsetShape(obj, child, offset) ViewProviderTree(obj.ViewObject) elif False: raise (NotImplementedError) pass # handle rotated cylinders and select edges that #radius = radius0 * m1.multiply(FreeCAD.Vector(0,0,1)).dot(edge.Curve.tangent(0)[0]) else: raise (NotImplementedError) elif namel == 'surface': obj = doc.addObject("Part::Feature", namel) #include filename? obj.Shape, xoff, yoff = makeSurfaceVolume(self.arguments['file']) if self.arguments['center']: center(obj, xoff, yoff, 0.0) return obj #import os #scadstr = 'surface(file = "%s", center = %s );' % \ # (self.arguments['file'], 'true' if self.arguments['center'] else 'false') #docname=os.path.split(self.arguments['file'])[1] #objname,extension = docname.split('.',1) #obj = openscadmesh(doc,scadstr,objname) elif namel in ['glide', 'hull']: raise (NotImplementedError) elif namel in ['render', 'subdiv'] or True: lenchld = len(self.children) if lenchld == 1: FreeCAD.Console.PrintMessage('Not recognized %s\n' % (self)) obj = self.children[0].addtofreecad(doc, fcpar) elif lenchld > 1: obj = Node(name='imp_union',\ children=self.children).addtofreecad(doc,fcpar or True) else: obj = doc.addObject("Part::Feature", 'Not_Impl_%s' % namel) if fcpar == True: #We are the last real object, our parent is not rendered. return obj if fcpar: try: obj.ViewObject.hide() except: raise if True: #never refine the Shape, as it itroduces crashes return obj else: #refine Shape import Draft if obj.Type =='Part::Extrusion' and obj.Base.Type == 'Part::Part2DObjectPython' and \ isinstance(obj.Base.Proxy,Draft._Polygon) or \ (not obj.isDerivedFrom('Part::Extrusion') and \ not obj.isDerivedFrom('Part::Boolean') and \ not obj.isDerivedFrom('Part::Cut') and \ not obj.isDerivedFrom('Part::MultiCommon') and \ not obj.isDerivedFrom('Part::MultiFuse') and \ not obj.isDerivedFrom('Part::Revolution') ) \ or (obj.isDerivedFrom('Part::FeaturePython') and isinstance(obj.Proxy,RefineShape)): return obj else: newobj = doc.addObject("Part::FeaturePython", 'refine') RefineShape(newobj, obj) ViewProviderTree(newobj.ViewObject) obj.ViewObject.hide() return newobj else: doc.recompute()
def p_multmatrix_action(p): 'multmatrix_action : multmatrix LPAREN matrix RPAREN OBRACE block_list EBRACE' if printverbose: print("MultMatrix") transform_matrix = FreeCAD.Matrix() if printverbose: print("Multmatrix") if printverbose: print(p[3]) m1l=sum(p[3],[]) if any('x' in me for me in m1l): #hexfloats m1l=[float.fromhex(me) for me in m1l] matrixisrounded=False elif max((len(me) for me in m1l)) >= 14: #might have double precision m1l=[float(me) for me in m1l] # assume precise output m1l=[(0 if (abs(me) < 1e-15) else me) for me in m1l] matrixisrounded=False else: #trucanted numbers m1l=[round(float(me),12) for me in m1l] #round matrixisrounded=True transform_matrix = FreeCAD.Matrix(*tuple(m1l)) if printverbose: print(transform_matrix) if printverbose: print("Apply Multmatrix") # If more than one object on the stack for multmatrix fuse first if (len(p[6]) == 0) : part = placeholder('group',[],'{}') elif (len(p[6]) > 1) : part = fuse(p[6],"Matrix Union") else : part = p[6][0] if (isspecialorthogonalpython(fcsubmatrix(transform_matrix))) : if printverbose: print("special orthogonal") if matrixisrounded: if printverbose: print("rotation rounded") plm=FreeCAD.Placement(transform_matrix) plm=FreeCAD.Placement(plm.Base,roundrotation(plm.Rotation)) part.Placement=plm.multiply(part.Placement) else: part.Placement=FreeCAD.Placement(transform_matrix).multiply(\ part.Placement) new_part = part elif isrotoinversionpython(fcsubmatrix(transform_matrix)): if printverbose: print("orthogonal and inversion") cmat,axisvec = decomposerotoinversion(transform_matrix) new_part=doc.addObject("Part::Mirroring",'mirr_%s'%part.Name) new_part.Source=part new_part.Normal=axisvec if matrixisrounded: if printverbose: print("rotation rounded") plm=FreeCAD.Placement(cmat) new_part.Placement=FreeCAD.Placement(plm.Base,roundrotation(plm.Rotation)) else: new_part.Placement=FreeCAD.Placement(cmat) new_part.Label="mirrored %s" % part.Label if gui: part.ViewObject.hide() elif FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\ GetBool('useMultmatrixFeature'): from OpenSCADFeatures import MatrixTransform new_part=doc.addObject("Part::FeaturePython",'Matrix Deformation') MatrixTransform(new_part,transform_matrix,part) if gui: if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\ GetBool('useViewProviderTree'): from OpenSCADFeatures import ViewProviderTree ViewProviderTree(new_part.ViewObject) else: new_part.ViewObject.Proxy = 0 part.ViewObject.hide() else : if printverbose: print("Transform Geometry") # Need to recompute to stop transformGeometry causing a crash doc.recompute() new_part = doc.addObject("Part::Feature","Matrix Deformation") # new_part.Shape = part.Base.Shape.transformGeometry(transform_matrix) new_part.Shape = part.Shape.transformGeometry(transform_matrix) if gui: part.ViewObject.hide() if False : # Does not fix problemfile or beltTighener although later is closer newobj=doc.addObject("Part::FeaturePython",'RefineMultMatrix') RefineShape(newobj,new_part) if gui: newobj.ViewObject.Proxy = 0 new_part.ViewObject.hide() p[0] = [newobj] else : p[0] = [new_part] if printverbose: print("Multmatrix applied")
def execute(self, obj): "constructs the shape of the stairs" if self.clone(obj): return import Part self.steps = [] self.pseudosteps = [] self.structures = [] pl = obj.Placement landings = 0 base = None if obj.Base: if hasattr(obj.Base, "Shape"): if obj.Base.Shape: if obj.Base.Shape.Solids: base = obj.Base.Shape.copy() if (not base) and obj.Width.Value and obj.Height.Value and ( obj.NumberOfSteps > 1): if obj.Base: if not obj.Base.isDerivedFrom("Part::Feature"): return if obj.Base.Shape.Solids: obj.Shape = obj.Base.Shape.copy() obj.Placement = FreeCAD.Placement( obj.Base.Placement).multiply(pl) obj.TreadDepth = 0.0 obj.RiserHeight = 0.0 return if not obj.Base.Shape.Edges: return if obj.Base.Shape.Faces: return if (len(obj.Base.Shape.Edges) == 1): edge = obj.Base.Shape.Edges[0] if isinstance(edge.Curve, (Part.LineSegment, Part.Line)): if obj.Landings == "At center": landings = 1 self.makeStraightStairsWithLanding(obj, edge) else: self.makeStraightStairs(obj, edge) else: if obj.Landings == "At center": landings = 1 self.makeCurvedStairsWithLandings(obj, edge) else: self.makeCurvedStairs(obj, edge) else: if not obj.Length.Value: return edge = Part.LineSegment(Vector(0, 0, 0), Vector(obj.Length.Value, 0, 0)).toShape() if obj.Landings == "At center": landings = 1 self.makeStraightStairsWithLanding(obj, edge) else: self.makeStraightStairs(obj, edge) if self.structures or self.steps: base = Part.makeCompound(self.structures + self.steps) elif self.pseudosteps: shape = Part.makeCompound(self.pseudosteps) obj.Shape = shape obj.Placement = pl return base = self.processSubShapes(obj, base, pl) if base: if not base.isNull(): obj.Shape = base obj.Placement = pl # compute step data if obj.NumberOfSteps > 1: l = obj.Length.Value h = obj.Height.Value if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): l = obj.Base.Shape.Length if obj.Base.Shape.BoundBox.ZLength: h = obj.Base.Shape.BoundBox.ZLength if obj.LandingDepth: obj.TreadDepth = float(l - (landings * obj.LandingDepth.Value)) / ( obj.NumberOfSteps - (1 + landings)) else: obj.TreadDepth = float(l - (landings * obj.Width.Value)) / ( obj.NumberOfSteps - (1 + landings)) obj.RiserHeight = float(h) / obj.NumberOfSteps obj.BlondelRatio = obj.RiserHeight.Value * 2 + obj.TreadDepth.Value
def calculate_placement(globalRotation, edge, offset, RefPt, xlate, align, normal=None, mode='Original', overrideNormal=False): """Orient shape to a local coordinate system (tangent, normal, binormal). Orient shape at parameter offset, normally length. http://en.wikipedia.org/wiki/Euler_angles (previous version) http://en.wikipedia.org/wiki/Quaternions """ # Start with a null Placement so the translation goes to the right place. # Then apply the global orientation. placement = App.Placement() placement.Rotation = globalRotation placement.move(RefPt + xlate) if not align: return placement nullv = App.Vector(0, 0, 0) defNormal = App.Vector(0.0, 0.0, 1.0) if normal: defNormal = normal try: t = edge.tangentAt(get_parameter_from_v0(edge, offset)) t.normalize() except Exception: _wrn(_tr("Cannot calculate path tangent. Copy not aligned.")) return placement if mode in ('Original', 'Tangent'): if normal is None: n = defNormal else: n = normal n.normalize() try: b = t.cross(n) b.normalize() except Exception: # weird special case, tangent and normal parallel b = nullv _wrn(_tr("Tangent and normal are parallel. Copy not aligned.")) return placement if overrideNormal: priority = "XZY" newRot = App.Rotation(t, b, n, priority) # t/x, b/y, n/z else: # must follow X, try to follow Z, Y is what it is priority = "XZY" newRot = App.Rotation(t, n, b, priority) elif mode == 'Frenet': try: n = edge.normalAt(get_parameter_from_v0(edge, offset)) n.normalize() except App.Base.FreeCADError: # no/infinite normals here n = defNormal _msg(_tr("Cannot calculate path normal, using default.")) try: b = t.cross(n) b.normalize() except Exception: b = nullv _wrn(_tr("Cannot calculate path binormal. Copy not aligned.")) return placement priority = "XZY" newRot = App.Rotation(t, n, b, priority) # t/x, n/y, b/z else: _msg(_tr("AlignMode {} is not implemented".format(mode))) return placement # Have valid tangent, normal, binormal newGRot = newRot.multiply(globalRotation) placement.Rotation = newGRot return placement
self.tooltip = tooltip def GetCommands(self): return tuple(self.cmdlist) def GetResources(self): return { 'MenuText': self.menu, 'ToolTip': self.tooltip } """ +-----------------------------------------------+ | the 3 base rotation Placements | +-----------------------------------------------+ """ rotX = App.Placement( App.Vector(0,0,0), App.Rotation( App.Vector(1,0,0), 90. ) ) rotY = App.Placement( App.Vector(0,0,0), App.Rotation( App.Vector(0,1,0), 90. ) ) rotZ = App.Placement( App.Vector(0,0,0), App.Rotation( App.Vector(0,0,1), 90. ) ) """ +-----------------------------------------------+ | returns the object Label (Name) | +-----------------------------------------------+ """ # Label (Name) def labelName( obj ):
def getSVG(section, allOn=False, renderMode="Wireframe", showHidden=False, showFill=False, scale=1, linewidth=1, fontsize=1, techdraw=False, rotation=0): """getSVG(section,[allOn,renderMode,showHidden,showFill,scale,linewidth,fontsize]) : returns an SVG fragment from an Arch section plane. If allOn is True, all cut objects are shown, regardless if they are visible or not. renderMode can be Wireframe (default) or Solid to use the Arch solid renderer. If showHidden is True, the hidden geometry above the section plane is shown in dashed line. If showFill is True, the cut areas get filled with a pattern""" if not section.Objects: return import Part, DraftGeomUtils p = FreeCAD.Placement(section.Placement) direction = p.Rotation.multVec(FreeCAD.Vector(0, 0, 1)) objs = Draft.getGroupContents(section.Objects, walls=True, addgroups=True) if not allOn: objs = Draft.removeHidden(objs) # separate spaces and Draft objects spaces = [] nonspaces = [] drafts = [] windows = [] cutface = None for o in objs: if Draft.getType(o) == "Space": spaces.append(o) elif Draft.getType(o) in ["Dimension", "Annotation"]: drafts.append(o) elif o.isDerivedFrom("Part::Part2DObject"): drafts.append(o) else: nonspaces.append(o) if Draft.getType(o) == "Window": windows.append(o) objs = nonspaces svg = '' fillpattern = '<pattern id="sectionfill" patternUnits="userSpaceOnUse" patternTransform="matrix(5,0,0,5,0,0)"' fillpattern += ' x="0" y="0" width="10" height="10">' fillpattern += '<g>' fillpattern += '<rect width="10" height="10" style="stroke:none; fill:#ffffff" /><path style="stroke:#000000; stroke-width:1" d="M0,0 l10,10" /></g></pattern>' # generating SVG if renderMode in ["Solid", 1]: # render using the Arch Vector Renderer import ArchVRM, WorkingPlane wp = WorkingPlane.plane() wp.setFromPlacement(section.Placement) #wp.inverse() render = ArchVRM.Renderer() render.setWorkingPlane(wp) render.addObjects(objs) if showHidden: render.cut(section.Shape, showHidden) else: render.cut(section.Shape) svg += '<g transform="scale(1,-1)">\n' svg += render.getViewSVG(linewidth="LWPlaceholder") svg += fillpattern svg += render.getSectionSVG(linewidth="SWPlaceholder", fillpattern="sectionfill") if showHidden: svg += render.getHiddenSVG(linewidth="LWPlaceholder") svg += '</g>\n' # print render.info() else: # render using the Drawing module import Drawing, Part shapes, hshapes, sshapes, cutface, cutvolume, invcutvolume = getCutShapes( objs, section, showHidden) if shapes: baseshape = Part.makeCompound(shapes) svgf = Drawing.projectToSVG(baseshape, direction) if svgf: svgf = svgf.replace('stroke-width="0.35"', 'stroke-width="LWPlaceholder"') svgf = svgf.replace('stroke-width="1"', 'stroke-width="LWPlaceholder"') svgf = svgf.replace('stroke-width:0.01', 'stroke-width:LWPlaceholder') svg += svgf if hshapes: hshapes = Part.makeCompound(hshapes) svgh = Drawing.projectToSVG(hshapes, direction) if svgh: svgh = svgh.replace('stroke-width="0.35"', 'stroke-width="LWPlaceholder"') svgh = svgh.replace('stroke-width="1"', 'stroke-width="LWPlaceholder"') svgh = svgh.replace('stroke-width:0.01', 'stroke-width:LWPlaceholder') svgh = svgh.replace( 'fill="none"', 'fill="none"\nstroke-dasharray="DAPlaceholder"') svg += svgh if sshapes: svgs = "" if showFill: #svgs += fillpattern svgs += '<g transform="rotate(180)">\n' for s in sshapes: if s.Edges: #f = Draft.getSVG(s,direction=direction.negative(),linewidth=0,fillstyle="sectionfill",color=(0,0,0)) # temporarily disabling fill patterns f = Draft.getSVG(s, direction=direction.negative(), linewidth=0, fillstyle="#aaaaaa", color=(0, 0, 0)) svgs += f svgs += "</g>\n" sshapes = Part.makeCompound(sshapes) svgs += Drawing.projectToSVG(sshapes, direction) if svgs: svgs = svgs.replace('stroke-width="0.35"', 'stroke-width="SWPlaceholder"') svgs = svgs.replace('stroke-width="1"', 'stroke-width="SWPlaceholder"') svgs = svgs.replace('stroke-width:0.01', 'stroke-width:SWPlaceholder') svgs = svgs.replace('stroke-width="0.35 px"', 'stroke-width="SWPlaceholder"') svgs = svgs.replace('stroke-width:0.35', 'stroke-width:SWPlaceholder') svg += svgs scaledlinewidth = linewidth / scale st = FreeCAD.ParamGet( "User parameter:BaseApp/Preferences/Mod/Arch").GetFloat( "CutLineThickness", 2) yt = FreeCAD.ParamGet( "User parameter:BaseApp/Preferences/Mod/Arch").GetFloat( "SymbolLineThickness", 0.6) da = FreeCAD.ParamGet( "User parameter:BaseApp/Preferences/Mod/Arch").GetString( "archHiddenPattern", "30,10") da = da.replace(" ", "") svg = svg.replace('LWPlaceholder', str(scaledlinewidth) + 'px') svg = svg.replace('SWPlaceholder', str(scaledlinewidth * st) + 'px') svg = svg.replace('DAPlaceholder', str(da)) if drafts: if not techdraw: svg += '<g transform="scale(1,-1)">' for d in drafts: svg += Draft.getSVG(d, scale=scale, linewidth=linewidth * yt, fontsize=fontsize, direction=direction, techdraw=techdraw, rotation=rotation) if not techdraw: svg += '</g>' # filter out spaces not cut by the section plane if cutface and spaces: spaces = [ s for s in spaces if s.Shape.BoundBox.intersect(cutface.BoundBox) ] if spaces: if not techdraw: svg += '<g transform="scale(1,-1)">' for s in spaces: svg += Draft.getSVG(s, scale=scale, linewidth=linewidth * yt, fontsize=fontsize, direction=direction, techdraw=techdraw, rotation=rotation) if not techdraw: svg += '</g>' # add additional edge symbols from windows if cutface and windows: cutwindows = [ w.Name for w in windows if w.Shape.BoundBox.intersect(cutface.BoundBox) ] if windows: sh = [] for w in windows: if not hasattr(w.Proxy, "sshapes"): w.Proxy.execute(w) if hasattr(w.Proxy, "sshapes"): if w.Proxy.sshapes and (w.Name in cutwindows): c = Part.makeCompound(w.Proxy.sshapes) c.Placement = w.Placement sh.append(c) # buggy for now... #if hasattr(w.Proxy,"vshapes"): # if w.Proxy.vshapes: # c = Part.makeCompound(w.Proxy.vshapes) # c.Placement = w.Placement # sh.append(c) if sh: if not techdraw: svg += '<g transform="scale(1,-1)">' for s in sh: svg += Draft.getSVG(s, scale=scale, linewidth=linewidth * yt, fontsize=fontsize, fillstyle="none", direction=direction, techdraw=techdraw, rotation=rotation) if not techdraw: svg += '</g>' #print "complete node:",svg return svg
def createAnnotation(annotation, doc, ifcscale, preferences): """creates an annotation object""" anno = None if annotation.is_a("IfcGrid"): axes = [] uvwaxes = () if annotation.UAxes: uvwaxes = annotation.UAxes if annotation.VAxes: uvwaxes = uvwaxes + annotation.VAxes if annotation.WAxes: uvwaxes = uvwaxes + annotation.WAxes for axis in uvwaxes: if axis.AxisCurve: sh = get2DShape(axis.AxisCurve, ifcscale) if sh and (len(sh[0].Vertexes) == 2): # currently only straight axes are supported sh = sh[0] l = sh.Length pl = FreeCAD.Placement() pl.Base = sh.Vertexes[0].Point pl.Rotation = FreeCAD.Rotation( FreeCAD.Vector(0, 1, 0), sh.Vertexes[-1].Point.sub(sh.Vertexes[0].Point)) o = Arch.makeAxis(1, l) o.Length = l o.Placement = pl o.CustomNumber = axis.AxisTag axes.append(o) if axes: name = "Grid" grid_placement = None if annotation.Name: name = annotation.Name if six.PY2: name = name.encode("utf8") if annotation.ObjectPlacement: # https://forum.freecadweb.org/viewtopic.php?f=39&t=40027 grid_placement = getPlacement(annotation.ObjectPlacement, scaling=1) if preferences['PREFIX_NUMBERS']: name = "ID" + str(aid) + " " + name anno = Arch.makeAxisSystem(axes, name) if grid_placement: anno.Placement = grid_placement print(" axis") else: name = "Annotation" if annotation.Name: name = annotation.Name if six.PY2: name = name.encode("utf8") if "annotation" not in name.lower(): name = "Annotation " + name if preferences['PREFIX_NUMBERS']: name = "ID" + str(aid) + " " + name shapes2d = [] for rep in annotation.Representation.Representations: if rep.RepresentationIdentifier in [ "Annotation", "FootPrint", "Axis" ]: sh = get2DShape(rep, ifcscale) if sh in doc.Objects: # dirty hack: get2DShape might return an object directly if non-shape based (texts for ex) anno = sh else: shapes2d.extend(sh) if shapes2d: import Part sh = Part.makeCompound(shapes2d) #if preferences['DEBUG']: print(" shape") anno = doc.addObject("Part::Feature", name) anno.Shape = sh p = getPlacement(annotation.ObjectPlacement, ifcscale) if p: # and annotation.is_a("IfcAnnotation"): anno.Placement = p #else: #if preferences['DEBUG']: print(" no shape") return anno
def getSVG(section, allOn=False, renderMode="Wireframe", showHidden=False, showFill=False, scale=1, linewidth=1, fontsize=1): """getSVG(section,[allOn,renderMode,showHidden,showFill,scale,linewidth,fontsize]) : returns an SVG fragment from an Arch section plane. If allOn is True, all cut objects are shown, regardless if they are visible or not. renderMode can be Wireframe (default) or Solid to use the Arch solid renderer. If showHidden is True, the hidden geometry above the section plane is shown in dashed line. If showFill is True, the cut areas get filled with a pattern""" if not section.Objects: return import DraftGeomUtils p = FreeCAD.Placement(section.Placement) direction = p.Rotation.multVec(FreeCAD.Vector(0, 0, 1)) objs = Draft.getGroupContents(section.Objects, walls=True, addgroups=True) if not allOn: objs = Draft.removeHidden(objs) # separate spaces spaces = [] nonspaces = [] for o in objs: if Draft.getType(o) == "Space": spaces.append(o) else: nonspaces.append(o) objs = nonspaces svg = '' fillpattern = '<pattern id="sectionfill" patternUnits="userSpaceOnUse" patternTransform="matrix(5,0,0,5,0,0)"' fillpattern += ' x="0" y="0" width="10" height="10">' fillpattern += '<g>' fillpattern += '<rect width="10" height="10" style="stroke:none; fill:#ffffff" /><path style="stroke:#000000; stroke-width:1" d="M0,0 l10,10" /></g></pattern>' # generating SVG if renderMode == "Solid": # render using the Arch Vector Renderer import ArchVRM, WorkingPlane wp = WorkingPlane.plane() wp.setFromPlacement(section.Placement) #wp.inverse() render = ArchVRM.Renderer() render.setWorkingPlane(wp) render.addObjects(objs) if showHidden: render.cut(section.Shape, showHidden) else: render.cut(section.Shape) svg += '<g transform="scale(1,-1)">\n' svg += render.getViewSVG(linewidth="LWPlaceholder") svg += fillpattern svg += render.getSectionSVG(linewidth="SWPlaceholder", fillpattern="sectionfill") if showHidden: svg += render.getHiddenSVG(linewidth="LWPlaceholder") svg += '</g>\n' # print render.info() else: # render using the Drawing module import Drawing, Part shapes = [] hshapes = [] sshapes = [] for o in objs: if o.isDerivedFrom("Part::Feature"): if o.Shape.isNull(): pass elif o.Shape.isValid(): if section.OnlySolids: shapes.extend(o.Shape.Solids) else: shapes.append(o.Shape) else: print section.Label, ": Skipping invalid object:", o.Label cutface, cutvolume, invcutvolume = ArchCommands.getCutVolume( section.Shape.copy(), shapes) if cutvolume: nsh = [] for sh in shapes: for sol in sh.Solids: if sol.Volume < 0: sol.reverse() c = sol.cut(cutvolume) s = sol.section(cutface) try: wires = DraftGeomUtils.findWires(s.Edges) for w in wires: f = Part.Face(w) sshapes.append(f) #s = Part.Wire(s.Edges) #s = Part.Face(s) except Part.OCCError: #print "ArchDrawingView: unable to get a face" sshapes.append(s) nsh.extend(c.Solids) #sshapes.append(s) if showHidden: c = sol.cut(invcutvolume) hshapes.append(c) shapes = nsh if shapes: baseshape = Part.makeCompound(shapes) svgf = Drawing.projectToSVG(baseshape, direction) if svgf: svgf = svgf.replace('stroke-width="0.35"', 'stroke-width="LWPlaceholder"') svgf = svgf.replace('stroke-width="1"', 'stroke-width="LWPlaceholder"') svgf = svgf.replace('stroke-width:0.01', 'stroke-width:LWPlaceholder') svg += svgf if hshapes: hshapes = Part.makeCompound(hshapes) svgh = Drawing.projectToSVG(hshapes, direction) if svgh: svgh = svgh.replace('stroke-width="0.35"', 'stroke-width="LWPlaceholder"') svgh = svgh.replace('stroke-width="1"', 'stroke-width="LWPlaceholder"') svgh = svgh.replace('stroke-width:0.01', 'stroke-width:LWPlaceholder') svgh = svgh.replace( 'fill="none"', 'fill="none"\nstroke-dasharray="DAPlaceholder"') svg += svgh if sshapes: svgs = "" if showFill: svgs += fillpattern svgs += '<g transform="rotate(180)">\n' for s in sshapes: if s.Edges: f = Draft.getSVG(s, direction=direction.negative(), linewidth=0, fillstyle="sectionfill", color=(0, 0, 0)) svgs += f svgs += "</g>\n" sshapes = Part.makeCompound(sshapes) svgs += Drawing.projectToSVG(sshapes, direction) if svgs: svgs = svgs.replace('stroke-width="0.35"', 'stroke-width="SWPlaceholder"') svgs = svgs.replace('stroke-width="1"', 'stroke-width="SWPlaceholder"') svgs = svgs.replace('stroke-width:0.01', 'stroke-width:SWPlaceholder') svgs = svgs.replace('stroke-width="0.35 px"', 'stroke-width="SWPlaceholder"') svgs = svgs.replace('stroke-width:0.35', 'stroke-width:SWPlaceholder') svg += svgs linewidth = linewidth / scale st = FreeCAD.ParamGet( "User parameter:BaseApp/Preferences/Mod/Arch").GetFloat( "CutLineThickness", 2) da = FreeCAD.ParamGet( "User parameter:BaseApp/Preferences/Mod/Arch").GetString( "archHiddenPattern", "30,10") da = da.replace(" ", "") svg = svg.replace('LWPlaceholder', str(linewidth) + 'px') svg = svg.replace('SWPlaceholder', str(linewidth * st) + 'px') svg = svg.replace('DAPlaceholder', str(da)) if spaces and round( direction.getAngle(FreeCAD.Vector(0, 0, 1)), Draft.precision()) in [0, round(math.pi, Draft.precision())]: svg += '<g transform="scale(1,-1)">' for s in spaces: svg += Draft.getSVG(s, scale=scale, fontsize=fontsize, direction=direction) svg += '</g>' # print "complete node:",svg return svg
def execute(self, obj): # When operating on the object, it is to be treated as a lattice object. If False, treat as a regular shape.''' if hasattr(obj, "isLattice"): if 'On' in obj.isLattice: print( obj.Name + " A generic shape is expected, but an array of placements was supplied. It will be treated as a generic shape.\n" ) rst = [] # variable to receive the final list of shapes shps = obj.Base.Shape.childShapes() if obj.FilterType == 'bypass': rst = shps elif obj.FilterType == 'specific items': rst = [] flags = [False] * len(shps) ranges = obj.items.split(';') for r in ranges: r_v = r.split(':') if len(r_v) == 1: i = int(r_v[0]) rst.append(shps[i]) flags[i] = True elif len(r_v) == 2 or len(r_v) == 3: if len(r_v) == 2: r_v.append( "" ) # fix issue #1: instead of checking length here and there, simply add the missing field =) (DeepSOIC) ifrom = None if len(r_v[0].strip()) == 0 else int(r_v[0]) ito = None if len(r_v[1].strip()) == 0 else int(r_v[1]) istep = None if len(r_v[2].strip()) == 0 else int(r_v[2]) rst = rst + shps[ifrom:ito:istep] for b in flags[ifrom:ito:istep]: b = True else: raise ValueError('index range cannot be parsed:' + r) if obj.Invert: rst = [] for i in xrange(0, len(shps)): if not flags[i]: rst.append(shps[i]) elif obj.FilterType == 'collision-pass': stencil = obj.Stencil.Shape for s in shps: d = s.distToShape(stencil) if bool(d[0] < DistConfusion) ^ bool(obj.Invert): rst.append(s) elif obj.FilterType == 'window-volume' or obj.FilterType == 'window-area' or obj.FilterType == 'window-length' or obj.FilterType == 'window-distance': vals = [0.0] * len(shps) for i in xrange(0, len(shps)): if obj.FilterType == 'window-volume': vals[i] = shps[i].Volume elif obj.FilterType == 'window-area': vals[i] = shps[i].Area elif obj.FilterType == 'window-length': vals[i] = shps[i].Length elif obj.FilterType == 'window-distance': vals[i] = shps[i].distToShape(obj.Stencil.Shape)[0] maxval = max(vals) if obj.Stencil: if obj.FilterType == 'window-volume': maxval = obj.Stencil.Shape.Volume elif obj.FilterType == 'window-area': maxval = obj.Stencil.Shape.Area elif obj.FilterType == 'window-length': maxval = obj.Stencil.Shape.Length if obj.OverrideMaxVal: maxval = obj.OverrideMaxVal valFrom = obj.WindowFrom / 100.0 * maxval valTo = obj.WindowTo / 100.0 * maxval for i in xrange(0, len(shps)): if bool(vals[i] >= valFrom and vals[i] <= valTo) ^ obj.Invert: rst.append(shps[i]) else: raise ValueError('Filter mode not implemented:' + obj.FilterType) if len(rst) == 0: scale = 1.0 if not obj.Base.Shape.isNull(): scale = obj.Base.Shape.BoundBox.DiagonalLength / math.sqrt( 3) / math.sqrt(len(shps)) if scale < DistConfusion * 100: scale = 1.0 print(scale) obj.Shape = getNullShapeShape(scale) raise ValueError( 'Nothing passes through the filter' ) # Feeding empty compounds to FreeCAD seems to cause rendering issues, otherwise it would have been a good idea to output nothing. if len(rst) > 1: obj.Shape = Part.makeCompound(rst) else: # don't make compound of one shape, output it directly sh = rst[0] sh.transformShape(sh.Placement.toMatrix(), True) # True = make copy sh.Placement = FreeCAD.Placement() obj.Shape = sh return
def _create_objects(doc=None, font_file="/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf" ): """Create the objects of the test file. Parameters ---------- doc: App::Document, optional It defaults to `None`, which then defaults to the current active document, or creates a new document. """ if not doc: doc = App.activeDocument() if not doc: doc = App.newDocument() # Line, wire, and fillet _msg(16 * "-") _msg("Line") Draft.make_line(Vector(0, 0, 0), Vector(500, 500, 0)) t_xpos = -50 t_ypos = -200 _set_text(["Line"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Wire") Draft.make_wire( [Vector(500, 0, 0), Vector(1000, 500, 0), Vector(1000, 1000, 0)]) t_xpos += 500 _set_text(["Wire"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Fillet") line_h_1 = Draft.make_line(Vector(1500, 0, 0), Vector(1500, 500, 0)) line_h_2 = Draft.make_line(Vector(1500, 500, 0), Vector(2000, 500, 0)) if App.GuiUp: line_h_1.ViewObject.DrawStyle = "Dotted" line_h_2.ViewObject.DrawStyle = "Dotted" doc.recompute() Draft.make_fillet([line_h_1, line_h_2], 400) t_xpos += 900 _set_text(["Fillet"], Vector(t_xpos, t_ypos, 0)) # Circle, arc, arc by 3 points _msg(16 * "-") _msg("Circle") circle = Draft.make_circle(350) circle.Placement.Base = Vector(2500, 500, 0) t_xpos += 1050 _set_text(["Circle"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Circular arc") arc = Draft.make_circle(350, startangle=0, endangle=100) arc.Placement.Base = Vector(3200, 500, 0) t_xpos += 800 _set_text(["Circular arc"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Circular arc 3 points") Draft.make_arc_3points( [Vector(4600, 0, 0), Vector(4600, 800, 0), Vector(4000, 1000, 0)]) t_xpos += 600 _set_text(["Circular arc 3 points"], Vector(t_xpos, t_ypos, 0)) # Ellipse, polygon, rectangle _msg(16 * "-") _msg("Ellipse") ellipse = Draft.make_ellipse(500, 300) ellipse.Placement.Base = Vector(5500, 250, 0) t_xpos += 1600 _set_text(["Ellipse"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Polygon") polygon = Draft.make_polygon(5, 250) polygon.Placement.Base = Vector(6500, 500, 0) t_xpos += 950 _set_text(["Polygon"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Rectangle") rectangle = Draft.make_rectangle(500, 1000, 0) rectangle.Placement.Base = Vector(7000, 0, 0) t_xpos += 650 _set_text(["Rectangle"], Vector(t_xpos, t_ypos, 0)) # Text _msg(16 * "-") _msg("Text") text = Draft.make_text(["Testing", "text"], Vector(7700, 500, 0)) if App.GuiUp: text.ViewObject.FontSize = 100 t_xpos += 700 _set_text(["Text"], Vector(t_xpos, t_ypos, 0)) # Linear dimension _msg(16 * "-") _msg("Linear dimension") line = Draft.make_wire([Vector(8700, 200, 0), Vector(8700, 1200, 0)]) dimension = Draft.make_linear_dimension(Vector(8600, 200, 0), Vector(8600, 1000, 0), Vector(8400, 750, 0)) if App.GuiUp: dimension.ViewObject.ArrowSize = 15 dimension.ViewObject.ExtLines = 1000 dimension.ViewObject.ExtOvershoot = 100 dimension.ViewObject.DimOvershoot = 50 dimension.ViewObject.FontSize = 100 dimension.ViewObject.ShowUnit = False doc.recompute() dim_obj = Draft.make_linear_dimension_obj(line, 1, 2, Vector(9000, 750, 0)) if App.GuiUp: dim_obj.ViewObject.ArrowSize = 15 dim_obj.ViewObject.ArrowType = "Arrow" dim_obj.ViewObject.ExtLines = 100 dim_obj.ViewObject.ExtOvershoot = 100 dim_obj.ViewObject.DimOvershoot = 50 dim_obj.ViewObject.FontSize = 100 dim_obj.ViewObject.ShowUnit = False t_xpos += 680 _set_text(["Dimension"], Vector(t_xpos, t_ypos, 0)) # Radius and diameter dimension _msg(16 * "-") _msg("Radius and diameter dimension") arc_h = Draft.make_circle(500, startangle=0, endangle=90) arc_h.Placement.Base = Vector(9500, 0, 0) doc.recompute() dimension_r = Draft.make_radial_dimension_obj(arc_h, 1, "radius", Vector(9750, 200, 0)) if App.GuiUp: dimension_r.ViewObject.ArrowSize = 15 dimension_r.ViewObject.FontSize = 100 dimension_r.ViewObject.ShowUnit = False arc_h2 = Draft.make_circle(450, startangle=-120, endangle=80) arc_h2.Placement.Base = Vector(10000, 1000, 0) doc.recompute() dimension_d = Draft.make_radial_dimension_obj(arc_h2, 1, "diameter", Vector(10750, 900, 0)) if App.GuiUp: dimension_d.ViewObject.ArrowSize = 15 dimension_d.ViewObject.FontSize = 100 dimension_d.ViewObject.ShowUnit = False t_xpos += 950 _set_text(["Radius dimension", "Diameter dimension"], Vector(t_xpos, t_ypos, 0)) # Angular dimension _msg(16 * "-") _msg("Angular dimension") Draft.make_line(Vector(10500, 300, 0), Vector(11500, 1000, 0)) Draft.make_line(Vector(10500, 300, 0), Vector(11500, 0, 0)) angle1 = -20 angle2 = 40 dimension_a = Draft.make_angular_dimension(Vector(10500, 300, 0), [angle1, angle2], Vector(11500, 300, 0)) if App.GuiUp: dimension_a.ViewObject.ArrowSize = 15 dimension_a.ViewObject.FontSize = 100 t_xpos += 1700 _set_text(["Angle dimension"], Vector(t_xpos, t_ypos, 0)) # BSpline _msg(16 * "-") _msg("BSpline") Draft.make_bspline([ Vector(12500, 0, 0), Vector(12500, 500, 0), Vector(13000, 500, 0), Vector(13000, 1000, 0) ]) t_xpos += 1500 _set_text(["BSpline"], Vector(t_xpos, t_ypos, 0)) # Point _msg(16 * "-") _msg("Point") point = Draft.make_point(13500, 500, 0) if App.GuiUp: point.ViewObject.PointSize = 10 t_xpos += 900 _set_text(["Point"], Vector(t_xpos, t_ypos, 0)) # Shapestring _msg(16 * "-") _msg("Shapestring") try: shape_string = Draft.make_shapestring("Testing", font_file, 100) shape_string.Placement.Base = Vector(14000, 500) except Exception: _wrn("Shapestring could not be created") _wrn("Possible cause: the font file may not exist") _wrn(font_file) rect = Draft.make_rectangle(500, 100) rect.Placement.Base = Vector(14000, 500) t_xpos += 600 _set_text(["Shapestring"], Vector(t_xpos, t_ypos, 0)) # Facebinder _msg(16 * "-") _msg("Facebinder") box = doc.addObject("Part::Box", "Cube") box.Length = 200 box.Width = 500 box.Height = 100 box.Placement.Base = Vector(15000, 0, 0) if App.GuiUp: box.ViewObject.Visibility = False facebinder = Draft.make_facebinder([(box, ("Face1", "Face3", "Face6"))]) facebinder.Extrusion = 10 t_xpos += 780 _set_text(["Facebinder"], Vector(t_xpos, t_ypos, 0)) # Cubic bezier curve, n-degree bezier curve _msg(16 * "-") _msg("Cubic bezier") Draft.make_bezcurve([ Vector(15500, 0, 0), Vector(15578, 485, 0), Vector(15879, 154, 0), Vector(15975, 400, 0), Vector(16070, 668, 0), Vector(16423, 925, 0), Vector(16500, 500, 0) ], degree=3) t_xpos += 680 _set_text(["Cubic bezier"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("N-degree bezier") Draft.make_bezcurve([ Vector(16500, 0, 0), Vector(17000, 500, 0), Vector(17500, 500, 0), Vector(17500, 1000, 0), Vector(17000, 1000, 0), Vector(17063, 1256, 0), Vector(17732, 1227, 0), Vector(17790, 720, 0), Vector(17702, 242, 0) ]) t_xpos += 1200 _set_text(["n-Bezier"], Vector(t_xpos, t_ypos, 0)) # Label _msg(16 * "-") _msg("Label") place = App.Placement(Vector(18500, 500, 0), App.Rotation()) label = Draft.make_label(target_point=Vector(18000, 0, 0), placement=place, custom_text="Example label", distance=-250) label.Text = "Testing" if App.GuiUp: label.ViewObject.ArrowSize = 15 label.ViewObject.TextSize = 100 doc.recompute() t_xpos += 1200 _set_text(["Label"], Vector(t_xpos, t_ypos, 0)) # Orthogonal array and orthogonal link array _msg(16 * "-") _msg("Orthogonal array") rect_h = Draft.make_rectangle(500, 500) rect_h.Placement.Base = Vector(1500, 2500, 0) if App.GuiUp: rect_h.ViewObject.Visibility = False Draft.make_ortho_array(rect_h, Vector(600, 0, 0), Vector(0, 600, 0), Vector(0, 0, 0), 3, 2, 1, use_link=False) t_xpos = 1700 t_ypos = 2200 _set_text(["Array"], Vector(t_xpos, t_ypos, 0)) rect_h_2 = Draft.make_rectangle(500, 100) rect_h_2.Placement.Base = Vector(1500, 5000, 0) if App.GuiUp: rect_h_2.ViewObject.Visibility = False _msg(16 * "-") _msg("Orthogonal link array") Draft.make_ortho_array(rect_h_2, Vector(800, 0, 0), Vector(0, 500, 0), Vector(0, 0, 0), 2, 4, 1, use_link=True) t_ypos += 2600 _set_text(["Link array"], Vector(t_xpos, t_ypos, 0)) # Polar array and polar link array _msg(16 * "-") _msg("Polar array") wire_h = Draft.make_wire([ Vector(5500, 3000, 0), Vector(6000, 3500, 0), Vector(6000, 3200, 0), Vector(5800, 3200, 0) ]) if App.GuiUp: wire_h.ViewObject.Visibility = False Draft.make_polar_array(wire_h, 8, 200, Vector(5000, 3000, 0), use_link=False) t_xpos = 4600 t_ypos = 2200 _set_text(["Polar array"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Polar link array") wire_h_2 = Draft.make_wire([ Vector(5500, 6000, 0), Vector(6000, 6000, 0), Vector(5800, 5700, 0), Vector(5800, 5750, 0) ]) if App.GuiUp: wire_h_2.ViewObject.Visibility = False Draft.make_polar_array(wire_h_2, 8, 200, Vector(5000, 6000, 0), use_link=True) t_ypos += 3200 _set_text(["Polar link array"], Vector(t_xpos, t_ypos, 0)) # Circular array and circular link array _msg(16 * "-") _msg("Circular array") poly_h = Draft.make_polygon(5, 200) poly_h.Placement.Base = Vector(8000, 3000, 0) if App.GuiUp: poly_h.ViewObject.Visibility = False Draft.make_circular_array(poly_h, 500, 600, 3, 1, Vector(0, 0, 1), Vector(0, 0, 0), use_link=False) t_xpos = 7700 t_ypos = 1700 _set_text(["Circular array"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Circular link array") poly_h_2 = Draft.make_polygon(6, 150) poly_h_2.Placement.Base = Vector(8000, 6250, 0) if App.GuiUp: poly_h_2.ViewObject.Visibility = False Draft.make_circular_array(poly_h_2, 550, 450, 3, 1, Vector(0, 0, 1), Vector(0, 0, 0), use_link=True) t_ypos += 3100 _set_text(["Circular link array"], Vector(t_xpos, t_ypos, 0)) # Path array and path link array _msg(16 * "-") _msg("Path array") poly_h = Draft.make_polygon(3, 250) poly_h.Placement.Base = Vector(10000, 3000, 0) if App.GuiUp: poly_h.ViewObject.Visibility = False bspline_path = Draft.make_bspline([ Vector(10500, 2500, 0), Vector(11000, 3000, 0), Vector(11500, 3200, 0), Vector(12000, 4000, 0) ]) Draft.make_path_array(poly_h, bspline_path, 5, use_link=False) t_xpos = 10400 t_ypos = 2200 _set_text(["Path array"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Path link array") poly_h_2 = Draft.make_polygon(4, 200) poly_h_2.Placement.Base = Vector(10000, 5000, 0) if App.GuiUp: poly_h_2.ViewObject.Visibility = False bspline_path_2 = Draft.make_bspline([ Vector(10500, 4500, 0), Vector(11000, 6800, 0), Vector(11500, 6000, 0), Vector(12000, 5200, 0) ]) Draft.make_path_array(poly_h_2, bspline_path_2, 6, use_link=True) t_ypos += 2000 _set_text(["Path link array"], Vector(t_xpos, t_ypos, 0)) # Point array _msg(16 * "-") _msg("Point array") poly_h = Draft.make_polygon(3, 250) poly_h.Placement.Base = Vector(12500, 2500, 0) point_1 = Draft.make_point(13000, 3000, 0) point_2 = Draft.make_point(13000, 3500, 0) point_3 = Draft.make_point(14000, 2500, 0) point_4 = Draft.make_point(14000, 3000, 0) add_list, delete_list = Draft.upgrade([point_1, point_2, point_3, point_4]) compound = add_list[0] if App.GuiUp: compound.ViewObject.PointSize = 5 Draft.make_point_array(poly_h, compound) t_xpos = 13000 t_ypos = 2200 _set_text(["Point array"], Vector(t_xpos, t_ypos, 0)) # Clone and mirror _msg(16 * "-") _msg("Clone") wire_h = Draft.make_wire([ Vector(15000, 2500, 0), Vector(15200, 3000, 0), Vector(15500, 2500, 0), Vector(15200, 2300, 0) ]) Draft.make_clone(wire_h, Vector(0, 1000, 0)) t_xpos = 15000 t_ypos = 2100 _set_text(["Clone"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Mirror") wire_h = Draft.make_wire([ Vector(17000, 2500, 0), Vector(16500, 4000, 0), Vector(16000, 2700, 0), Vector(16500, 2500, 0), Vector(16700, 2700, 0) ]) Draft.mirror(wire_h, Vector(17100, 2000, 0), Vector(17100, 4000, 0)) t_xpos = 17000 t_ypos = 2200 _set_text(["Mirror"], Vector(t_xpos, t_ypos, 0)) doc.recompute()
def onBeforeChange(self, obj, prop): if prop == "Placement": self.oldPlacement = FreeCAD.Placement(obj.Placement)
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 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 normal = baseprofile.Faces[0].normalAt( 0, 0).multiply(thickness) base = base.extrude(normal) elif base.Wires: closed = True for w in base.Wires: if not w.isClosed(): closed = False if closed: baseprofile = ArchCommands.makeFace(base.Wires) 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: 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 onChanged(self, vobj, prop): if prop == "LineColor": l = vobj.LineColor self.mat1.diffuseColor.setValue([l[0], l[1], l[2]]) self.mat2.diffuseColor.setValue([l[0], l[1], l[2]]) elif prop == "Transparency": if hasattr(vobj, "Transparency"): self.mat2.transparency.setValue(vobj.Transparency / 100.0) elif prop in ["DisplayLength", "DisplayHeight", "ArrowSize"]: if hasattr(vobj, "DisplayLength"): ld = vobj.DisplayLength.Value / 2 hd = vobj.DisplayHeight.Value / 2 elif hasattr(vobj, "DisplaySize"): # old objects ld = vobj.DisplaySize.Value / 2 hd = vobj.DisplaySize.Value / 2 else: ld = 1 hd = 1 verts = [] fverts = [] for v in [[-ld, -hd], [ld, -hd], [ld, hd], [-ld, hd]]: if hasattr(vobj, "ArrowSize"): l1 = vobj.ArrowSize.Value if vobj.ArrowSize.Value > 0 else 0.1 else: l1 = 0.1 l2 = l1 / 3 pl = FreeCAD.Placement(vobj.Object.Placement) p1 = pl.multVec(Vector(v[0], v[1], 0)) p2 = pl.multVec(Vector(v[0], v[1], -l1)) p3 = pl.multVec(Vector(v[0] - l2, v[1], -l1 + l2)) p4 = pl.multVec(Vector(v[0] + l2, v[1], -l1 + l2)) p5 = pl.multVec(Vector(v[0], v[1] - l2, -l1 + l2)) p6 = pl.multVec(Vector(v[0], v[1] + l2, -l1 + l2)) verts.extend([[p1.x, p1.y, p1.z], [p2.x, p2.y, p2.z]]) fverts.append([p1.x, p1.y, p1.z]) verts.extend([[p2.x, p2.y, p2.z], [p3.x, p3.y, p3.z], [p4.x, p4.y, p4.z], [p2.x, p2.y, p2.z]]) verts.extend([[p2.x, p2.y, p2.z], [p5.x, p5.y, p5.z], [p6.x, p6.y, p6.z], [p2.x, p2.y, p2.z]]) verts.extend(fverts + [fverts[0]]) self.lcoords.point.setValues(verts) self.fcoords.point.setValues(fverts) elif prop == "LineWidth": self.drawstyle.lineWidth = vobj.LineWidth elif prop == "CutView": if hasattr(vobj, "CutView") and FreeCADGui.ActiveDocument.ActiveView: sg = FreeCADGui.ActiveDocument.ActiveView.getSceneGraph() if vobj.CutView: if self.clip: sg.removeChild(self.clip) self.clip = None for o in Draft.getGroupContents(vobj.Object.Objects, walls=True): if hasattr(o.ViewObject, "Lighting"): o.ViewObject.Lighting = "One side" self.clip = coin.SoClipPlane() self.clip.on.setValue(True) norm = vobj.Object.Proxy.getNormal(vobj.Object) mp = vobj.Object.Shape.CenterOfMass mp = DraftVecUtils.project(mp, norm) dist = mp.Length #- 0.1 # to not clip exactly on the section object norm = norm.negative() if mp.getAngle(norm) > 1: dist += 1 dist = -dist else: dist -= 0.1 plane = coin.SbPlane(coin.SbVec3f(norm.x, norm.y, norm.z), dist) self.clip.plane.setValue(plane) sg.insertChild(self.clip, 0) else: if self.clip: sg.removeChild(self.clip) self.clip = None return
def make_text(string, placement=None, screen=False): """Create a Text object containing the given list of strings. The current color and text height and font specified in preferences are used. Parameters ---------- string: str, or list of str String to display on screen. If it is a list, each element in the list represents a new text line. placement: Base::Placement, Base::Vector3, or Base::Rotation, optional It defaults to `None`. If it is provided, it is the placement of the new text. The input could be a full placement, just a vector indicating the translation, or just a rotation. screen: bool, optional It defaults to `False`, in which case the text is placed in 3D space oriented like any other object, on top of a given plane, by the default the XY plane. If it is `True`, the text will always face perpendicularly to the camera direction, that is, it will be flat on the screen. Returns ------- App::FeaturePython A scripted object of type `'Text'`. This object does not have a `Shape` attribute, as the text is created on screen by Coin (pivy). None If there is a problem it will return `None`. """ _name = "make_text" utils.print_header(_name, "Text") found, doc = utils.find_doc(App.activeDocument()) if not found: _err(translate("draft", "No active document. Aborting.")) return None _msg("string: {}".format(string)) try: utils.type_check([(string, (str, list))], name=_name) except TypeError: _err( translate( "draft", "Wrong input: must be a list of strings or a single string.")) return None if (type(string) is list and not all(isinstance(element, str) for element in string)): _err( translate( "draft", "Wrong input: must be a list of strings or a single string.")) return None _msg("placement: {}".format(placement)) if not placement: placement = App.Placement() try: utils.type_check([(placement, (App.Placement, App.Vector, App.Rotation))], name=_name) except TypeError: _err( translate( "draft", "Wrong input: must be a placement, a vector, or a rotation.")) return None # Convert the vector or rotation to a full placement if isinstance(placement, App.Vector): placement = App.Placement(placement, App.Rotation()) elif isinstance(placement, App.Rotation): placement = App.Placement(App.Vector(), placement) new_obj = doc.addObject("App::FeaturePython", "Text") Text(new_obj) new_obj.Text = string new_obj.Placement = placement if App.GuiUp: ViewProviderText(new_obj.ViewObject) h = utils.get_param("textheight", 2) new_obj.ViewObject.DisplayMode = "3D text" if screen: _msg("screen: {}".format(screen)) new_obj.ViewObject.DisplayMode = "2D text" h = h * 10 new_obj.ViewObject.FontSize = h new_obj.ViewObject.FontName = utils.get_param("textfont", "") new_obj.ViewObject.LineSpacing = 1 gui_utils.format_object(new_obj) gui_utils.select(new_obj) return new_obj
def getProfiles(self, obj, noplacement=False): "Returns the base profile(s) of this component, if applicable" wires = [] n, l, w, h = self.getDefaultValues(obj) if obj.Base: if obj.Base.isDerivedFrom("Part::Extrusion"): if obj.Base.Base: base = obj.Base.Base.Shape.copy() #if noplacement: # base.Placement = FreeCAD.Placement() return [base] elif obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape: base = obj.Base.Shape.copy() if noplacement: base.Placement = FreeCAD.Placement() if not base.Solids: if base.Faces: import DraftGeomUtils if not DraftGeomUtils.isCoplanar(base.Faces): return [] return [base] basewires = [] if not base.Wires: if len(base.Edges) == 1: import Part basewires = [Part.Wire(base.Edges)] else: basewires = base.Wires if basewires: import DraftGeomUtils, DraftVecUtils, Part for wire in basewires: e = wire.Edges[0] if isinstance(e.Curve, Part.Circle): dvec = e.Vertexes[0].Point.sub( e.Curve.Center) else: dvec = DraftGeomUtils.vec( wire.Edges[0]).cross(n) if not DraftVecUtils.isNull(dvec): dvec.normalize() sh = None if hasattr(obj, "Align"): if obj.Align == "Left": dvec.multiply(w) if hasattr(obj, "Offset"): if obj.Offset.Value: dvec2 = DraftVecUtils.scaleTo( dvec, obj.Offset.Value) wire = DraftGeomUtils.offsetWire( wire, dvec2) w2 = DraftGeomUtils.offsetWire( wire, dvec) w1 = Part.Wire( Part.__sortEdges__(wire.Edges)) sh = DraftGeomUtils.bind(w1, w2) elif obj.Align == "Right": dvec.multiply(w) dvec = dvec.negative() if hasattr(obj, "Offset"): if obj.Offset.Value: dvec2 = DraftVecUtils.scaleTo( dvec, obj.Offset.Value) wire = DraftGeomUtils.offsetWire( wire, dvec2) w2 = DraftGeomUtils.offsetWire( wire, dvec) w1 = Part.Wire( Part.__sortEdges__(wire.Edges)) sh = DraftGeomUtils.bind(w1, w2) elif obj.Align == "Center": dvec.multiply(w / 2) w1 = DraftGeomUtils.offsetWire( wire, dvec) dvec = dvec.negative() w2 = DraftGeomUtils.offsetWire( wire, dvec) sh = DraftGeomUtils.bind(w1, w2) if sh: wires.append(sh) else: wires.append(wire) elif Draft.getType(obj) in ["Wall", "Structure"]: if (Draft.getType(obj) == "Structure") and (l > h): if noplacement: h2 = h / 2 or 0.5 w2 = w / 2 or 0.5 v1 = Vector(-h2, -w2, 0) v2 = Vector(h2, -w2, 0) v3 = Vector(h2, w2, 0) v4 = Vector(-h2, w2, 0) else: h2 = h / 2 or 0.5 w2 = w / 2 or 0.5 v1 = Vector(0, -w2, -h2) v2 = Vector(0, -w2, h2) v3 = Vector(0, w2, h2) v4 = Vector(0, w2, -h2) else: l2 = l / 2 or 0.5 w2 = w / 2 or 0.5 v1 = Vector(-l2, -w2, 0) v2 = Vector(l2, -w2, 0) v3 = Vector(l2, w2, 0) v4 = Vector(-l2, w2, 0) import Part base = Part.makePolygon([v1, v2, v3, v4, v1]) return [base] return wires
def getExtrusionData(self,obj): """returns (shape,extrusion vector,placement) or None""" import Part,DraftGeomUtils data = ArchComponent.Component.getExtrusionData(self,obj) if data: if not isinstance(data[0],list): # multifuses not considered here return data length = obj.Length.Value width = obj.Width.Value height = obj.Height.Value if not height: for p in obj.InList: if Draft.getType(p) in ["Floor","BuildingPart"]: if p.Height.Value: height = p.Height.Value if not height: return None if obj.Normal == Vector(0,0,0): normal = Vector(0,0,1) else: normal = Vector(obj.Normal) base = None placement = None self.basewires = None # build wall layers layers = [] if hasattr(obj,"Material"): if obj.Material: if hasattr(obj.Material,"Materials"): varwidth = 0 restwidth = width - sum(obj.Material.Thicknesses) if restwidth > 0: varwidth = [t for t in obj.Material.Thicknesses if t == 0] if varwidth: varwidth = restwidth/len(varwidth) for t in obj.Material.Thicknesses: if t: layers.append(t) elif varwidth: layers.append(varwidth) if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape: if obj.Base.Shape.Solids: return None elif obj.Face > 0: if len(obj.Base.Shape.Faces) >= obj.Face: face = obj.Base.Shape.Faces[obj.Face-1] # this wall is based on a specific face of its base object if obj.Normal != Vector(0,0,0): normal = face.normalAt(0,0) if normal.getAngle(Vector(0,0,1)) > math.pi/4: normal.multiply(width) base = face.extrude(normal) if obj.Align == "Center": base.translate(normal.negative().multiply(0.5)) elif obj.Align == "Right": base.translate(normal.negative()) else: normal.multiply(height) base = face.extrude(normal) base,placement = self.rebase(base) return (base,normal,placement) elif obj.Base.Shape.Faces: if not DraftGeomUtils.isCoplanar(obj.Base.Shape.Faces): return None else: base,placement = self.rebase(obj.Base.Shape) elif len(obj.Base.Shape.Edges) == 1: self.basewires = [Part.Wire(obj.Base.Shape.Edges)] else: # self.basewires = obj.Base.Shape.Wires self.basewires = [] for cluster in Part.getSortedClusters(obj.Base.Shape.Edges): for c in Part.sortEdges(cluster): self.basewires.append(Part.Wire(c)) if self.basewires and width: if (len(self.basewires) == 1) and layers: self.basewires = [self.basewires[0] for l in layers] layeroffset = 0 baseface = None for i,wire in enumerate(self.basewires): e = wire.Edges[0] if isinstance(e.Curve,Part.Circle): dvec = e.Vertexes[0].Point.sub(e.Curve.Center) else: dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal) if not DraftVecUtils.isNull(dvec): dvec.normalize() sh = None if obj.Align == "Left": off = obj.Offset.Value if layers: off = off+layeroffset dvec.multiply(layers[i]) layeroffset += layers[i] else: dvec.multiply(width) if off: dvec2 = DraftVecUtils.scaleTo(dvec,off) wire = DraftGeomUtils.offsetWire(wire,dvec2) w2 = DraftGeomUtils.offsetWire(wire,dvec) w1 = Part.Wire(Part.__sortEdges__(wire.Edges)) sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Right": dvec = dvec.negative() off = obj.Offset.Value if layers: off = off+layeroffset dvec.multiply(layers[i]) layeroffset += layers[i] else: dvec.multiply(width) if off: dvec2 = DraftVecUtils.scaleTo(dvec,off) wire = DraftGeomUtils.offsetWire(wire,dvec2) w2 = DraftGeomUtils.offsetWire(wire,dvec) w1 = Part.Wire(Part.__sortEdges__(wire.Edges)) sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Center": if layers: off = width/2-layeroffset d1 = Vector(dvec).multiply(off) w1 = DraftGeomUtils.offsetWire(wire,d1) layeroffset += layers[i] off = width/2-layeroffset d1 = Vector(dvec).multiply(off) w2 = DraftGeomUtils.offsetWire(wire,d1) else: dvec.multiply(width/2) w1 = DraftGeomUtils.offsetWire(wire,dvec) dvec = dvec.negative() w2 = DraftGeomUtils.offsetWire(wire,dvec) sh = DraftGeomUtils.bind(w1,w2) if sh: sh.fix(0.1,0,1) # fixes self-intersecting wires f = Part.Face(sh) if baseface: if layers: baseface.append(f) else: baseface = baseface.fuse(f) # baseface = baseface.removeSplitter() s = DraftGeomUtils.removeSplitter(baseface) if s: baseface = s else: if layers: baseface = [f] else: baseface = f if baseface: base,placement = self.rebase(baseface) else: if layers: totalwidth = sum(layers) offset = 0 base = [] for l in layers: l2 = length/2 or 0.5 w1 = -totalwidth/2 + offset w2 = w1 + l v1 = Vector(-l2,w1,0) v2 = Vector(l2,w1,0) v3 = Vector(l2,w2,0) v4 = Vector(-l2,w2,0) base.append(Part.Face(Part.makePolygon([v1,v2,v3,v4,v1]))) offset += l else: l2 = length/2 or 0.5 w2 = width/2 or 0.5 v1 = Vector(-l2,-w2,0) v2 = Vector(l2,-w2,0) v3 = Vector(l2,w2,0) v4 = Vector(-l2,w2,0) base = Part.Face(Part.makePolygon([v1,v2,v3,v4,v1])) placement = FreeCAD.Placement() if base and placement: extrusion = normal.multiply(height) if placement.Rotation.Angle > 0: extrusion = placement.inverse().Rotation.multVec(extrusion) return (base,extrusion,placement) return None
def processSubShapes(self, obj, base, placement=None): "Adds additions and subtractions to a base shape" import Draft, Part #print("Processing subshapes of ",obj.Label, " : ",obj.Additions) if placement: if placement.isNull(): placement = None else: placement = FreeCAD.Placement(placement) placement = placement.inverse() # treat additions for o in obj.Additions: if not base: if o.isDerivedFrom("Part::Feature"): base = o.Shape else: if base.isNull(): if o.isDerivedFrom("Part::Feature"): base = o.Shape else: # special case, both walls with coinciding endpoints import ArchWall js = ArchWall.mergeShapes(o, obj) if js: add = js.cut(base) if placement: add.Placement = add.Placement.multiply(placement) base = base.fuse(add) elif (Draft.getType(o) == "Window") or (Draft.isClone( o, "Window", True)): if hasattr(o.Proxy, "getSubVolume"): f = o.Proxy.getSubVolume(o) if f: if base.Solids and f.Solids: if placement: f.Placement = f.Placement.multiply( placement) base = base.cut(f) elif o.isDerivedFrom("Part::Feature"): if o.Shape: if not o.Shape.isNull(): if o.Shape.Solids: s = o.Shape.copy() if placement: s.Placement = s.Placement.multiply( placement) if base: if base.Solids: try: base = base.fuse(s) except Part.OCCError: print( "Arch: unable to fuse object ", obj.Name, " with ", o.Name) else: base = s # treat subtractions for o in obj.Subtractions: if base: if base.isNull(): base = None if base: if (Draft.getType(o) == "Window") or (Draft.isClone( o, "Window", True)): # windows can be additions or subtractions, treated the same way f = o.Proxy.getSubVolume(o) if f: if base.Solids and f.Solids: if placement: f.Placement = f.Placement.multiply(placement) base = base.cut(f) elif (Draft.getType(o) == "Roof") or (Draft.isClone(o, "Roof")): # roofs define their own special subtraction volume f = o.Proxy.getSubVolume(o) if f: if base.Solids and f.Solids: base = base.cut(f) elif o.isDerivedFrom("Part::Feature"): if o.Shape: if not o.Shape.isNull(): if o.Shape.Solids and base.Solids: s = o.Shape.copy() if placement: s.Placement = s.Placement.multiply( placement) try: base = base.cut(s) except Part.OCCError: print("Arch: unable to cut object ", o.Name, " from ", obj.Name) return base
def loadStockSettings(self): stock = PathPreferences.defaultStockTemplate() index = -1 if stock: attrs = json.loads(stock) if attrs.get('version') and 1 == int(attrs['version']): stockType = attrs.get('create') if stockType == PathStock.StockType.FromBase: index = 2 elif stockType == PathStock.StockType.CreateBox: index = 0 elif stockType == PathStock.StockType.CreateCylinder: index = 1 else: index = -1 if -1 == index: attrs = {} self.form.stockGroup.setChecked(False) else: self.form.stockGroup.setChecked(True) self.form.stock.setCurrentIndex(index) # this either sets the default value or the value from the template for each field self.form.stockExtXneg.setText(attrs.get('xneg', '1 mm')) self.form.stockExtXpos.setText(attrs.get('xpos', '1 mm')) self.form.stockExtYneg.setText(attrs.get('yneg', '1 mm')) self.form.stockExtYpos.setText(attrs.get('ypos', '1 mm')) self.form.stockExtZneg.setText(attrs.get('zneg', '1 mm')) self.form.stockExtZpos.setText(attrs.get('zpos', '1 mm')) self.form.stockBoxLength.setText(attrs.get('length', '10 mm')) self.form.stockBoxWidth.setText(attrs.get('width', '10 mm')) self.form.stockBoxHeight.setText(attrs.get('height', '10 mm')) self.form.stockCylinderRadius.setText(attrs.get('radius', '5 mm')) self.form.stockCylinderHeight.setText(attrs.get('height', '10 mm')) posX = attrs.get('posX') posY = attrs.get('posY') posZ = attrs.get('posZ') rotX = attrs.get('rotX') rotY = attrs.get('rotY') rotZ = attrs.get('rotZ') rotW = attrs.get('rotW') if posX is not None and posY is not None and posZ is not None and rotX is not None and rotY is not None and rotZ is not None and rotW is not None: pos = FreeCAD.Vector(float(posX), float(posY), float(posZ)) rot = FreeCAD.Rotation(float(rotX), float(rotY), float(rotZ), float(rotW)) placement = FreeCAD.Placement(pos, rot) self.form.stockPlacementGroup.setChecked(True) else: placement = FreeCAD.Placement() self.form.stockPlacementGroup.setChecked(False) self.form.stockAngle.setText( FreeCAD.Units.Quantity("%f rad" % placement.Rotation.Angle).UserString) self.form.stockAxisX.setValue(placement.Rotation.Axis.x) self.form.stockAxisY.setValue(placement.Rotation.Axis.y) self.form.stockAxisZ.setValue(placement.Rotation.Axis.z) self.form.stockPositionX.setText( FreeCAD.Units.Quantity(placement.Base.x, FreeCAD.Units.Length).UserString) self.form.stockPositionY.setText( FreeCAD.Units.Quantity(placement.Base.y, FreeCAD.Units.Length).UserString) self.form.stockPositionZ.setText( FreeCAD.Units.Quantity(placement.Base.z, FreeCAD.Units.Length).UserString) self.setupStock(index) self.form.stock.currentIndexChanged.connect(self.setupStock)
def platonicsolid(solid='cube', name=None, clearall=False, vertexpolygon=False, cloud=False, solidoutline=False, solidobject=True, outerradius=None, edgelength=None): platonic_solid = platonic_solids[solid] if name == None: name = solid doc = FreeCAD.activeDocument() if clearall: clearobjects(doc) #print(doc.supportedTypes()) radius = platonic_solid['radius'] if outerradius: factor = outerradius / radius print(f"Outerradius: {outerradius}") elif edgelength: factor = edgelength / platonic_solid['edgelength'] print(f"Factor: {factor} = {factor/platonic_solid['radius']} * R") print(f"Edge length: {platonic_solid['edgelength']}") if vertexpolygon: p = Part.makePolygon( [normalize(x, factor) for x in platonic_solid['vertices']]) solidwire(doc, p, name=f"{name}_vertices", radius=factor * platonic_solid['edgelength'] / 20) platonic_solid['edges'] = [] if cloud: spheres = [] for i, vertex in enumerate(platonic_solid['vertices']): s = doc.addObject("Part::Sphere", f"{name}_sphere{i}") s.Radius = 0.2 p = FreeCAD.Placement() p.Base = FreeCAD.Vector( normalize((vertex[0], vertex[1], vertex[2]), factor)) s.Placement = p s.Visibility = False spheres.append(s) spherefusion = doc.addObject("Part::MultiFuse", f"{name}_cloud") spherefusion.Shapes = spheres facelist = [] solidfaces = [] for i, face in enumerate(platonic_solid['faces']): edgelist = [] verts = platonic_solid['vertices'] prev = None for v in face: if prev is not None: edge = Part.makeLine(normalize(verts[prev], factor), normalize(verts[v], factor)) edgelist.append(edge) prev = v edge = Part.makeLine(normalize(verts[prev], factor), normalize(verts[face[0]], factor)) edgelist.append(edge) wire = Part.Wire(edgelist) if solidoutline: solidfaces.append( solidwire(doc, wire, f"{name}_face{i}", radius=factor * platonic_solid['edgelength'] / 20)) face = Part.Face(wire) facelist.append(face) if solidoutline: solidfacefusion = doc.addObject("Part::MultiFuse", f"{name}_solidfaces") solidfacefusion.Shapes = solidfaces if solidobject: shell = Part.makeShell(facelist) solid = doc.addObject("Part::Feature", name) solid.Shape = Part.makeSolid(shell)
def Activated(self): import expandplacements for selobj in FreeCADGui.Selection.getSelectionEx(): expandplacements.expandplacements(selobj.Object, FreeCAD.Placement()) FreeCAD.ActiveDocument.recompute()
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.Solids: return # creating base shape pl = obj.Placement base = None normal = None if obj.Base: p = FreeCAD.Placement(obj.Base.Placement) normal = p.Rotation.multVec(Vector(0,0,1)) normal = normal.multiply(thickness) base = obj.Base.Shape.copy() if base.Solids: pass elif base.Faces: self.BaseProfile = base self.ExtrusionVector = normal base = base.extrude(normal) elif base.Wires: closed = True for w in base.Wires: if not w.isClosed(): closed = False if closed: base = ArchCommands.makeFace(base.Wires) self.BaseProfile = base self.ExtrusionVector = normal base = base.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: normal = Vector(0,0,1).multiply(thickness) self.ExtrusionVector = normal 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]) base = Part.Face(base) self.BaseProfile = base base = base.extrude(self.ExtrusionVector) 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 center(obj,x,y,z): obj.Placement = FreeCAD.Placement(\ FreeCAD.Vector(-x/2.0,-y/2.0,-z/2.0),\ FreeCAD.Rotation(0,0,0,1))
def getRotation(self): "returns a placement describing the working plane orientation ONLY" m = DraftVecUtils.getPlaneRotation(self.u, self.v, self.axis) return FreeCAD.Placement(m)
def updateData(self, obj, prop): """called when the base object is changed""" import DraftGui if prop in ["Start","End","Dimline","Direction"]: if obj.Start == obj.End: return if not hasattr(self,"node"): return import Part, DraftGeomUtils from pivy import coin # calculate the 4 points self.p1 = obj.Start self.p4 = obj.End base = None if hasattr(obj,"Direction"): if not DraftVecUtils.isNull(obj.Direction): v2 = self.p1.sub(obj.Dimline) v3 = self.p4.sub(obj.Dimline) v2 = DraftVecUtils.project(v2,obj.Direction) v3 = DraftVecUtils.project(v3,obj.Direction) self.p2 = obj.Dimline.add(v2) self.p3 = obj.Dimline.add(v3) if DraftVecUtils.equals(self.p2,self.p3): base = None proj = None else: base = Part.LineSegment(self.p2,self.p3).toShape() proj = DraftGeomUtils.findDistance(self.p1,base) if proj: proj = proj.negative() if not base: if DraftVecUtils.equals(self.p1,self.p4): base = None proj = None else: base = Part.LineSegment(self.p1,self.p4).toShape() proj = DraftGeomUtils.findDistance(obj.Dimline,base) if proj: self.p2 = self.p1.add(proj.negative()) self.p3 = self.p4.add(proj.negative()) else: self.p2 = self.p1 self.p3 = self.p4 if proj: if hasattr(obj.ViewObject,"ExtLines") and hasattr(obj.ViewObject,"ScaleMultiplier"): dmax = obj.ViewObject.ExtLines.Value * obj.ViewObject.ScaleMultiplier if dmax and (proj.Length > dmax): if (dmax > 0): self.p1 = self.p2.add(DraftVecUtils.scaleTo(proj,dmax)) self.p4 = self.p3.add(DraftVecUtils.scaleTo(proj,dmax)) else: rest = proj.Length + dmax self.p1 = self.p2.add(DraftVecUtils.scaleTo(proj,rest)) self.p4 = self.p3.add(DraftVecUtils.scaleTo(proj,rest)) else: proj = (self.p3.sub(self.p2)).cross(App.Vector(0,0,1)) # calculate the arrows positions self.trans1.translation.setValue((self.p2.x,self.p2.y,self.p2.z)) self.coord1.point.setValue((self.p2.x,self.p2.y,self.p2.z)) self.trans2.translation.setValue((self.p3.x,self.p3.y,self.p3.z)) self.coord2.point.setValue((self.p3.x,self.p3.y,self.p3.z)) # calculate dimension and extension lines overshoots positions self.transDimOvershoot1.translation.setValue((self.p2.x,self.p2.y,self.p2.z)) self.transDimOvershoot2.translation.setValue((self.p3.x,self.p3.y,self.p3.z)) self.transExtOvershoot1.translation.setValue((self.p2.x,self.p2.y,self.p2.z)) self.transExtOvershoot2.translation.setValue((self.p3.x,self.p3.y,self.p3.z)) # calculate the text position and orientation if hasattr(obj,"Normal"): if DraftVecUtils.isNull(obj.Normal): if proj: norm = (self.p3.sub(self.p2).cross(proj)).negative() else: norm = App.Vector(0,0,1) else: norm = App.Vector(obj.Normal) else: if proj: norm = (self.p3.sub(self.p2).cross(proj)).negative() else: norm = App.Vector(0,0,1) if not DraftVecUtils.isNull(norm): norm.normalize() u = self.p3.sub(self.p2) u.normalize() v1 = norm.cross(u) rot1 = App.Placement(DraftVecUtils.getPlaneRotation(u,v1,norm)).Rotation.Q self.transDimOvershoot1.rotation.setValue((rot1[0],rot1[1],rot1[2],rot1[3])) self.transDimOvershoot2.rotation.setValue((rot1[0],rot1[1],rot1[2],rot1[3])) if hasattr(obj.ViewObject,"FlipArrows"): if obj.ViewObject.FlipArrows: u = u.negative() v2 = norm.cross(u) rot2 = App.Placement(DraftVecUtils.getPlaneRotation(u,v2,norm)).Rotation.Q self.trans1.rotation.setValue((rot2[0],rot2[1],rot2[2],rot2[3])) self.trans2.rotation.setValue((rot2[0],rot2[1],rot2[2],rot2[3])) if self.p1 != self.p2: u3 = self.p1.sub(self.p2) u3.normalize() v3 = norm.cross(u3) rot3 = App.Placement(DraftVecUtils.getPlaneRotation(u3,v3,norm)).Rotation.Q self.transExtOvershoot1.rotation.setValue((rot3[0],rot3[1],rot3[2],rot3[3])) self.transExtOvershoot2.rotation.setValue((rot3[0],rot3[1],rot3[2],rot3[3])) if hasattr(obj.ViewObject,"TextSpacing") and hasattr(obj.ViewObject,"ScaleMultiplier"): ts = obj.ViewObject.TextSpacing.Value * obj.ViewObject.ScaleMultiplier offset = DraftVecUtils.scaleTo(v1,ts) else: offset = DraftVecUtils.scaleTo(v1,0.05) rott = rot1 if hasattr(obj.ViewObject,"FlipText"): if obj.ViewObject.FlipText: rott = App.Rotation(*rott).multiply(App.Rotation(norm,180)).Q offset = offset.negative() # setting text try: m = obj.ViewObject.DisplayMode except: # swallow all exceptions here since it always fails on first run (Displaymode enum no set yet) m = ["2D","3D"][utils.get_param("dimstyle",0)] if m == "3D": offset = offset.negative() self.tbase = (self.p2.add((self.p3.sub(self.p2).multiply(0.5)))).add(offset) if hasattr(obj.ViewObject,"TextPosition"): if not DraftVecUtils.isNull(obj.ViewObject.TextPosition): self.tbase = obj.ViewObject.TextPosition self.textpos.translation.setValue([self.tbase.x,self.tbase.y,self.tbase.z]) self.textpos.rotation = coin.SbRotation(rott[0],rott[1],rott[2],rott[3]) su = True if hasattr(obj.ViewObject,"ShowUnit"): su = obj.ViewObject.ShowUnit # set text value l = self.p3.sub(self.p2).Length unit = None if hasattr(obj.ViewObject,"UnitOverride"): unit = obj.ViewObject.UnitOverride # special representation if "Building US" scheme if App.ParamGet("User parameter:BaseApp/Preferences/Units").GetInt("UserSchema",0) == 5: s = App.Units.Quantity(l,App.Units.Length).UserString self.string = s.replace("' ","'- ") self.string = s.replace("+"," ") elif hasattr(obj.ViewObject,"Decimals"): self.string = DraftGui.displayExternal(l,obj.ViewObject.Decimals,'Length',su,unit) else: self.string = DraftGui.displayExternal(l,None,'Length',su,unit) if hasattr(obj.ViewObject,"Override"): if obj.ViewObject.Override: self.string = obj.ViewObject.Override.replace("$dim",\ self.string) self.text.string = self.text3d.string = utils.string_encode_coin(self.string) # set the lines if m == "3D": # calculate the spacing of the text textsize = (len(self.string)*obj.ViewObject.FontSize.Value)/4.0 spacing = ((self.p3.sub(self.p2)).Length/2.0) - textsize self.p2a = self.p2.add(DraftVecUtils.scaleTo(self.p3.sub(self.p2),spacing)) self.p2b = self.p3.add(DraftVecUtils.scaleTo(self.p2.sub(self.p3),spacing)) self.coords.point.setValues([[self.p1.x,self.p1.y,self.p1.z], [self.p2.x,self.p2.y,self.p2.z], [self.p2a.x,self.p2a.y,self.p2a.z], [self.p2b.x,self.p2b.y,self.p2b.z], [self.p3.x,self.p3.y,self.p3.z], [self.p4.x,self.p4.y,self.p4.z]]) #self.line.numVertices.setValues([3,3]) self.line.coordIndex.setValues(0,7,(0,1,2,-1,3,4,5)) else: self.coords.point.setValues([[self.p1.x,self.p1.y,self.p1.z], [self.p2.x,self.p2.y,self.p2.z], [self.p3.x,self.p3.y,self.p3.z], [self.p4.x,self.p4.y,self.p4.z]]) #self.line.numVertices.setValue(4) self.line.coordIndex.setValues(0,4,(0,1,2,3))
def setFromPlacement(self, pl): "sets the working plane from a placement (rotaton ONLY)" rot = FreeCAD.Placement(pl).Rotation self.u = rot.multVec(FreeCAD.Vector(1, 0, 0)) self.v = rot.multVec(FreeCAD.Vector(0, 1, 0)) self.axis = rot.multVec(FreeCAD.Vector(0, 0, 1))
def createFromProperties(propsets, ifcfile, parametrics): """ Creates a FreeCAD parametric object from a set of properties. """ obj = None sets = [] appset = None guiset = None for pset in propsets.keys(): if ifcfile[pset].Name == "FreeCADPropertySet": appset = {} for pid in propsets[pset]: p = ifcfile[pid] appset[p.Name] = p.NominalValue.wrappedValue elif ifcfile[pset].Name == "FreeCADGuiPropertySet": guiset = {} for pid in propsets[pset]: p = ifcfile[pid] guiset[p.Name] = p.NominalValue.wrappedValue if appset: oname = None otype = None if "FreeCADType" in appset.keys(): if "FreeCADName" in appset.keys(): obj = FreeCAD.ActiveDocument.addObject(appset["FreeCADType"], appset["FreeCADName"]) if "FreeCADAppObject" in appset: mod, cla = appset["FreeCADAppObject"].split(".") if "'" in mod: mod = mod.split("'")[-1] if "'" in cla: cla = cla.split("'")[0] import importlib mod = importlib.import_module(mod) getattr(mod, cla)(obj) sets.append(("App", appset)) if FreeCAD.GuiUp: if guiset: if "FreeCADGuiObject" in guiset: mod, cla = guiset["FreeCADGuiObject"].split(".") if "'" in mod: mod = mod.split("'")[-1] if "'" in cla: cla = cla.split("'")[0] import importlib mod = importlib.import_module(mod) getattr(mod, cla)(obj.ViewObject) sets.append(("Gui", guiset)) if obj and sets: for realm, pset in sets: if realm == "App": target = obj else: target = obj.ViewObject for key, val in pset.items(): if key.startswith("FreeCAD_") or key.startswith("FreeCADGui_"): name = key.split("_")[1] if name in target.PropertiesList: if not target.getEditorMode(name): ptype = target.getTypeIdOfProperty(name) if ptype in [ "App::PropertyString", "App::PropertyEnumeration", "App::PropertyInteger", "App::PropertyFloat" ]: setattr(target, name, val) elif ptype in [ "App::PropertyLength", "App::PropertyDistance" ]: setattr(target, name, val * 1000) elif ptype == "App::PropertyBool": if val in [".T.", True]: setattr(target, name, True) else: setattr(target, name, False) elif ptype == "App::PropertyVector": setattr( target, name, FreeCAD.Vector([ float(s) for s in val.split("(") [1].strip(")").split(",") ])) elif ptype == "App::PropertyArea": setattr(target, name, val * 1000000) elif ptype == "App::PropertyPlacement": data = val.split("[")[1].strip("]").split("(") data = [ data[1].split(")")[0], data[2].strip(")") ] v = FreeCAD.Vector( [float(s) for s in data[0].split(",")]) r = FreeCAD.Rotation( *[float(s) for s in data[1].split(",")]) setattr(target, name, FreeCAD.Placement(v, r)) elif ptype == "App::PropertyLink": link = val.split("_")[1] parametrics.append([target, name, link]) else: print("Unhandled FreeCAD property:", name, " of type:", ptype) return obj, parametrics
def onChanged(self, vobj, prop): """Execute when a view property is changed.""" super(ViewProviderLabel, self).onChanged(vobj, prop) if prop == "ScaleMultiplier": if not hasattr(vobj, "ScaleMultiplier"): return if hasattr(vobj, "TextSize") and hasattr(vobj, "TextAlignment"): self.update_label(vobj) if hasattr(vobj, "ArrowSize"): s = vobj.ArrowSize.Value * vobj.ScaleMultiplier if s: self.arrowpos.scaleFactor.setValue((s, s, s)) elif prop == "LineColor": if hasattr(vobj, "LineColor"): l = vobj.LineColor self.matline.diffuseColor.setValue([l[0], l[1], l[2]]) elif prop == "TextColor": if hasattr(vobj, "TextColor"): l = vobj.TextColor self.mattext.diffuseColor.setValue([l[0], l[1], l[2]]) elif prop == "LineWidth": if hasattr(vobj, "LineWidth"): self.drawstyle.lineWidth = vobj.LineWidth elif (prop == "TextFont"): if hasattr(vobj, "TextFont"): self.font.name = vobj.TextFont.encode("utf8") elif prop in ["TextSize", "TextAlignment"] and hasattr( vobj, "ScaleMultiplier"): if hasattr(vobj, "TextSize") and hasattr(vobj, "TextAlignment"): self.update_label(vobj) elif prop == "Line": if hasattr(vobj, "Line"): if vobj.Line: self.lineswitch.whichChild = 0 else: self.lineswitch.whichChild = -1 elif prop == "ArrowType": if hasattr(vobj, "ArrowType"): if len(vobj.Object.Points) > 1: if hasattr(self, "symbol"): if self.arrow.findChild(self.symbol) != -1: self.arrow.removeChild(self.symbol) s = utils.ARROW_TYPES.index(vobj.ArrowType) self.symbol = gui_utils.dim_symbol(s) self.arrow.addChild(self.symbol) self.arrowpos.translation.setValue(vobj.Object.Points[-1]) v1 = vobj.Object.Points[-2].sub(vobj.Object.Points[-1]) if not DraftVecUtils.isNull(v1): v1.normalize() v2 = App.Vector(0, 0, 1) if round(v2.getAngle(v1), 4) in [0, round(math.pi, 4)]: v2 = App.Vector(0, 1, 0) v3 = v1.cross(v2).negative() q = App.Placement( DraftVecUtils.getPlaneRotation(v1, v3, v2)).Rotation.Q self.arrowpos.rotation.setValue( (q[0], q[1], q[2], q[3])) elif prop == "ArrowSize": if hasattr(vobj, "ArrowSize") and hasattr(vobj, "ScaleMultiplier"): s = vobj.ArrowSize.Value * vobj.ScaleMultiplier if s: self.arrowpos.scaleFactor.setValue((s, s, s)) elif prop == "Frame": if hasattr(vobj, "Frame"): self.frame.coordIndex.deleteValues(0) if vobj.Frame == "Rectangle": tsize = self.getTextSize(vobj) pts = [] base = vobj.Object.Placement.Base.sub( App.Vector( self.textpos.translation.getValue().getValue())) pts.append(base.add(App.Vector(0, tsize[1] * 3, 0))) pts.append(pts[-1].add(App.Vector(-tsize[0] * 6, 0, 0))) pts.append(pts[-1].add(App.Vector(0, -tsize[1] * 6, 0))) pts.append(pts[-1].add(App.Vector(tsize[0] * 6, 0, 0))) pts.append(pts[0]) self.fcoords.point.setValues(pts) self.frame.coordIndex.setValues(0, len(pts), range(len(pts)))