def check(objectslist, includehidden=False): """check(objectslist,includehidden=False): checks if the given objects contain only solids""" objs = Draft.getGroupContents(objectslist) if not includehidden: objs = Draft.removeHidden(objs) bad = [] for o in objs: if not o.isDerivedFrom("Part::Feature"): bad.append([o, "is not a Part-based object"]) else: s = o.Shape if (not s.isClosed()) and (not (Draft.getType(o) == "Axis")): bad.append([o, translate("Arch", "is not closed")]) elif not s.isValid(): bad.append([o, translate("Arch", "is not valid")]) elif (not s.Solids) and (not (Draft.getType(o) == "Axis")): bad.append([o, translate("Arch", "doesn't contain any solid")]) else: f = 0 for sol in s.Solids: f += len(sol.Faces) if not sol.isClosed(): bad.append([o, translate("Arch", "contains a non-closed solid")]) if len(s.Faces) != f: bad.append([o, translate("Arch", "contains faces that are not part of any solid")]) return bad
def fixWindow(obj): """fixWindow(object): Fixes non-DAG problems in windows by removing supports and external geometry from underlying sketches""" if Draft.getType(obj) == "Window": if obj.Base: if hasattr(obj.Base, "Support"): if obj.Base.Support: if isinstance(o.Base.Support, tuple): if obj.Base.Support[0]: FreeCAD.Console.PrintMessage( translate("Arch", "removing sketch support to avoid cross-referencing") ) obj.Base.Support = None elif obj.Base.Support: FreeCAD.Console.PrintMessage( translate("Arch", "removing sketch support to avoid cross-referencing") ) obj.Base.Support = None if hasattr(obj.Base, "ExternalGeometry"): if obj.Base.ExternalGeometry: for i in range(len(obj.Base.ExternalGeometry)): obj.Base.delExternal(0) FreeCAD.Console.PrintMessage( translate("Arch", "removing sketch external references to avoid cross-referencing") )
def Activated(self): sel = FreeCADGui.Selection.getSelection() if Draft.getType(sel[-1]) == "Space": FreeCAD.ActiveDocument.openTransaction(str(translate("Arch", "Remove space boundary"))) FreeCADGui.doCommand("import Arch") FreeCADGui.doCommand( "Arch.removeSpaceBoundaries( FreeCAD.ActiveDocument." + sel[-1].Name + ", FreeCADGui.Selection.getSelection() )" ) else: FreeCAD.ActiveDocument.openTransaction(str(translate("Arch", "Ungrouping"))) if (Draft.getType(sel[-1]) in ["Wall", "Structure", "Stairs", "Roof", "Window"]) and (len(sel) > 1): host = sel.pop() ss = "[" for o in sel: if len(ss) > 1: ss += "," ss += "FreeCAD.ActiveDocument." + o.Name ss += "]" FreeCADGui.doCommand("import Arch") FreeCADGui.doCommand("Arch.removeComponents(" + ss + ",FreeCAD.ActiveDocument." + host.Name + ")") else: FreeCADGui.doCommand("import Arch") FreeCADGui.doCommand("Arch.removeComponents(FreeCAD.ActiveDocument." + sel[-1].Name + ")") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute()
def __init__(self,obj): ArchComponent.Component.__init__(self,obj) obj.addProperty("App::PropertyLink","Tool","Arch", translate("Arch","An optional extrusion path for this element")) obj.addProperty("App::PropertyLength","Length","Arch", translate("Arch","The length of this element, if not based on a profile")) obj.addProperty("App::PropertyLength","Width","Arch", translate("Arch","The width of this element, if not based on a profile")) obj.addProperty("App::PropertyLength","Height","Arch", translate("Arch","The height or extrusion depth of this element. Keep 0 for automatic")) obj.addProperty("App::PropertyLinkList","Axes","Arch", translate("Arch","Axes systems this structure is built on")) obj.addProperty("App::PropertyLinkList","Armatures","Arch", translate("Arch","Armatures contained in this element")) obj.addProperty("App::PropertyVector","Normal","Arch", translate("Arch","The normal extrusion direction of this object (keep (0,0,0) for automatic normal)")) obj.addProperty("App::PropertyIntegerList","Exclude","Arch", translate("Arch","The element numbers to exclude when this structure is based on axes")) obj.addProperty("App::PropertyEnumeration","Role","Arch", translate("Arch","The role of this structural element")) obj.addProperty("App::PropertyVectorList","Nodes","Arch", translate("Arch","The structural nodes of this element")) self.Type = "Structure" obj.Length = 1 obj.Width = 1 obj.Height = 1 obj.Role = Roles
def Activated(self): sel = FreeCADGui.Selection.getSelectionEx() if sel: sel = sel[0] obj = sel.Object if sel.HasSubObjects: if "Face" in sel.SubElementNames[0]: idx = int(sel.SubElementNames[0][4:]) FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Roof"))) FreeCADGui.doCommand("import Arch") FreeCADGui.doCommand("Arch.makeRoof(FreeCAD.ActiveDocument."+obj.Name+","+str(idx)+")") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() return if obj.isDerivedFrom("Part::Feature"): if obj.Shape.Wires: FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Roof"))) FreeCADGui.doCommand("import Arch") FreeCADGui.doCommand("Arch.makeRoof(FreeCAD.ActiveDocument."+obj.Name+")") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() return else: FreeCAD.Console.PrintMessage(str(translate("Arch","Unable to create a roof"))) else: FreeCAD.Console.PrintMessage(str(translate("Arch","No object selected")))
def Activated(self): sel = FreeCADGui.Selection.getSelection() p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") link = p.GetBool("FreeLinking",False) siteobj = [] warning = False for obj in sel : if Draft.getType(obj) == "Building": siteobj.append(obj) else : if link == True : siteobj.append(obj) else: warning = True if warning : message = translate( "Arch" , "Please select only Building objects or nothing!\n\ Site are not allowed to accept other object than Building.\n\ Other objects will be removed from the selection.\n\ You can change that in the preferences." ) ArchCommands.printMessage( message ) if sel and len(siteobj) == 0: message = translate( "Arch" , "There is no valid object in the selection.\n\ Site creation aborted." ) ArchCommands.printMessage( message ) else : ss = "[ " for o in siteobj: ss += "FreeCAD.ActiveDocument." + o.Name + ", " ss += "]" FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create Site")) FreeCADGui.addModule("Arch") FreeCADGui.doCommand("Arch.makeSite("+ss+")") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute()
def Activated(self): sel = FreeCADGui.Selection.getSelection() p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") link = p.GetBool("FreeLinking",False) floorobj = [] warning = False for obj in sel : if not Draft.getType(obj) in ["Site", "Building"] : floorobj.append(obj) else : if link == True : floorobj.append(obj) else: warning = True if warning : message = translate( "Arch" , "You can put anything but Site, Building, Floor object in a Floor object.\n\ Floor object are not allowed to accept Site or Building object.\n\ Site, Building and Floor objects will be removed from the selection.\n\ You can change that in the preferences.\n" ) ArchCommands.printMessage( message ) if sel and len(floorobj) == 0: message = translate( "Arch" , "There is no valid object in the selection.\n\ Floor creation aborted.\n" ) ArchCommands.printMessage( message ) else : ss = "[ " for o in floorobj: ss += "FreeCAD.ActiveDocument." + o.Name + ", " ss += "]" FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create Floor")) FreeCADGui.addModule("Arch") FreeCADGui.doCommand("Arch.makeFloor("+ss+")") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute()
def __init__(self,obj): obj.Proxy = self obj.addProperty("App::PropertyLink","Base","Arch", str(translate("Arch","A base shape defining this space"))) obj.addProperty("App::PropertyLinkSubList","Boundaries","Arch", str(translate("Arch","The objects that make the boundaries of this space object"))) self.Type = "Space"
def __init__(self,spreadsheet=None): from DraftTools import translate QtGui.QWidget.__init__(self) self.setWindowTitle(str(translate("Spreadsheet","Spreadsheet"))) self.setObjectName("Spreadsheet viewer") self.verticalLayout = QtGui.QVBoxLayout(self) self.doNotChange = False # add editor line self.horizontalLayout = QtGui.QHBoxLayout() self.label = QtGui.QLabel(self) self.label.setMinimumSize(QtCore.QSize(82, 0)) self.label.setText(str(translate("Spreadsheet","Cell"))+" A1 :") self.horizontalLayout.addWidget(self.label) self.lineEdit = QtGui.QLineEdit(self) self.horizontalLayout.addWidget(self.lineEdit) self.verticalLayout.addLayout(self.horizontalLayout) # add table self.table = QtGui.QTableWidget(30,26,self) for i in range(26): ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i] self.table.setHorizontalHeaderItem(i, QtGui.QTableWidgetItem(ch)) self.verticalLayout.addWidget(self.table) self.table.setCurrentCell(0,0) self.spreadsheet = spreadsheet self.update() QtCore.QObject.connect(self.table, QtCore.SIGNAL("cellChanged(int,int)"), self.changeCell) QtCore.QObject.connect(self.table, QtCore.SIGNAL("currentCellChanged(int,int,int,int)"), self.setEditLine) QtCore.QObject.connect(self.lineEdit, QtCore.SIGNAL("returnPressed()"), self.getEditLine) QtCore.QObject.connect(self, QtCore.SIGNAL("destroyed()"), self.destroy)
def applyShape(self, obj, shape, placement, allowinvalid=False, allownosolid=False): "checks and cleans the given shape, and apply it to the object" if shape: if not shape.isNull(): if shape.isValid(): if shape.Solids: if shape.Volume < 0: shape.reverse() if shape.Volume < 0: FreeCAD.Console.PrintError( translate("Arch", "Error computing the shape of this object") + "\n" ) return shape = shape.removeSplitter() obj.Shape = shape if not placement.isNull(): obj.Placement = placement else: if allownosolid: obj.Shape = shape if not placement.isNull(): obj.Placement = placement else: FreeCAD.Console.PrintWarning(obj.Label + " " + translate("Arch", "has no solid") + "\n") else: if allowinvalid: obj.Shape = shape if not placement.isNull(): obj.Placement = placement else: FreeCAD.Console.PrintWarning(obj.Label + " " + translate("Arch", "has an invalid shape") + "\n") else: FreeCAD.Console.PrintWarning(obj.Label + " " + translate("Arch", "has a null shape") + "\n") self.computeAreas(obj)
def makeWall(baseobj=None,length=None,width=None,height=None,align="Center",face=None,name="Wall"): '''makeWall([obj],[length],[width],[height],[align],[face],[name]): creates a wall based on the given object, which can be a sketch, a draft object, a face or a solid, or no object at all, then you must provide length, width and height. Align can be "Center","Left" or "Right", face can be an index number of a face in the base object to base the wall on.''' p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name) obj.Label = translate("Arch",name) _Wall(obj) if FreeCAD.GuiUp: _ViewProviderWall(obj.ViewObject) if baseobj: if baseobj.isDerivedFrom("Part::Feature") or baseobj.isDerivedFrom("Mesh::Feature"): obj.Base = baseobj else: FreeCAD.Console.PrintWarning(str(translate("Arch","Walls can only be based on Part or Mesh objects"))) if face: obj.Face = face if length: obj.Length = length if width: obj.Width = width else: obj.Width = p.GetFloat("WallWidth",200) if height: obj.Height = height else: obj.Height = p.GetFloat("WallHeight",3000) obj.Align = align if obj.Base and FreeCAD.GuiUp: if Draft.getType(obj.Base) != "Space": obj.Base.ViewObject.hide() return obj
def __init__(self, obj): ArchComponent.Component.__init__(self, obj) obj.addProperty( "Part::PropertyPartShape", "TopView", "Arch", translate("Arch", "an optional 2D shape representing a top view of this equipment"), ) obj.addProperty( "Part::PropertyPartShape", "FrontView", "Arch", translate("Arch", "an optional 2D shape representing a front view of this equipment"), ) obj.addProperty( "Part::PropertyPartShape", "SideView", "Arch", translate("Arch", "an optional 2D shape representing a side view of this equipment"), ) obj.addProperty( "App::PropertyString", "Model", "Arch", translate("Arch", "The model description of this equipment") ) obj.addProperty( "App::PropertyString", "Url", "Arch", translate("Arch", "The url of the product page of this equipment") ) self.Type = "Equipment" obj.Role = Roles obj.Proxy = self
def Activated(self): import Draft from DraftTools import translate sel = FreeCADGui.Selection.getSelection() if (len(sel) == 1) and Draft.getType(sel[0]) == "Spreadsheet": n = FreeCADGui.Selection.getSelection()[0].Name FreeCAD.ActiveDocument.openTransaction(str(translate("Spreadsheet","Add property controller"))) FreeCADGui.doCommand("import Spreadsheet") FreeCADGui.doCommand("Spreadsheet.makeSpreadsheetPropertyController(FreeCAD.ActiveDocument."+n+")") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() elif (len(sel) == 2): if (Draft.getType(sel[0]) == "Spreadsheet") and (Draft.getType(sel[1]) == "SpreadsheetPropertyController"): s = sel[0].Name o = sel[1].Name elif (Draft.getType(sel[1]) == "Spreadsheet") and (Draft.getType(sel[0]) == "SpreadsheetPropertyController"): s = sel[1].Name o = sel[0].Name else: return FreeCAD.ActiveDocument.openTransaction(str(translate("Spreadsheet","Add property controller"))) FreeCADGui.doCommand("import Spreadsheet") FreeCADGui.doCommand("Spreadsheet.makeSpreadsheetPropertyController(FreeCAD.ActiveDocument."+s+",FreeCAD.ActiveDocument."+o+")") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute()
def __init__(self,obj): ArchComponent.Component.__init__(self,obj) obj.addProperty("App::PropertyAngle","Angle","Base", str(translate("Arch","The angle of this roof"))) obj.addProperty("App::PropertyInteger","Face","Base", str(translate("Arch","The face number of the base object used to build this roof"))) self.Type = "Roof"
def Activated(self): sel = FreeCADGui.Selection.getSelectionEx() if sel: sel = sel[0] obj = sel.Object FreeCADGui.Control.closeDialog() if sel.HasSubObjects: if "Face" in sel.SubElementNames[0]: idx = int(sel.SubElementNames[0][4:]) FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create Roof")) FreeCADGui.doCommand("import Arch") FreeCADGui.doCommand("Arch.makeRoof(FreeCAD.ActiveDocument."+obj.Name+","+str(idx)+")") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() return if obj.isDerivedFrom("Part::Feature"): if obj.Shape.Wires: FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create Roof")) FreeCADGui.doCommand("import Arch") FreeCADGui.doCommand("Arch.makeRoof(FreeCAD.ActiveDocument."+obj.Name+")") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() return else: FreeCAD.Console.PrintMessage(translate("Arch","Unable to create a roof")) else: FreeCAD.Console.PrintMessage(translate("Arch","Please select a base object\n")) FreeCADGui.Control.showDialog(ArchComponent.SelectionTaskPanel()) FreeCAD.ArchObserver = ArchComponent.ArchSelectionObserver(nextCommand="Arch_Roof") FreeCADGui.Selection.addObserver(FreeCAD.ArchObserver)
def Activated(self): sel = FreeCADGui.Selection.getSelection() ok = False if (len(sel) == 1): if Draft.getType(sel[0]) in ["Cell","Building","Floor"]: FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Type conversion"))) FreeCADGui.doCommand("import Arch") FreeCADGui.doCommand("obj = Arch.makeSite()") FreeCADGui.doCommand("Arch.copyProperties(FreeCAD.ActiveDocument."+sel[0].Name+",obj)") FreeCADGui.doCommand('FreeCAD.ActiveDocument.removeObject("'+sel[0].Name+'")') nobj = makeSite() ArchCommands.copyProperties(sel[0],nobj) FreeCAD.ActiveDocument.removeObject(sel[0].Name) FreeCAD.ActiveDocument.commitTransaction() ok = True if not ok: ss = "[" for o in sel: if len(ss) > 1: ss += "," ss += "FreeCAD.ActiveDocument."+o.Name ss += "]" FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Site"))) FreeCADGui.doCommand("import Arch") FreeCADGui.doCommand("Arch.makeSite("+ss+")") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute()
def Activated(self): walls = FreeCADGui.Selection.getSelection() if len(walls) == 1: if Draft.getType(walls[0]) == "Wall": ostr = "FreeCAD.ActiveDocument."+ walls[0].Name ok = False for o in walls[0].Additions: if Draft.getType(o) == "Wall": ostr += ",FreeCAD.ActiveDocument." + o.Name ok = True if ok: FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Merge Wall"))) FreeCADGui.doCommand("import Arch") FreeCADGui.doCommand("Arch.joinWalls(["+ostr+"],delete=True)") FreeCAD.ActiveDocument.commitTransaction() return else: FreeCAD.Console.PrintWarning(str(translate("Arch","The selected wall contain no subwall to merge"))) return else: FreeCAD.Console.PrintWarning(str(translate("Arch","Please select only wall objects"))) return for w in walls: if Draft.getType(w) != "Wall": FreeCAD.Console.PrintMessage(str(translate("Arch","Please select only wall objects"))) return FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Merge Walls"))) FreeCADGui.doCommand("import Arch") FreeCADGui.doCommand("Arch.joinWalls(FreeCADGui.Selection.getSelection(),delete=True)") FreeCAD.ActiveDocument.commitTransaction()
def __init__(self,obj): obj.addProperty("App::PropertyFloatList","Distances","Arch", str(translate("Arch","The intervals between axes"))) obj.addProperty("App::PropertyFloatList","Angles","Arch", str(translate("Arch","The angles of each axis"))) obj.addProperty("App::PropertyFloat","Length","Arch", str(translate("Arch","The length of the axes"))) self.Type = "Axis" obj.Length=1.0 obj.Proxy = self
def __init__(self,vobj): ArchComponent.ViewProviderComponent.__init__(self,vobj) vobj.Transparency = 85 vobj.LineWidth = 1 vobj.LineColor = (1.0,0.0,0.0,1.0) vobj.DrawStyle = "Dotted" vobj.addProperty("App::PropertyStringList", "Text", "Arch",translate("Arch","The text to show. Use $area, $label, $tag, $floor, $walls, $ceiling to insert the respective data")) vobj.addProperty("App::PropertyString", "FontName", "Arch",translate("Arch","The name of the font")) vobj.addProperty("App::PropertyColor", "TextColor", "Arch",translate("Arch","The color of the area text")) vobj.addProperty("App::PropertyLength", "FontSize", "Arch",translate("Arch","The size of the text font")) vobj.addProperty("App::PropertyLength", "FirstLine", "Arch",translate("Arch","The size of the first line of text")) vobj.addProperty("App::PropertyFloat", "LineSpacing", "Arch",translate("Arch","The space between the lines of text")) vobj.addProperty("App::PropertyVector", "TextPosition","Arch",translate("Arch","The position of the text. Leave (0,0,0) for automatic position")) vobj.addProperty("App::PropertyEnumeration","TextAlign", "Arch",translate("Arch","The justification of the text")) vobj.addProperty("App::PropertyInteger", "Decimals", "Arch",translate("Arch","The number of decimals to use for calculated texts")) vobj.addProperty("App::PropertyBool", "ShowUnit", "Arch",translate("Arch","Show the unit suffix")) vobj.TextColor = (0.0,0.0,0.0,1.0) vobj.Text = ["$label","$area"] vobj.TextAlign = ["Left","Center","Right"] vobj.FontSize = Draft.getParam("textheight",10) vobj.FirstLine = Draft.getParam("textheight",10) vobj.FontName = Draft.getParam("textfont","") vobj.Decimals = Draft.getParam("dimPrecision",2) vobj.ShowUnit = Draft.getParam("showUnit",True) vobj.LineSpacing = 1.0
def __init__(self, vobj): vobj.addProperty( "App::PropertyLength", "DisplayLength", "Arch", translate("Arch", "The display length of this section plane"), ) vobj.addProperty( "App::PropertyLength", "DisplayHeight", "Arch", translate("Arch", "The display height of this section plane"), ) vobj.addProperty( "App::PropertyLength", "ArrowSize", "Arch", translate("Arch", "The size of the arrows of this section plane"), ) vobj.addProperty("App::PropertyPercent", "Transparency", "Base", "") vobj.addProperty("App::PropertyFloat", "LineWidth", "Base", "") vobj.addProperty("App::PropertyColor", "LineColor", "Base", "") vobj.addProperty("App::PropertyBool", "CutView", "Arch", translate("Arch", "Show the cut in the 3D view")) vobj.DisplayLength = 1000 vobj.DisplayHeight = 1000 vobj.ArrowSize = 50 vobj.Transparency = 85 vobj.LineWidth = 1 vobj.LineColor = (0.0, 0.0, 0.4, 1.0) vobj.CutView = False vobj.Proxy = self self.Object = vobj.Object
def __init__(self,obj): obj.Proxy = self obj.addProperty("App::PropertyPlacement","Placement","Base",translate("Arch","The placement of this object")) obj.addProperty("Part::PropertyPartShape","Shape","Base","") obj.addProperty("App::PropertyLinkList","Objects","Arch",translate("Arch","The objects that must be considered by this section plane. Empty means all document")) obj.addProperty("App::PropertyBool","OnlySolids","Arch",translate("Arch","If false, non-solids will be cut too, with possible wrong results.")) obj.OnlySolids = True self.Type = "SectionPlane"
def __init__(self,obj): ArchComponent.Component.__init__(self,obj) obj.addProperty("App::PropertyLinkSubList","Boundaries", "Arch",translate("Arch","The objects that make the boundaries of this space object")) obj.addProperty("App::PropertyFloat", "Area", "Arch",translate("Arch","The computed floor area of this space")) obj.addProperty("App::PropertyString", "FinishFloor", "Arch",translate("Arch","The finishing of the floor of this space")) obj.addProperty("App::PropertyString", "FinishWalls", "Arch",translate("Arch","The finishing of the walls of this space")) obj.addProperty("App::PropertyString", "FinishCeiling","Arch",translate("Arch","The finishing of the ceiling of this space")) self.Type = "Space"
def __init__(self,obj): ArchComponent.Component.__init__(self,obj) obj.addProperty("App::PropertyLength","Length","Arch",translate("Arch","The length of this element, if not based on a profile")) obj.addProperty("App::PropertyLength","Width","Arch",translate("Arch","The width of this element, if not based on a profile")) obj.addProperty("App::PropertyLength","Thickness","Arch",translate("Arch","The thickness or extrusion depth of this element")) obj.addProperty("App::PropertyInteger","Sheets","Arch",translate("Arch","The number of sheets to use")) obj.Sheets = 1 self.Type = "Panel"
def __init__(self,obj): ArchFloor._Floor.__init__(self,obj) obj.addProperty("App::PropertyLink","Terrain","Arch",translate("Arch","The terrain of this site")) obj.addProperty("App::PropertyString","Address","Arch",translate("Arch","The address of this site")) obj.addProperty("App::PropertyString","Coordinates","Arch",translate("Arch","The geographic coordinates of this site")) obj.addProperty("App::PropertyString","Url","Arch",translate("Arch","An url that shows this site in a mapping website")) self.Type = "Site" obj.setEditorMode('Height',2)
def __init__(self,obj): obj.Proxy = self obj.addProperty("App::PropertyPlacement","Placement","Base", translate("Arch","The placement of this object")) obj.addProperty("Part::PropertyPartShape","Shape","Base","") obj.addProperty("App::PropertyLinkList","Objects","Arch", translate("Arch","The objects that must be considered by this section plane. Empty means all document")) self.Type = "SectionPlane"
def __init__(self,obj): obj.addProperty("App::PropertyLength","Height","Arch", str(translate("Arch","The height of this floor"))) obj.addProperty("App::PropertyPlacement","Placement","Arch", str(translate("Arch","The placement of this group"))) self.Type = "Floor" obj.Proxy = self self.Object = obj
def Activated(self): sel = FreeCADGui.Selection.getSelectionEx() if sel: obj = sel[0].Object if Draft.getType(obj) == "Structure": if len(sel) > 1: sk = sel[1].Object if Draft.getType(sk) == "Sketch": # we have a base object and a sketch: create the rebar now FreeCAD.ActiveDocument.openTransaction(translate("Arch", "Create Rebar")) FreeCADGui.doCommand("import Arch") FreeCADGui.doCommand( "Arch.makeRebar(FreeCAD.ActiveDocument." + obj.Name + ",FreeCAD.ActiveDocument." + sk.Name + ")" ) FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() return else: # we have only a base object: open the sketcher FreeCADGui.activateWorkbench("SketcherWorkbench") FreeCADGui.runCommand("Sketcher_NewSketch") FreeCAD.ArchObserver = ArchComponent.ArchSelectionObserver( obj, FreeCAD.ActiveDocument.Objects[-1], hide=False, nextCommand="Arch_Rebar" ) FreeCADGui.Selection.addObserver(FreeCAD.ArchObserver) return elif Draft.getType(obj) == "Sketch": # we have only the sketch: extract the base object from it if hasattr(obj, "Support"): if obj.Support: if isinstance(obj.Support, tuple): sup = obj.Support[0] else: sup = obj.Support FreeCAD.ActiveDocument.openTransaction(translate("Arch", "Create Rebar")) FreeCADGui.doCommand("import Arch") FreeCADGui.doCommand( "Arch.makeRebar(FreeCAD.ActiveDocument." + sup.Name + ",FreeCAD.ActiveDocument." + obj.Name + ")" ) FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() return else: print "Arch: error: couldn't extract a base object" return FreeCAD.Console.PrintMessage(translate("Arch", "Please select a base face on a structural object\n")) FreeCADGui.Control.showDialog(ArchComponent.SelectionTaskPanel()) FreeCAD.ArchObserver = ArchComponent.ArchSelectionObserver(nextCommand="Arch_Rebar") FreeCADGui.Selection.addObserver(FreeCAD.ArchObserver)
def execute(self,obj): "builds the wall shape" if self.clone(obj): return import Part, DraftGeomUtils base = None pl = obj.Placement extdata = self.getExtrusionData(obj) if extdata: base = extdata[0] extv = extdata[2].Rotation.multVec(extdata[1]) if isinstance(base,list): shps = [] for b in base: b.Placement = extdata[2].multiply(b.Placement) b = b.extrude(extv) shps.append(b) base = Part.makeCompound(shps) else: base.Placement = extdata[2].multiply(base.Placement) base = base.extrude(extv) if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.isNull(): return if not obj.Base.Shape.isValid(): if not obj.Base.Shape.Solids: # let pass invalid objects if they have solids... return elif obj.Base.Shape.Solids: base = obj.Base.Shape.copy() 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 and (not sh.isNull()): base = sh else: FreeCAD.Console.PrintWarning(translate("Arch","This mesh is an invalid solid")+"\n") obj.Base.ViewObject.show() if not base: FreeCAD.Console.PrintError(translate("Arch","Error: Invalid base object")+"\n") return base = self.processSubShapes(obj,base,pl) self.applyShape(obj,base,pl) # set the length property if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.Edges: if not obj.Base.Shape.Faces: if hasattr(obj.Base.Shape,"Length"): l = obj.Base.Shape.Length if obj.Length.Value != l: obj.Length = l
def removeComponents(objectsList,host=None): '''removeComponents(objectsList,[hostObject]): removes the given component or the components from the given list from their parents. If a host object is specified, this function will try adding the components as holes to the host object instead.''' if not isinstance(objectsList,list): objectsList = [objectsList] if host: if Draft.getType(host) in ["Wall","Structure"]: if hasattr(host,"Axes"): a = host.Axes for o in objectsList[:]: if o in a: a.remove(o) objectsList.remove(o) s = host.Subtractions for o in objectsList: if not o in s: s.append(o) if Draft.getType(o) == "Window": # fix for sketch-based windows if o.Base: if o.Base.Support: if isinstance(o.Base.Support,tuple): if o.Base.Support[0].Name == host.Name: FreeCAD.Console.PrintMessage(str(translate("Arch","removing sketch support to avoid cross-referencing"))) o.Base.Support = None elif o.Base.Support.Name == host.Name: FreeCAD.Console.PrintMessage(str(translate("Arch","removing sketch support to avoid cross-referencing"))) o.Base.Support = None host.Subtractions = s else: for o in objectsList: if o.InList: h = o.InList[0] tp = Draft.getType(h) if tp in ["Cell","Floor","Building","Site"]: c = h.Components if o in c: c.remove(o) h.Components = c o.ViewObject.show() elif tp in ["Wall","Structure"]: a = h.Additions s = h.Subtractions if o in a: a.remove(o) h.Additions = a o.ViewObject.show() elif o in s: s.remove(o) h.Subtractions = s o.ViewObject.show() elif tp in ["SectionPlane"]: a = h.Objects if o in a: a.remove(o) h.Objects = a
def getIndices(shape,offset): "returns a list with 2 lists: vertices and face indexes, offsetted with the given amount" vlist = [] elist = [] flist = [] curves = None if isinstance(shape,Part.Shape): for e in shape.Edges: try: if not isinstance(e.Curve,Part.LineSegment): if not curves: curves = shape.tessellate(1) FreeCAD.Console.PrintWarning(translate("Arch","Found a shape containing curves, triangulating")+"\n") break except: # unimplemented curve type curves = shape.tessellate(1) FreeCAD.Console.PrintWarning(translate("Arch","Found a shape containing curves, triangulating")+"\n") break elif isinstance(shape,Mesh.Mesh): curves = shape.Topology if curves: for v in curves[0]: vlist.append(" "+str(round(v.x,p))+" "+str(round(v.y,p))+" "+str(round(v.z,p))) for f in curves[1]: fi = "" for vi in f: fi += " " + str(vi + offset) flist.append(fi) else: for v in shape.Vertexes: vlist.append(" "+str(round(v.X,p))+" "+str(round(v.Y,p))+" "+str(round(v.Z,p))) if not shape.Faces: for e in shape.Edges: if DraftGeomUtils.geomType(e) == "Line": ei = " " + str(findVert(e.Vertexes[0],shape.Vertexes) + offset) ei += " " + str(findVert(e.Vertexes[-1],shape.Vertexes) + offset) elist.append(ei) for f in shape.Faces: if len(f.Wires) > 1: # if we have holes, we triangulate tris = f.tessellate(1) for fdata in tris[1]: fi = "" for vi in fdata: vdata = Part.Vertex(tris[0][vi]) fi += " " + str(findVert(vdata,shape.Vertexes) + offset) flist.append(fi) else: fi = "" for e in f.OuterWire.OrderedEdges: #print(e.Vertexes[0].Point,e.Vertexes[1].Point) v = e.Vertexes[0] ind = findVert(v,shape.Vertexes) if ind == None: return None,None,None fi += " " + str(ind + offset) flist.append(fi) return vlist,elist,flist
def getIndices(shape, offset): "returns a list with 2 lists: vertices and face indexes, offsetted with the given amount" vlist = [] elist = [] flist = [] curves = None for e in shape.Edges: try: if not isinstance(e.Curve, Part.LineSegment): if not curves: curves = shape.tessellate(1) FreeCAD.Console.PrintWarning( translate( "Arch", "Found a shape containing curves, triangulating\n" ).decode('utf8')) break except: # unimplemented curve type curves = shape.tessellate(1) FreeCAD.Console.PrintWarning( translate( "Arch", "Found a shape containing curves, triangulating\n").decode( 'utf8')) break if curves: for v in curves[0]: vlist.append(" " + str(round(v.x, p)) + " " + str(round(v.y, p)) + " " + str(round(v.z, p))) for f in curves[1]: fi = "" for vi in f: fi += " " + str(vi + offset) flist.append(fi) else: for v in shape.Vertexes: vlist.append(" " + str(round(v.X, p)) + " " + str(round(v.Y, p)) + " " + str(round(v.Z, p))) if not shape.Faces: for e in shape.Edges: if DraftGeomUtils.geomType(e) == "Line": ei = " " + str( findVert(e.Vertexes[0], shape.Vertexes) + offset) ei += " " + str( findVert(e.Vertexes[-1], shape.Vertexes) + offset) elist.append(ei) for f in shape.Faces: if len(f.Wires) > 1: # if we have holes, we triangulate tris = f.tessellate(1) for fdata in tris[1]: fi = "" for vi in fdata: vdata = Part.Vertex(tris[0][vi]) fi += " " + str( findVert(vdata, shape.Vertexes) + offset) flist.append(fi) else: fi = "" # OCC vertices are unsorted. We need to sort in the right order... edges = Part.__sortEdges__(f.OuterWire.Edges) #print edges for e in edges: #print e.Vertexes[0].Point,e.Vertexes[1].Point v = e.Vertexes[0] ind = findVert(v, shape.Vertexes) if ind == None: return None, None, None fi += " " + str(ind + offset) flist.append(fi) return vlist, elist, flist
def onChanged(self, obj, prop): if prop in ["Source", "RenderingMode", "ShowCut"]: import Part, DraftGeomUtils if hasattr(obj, "Source"): if obj.Source: if obj.Source.Objects: objs = Draft.getGroupContents(obj.Source.Objects, walls=True) objs = Draft.removeHidden(objs) # separate spaces self.spaces = [] os = [] for o in objs: if Draft.getType(o) == "Space": self.spaces.append(o) else: os.append(o) objs = os self.svg = '' # generating SVG if obj.RenderingMode == "Solid": # render using the Arch Vector Renderer import ArchVRM render = ArchVRM.Renderer() render.setWorkingPlane(obj.Source.Placement) render.addObjects(objs) if hasattr(obj, "ShowCut"): render.cut(obj.Source.Shape, obj.ShowCut) else: render.cut(obj.Source.Shape) self.svg += render.getViewSVG( linewidth="LWPlaceholder") self.svg += render.getSectionSVG( linewidth="SWPLaceholder") if hasattr(obj, "ShowCut"): if obj.ShowCut: self.svg += render.getHiddenSVG( linewidth="LWPlaceholder") # print render.info() else: # render using the Drawing module import Drawing, Part shapes = [] hshapes = [] sshapes = [] p = FreeCAD.Placement(obj.Source.Placement) self.direction = p.Rotation.multVec( FreeCAD.Vector(0, 0, 1)) for o in objs: if o.isDerivedFrom("Part::Feature"): if o.Shape.isNull(): pass #FreeCAD.Console.PrintWarning(translate("Arch","Skipping empty object: ")+o.Name) elif o.Shape.isValid(): if hasattr(obj.Source, "OnlySolids"): if obj.Source.OnlySolids: shapes.extend(o.Shape.Solids) else: shapes.append(o.Shape) else: shapes.extend(o.Shape.Solids) else: FreeCAD.Console.PrintWarning( translate( "Arch", "Skipping invalid object: ") + o.Name) cutface, cutvolume, invcutvolume = ArchCommands.getCutVolume( obj.Source.Shape.copy(), shapes) if cutvolume: nsh = [] for sh in shapes: for sol in sh.Solids: if sol.Volume < 0: sol.reverse() c = sol.cut(cutvolume) s = sol.section(cutface) try: s = Part.Wire(s.Edges) s = Part.Face(s) except Part.OCCError: pass nsh.extend(c.Solids) sshapes.append(s) if hasattr(obj, "ShowCut"): if obj.ShowCut: c = sol.cut(invcutvolume) hshapes.append(c) shapes = nsh if shapes: self.shapes = shapes self.baseshape = Part.makeCompound(shapes) svgf = Drawing.projectToSVG( self.baseshape, self.direction) if svgf: svgf = svgf.replace( 'stroke-width="0.35"', 'stroke-width="LWPlaceholder"') svgf = svgf.replace( 'stroke-width="1"', 'stroke-width="LWPlaceholder"') svgf = svgf.replace( 'stroke-width:0.01', 'stroke-width:LWPlaceholder') self.svg += svgf if hshapes: hshapes = Part.makeCompound(hshapes) self.hiddenshape = hshapes svgh = Drawing.projectToSVG( hshapes, self.direction) if svgh: svgh = svgh.replace( 'stroke-width="0.35"', 'stroke-width="LWPlaceholder"') svgh = svgh.replace( 'stroke-width="1"', 'stroke-width="LWPlaceholder"') svgh = svgh.replace( 'stroke-width:0.01', 'stroke-width:LWPlaceholder') svgh = svgh.replace( 'fill="none"', 'fill="none"\nstroke-dasharray="DAPlaceholder"' ) self.svg += svgh if sshapes: sshapes = Part.makeCompound(sshapes) self.sectionshape = sshapes svgs = Drawing.projectToSVG( sshapes, self.direction) if svgs: svgs = svgs.replace( 'stroke-width="0.35"', 'stroke-width="SWPlaceholder"') svgs = svgs.replace( 'stroke-width="1"', 'stroke-width="SWPlaceholder"') svgs = svgs.replace( 'stroke-width:0.01', 'stroke-width:SWPlaceholder') self.svg += svgs
def getPoint(self, point=None, obj=None): "this function is called by the snapper when it has a 3D point" if obj: if Draft.getType(obj) == "Wall": if not obj in self.existing: self.existing.append(obj) if point == None: self.tracker.finalize() return self.points.append(point) if len(self.points) == 1: self.tracker.width(self.Width) self.tracker.height(self.Height) self.tracker.on() FreeCADGui.Snapper.getPoint(last=self.points[0], callback=self.getPoint, movecallback=self.update, extradlg=self.taskbox()) elif len(self.points) == 2: import Part l = Part.Line( FreeCAD.DraftWorkingPlane.getLocalCoords(self.points[0]), FreeCAD.DraftWorkingPlane.getLocalCoords(self.points[1])) self.tracker.finalize() FreeCAD.ActiveDocument.openTransaction( translate("Arch", "Create Wall")) FreeCADGui.addModule("Arch") FreeCADGui.doCommand('import Part') FreeCADGui.doCommand('trace=Part.Line(FreeCAD.' + str(l.StartPoint) + ',FreeCAD.' + str(l.EndPoint) + ')') if not self.existing: # no existing wall snapped, just add a default wall self.addDefault(l) else: if self.JOIN_WALLS_SKETCHES: # join existing subwalls first if possible, then add the new one w = joinWalls(self.existing) if w: if areSameWallTypes([w, self]): FreeCADGui.doCommand('FreeCAD.ActiveDocument.' + w.Name + '.Base.addGeometry(trace)') else: # if not possible, add new wall as addition to the existing one self.addDefault(l) if self.AUTOJOIN: FreeCADGui.doCommand( 'Arch.addComponents(FreeCAD.ActiveDocument.' + FreeCAD.ActiveDocument.Objects[-1].Name + ',FreeCAD.ActiveDocument.' + w.Name + ')') else: self.addDefault(l) else: # add new wall as addition to the first existing one self.addDefault(l) if self.AUTOJOIN: FreeCADGui.doCommand( 'Arch.addComponents(FreeCAD.ActiveDocument.' + FreeCAD.ActiveDocument.Objects[-1].Name + ',FreeCAD.ActiveDocument.' + self.existing[0].Name + ')') FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() if self.continueCmd: self.Activated()
def Activated(self): FreeCAD.ActiveDocument.openTransaction( str(translate("Arch", "Create Axis"))) FreeCADGui.doCommand("import Arch") FreeCADGui.doCommand("Arch.makeAxis()") FreeCAD.ActiveDocument.commitTransaction()
def Activated(self): try: import ifcopenshell except: FreeCAD.Console.PrintError( translate( "BIM", "IfcOpenShell was not found on this system. IFC support is disabled" ) + "\n") return # draw the main tree widget self.tree = QtGui.QTreeWidget() self.tree.setColumnCount(1) self.tree.setWordWrap(True) self.tree.header().setDefaultSectionSize(60) self.tree.header().resizeSection(0, 180) self.tree.header().setStretchLastSection(True) self.tree.headerItem().setText(0, translate("BIM", "Objects structure")) # draw the attributes widget self.attributes = QtGui.QTreeWidget() self.attributes.setColumnCount(2) self.attributes.setWordWrap(True) self.attributes.header().setDefaultSectionSize(60) self.attributes.header().resizeSection(0, 120) self.attributes.header().resizeSection(1, 200) self.attributes.header().setStretchLastSection(True) self.attributes.headerItem().setText(0, translate("BIM", "Attribute")) self.attributes.headerItem().setText(1, translate("BIM", "Value")) # draw the properties widget self.properties = QtGui.QTreeWidget() self.properties.setColumnCount(2) self.properties.setWordWrap(True) self.properties.header().setDefaultSectionSize(60) self.properties.header().resizeSection(0, 120) self.properties.header().resizeSection(1, 200) self.properties.header().setStretchLastSection(True) self.properties.headerItem().setText(0, translate("BIM", "Property")) self.properties.headerItem().setText(1, translate("BIM", "Value")) # create the dialog self.dialog = QtGui.QDialog() self.dialog.setObjectName("IfcExplorer") self.dialog.setWindowTitle(translate("BIM", "Ifc Explorer")) self.dialog.resize(720, 540) toolbar = QtGui.QToolBar() layout = QtGui.QVBoxLayout(self.dialog) layout.addWidget(toolbar) hlayout = QtGui.QHBoxLayout(self.dialog) hlayout.addWidget(self.tree) layout.addLayout(hlayout) vlayout = QtGui.QVBoxLayout(self.dialog) hlayout.addLayout(vlayout) vlayout.addWidget(self.attributes) vlayout.addWidget(self.properties) # draw the toolbar buttons self.openAction = QtGui.QAction(translate("BIM", "Open"), None) self.openAction.setToolTip(translate("BIM", "Open another IFC file...")) self.openAction.triggered.connect(self.open) self.openAction.setIcon(QtGui.QIcon(":/icons/document-open.svg")) toolbar.addAction(self.openAction) self.backAction = QtGui.QAction(translate("BIM", "Back"), None) self.backAction.setToolTip( translate("BIM", "Go back to last item selected")) self.backAction.triggered.connect(self.back) self.backAction.setIcon(QtGui.QIcon(":/icons/edit-undo.svg")) toolbar.addAction(self.backAction) self.shapeAction = QtGui.QAction(translate("BIM", "Insert"), None) self.shapeAction.setToolTip( translate( "BIM", "Inserts the selected object and its children in the active document" )) self.shapeAction.triggered.connect(self.insert) self.shapeAction.setIcon(QtGui.QIcon(":icons/Tree_Part.svg")) self.shapeAction.setEnabled(False) toolbar.addAction(self.shapeAction) self.meshAction = QtGui.QAction(translate("BIM", "Mesh"), None) self.meshAction.setToolTip(translate("BIM", "Turn mesh display on/off")) self.meshAction.triggered.connect(self.toggleMesh) self.meshAction.setCheckable(True) self.meshAction.setChecked(False) self.meshAction.setIcon(QtGui.QIcon(":/icons/DrawStyleShaded.svg")) toolbar.addAction(self.meshAction) # connect signals/slots self.tree.currentItemChanged.connect(self.onSelectTree) self.attributes.itemDoubleClicked.connect(self.onDoubleClickTree) self.properties.itemDoubleClicked.connect(self.onDoubleClickTree) self.dialog.rejected.connect(self.close) # center the dialog over FreeCAD window mw = FreeCADGui.getMainWindow() self.dialog.move(mw.frameGeometry().topLeft() + mw.rect().center() - self.dialog.rect().center()) # open a file and show the dialog self.open() self.dialog.show()
def setTabShoulder(self): ui = FreeCADGui.UiLoader() self.foreGroup = QtGui.QGroupBox( translate('Rocket', "Forward Shoulder"), self) self.foreGroup.setCheckable(True) self.foreShoulderDiameterLabel = QtGui.QLabel( translate('Rocket', "Diameter"), self) self.foreShoulderDiameterInput = ui.createWidget("Gui::InputField") self.foreShoulderDiameterInput.unit = 'mm' self.foreShoulderDiameterInput.setFixedWidth(80) self.foreShoulderLengthLabel = QtGui.QLabel( translate('Rocket', "Length"), self) self.foreShoulderLengthInput = ui.createWidget("Gui::InputField") self.foreShoulderLengthInput.unit = 'mm' self.foreShoulderLengthInput.setFixedWidth(80) self.foreShoulderThicknessLabel = QtGui.QLabel( translate('Rocket', "Thickness"), self) self.foreShoulderThicknessInput = ui.createWidget("Gui::InputField") self.foreShoulderThicknessInput.unit = 'mm' self.foreShoulderThicknessInput.setFixedWidth(80) self.aftGroup = QtGui.QGroupBox(translate('Rocket', "Aft Shoulder"), self) self.aftGroup.setCheckable(True) self.aftShoulderDiameterLabel = QtGui.QLabel( translate('Rocket', "Diameter"), self) self.aftShoulderDiameterInput = ui.createWidget("Gui::InputField") self.aftShoulderDiameterInput.unit = 'mm' self.aftShoulderDiameterInput.setFixedWidth(80) self.aftShoulderLengthLabel = QtGui.QLabel( translate('Rocket', "Length"), self) self.aftShoulderLengthInput = ui.createWidget("Gui::InputField") self.aftShoulderLengthInput.unit = 'mm' self.aftShoulderLengthInput.setFixedWidth(80) self.aftShoulderThicknessLabel = QtGui.QLabel( translate('Rocket', "Thickness"), self) self.aftShoulderThicknessInput = ui.createWidget("Gui::InputField") self.aftShoulderThicknessInput.unit = 'mm' self.aftShoulderThicknessInput.setFixedWidth(80) row = 0 layout = QGridLayout() layout.addWidget(self.foreShoulderLengthLabel, row, 0) layout.addWidget(self.foreShoulderLengthInput, row, 1) row += 1 layout.addWidget(self.foreShoulderDiameterLabel, row, 0) layout.addWidget(self.foreShoulderDiameterInput, row, 1) row += 1 layout.addWidget(self.foreShoulderThicknessLabel, row, 0) layout.addWidget(self.foreShoulderThicknessInput, row, 1) self.foreGroup.setLayout(layout) row = 0 layout = QGridLayout() layout.addWidget(self.aftShoulderLengthLabel, row, 0) layout.addWidget(self.aftShoulderLengthInput, row, 1) row += 1 layout.addWidget(self.aftShoulderDiameterLabel, row, 0) layout.addWidget(self.aftShoulderDiameterInput, row, 1) row += 1 layout.addWidget(self.aftShoulderThicknessLabel, row, 0) layout.addWidget(self.aftShoulderThicknessInput, row, 1) self.aftGroup.setLayout(layout) layout = QVBoxLayout() layout.addWidget(self.foreGroup) layout.addWidget(self.aftGroup) layout.addItem( QtGui.QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Expanding)) self.tabShoulder.setLayout(layout)
def createGeometry(self, obj): import Part, DraftGeomUtils # getting default values height = width = length = 1 if hasattr(obj, "Length"): if obj.Length: length = obj.Length if hasattr(obj, "Width"): if obj.Width: width = obj.Width if hasattr(obj, "Height"): if obj.Height: height = obj.Height # creating base shape pl = obj.Placement base = None if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if hasattr(obj, "Tool"): if obj.Tool: try: base = obj.Tool.Shape.copy().makePipe( obj.Base.Shape.copy()) except: FreeCAD.Console.PrintError( str( translate( "Arch", "Error: The base shape couldn't be extruded along this tool object" ))) return if not base: if obj.Normal == Vector(0, 0, 0): p = FreeCAD.Placement(obj.Base.Placement) normal = p.Rotation.multVec(Vector(0, 0, 1)) else: normal = Vector(obj.Normal) normal = normal.multiply(height) base = obj.Base.Shape.copy() if base.Solids: pass elif base.Faces: base = base.extrude(normal) elif (len(base.Wires) == 1): if base.Wires[0].isClosed(): base = Part.Face(base.Wires[0]) 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: if obj.Normal == Vector(0, 0, 0): normal = Vector(0, 0, 1) else: normal = Vector(obj.Normal) normal = normal.multiply(height) 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) base = base.extrude(normal) base = self.processSubShapes(obj, base) if base: # applying axes pts = self.getAxisPoints(obj) apl = self.getAxisPlacement(obj) if pts: fsh = [] for i in range(len(pts)): if hasattr(obj, "Exclude"): if i in obj.Exclude: continue sh = base.copy() if apl: sh.Placement.Rotation = apl.Rotation sh.translate(pts[i]) fsh.append(sh) obj.Shape = Part.makeCompound(fsh) # finalizing else: 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( str( translate("Arch", "Couldn't compute a shape"))) return base = base.removeSplitter() obj.Shape = base if not DraftGeomUtils.isNull(pl): obj.Placement = pl
def makeRoof(baseobj=None, facenr=1, angles=[ 45., ], run=[], idrel=[ 0, ], thickness=[ 1., ], overhang=[ 2., ], name=translate("Arch", "Roof")): '''makeRoof(baseobj,[facenr],[angle],[name]) : Makes a roof based on a closed wire. face from an existing object. You can provide a list of angles, run, idrel, thickness, overhang for each edges in the wire to define the roof shape. The default for angle is 45 and the list is automatically complete to match with number of edges in the wire.''' obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", name) _Roof(obj) if FreeCAD.GuiUp: _ViewProviderRoof(obj.ViewObject) if baseobj: obj.Base = baseobj if obj.Base.isDerivedFrom("Part::Feature"): if (obj.Base.Shape.Faces and obj.Face): w = obj.Base.Shape.Faces[obj.Face - 1].Wires[0] elif obj.Base.Shape.Wires: w = obj.Base.Shape.Wires[0] if w: if w.isClosed(): edges = DraftGeomUtils.sortEdges(w.Edges) l = len(edges) la = len(angles) alist = angles for i in range(l - la): alist.append(angles[0]) obj.Angles = alist lr = len(run) rlist = run for i in range(l - lr): rlist.append(w.Edges[i].Length / 2.) obj.Runs = rlist lidrel = len(idrel) rellist = idrel for i in range(l - lidrel): rellist.append(0) obj.IdRel = rellist lthick = len(thickness) tlist = thickness for i in range(l - lthick): tlist.append(thickness[0]) obj.Thickness = tlist lover = len(overhang) olist = overhang for i in range(l - lover): olist.append(overhang[0]) obj.Overhang = olist obj.Face = facenr return obj
def Activated(self): # you need two documents open, containing BIM objects with same IDs # make the main doc the active one before running this script! # what will be compared: IDs, geometry, materials. Everything else is discarded. MOVE_TOLERANCE = 0.2 # the max allowed move in mm VOL_TOLERANCE = 250 # the max allowed volume diff in mm^3 documents = FreeCAD.listDocuments() if len(documents) == 2: reply = QtGui.QMessageBox.question( None, "", translate( "BIM", "The document currently viewed must be your main one. The other contains newer objects that you wish to merge into this one. Make sure only the objects you wish to compare are visible in both. Proceed?" ), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: activedoc = FreeCAD.ActiveDocument if list(documents.keys())[0] == activedoc.Name: otherdoc = list(documents.values())[1] else: otherdoc = list(documents.values())[0] # build lists of BIM objects with IFC ID objswithoutid = [] # let's try to match these later on activedocids = {} # main document, the original freecad one for obj in activedoc.Objects: if hasattr(obj, "IfcData") and obj.ViewObject.Visibility: if "IfcUID" in obj.IfcData: activedocids[obj.IfcData["IfcUID"]] = obj elif obj.isDerivedFrom( "Part::Feature"): # discard BuildingParts objswithoutid.append(obj) otherdocids = {} # other doc to be merged to the main one for obj in otherdoc.Objects: if hasattr(obj, "IfcData") and obj.ViewObject.Visibility: if "IfcUID" in obj.IfcData: otherdocids[obj.IfcData["IfcUID"]] = obj toselect = [] # objects to select when finished additions = [] # objects added subtractions = [] # objects subtracted modified = [] # objects modified moved = [] # objects moved matchanged = [] # object is same, but material changed matchangedghost = [ ] # store shapes of objects whose material has changed to print a blue ghost later on renamed = {} # object label changes propertieschanged = { } # objects whose IFC properties are different for id, obj in otherdocids.items(): if id in activedocids: # this object already exists mainobj = activedocids[id] if obj.Label != mainobj.Label: # object has a different name renamed[mainobj.Name] = obj.Label if obj.IfcProperties and (obj.IfcProperties != mainobj.IfcProperties): # properties have changed propertieschanged[id] = obj.IfcProperties if hasattr(obj, "Shape") and hasattr(mainobj, "Shape"): v = abs(obj.Shape.Volume - mainobj.Shape.Volume) if v < VOL_TOLERANCE: # identical volume l = (obj.Shape.BoundBox.Center.sub( mainobj.Shape.BoundBox.Center)).Length if l < MOVE_TOLERANCE: # identical position if abs(obj.Shape.BoundBox.XMin - mainobj.Shape.BoundBox.XMin) < MOVE_TOLERANCE and \ abs(obj.Shape.BoundBox.YMin - mainobj.Shape.BoundBox.YMin) < MOVE_TOLERANCE and \ abs(obj.Shape.BoundBox.YMin - mainobj.Shape.BoundBox.YMin) < MOVE_TOLERANCE: # same boundbox if hasattr(obj, "Material") and hasattr( mainobj, "Material") and ( obj.Material and mainobj.Material and (obj.Material.Label == mainobj.Material.Label) ) or (obj.Material == mainobj.Material): # same material names obj.ViewObject.hide() else: print("Object", mainobj.Label, "material has changed") obj.ViewObject.hide( ) # we hide these objects since the shape hasn't changed but we keep their shapes matchangedghost.append(obj.Shape) matchanged.append(obj) else: print("Object", mainobj.Label, "shape bound box has changed") toselect.append(obj) modified.append(obj) else: print("Object", mainobj.Label, "position has moved by", l, "mm") toselect.append(obj) moved.append(obj) else: print("Object", mainobj.Label, "shape has changed by", v, "mm^3") toselect.append(obj) modified.append(obj) else: print("Object", mainobj.Label, "one of the objects has no shape") toselect.append(obj) else: print("Object", obj.Label, "doesn't exist yet in main doc") toselect.append(obj) additions.append(obj) for id, obj in activedocids.items(): if not id in otherdocids: if obj.isDerivedFrom( "Part::Feature"): # don't count building parts print("Object", obj.Label, "doesn't exist anymore in new doc") subtractions.append(obj) # try to find our objects without ID newids = {} for obj in objswithoutid: for id, otherobj in otherdocids.items(): if not id in activedocids: if abs(otherobj.Shape.Volume - obj.Shape.Volume) < VOL_TOLERANCE: if (otherobj.Shape.BoundBox.Center.sub( obj.Shape.BoundBox.Center) ).Length < MOVE_TOLERANCE: if abs(obj.Shape.BoundBox.XMin - otherobj.Shape.BoundBox.XMin) < MOVE_TOLERANCE and \ abs(obj.Shape.BoundBox.YMin - otherobj.Shape.BoundBox.YMin) < MOVE_TOLERANCE and \ abs(obj.Shape.BoundBox.YMin - otherobj.Shape.BoundBox.YMin) < MOVE_TOLERANCE: # shapes are identical. It's the same object! newids[obj.Name] = id break else: print("Object", obj.Label, "has no ID and wasn't found in the new doc") subtractions.append(obj) matnames = {} # existing materials for obj in activedoc.Objects: if Draft.getType(obj) == "Material": matnames[obj.Label] = obj newmats = {} # new materials for obj in otherdoc.Objects: if Draft.getType(obj) == "Material": if not obj.Label in matnames: print("Material", obj.Label, "doesn't exist in main doc") toselect.append(obj) newmats[obj.Label] = obj if newmats: group = otherdoc.addObject("App::DocumentObjectGroup", "New_materials") for newmat in newmats.values(): group.addObject(newmat) if toselect: FreeCAD.setActiveDocument(otherdoc.Name) FreeCAD.ActiveDocument = FreeCADGui.getDocument( otherdoc.Name) FreeCADGui.ActiveDocument = FreeCADGui.getDocument( otherdoc.Name) FreeCADGui.Selection.clearSelection() for obj in toselect: FreeCADGui.Selection.addSelection(obj) if additions: shape = Part.makeCompound([a.Shape for a in additions]) obj = activedoc.addObject("Part::Feature", "Additions") obj.Shape = shape obj.ViewObject.LineWidth = 5 obj.ViewObject.LineColor = (0.0, 1.0, 0.0) obj.ViewObject.ShapeColor = (0.0, 1.0, 0.0) obj.ViewObject.Transparency = 60 if subtractions: shape = Part.makeCompound([s.Shape for s in subtractions]) obj = activedoc.addObject("Part::Feature", "Subtractions") obj.Shape = shape obj.ViewObject.LineWidth = 5 obj.ViewObject.LineColor = (1.0, 0.0, 0.0) obj.ViewObject.ShapeColor = (1.0, 0.0, 0.0) obj.ViewObject.Transparency = 60 if modified: shape = Part.makeCompound([m.Shape for m in modified]) obj = activedoc.addObject("Part::Feature", "Modified") obj.Shape = shape obj.ViewObject.LineWidth = 5 obj.ViewObject.LineColor = (1.0, 0.5, 0.0) obj.ViewObject.ShapeColor = (1.0, 0.5, 0.0) obj.ViewObject.Transparency = 60 if moved: shape = Part.makeCompound([m.Shape for m in moved]) obj = activedoc.addObject("Part::Feature", "Moved") obj.Shape = shape obj.ViewObject.LineWidth = 5 obj.ViewObject.LineColor = (1.0, 1.0, 0.0) obj.ViewObject.ShapeColor = (1.0, 1.0, 0.0) obj.ViewObject.Transparency = 60 if matchangedghost: shape = Part.makeCompound(matchangedghost) obj = otherdoc.addObject("Part::Feature", "Material_changed") obj.Shape = shape obj.ViewObject.LineWidth = 1 obj.ViewObject.LineColor = (0.0, 0.0, 1.0) obj.ViewObject.ShapeColor = (0.0, 0.0, 1.0) obj.ViewObject.Transparency = 90 if matchanged: reply = QtGui.QMessageBox.question( None, "", str(len(matchanged)) + " " + translate( "BIM", "objects still have the same shape but have a different material. Do you wish to update them in the main document?" ), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: for obj in matchanged: mat = obj.Material if mat: mainobj = activedocids[obj.IfcData["IfcUID"]] if mainobj.Material: mainmatlabel = mainobj.Material.Label else: mainmatlabel = "None" if mat.Label in matnames: # the new material already exists, just change it print("Changing material of", mainobj.Label, "from", mainmatlabel, "to", mat.Label) mainobj.Material = matnames[mat.Label] else: # copy the material over newmat = activedoc.addObject( "App::MaterialObjectPython", "Material") newmat.Label = mat.Label import ArchMaterial ArchMaterial._ArchMaterial(newmat) ArchMaterial._ViewProviderArchMaterial( newmat.ViewObject) newmat.Material = mat.Material print("Changing material of", mainobj.Label, "from", mainmatlabel, "to", newmat.Label) mainobj.Material = newmat matnames[newmat.Label] = newmat if newids: reply = QtGui.QMessageBox.question( None, "", str(len(newids)) + " " + translate( "BIM", "objects have no IFC ID in the main document, but an identical object with an ID exists in the new document. Transfer these IDs to the original objects?" ), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: for name, id in newids.items(): obj = activedoc.getObject(name) if obj: print("Transferring new id to object", obj.Label) a = obj.IfcData a["IfcUID"] = id obj.IfcData = a if renamed: reply = QtGui.QMessageBox.question( None, "", str(len(renamed)) + " " + translate( "BIM", "objects had their name changed. Rename them?"), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: for name, label in renamed.items(): obj = activedoc.getObject(name) if obj: print("Renaming object", obj.Label, "to", label) obj.Label = label if propertieschanged: reply = QtGui.QMessageBox.question( None, "", str(len(propertieschanged)) + " " + translate( "BIM", "objects had their properties changed. Update?"), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: for id, prop in propertieschanged.items(): obj = activedocids[id] print("Updating properties of ", obj.Label) obj.IfcProperties = prop if moved: reply = QtGui.QMessageBox.question( None, "", str(len(moved)) + " " + translate( "BIM", "objects have their location changed. Move them to their new position?" ), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: for obj in moved: mainobj = activedocids[obj.IfcData["IfcUID"]] otherobj = otherdocids[obj.IfcData["IfcUID"]] delta = otherobj.Shape.BoundBox.Center.sub( mainobj.Shape.BoundBox.Center) print("Moving object ", mainobj.Label) Draft.move(mainobj, delta) reply = QtGui.QMessageBox.question( None, "", translate( "BIM", "Do you wish to colorize the objects that have moved in yellow in the other file (to serve as a diff)?" ), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: for obj in moved: otherobj = otherdocids[obj.IfcData["IfcUID"]] try: otherobj.ViewObject.LineColor = (1.0, 1.0, 0.0) otherobj.ViewObject.ShapeColor = (1.0, 1.0, 0.0) otherobj.ViewObject.Transparency = 60 except AttributeError: print(otherobj.Label, "cannot be colorized") if modified: reply = QtGui.QMessageBox.question( None, "", translate( "BIM", "Do you wish to colorize the objects that have been modified in orange in the other file (to serve as a diff)?" ), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: for obj in modified: otherobj = otherdocids[obj.IfcData["IfcUID"]] try: otherobj.ViewObject.LineColor = (1.0, 0.5, 0.0) otherobj.ViewObject.ShapeColor = (1.0, 0.5, 0.0) otherobj.ViewObject.Transparency = 60 except AttributeError: print(otherobj.Label, "cannot be colorized") if subtractions: reply = QtGui.QMessageBox.question( None, "", str(len(subtractions)) + " " + translate( "BIM", "objects don't exist anymore in the new document. Move them to a 'To Delete' group?" ), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: group = activedoc.addObject("App::DocumentObjectGroup", "ToDelete") group.Label = "To Delete" for obj in subtractions: group.addObject(obj) reply = QtGui.QMessageBox.question( None, "", translate( "BIM", "Do you wish to colorize the objects that have been removed in red in the other file (to serve as a diff)?" ), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: for obj in subtractions: otherobj = otherdoc.addObject( "Part::Feature", "Deleted") otherobj.Shape = obj.Shape otherobj.ViewObject.LineColor = (1.0, 0.0, 0.0) otherobj.ViewObject.ShapeColor = (1.0, 0.0, 0.0) otherobj.ViewObject.Transparency = 60 if additions: reply = QtGui.QMessageBox.question( None, "", translate( "BIM", "Do you wish to colorize the objects that have been added in green in the other file (to serve as a diff)?" ), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: for obj in additions: otherobj = otherdocids[obj.IfcData["IfcUID"]] try: otherobj.ViewObject.LineColor = (0.0, 1.0, 0.0) otherobj.ViewObject.ShapeColor = (0.0, 1.0, 0.0) otherobj.ViewObject.Transparency = 60 except AttributeError: print(otherobj.Label, "cannot be colorized") else: QtGui.QMessageBox.information( None, "", translate( "BIM", "You need two documents open to run this tool. One which is your main document, and one that contains new objects that you wish to compare against the existing one. Make sure only the objects you wish to compare in both documents are visible." ))
def taskbox(self): "sets up a taskbox widget" w = QtGui.QWidget() ui = FreeCADGui.UiLoader() w.setWindowTitle(translate("Arch", "Wall options").decode("utf8")) grid = QtGui.QGridLayout(w) label5 = QtGui.QLabel(translate("Arch", "Length").decode("utf8")) self.Length = ui.createWidget("Gui::InputField") self.Length.setText("0.00 mm") grid.addWidget(label5, 0, 0, 1, 1) grid.addWidget(self.Length, 0, 1, 1, 1) label1 = QtGui.QLabel(translate("Arch", "Width").decode("utf8")) value1 = ui.createWidget("Gui::InputField") value1.setText( FreeCAD.Units.Quantity(self.Width, FreeCAD.Units.Length).UserString) grid.addWidget(label1, 1, 0, 1, 1) grid.addWidget(value1, 1, 1, 1, 1) label2 = QtGui.QLabel(translate("Arch", "Height").decode("utf8")) value2 = ui.createWidget("Gui::InputField") value2.setText( FreeCAD.Units.Quantity(self.Height, FreeCAD.Units.Length).UserString) grid.addWidget(label2, 2, 0, 1, 1) grid.addWidget(value2, 2, 1, 1, 1) label3 = QtGui.QLabel(translate("Arch", "Alignment").decode("utf8")) value3 = QtGui.QComboBox() items = ["Center", "Left", "Right"] value3.addItems(items) value3.setCurrentIndex(items.index(self.Align)) grid.addWidget(label3, 3, 0, 1, 1) grid.addWidget(value3, 3, 1, 1, 1) label4 = QtGui.QLabel(translate("Arch", "Con&tinue").decode("utf8")) value4 = QtGui.QCheckBox() value4.setObjectName("ContinueCmd") value4.setLayoutDirection(QtCore.Qt.RightToLeft) label4.setBuddy(value4) if hasattr(FreeCADGui, "draftToolBar"): value4.setChecked(FreeCADGui.draftToolBar.continueMode) self.continueCmd = FreeCADGui.draftToolBar.continueMode grid.addWidget(label4, 4, 0, 1, 1) grid.addWidget(value4, 4, 1, 1, 1) QtCore.QObject.connect(self.Length, QtCore.SIGNAL("valueChanged(double)"), self.setLength) QtCore.QObject.connect(value1, QtCore.SIGNAL("valueChanged(double)"), self.setWidth) QtCore.QObject.connect(value2, QtCore.SIGNAL("valueChanged(double)"), self.setHeight) QtCore.QObject.connect(value3, QtCore.SIGNAL("currentIndexChanged(int)"), self.setAlign) QtCore.QObject.connect(value4, QtCore.SIGNAL("stateChanged(int)"), self.setContinue) QtCore.QObject.connect(self.Length, QtCore.SIGNAL("returnPressed()"), value1.setFocus) QtCore.QObject.connect(self.Length, QtCore.SIGNAL("returnPressed()"), value1.selectAll) QtCore.QObject.connect(value1, QtCore.SIGNAL("returnPressed()"), value2.setFocus) QtCore.QObject.connect(value1, QtCore.SIGNAL("returnPressed()"), value2.selectAll) QtCore.QObject.connect(value2, QtCore.SIGNAL("returnPressed()"), self.createFromGUI) return w
def taskbox(self): "sets up a taskbox widget" d = FreeCAD.ParamGet( "User parameter:BaseApp/Preferences/Units").GetInt("Decimals", 2) w = QtGui.QWidget() w.setWindowTitle(str(translate("Arch", "Structure options"))) lay0 = QtGui.QVBoxLayout(w) # presets box layp = QtGui.QHBoxLayout() lay0.addLayout(layp) labelp = QtGui.QLabel(str(translate("Arch", "Preset"))) layp.addWidget(labelp) valuep = QtGui.QComboBox() fpresets = [" "] for p in Presets[1:]: fpresets.append( str(translate("Arch", p[0])) + " " + p[1] + " (" + str(p[2]) + "x" + str(p[3]) + "mm)") valuep.addItems(fpresets) layp.addWidget(valuep) # length lay1 = QtGui.QHBoxLayout() lay0.addLayout(lay1) label1 = QtGui.QLabel(str(translate("Arch", "Length"))) lay1.addWidget(label1) self.vLength = QtGui.QDoubleSpinBox() self.vLength.setDecimals(d) self.vLength.setMaximum(99999.99) self.vLength.setValue(self.Length) lay1.addWidget(self.vLength) # width lay2 = QtGui.QHBoxLayout() lay0.addLayout(lay2) label2 = QtGui.QLabel(str(translate("Arch", "Width"))) lay2.addWidget(label2) self.vWidth = QtGui.QDoubleSpinBox() self.vWidth.setDecimals(d) self.vWidth.setMaximum(99999.99) self.vWidth.setValue(self.Width) lay2.addWidget(self.vWidth) # height lay3 = QtGui.QHBoxLayout() lay0.addLayout(lay3) label3 = QtGui.QLabel(str(translate("Arch", "Height"))) lay3.addWidget(label3) self.vHeight = QtGui.QDoubleSpinBox() self.vHeight.setDecimals(d) self.vHeight.setMaximum(99999.99) self.vHeight.setValue(self.Height) lay3.addWidget(self.vHeight) # horizontal button value5 = QtGui.QPushButton(str(translate("Arch", "Rotate"))) lay0.addWidget(value5) # continue button value4 = QtGui.QCheckBox(str(translate("Arch", "Continue"))) lay0.addWidget(value4) QtCore.QObject.connect(valuep, QtCore.SIGNAL("currentIndexChanged(int)"), self.setPreset) QtCore.QObject.connect(self.vLength, QtCore.SIGNAL("valueChanged(double)"), self.setLength) QtCore.QObject.connect(self.vWidth, QtCore.SIGNAL("valueChanged(double)"), self.setWidth) QtCore.QObject.connect(self.vHeight, QtCore.SIGNAL("valueChanged(double)"), self.setHeight) QtCore.QObject.connect(value4, QtCore.SIGNAL("stateChanged(int)"), self.setContinue) QtCore.QObject.connect(value5, QtCore.SIGNAL("pressed()"), self.rotate) return w
def __init__(self, obj): obj.addProperty("App::PropertyPlacement", "Placement", "Arch", translate("Arch", "The placement of this group")) self.Type = "Group" obj.Proxy = self self.Object = obj
def addLayer(self): item1 = QtGui.QStandardItem(translate("Arch", "New layer")) item2 = QtGui.QStandardItem() item3 = QtGui.QStandardItem() self.model.appendRow([item1, item2, item3])
def read(filename): "Parses an IFC file" # parsing the IFC file t1 = time.time() num_lines = sum(1 for line in pyopen(filename)) if getIfcOpenShell() and not FORCE_PYTHON_PARSER: # use the IfcOpenShell parser # preparing IfcOpenShell if DEBUG: global ifcObjects, ifcParents ifcObjects = {} # a table to relate ifc id with freecad object ifcParents = {} # a table to relate ifc id with parent id if not IMPORT_IFC_FURNITURE: SKIP.append("IfcFurnishingElement") if hasattr(IfcImport, "DISABLE_OPENING_SUBTRACTIONS") and SEPARATE_OPENINGS: IfcImport.Settings(IfcImport.DISABLE_OPENING_SUBTRACTIONS, True) else: SKIP.append("IfcOpeningElement") useShapes = False if hasattr(IfcImport, "USE_BREP_DATA"): IfcImport.Settings(IfcImport.USE_BREP_DATA, True) useShapes = True else: if DEBUG: print "Warning: IfcOpenShell version very old, unable to handle Brep data" # processing geometry if IfcImport.Init(filename): while True: obj = IfcImport.Get() if DEBUG: print "[" + str( int((float(obj.id) / num_lines) * 100) ) + "%] parsing ", obj.id, ": ", obj.name, " of type ", obj.type meshdata = [] # retrieving name n = getName(obj) # skip types if obj.type in SKIP: if DEBUG: print "skipping because type is in skip list" nobj = None else: # build shape shape = None if useShapes: shape = getShape(obj) # walls if obj.type in ["IfcWallStandardCase", "IfcWall"]: nobj = makeWall(obj.id, shape, n) # windows elif obj.type in ["IfcWindow", "IfcDoor"]: nobj = makeWindow(obj.id, shape, n) # structs elif obj.type in [ "IfcBeam", "IfcColumn", "IfcSlab", "IfcFooting" ]: nobj = makeStructure(obj.id, shape, n) # roofs elif obj.type in ["IfcRoof"]: nobj = makeRoof(obj.id, shape, n) # furniture elif obj.type in ["IfcFurnishingElement"]: nobj = FreeCAD.ActiveDocument.addObject( "Part::Feature", n) nobj.Shape = shape # sites elif obj.type in ["IfcSite"]: nobj = makeSite(obj.id, shape, n) elif shape: # treat as dumb parts #if DEBUG: print "Fixme: Shape-containing object not handled: ",obj.id, " ", obj.type nobj = FreeCAD.ActiveDocument.addObject( "Part::Feature", n) nobj.Shape = shape else: # treat as meshes if DEBUG: print "Warning: Object without shape: ", obj.id, " ", obj.type me, pl = getMesh(obj) nobj = FreeCAD.ActiveDocument.addObject( "Mesh::Feature", n) nobj.Mesh = me nobj.Placement = pl # registering object number and parent if obj.parent_id > 0: ifcParents[obj.id] = [ obj.parent_id, not (obj.type in subtractiveTypes) ] ifcObjects[obj.id] = nobj if not IfcImport.Next(): break # processing non-geometry and relationships parents_temp = dict(ifcParents) import ArchCommands while parents_temp: id, c = parents_temp.popitem() parent_id = c[0] additive = c[1] if (id <= 0) or (parent_id <= 0): # root dummy object parent = None elif parent_id in ifcObjects: parent = ifcObjects[parent_id] # check if parent is a subtraction, if yes parent to grandparent if parent_id in ifcParents: if ifcParents[parent_id][1] == False: grandparent_id = ifcParents[parent_id][0] if grandparent_id in ifcObjects: parent = ifcObjects[grandparent_id] else: # creating parent if needed parent_ifcobj = IfcImport.GetObject(parent_id) if DEBUG: print "[" + str( int((float(parent_ifcobj.id) / num_lines) * 100) ) + "%] parsing ", parent_ifcobj.id, ": ", parent_ifcobj.name, " of type ", parent_ifcobj.type n = getName(parent_ifcobj) if parent_ifcobj.id <= 0: parent = None elif parent_ifcobj.type == "IfcBuildingStorey": parent = Arch.makeFloor(name=n) elif parent_ifcobj.type == "IfcBuilding": parent = Arch.makeBuilding(name=n) elif parent_ifcobj.type == "IfcSite": parent = Arch.makeSite(name=n) elif parent_ifcobj.type == "IfcWindow": parent = Arch.makeWindow(name=n) else: if DEBUG: print "Fixme: skipping unhandled parent: ", parent_ifcobj.id, " ", parent_ifcobj.type parent = None # registering object number and parent if parent_ifcobj.parent_id > 0: ifcParents[parent_ifcobj.id] = [ parent_ifcobj.parent_id, True ] parents_temp[parent_ifcobj.id] = [ parent_ifcobj.parent_id, True ] if parent and (not parent_ifcobj.id in ifcObjects): ifcObjects[parent_ifcobj.id] = parent # attributing parent if parent and (id in ifcObjects): if ifcObjects[id]: if additive: ArchCommands.addComponents(ifcObjects[id], parent) else: ArchCommands.removeComponents(ifcObjects[id], parent) IfcImport.CleanUp() else: # use only the internal python parser FreeCAD.Console.PrintWarning( str( translate( "Arch", "IfcOpenShell not found, falling back on internal parser.\n" ))) schema = getSchema() if schema: if DEBUG: global ifc if DEBUG: print "opening", filename, "..." ifc = ifcReader.IfcDocument(filename, schema=schema, debug=DEBUG) else: FreeCAD.Console.PrintWarning( str( translate("Arch", "IFC Schema not found, IFC import disabled.\n"))) return None t2 = time.time() if DEBUG: print "Successfully loaded", ifc, "in %s s" % ((t2 - t1)) # getting walls for w in ifc.getEnt("IfcWallStandardCase"): nobj = makeWall(w) # getting windows and doors for w in (ifc.getEnt("IfcWindow") + ifc.getEnt("IfcDoor")): nobj = makeWindow(w) # getting structs for w in (ifc.getEnt("IfcSlab") + ifc.getEnt("IfcBeam") + ifc.getEnt("IfcColumn") \ + ifc.getEnt("IfcFooting")): nobj = makeStructure(w) # getting floors for f in ifc.getEnt("IfcBuildingStorey"): group(f, ifc, "Floor") # getting buildings for b in ifc.getEnt("IfcBuilding"): group(b, ifc, "Building") # getting sites for s in ifc.getEnt("IfcSite"): group(s, ifc, "Site") if DEBUG: print "done parsing. Recomputing..." FreeCAD.ActiveDocument.recompute() t3 = time.time() if DEBUG: print "done processing IFC file in %s s" % ((t3 - t1)) return None
def execute(self, obj): "creates the structure shape" import Part, DraftGeomUtils if self.clone(obj): return normal, length, width, height = self.getDefaultValues(obj) # creating base shape pl = obj.Placement base = None if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.isNull(): return if not obj.Base.Shape.isValid(): if not obj.Base.Shape.Solids: # let pass invalid objects if they have solids... return if hasattr(obj, "Tool"): if obj.Tool: try: base = obj.Tool.Shape.copy().makePipe( obj.Base.Shape.copy()) except Part.OCCError: FreeCAD.Console.PrintError( translate( "Arch", "Error: The base shape couldn't be extruded along this tool object" )) return if not base: if not height: return if obj.Normal == Vector(0, 0, 0): if len(obj.Base.Shape.Faces) > 0: normal = obj.Base.Shape.Faces[0].normalAt(.5, .5) else: normal = DraftGeomUtils.getNormal(obj.Base.Shape) if not normal: normal = FreeCAD.Vector(0, 0, 1) #p = FreeCAD.Placement(obj.Base.Placement) #normal = p.Rotation.multVec(normal) else: normal = Vector(obj.Normal) normal = normal.multiply(height) base = obj.Base.Shape.copy() if base.Solids: pass elif base.Faces: base = base.extrude(normal) elif (len(base.Wires) == 1): if base.Wires[0].isClosed(): try: base = Part.Face(base.Wires[0]) base = base.extrude(normal) except Part.OCCError: FreeCAD.Console.PrintError( obj.Label + " : " + str( translate( "Arch", "Unable to extrude the base shape\n" ))) return 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 and ( not sh.isNull()): base = sh else: FreeCAD.Console.PrintWarning( str( translate( "Arch", "This mesh is an invalid solid"))) obj.Base.ViewObject.show() else: base = self.getProfiles(obj) if base: if length > height: normal = normal.multiply(length) else: normal = normal.multiply(height) base = Part.Face(base[0]) base = base.extrude(normal) base = self.processSubShapes(obj, base, pl) self.applyShape(obj, base, pl)
def execute(self, obj): "builds the wall shape" if self.clone(obj): return import Part, DraftGeomUtils pl = obj.Placement normal, length, width, height = self.getDefaultValues(obj) base = None face = None if obj.Base: # computing a shape from a base object if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.isNull(): return if not obj.Base.Shape.isValid(): if not obj.Base.Shape.Solids: # let pass invalid objects if they have solids... return if hasattr(obj, "Face"): if obj.Face > 0: if len(obj.Base.Shape.Faces) >= obj.Face: face = obj.Base.Shape.Faces[obj.Face - 1] if face: # case 1: this wall is based on a specific face of its base object normal = face.normalAt(0, 0) if normal.getAngle(Vector(0, 0, 1)) > math.pi / 4: normal.multiply(width) base = face.extrude(normal) if obj.Align == "Center": base.translate(normal.negative().multiply(0.5)) elif obj.Align == "Right": base.translate(normal.negative()) else: normal.multiply(height) base = face.extrude(normal) elif obj.Base.Shape.Solids: # case 2: the base is already a solid base = obj.Base.Shape.copy() elif obj.Base.Shape.Edges: # case 3: the base is flat, we need to extrude it if not obj.Base.Shape.Faces: # set the length property if hasattr(obj.Base.Shape, "Length"): l = obj.Base.Shape.Length if obj.Length != l: obj.Length = l profiles = self.getProfiles(obj) if profiles: normal.multiply(height) base = profiles.pop() base.fix(0.1, 0, 1) base = base.extrude(normal) for p in profiles: p.fix(0.1, 0, 1) p = p.extrude(normal) base = base.fuse(p) else: base = None else: base = None FreeCAD.Console.PrintError( str(translate("Arch", "Error: Invalid base object"))) 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 and ( not sh.isNull()): base = sh else: FreeCAD.Console.PrintWarning( str( translate( "Arch", "This mesh is an invalid solid"))) obj.Base.ViewObject.show() else: # computing a shape from scratch if length and width and height: base = Part.makeBox(length, width, height) base = self.processSubShapes(obj, base, pl) self.applyShape(obj, base, pl)
def taskbox(self): "sets up a taskbox widget" w = QtGui.QWidget() ui = FreeCADGui.UiLoader() w.setWindowTitle(translate("Arch", "Structure options").decode("utf8")) grid = QtGui.QGridLayout(w) # categories box labelc = QtGui.QLabel(translate("Arch", "Category").decode("utf8")) valuec = QtGui.QComboBox() valuec.addItems([" ", "Precast concrete"] + Categories) grid.addWidget(labelc, 0, 0, 1, 1) grid.addWidget(valuec, 0, 1, 1, 1) # presets box labelp = QtGui.QLabel(translate("Arch", "Preset").decode("utf8")) self.vPresets = QtGui.QComboBox() self.pSelect = [None] fpresets = [" "] self.vPresets.addItems(fpresets) grid.addWidget(labelp, 1, 0, 1, 1) grid.addWidget(self.vPresets, 1, 1, 1, 1) # length label1 = QtGui.QLabel(translate("Arch", "Length").decode("utf8")) self.vLength = ui.createWidget("Gui::InputField") self.vLength.setText( FreeCAD.Units.Quantity(self.Length, FreeCAD.Units.Length).UserString) grid.addWidget(label1, 2, 0, 1, 1) grid.addWidget(self.vLength, 2, 1, 1, 1) # width label2 = QtGui.QLabel(translate("Arch", "Width").decode("utf8")) self.vWidth = ui.createWidget("Gui::InputField") self.vWidth.setText( FreeCAD.Units.Quantity(self.Width, FreeCAD.Units.Length).UserString) grid.addWidget(label2, 3, 0, 1, 1) grid.addWidget(self.vWidth, 3, 1, 1, 1) # height label3 = QtGui.QLabel(translate("Arch", "Height").decode("utf8")) self.vHeight = ui.createWidget("Gui::InputField") self.vHeight.setText( FreeCAD.Units.Quantity(self.Height, FreeCAD.Units.Length).UserString) grid.addWidget(label3, 4, 0, 1, 1) grid.addWidget(self.vHeight, 4, 1, 1, 1) # horizontal button value5 = QtGui.QPushButton( translate("Arch", "Switch L/H").decode("utf8")) grid.addWidget(value5, 5, 0, 1, 1) value6 = QtGui.QPushButton( translate("Arch", "Switch L/W").decode("utf8")) grid.addWidget(value6, 5, 1, 1, 1) # continue button label4 = QtGui.QLabel(translate("Arch", "Con&tinue").decode("utf8")) value4 = QtGui.QCheckBox() value4.setObjectName("ContinueCmd") value4.setLayoutDirection(QtCore.Qt.RightToLeft) label4.setBuddy(value4) if hasattr(FreeCADGui, "draftToolBar"): value4.setChecked(FreeCADGui.draftToolBar.continueMode) self.continueCmd = FreeCADGui.draftToolBar.continueMode grid.addWidget(label4, 6, 0, 1, 1) grid.addWidget(value4, 6, 1, 1, 1) QtCore.QObject.connect(valuec, QtCore.SIGNAL("currentIndexChanged(int)"), self.setCategory) QtCore.QObject.connect(self.vPresets, QtCore.SIGNAL("currentIndexChanged(int)"), self.setPreset) QtCore.QObject.connect(self.vLength, QtCore.SIGNAL("valueChanged(double)"), self.setLength) QtCore.QObject.connect(self.vWidth, QtCore.SIGNAL("valueChanged(double)"), self.setWidth) QtCore.QObject.connect(self.vHeight, QtCore.SIGNAL("valueChanged(double)"), self.setHeight) QtCore.QObject.connect(value4, QtCore.SIGNAL("stateChanged(int)"), self.setContinue) QtCore.QObject.connect(value5, QtCore.SIGNAL("pressed()"), self.rotateLH) QtCore.QObject.connect(value6, QtCore.SIGNAL("pressed()"), self.rotateLW) return w
def uploadFile(self): self.form.labelStatus.setText("") if (self.form.comboProjects.currentIndex() >= 0) and (len( self.Projects) > self.form.comboProjects.currentIndex()) and ( self.form.comboRoot.currentIndex() >= 0): project = self.Projects[self.form.comboProjects.currentIndex()] import requests, json url, token = self.getPrefs() if url and token: url += "/json" deserializer = None FreeCAD.Console.PrintMessage( translate("Arch", "Saving file...\n")) self.form.labelStatus.setText( translate("Arch", "Checking available deserializers...")) import ifcopenshell schema = ifcopenshell.schema_identifier.lower() data = { "token": token, "request": { "interface": "PluginInterface", "method": "getAllDeserializers", "parameters": { "onlyEnabled": "true" } } } resp = requests.post(url, data=json.dumps(data)) if resp.ok: try: for d in resp.json()["response"]["result"]: if schema in d["name"].lower(): deserializer = d break except: pass if not deserializer: FreeCAD.Console.PrintError( translate( "Arch", "Unable to get a valid deserializer for the schema" ) + " " + schema + "\n") return tf = QtGui.QFileDialog.getSaveFileName( QtGui.qApp.activeWindow(), translate("Arch", "Save the IFC file before uploading?"), None, translate("Arch", "IFC files (*.ifc)")) if tf: tf = tf[0] if not tf: tf = os.path.join( tempfile._get_default_tempdir(), next(tempfile._get_candidate_names()) + ".ifc") import importIFC self.form.labelStatus.setText( translate("Arch", "Saving file...")) importIFC.export( [self.RootObjects[self.form.comboRoot.currentIndex()]], tf) f = open(tf, "rb") ifcdata = base64.b64encode(f.read()) f.close() FreeCAD.Console.PrintMessage( translate("Arch", "Uploading file to Bimserver...\n")) self.form.labelStatus.setText( translate("Arch", "Uploading file...")) data = { "token": token, "request": { "interface": "ServiceInterface", "method": "checkin", "parameters": { "poid": project["oid"], "comment": self.form.editComment.text(), "deserializerOid": deserializer["oid"], "fileSize": os.path.getsize(tf), "fileName": os.path.basename(tf), "data": ifcdata, "merge": "false", "sync": "true" } } } resp = requests.post(url, data=json.dumps(data)) if resp.ok: if resp.json()["response"]["result"]: FreeCAD.Console.PrintMessage( translate("Arch", "File upload successful\n")) self.getRevisions( self.form.comboProjects.currentIndex()) else: FreeCAD.Console.PrintError( translate("Arch", "File upload failed\n")) self.form.labelStatus.setText("")
def isValidShape(self): #Perform some general validations if self._style in [STYLE_HOLLOW, STYLE_CAPPED]: if self._thickness <= 0: _err( translate('Rocket', "For %s transitions thickness must be > 0") % self._style) return False if self._thickness >= self._foreRadius or self._thickness >= self._aftRadius: _err( translate( 'Rocket', "Transition thickness must be less than the front or back radius" )) return False elif self._style == STYLE_SOLID_CORE: if self._coreRadius >= self._foreRadius or self._coreRadius >= self._aftRadius: _err( translate( 'Rocket', "Transition core must be less than the front or back diameter" )) return False if self._foreShoulder: if self._coreRadius >= self._foreShoulderRadius: _err( translate( 'Rocket', "Transition core must be less than the shoulder diameter" )) return False if self._aftShoulder: if self._coreRadius >= self._aftShoulderRadius: _err( translate( 'Rocket', "Transition core must be less than the shoulder diameter" )) return False if self._foreShoulder: if self._foreShoulderLength <= 0: _err(translate('Rocket', "Forward shoulder length must be > 0")) return False if self._foreShoulderRadius <= 0: _err( translate('Rocket', "Forward shoulder diameter must be > 0")) return False if self._foreShoulderRadius > self._foreRadius: _err( translate( 'Rocket', "Forward shoulder diameter can not exceed the transition diameter at the shoulder" )) return False if self._style in [STYLE_HOLLOW, STYLE_CAPPED]: if self._foreShoulderThickness <= 0: _err( translate( 'Rocket', "For %s transitions with a shoulder, shoulder thickness must be > 0" ) % self._style) return False if self._foreShoulderThickness >= self._foreShoulderRadius: _err( translate( 'Rocket', "Shoulder thickness must be less than the shoulder radius" )) return False if self._aftShoulder: if self._aftShoulderLength <= 0: _err(translate('Rocket', "Aft shoulder length must be > 0")) return False if self._aftShoulderRadius <= 0: _err(translate('Rocket', "Aft shoulder diameter must be > 0")) return False if self._aftShoulderRadius > self._aftRadius: _err( translate( 'Rocket', "Aft shoulder diameter can not exceed the transition diameter at the shoulder" )) return False if self._style in [STYLE_HOLLOW, STYLE_CAPPED]: if self._aftShoulderThickness <= 0: _err( translate( 'Rocket', "For %s transitions with a shoulder, shoulder thickness must be > 0" ) % self._style) return False if self._aftShoulderThickness >= self._aftShoulderRadius: _err( translate( 'Rocket', "Shoulder thickness must be less than the shoulder radius" )) return False return True
def openFile(self): self.form.labelStatus.setText("") if (self.form.listRevisions.currentRow() >= 0) and (len( self.Revisions) > self.form.listRevisions.currentRow()): rev = self.Revisions[self.form.listRevisions.currentRow()] import requests, json url, token = self.getPrefs() if url and token: FreeCAD.Console.PrintMessage( translate("Arch", "Downloading file from Bimserver...\n")) self.form.labelStatus.setText( translate("Arch", "Checking available serializers...")) url += "/json" serializer = None for s in [ "Ifc2x3tc1" ]: # Ifc4 seems unreliable ATM, let's stick with good old Ifc2x3... data = { "token": token, "request": { "interface": "ServiceInterface", "method": "getSerializerByName", "parameters": { "serializerName": s } } } resp = requests.post(url, data=json.dumps(data)) if resp.ok: try: srl = resp.json()["response"]["result"] except: pass # unable to get this serializer else: serializer = srl break if not serializer: FreeCAD.Console.PrintError( translate( "Arch", "Unable to get a valid serializer from the BimServer\n" )) return tf = QtGui.QFileDialog.getSaveFileName( QtGui.qApp.activeWindow(), "Save the downloaded IFC file?", None, "IFC files (*.ifc)") if tf: tf = tf[0] self.form.labelStatus.setText( translate("Arch", "Downloading file...")) data = { "token": token, "request": { "interface": "ServiceInterface", "method": "downloadRevisions", "parameters": { "roids": [rev["oid"]], "serializerOid": serializer["oid"], "sync": "false" } } } resp = requests.post(url, data=json.dumps(data)) if resp.ok: try: downloadid = resp.json()["response"]["result"] except: FreeCAD.Console.PrintError( translate( "Arch", "Unable to obtain a valid download for this revision from the BimServer\n" )) return data = { "token": token, "request": { "interface": "ServiceInterface", "method": "getDownloadData", "parameters": { "topicId": downloadid } } } resp = requests.post(url, data=json.dumps(data)) if resp.ok: try: downloaddata = resp.json( )["response"]["result"]["file"] except: FreeCAD.Console.PrintError( translate( "Arch", "Unable to download the data for this revision.\n" )) return else: FreeCAD.Console.PrintMessage( translate("Arch", "Opening file...\n")) self.form.labelStatus.setText( translate("Arch", "Opening file...")) if not tf: th, tf = tempfile.mkstemp(suffix=".ifc") f = open(tf, "wb") f.write(base64.b64decode(downloaddata)) f.close() os.close(th) import importIFC importIFC.open(tf) os.remove(tf) self.form.labelStatus.setText("")
def addDefault(self,l): FreeCADGui.doCommand('base=FreeCAD.ActiveDocument.addObject("Sketcher::SketchObject","'+translate('Arch','WallTrace')+'")') FreeCADGui.doCommand('base.Placement = FreeCAD.DraftWorkingPlane.getPlacement()') FreeCADGui.doCommand('base.addGeometry(trace)') FreeCADGui.doCommand('wall = Arch.makeWall(base,width='+str(self.Width)+',height='+str(self.Height)+',align="'+str(self.Align)+'")') FreeCADGui.doCommand('wall.Normal = FreeCAD.DraftWorkingPlane.axis')
def getProjects(self): self.setLogged(False) self.Projects = [] self.form.labelStatus.setText("") import requests, json url, token = self.getPrefs() if url and token: self.form.labelStatus.setText( translate("Arch", "Getting projects list...")) url += "/json" data = { "token": token, "request": { "interface": "SettingsInterface", "method": "getServerSettings", "parameters": {} } } try: resp = requests.post(url, data=json.dumps(data)) except: FreeCAD.Console.PrintError( translate("Arch", "Unable to connect to BimServer at") + " " + url[:-5] + "\n") self.form.labelStatus.setText( translate("Arch", "Connection failed.")) return if resp.ok: try: name = resp.json()["response"]["result"]["name"] except: pass # unable to get the server name else: self.form.labelServerName.setText(name) data = { "token": token, "request": { "interface": "ServiceInterface", "method": "getAllProjects", "parameters": { "onlyTopLevel": "false", "onlyActive": "true" } } } resp = requests.post(url, data=json.dumps(data)) if resp.ok: try: projects = resp.json()["response"]["result"] except: FreeCAD.Console.PrintError( translate( "Arch", "Unable to get projects list from BimServer\n")) else: self.setLogged(True) self.form.comboProjects.clear() for p in projects: self.form.comboProjects.addItem(p["name"]) self.Projects = projects self.form.comboProjects.setCurrentIndex(0) self.getRevisions(0) self.form.labelStatus.setText("")
def setTabGeneral(self): ui = FreeCADGui.UiLoader() # Select the type of transition self.transitionTypeLabel = QtGui.QLabel( translate('Rocket', "Transition Shape"), self) self.transitionTypes = (TYPE_CONE, TYPE_ELLIPTICAL, TYPE_OGIVE, TYPE_PARABOLA, TYPE_PARABOLIC, TYPE_POWER, TYPE_VON_KARMAN, TYPE_HAACK) self.transitionTypesCombo = QtGui.QComboBox(self) self.transitionTypesCombo.addItems(self.transitionTypes) self.clippedCheckbox = QtGui.QCheckBox(translate('Rocket', "Clipped"), self) self.clippedCheckbox.setCheckState(QtCore.Qt.Checked) self.coefficientLabel = QtGui.QLabel( translate('Rocket', "Shape Parameter"), self) self.coefficientValidator = QtGui.QDoubleValidator(self) self.coefficientValidator.setBottom(0.0) self.coefficientInput = QtGui.QLineEdit(self) self.coefficientInput.setFixedWidth(80) self.coefficientInput.setValidator(self.coefficientValidator) self.coefficientInput.setEnabled(False) # Select the type of sketch self.transitionStyleLabel = QtGui.QLabel(translate('Rocket', "Style"), self) self.transitionStyles = (STYLE_SOLID, STYLE_SOLID_CORE, STYLE_HOLLOW, STYLE_CAPPED) self.transitionStylesCombo = QtGui.QComboBox(self) self.transitionStylesCombo.addItems(self.transitionStyles) # Get the transition parameters: length, width, etc... self.lengthLabel = QtGui.QLabel(translate('Rocket', "Length"), self) self.lengthInput = ui.createWidget("Gui::InputField") self.lengthInput.unit = 'mm' self.lengthInput.setFixedWidth(80) self.foreDiameterLabel = QtGui.QLabel( translate('Rocket', "Forward Diameter"), self) self.foreDiameterInput = ui.createWidget("Gui::InputField") self.foreDiameterInput.unit = 'mm' self.foreDiameterInput.setFixedWidth(80) self.aftDiameterLabel = QtGui.QLabel( translate('Rocket', "Aft Diameter"), self) self.aftDiameterInput = ui.createWidget("Gui::InputField") self.aftDiameterInput.unit = 'mm' self.aftDiameterInput.setFixedWidth(80) self.coreDiameterLabel = QtGui.QLabel( translate('Rocket', "Core Diameter"), self) self.coreDiameterInput = ui.createWidget("Gui::InputField") self.coreDiameterInput.unit = 'mm' self.coreDiameterInput.setFixedWidth(80) self.thicknessLabel = QtGui.QLabel(translate('Rocket', "Thickness"), self) self.thicknessInput = ui.createWidget("Gui::InputField") self.thicknessInput.unit = 'mm' self.thicknessInput.setFixedWidth(80) row = 0 layout = QGridLayout() layout.addWidget(self.transitionTypeLabel, row, 0, 1, 2) layout.addWidget(self.transitionTypesCombo, row, 1) layout.addWidget(self.clippedCheckbox, row, 2) row += 1 layout.addWidget(self.coefficientLabel, row, 0) layout.addWidget(self.coefficientInput, row, 1) row += 1 layout.addWidget(self.transitionStyleLabel, row, 0) layout.addWidget(self.transitionStylesCombo, row, 1) row += 1 layout.addWidget(self.lengthLabel, row, 0) layout.addWidget(self.lengthInput, row, 1) row += 1 layout.addWidget(self.foreDiameterLabel, row, 0) layout.addWidget(self.foreDiameterInput, row, 1) row += 1 layout.addWidget(self.aftDiameterLabel, row, 0) layout.addWidget(self.aftDiameterInput, row, 1) row += 1 layout.addWidget(self.coreDiameterLabel, row, 0) layout.addWidget(self.coreDiameterInput, row, 1) row += 1 layout.addWidget(self.thicknessLabel, row, 0) layout.addWidget(self.thicknessInput, row, 1) layout.addItem( QtGui.QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Expanding)) self.tabGeneral.setLayout(layout)
def export(exportList, filename): """Export the OCA file with a given list of objects. The objects must be edges or faces, in order to be processed and exported. Parameters ---------- exportList : list List of document objects to export. filename : str Path to the new file. Returns ------- None If `exportList` doesn't have shapes to export. """ faces = [] edges = [] # getting faces and edges for ob in exportList: if ob.Shape.Faces: for f in ob.Shape.Faces: faces.append(f) else: for e in ob.Shape.Edges: edges.append(e) if not (edges or faces): FCC.PrintMessage( translate("importOCA", "OCA: found no data to export") + "\n") return # writing file oca = pythonopen(filename, 'w') oca.write("#oca file generated from FreeCAD\r\n") oca.write("# edges\r\n") count = 1 for e in edges: if DraftGeomUtils.geomType(e) == "Line": oca.write("L" + str(count) + "=") oca.write(writepoint(e.Vertexes[0].Point)) oca.write(" ") oca.write(writepoint(e.Vertexes[-1].Point)) oca.write("\r\n") elif DraftGeomUtils.geomType(e) == "Circle": if len(e.Vertexes) > 1: oca.write("C" + str(count) + "=ARC ") oca.write(writepoint(e.Vertexes[0].Point)) oca.write(" ") oca.write(writepoint(DraftGeomUtils.findMidpoint(e))) oca.write(" ") oca.write(writepoint(e.Vertexes[-1].Point)) else: oca.write("C" + str(count) + "= ") oca.write(writepoint(e.Curve.Center)) oca.write(" ") oca.write(str(e.Curve.Radius)) oca.write("\r\n") count += 1 oca.write("# faces\r\n") for f in faces: oca.write("A" + str(count) + "=S(POL") for v in f.Vertexes: oca.write(" ") oca.write(writepoint(v.Point)) oca.write(" ") oca.write(writepoint(f.Vertexes[0].Point)) oca.write(")\r\n") count += 1 # closing oca.close() FCC.PrintMessage( translate("importOCA", "successfully exported ") + filename + "\n")
def testCommonPsets(self): "tests for common property sets" test = "testCommonPsets" if getattr(self.form, test).text() == "Failed": self.show(test) else: QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) self.reset(test) self.results[test] = None self.culprits[test] = [] msg = None psets = [] psetspath = os.path.join(FreeCAD.getResourceDir(), "Mod", "Arch", "Presets", "pset_definitions.csv") if os.path.exists(psetspath): with open(psetspath, "r") as csvfile: reader = csv.reader(csvfile, delimiter=';') for row in reader: if "Common" in row[0]: psets.append(row[0][5:-6]) psets = [ ''.join(map(lambda x: x if x.islower() else " " + x, p)) for p in psets ] psets = [pset.strip() for pset in psets] #print(psets) for obj in self.getObjects(): ok = True if hasattr(obj, "IfcProperties") and isinstance( obj.IfcProperties, dict): r = None if hasattr(obj, "IfcType"): r = obj.IfcType if hasattr(obj, "IfcRole"): r = obj.IfcRole if r and (r in psets): ok = False if "Pset_" + r.replace(" ", "") + "Common" in ','.join( obj.IfcProperties.values()): ok = True if not ok: self.culprits[test].append(obj) if self.culprits[test]: msg = self.getToolTip(test) msg += translate( "BIM", "The objects below have a defined IFC type but do not have the associated common property set:" ) + "\n\n" for o in self.culprits[test]: msg += o.Label + "\n" msg += "\n" + translate( "BIM", "To add common property sets to these objects, use the IFC properties manager tool located under menu Manage -> Manage IFC Properties..." ) if msg: self.failed(test) else: self.passed(test) self.results[test] = msg QtGui.QApplication.restoreOverrideCursor()
def addAttributes(self, eid, parent): "adds the attributes of the given IFC entity under the given QTreeWidgetITem" import ifcopenshell entity = self.ifc[eid] i = 0 while True: try: argname = entity.attribute_name(i) except: break else: try: argvalue = getattr(entity, argname) except: FreeCAD.Console.PrintError( translate("BIM", "Error in entity") + " " + self.tostr(entity) + "\n") break else: if argname not in ["Id", "GlobalId"]: colored = False if isinstance(argvalue, ifcopenshell.entity_instance): if argvalue.id() == 0: t = self.tostr(argvalue) else: colored = True t = "#" + self.tostr( argvalue.id()) + ": " + self.tostr( argvalue.is_a()) elif isinstance(argvalue, (list, tuple)): t = "" else: t = self.tostr(argvalue) item = QtGui.QTreeWidgetItem(parent) item.setText(0, self.tostr(argname)) if t and (t != "None"): item.setText(1, t) if colored: item.setForeground(1, linkbrush) item.setFont(1, linkfont) if argname == "Name": item.setFont(1, bold) if isinstance(argvalue, (list, tuple)): j = 0 for argitem in argvalue: colored = False if isinstance(argitem, ifcopenshell.entity_instance): if argitem.id() == 0: t = self.tostr(argitem) else: colored = True t = "#" + self.tostr( argitem.id()) + ": " + self.tostr( argitem.is_a()) else: t = argitem t = self.tostr(t) if j == 0: item.setText(1, t) if colored: item.setForeground(1, linkbrush) item.setFont(1, linkfont) else: subitem = QtGui.QTreeWidgetItem(item) subitem.setText(1, t) if colored: subitem.setForeground(1, linkbrush) subitem.setFont(1, linkfont) j += 1 i += 1
def execute(self, obj): # fills columns A, B and C of the spreadsheet if not obj.Description: return for p in [obj.Value, obj.Unit, obj.Objects, obj.Filter]: if len(obj.Description) != len(p): return if not hasattr(obj, "Result"): # silently fail on old schedule objects return if not obj.Result: FreeCAD.Console.PrintError( translate("Arch", "No spreadsheet attached to this schedule") + "\n") return obj.Result.clearAll() obj.Result.set("A1", "Description") obj.Result.set("B1", "Value") obj.Result.set("C1", "Unit") obj.Result.setStyle('A1:C1', 'bold', 'add') for i in range(len(obj.Description)): if not obj.Description[i]: # blank line continue # write description obj.Result.set("A" + str(i + 2), obj.Description[i].encode("utf8")) if verbose: l = "OPERATION: " + obj.Description[i] print(l) print(len(l) * "=") # get list of objects objs = obj.Objects[i] val = obj.Value[i] if val: import Draft, Arch if objs: objs = objs.split(";") objs = [FreeCAD.ActiveDocument.getObject(o) for o in objs] else: objs = FreeCAD.ActiveDocument.Objects if len(objs) == 1: # remove object itself if the object is a group if objs[0].isDerivedFrom("App::DocumentObjectGroup"): objs = objs[0].Group objs = Draft.getGroupContents(objs, walls=True, addgroups=True) objs = Arch.pruneIncluded(objs, strict=True) if obj.Filter[i]: # apply filters nobjs = [] for o in objs: ok = True for f in obj.Filter[i].split(";"): args = [a.strip() for a in f.strip().split(":")] if args[0].upper() == "NAME": if not (args[1].upper() in o.Name.upper()): ok = False elif args[0].upper() == "!NAME": if (args[1].upper() in o.Name.upper()): ok = False elif args[0].upper() == "LABEL": if not (args[1].upper() in o.Label.upper()): ok = False elif args[0].upper() == "!LABEL": if args[1].upper() in o.Label.upper(): ok = False elif args[0].upper() == "TYPE": if Draft.getType(o).upper() != args[1].upper(): ok = False elif args[0].upper() == "!TYPE": if Draft.getType(o).upper() == args[1].upper(): ok = False elif args[0].upper() == "ROLE": if hasattr(o, "Role"): if o.Role.upper() != args[1].upper(): ok = False else: ok = False elif args[0].upper() == "!ROLE": if hasattr(o, "Role"): if o.Role.upper() == args[1].upper(): ok = False if ok: nobjs.append(o) objs = nobjs # perform operation if val.upper() == "COUNT": val = len(objs) if verbose: print(val, ",".join([o.Label for o in objs])) obj.Result.set("B" + str(i + 2), str(val)) else: vals = val.split(".") sumval = 0 for o in objs: if verbose: l = o.Name + " (" + o.Label + "):" print(l + (40 - len(l)) * " ", ) try: d = o for v in vals[1:]: d = getattr(d, v) if verbose: print(d) if hasattr(d, "Value"): d = d.Value except: FreeCAD.Console.PrintWarning( translate( "Arch", "Unable to retrieve value from object") + ": " + o.Name + "." + ".".join(vals) + "\n") else: if not sumval: sumval = d else: sumval += d val = sumval # get unit if obj.Unit[i]: ustr = obj.Unit[i].encode("utf8") unit = ustr.replace("²", "^2") unit = unit.replace("³", "^3") if "2" in unit: tp = FreeCAD.Units.Area elif "3" in unit: tp = FreeCAD.Units.Volume elif "deg" in unit: tp = FreeCAD.Units.Angle else: tp = FreeCAD.Units.Length q = FreeCAD.Units.Quantity(val, tp) obj.Result.set("B" + str(i + 2), str(q.getValueAs(unit).Value)) obj.Result.set("C" + str(i + 2), ustr) else: obj.Result.set("B" + str(i + 2), str(val)) if verbose: print("TOTAL:" + 34 * " " + str(val))
def testPsets(self): "tests for property sets integrity" test = "testPsets" if getattr(self.form, test).text() == "Failed": self.show(test) else: QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) self.reset(test) self.results[test] = None self.culprits[test] = [] msg = None psets = {} psetspath = os.path.join(FreeCAD.getResourceDir(), "Mod", "Arch", "Presets", "pset_definitions.csv") if os.path.exists(psetspath): with open(psetspath, "r") as csvfile: reader = csv.reader(csvfile, delimiter=';') for row in reader: if "Common" in row[0]: psets[row[0]] = row[1:] for obj in self.getObjects(): ok = True if hasattr(obj, "IfcProperties") and isinstance( obj.IfcProperties, dict): r = None if hasattr(obj, "IfcType"): r = obj.IfcType elif hasattr(obj, "IfcRole"): r = obj.IfcRole if r and (r != "Undefined"): found = None for pset in psets.keys(): for val in obj.IfcProperties.values(): if pset in val: found = pset break if found: for i in range(int(len(psets[found]) / 2)): p = psets[found][i * 2] t = psets[found][i * 2 + 1] #print("testing for ",p,t,found," in ",obj.IfcProperties) if p in obj.IfcProperties: if (not found in obj.IfcProperties[p]) or ( not t in obj.IfcProperties[p]): ok = False else: ok = False if not ok: self.culprits[test].append(obj) if self.culprits[test]: msg = self.getToolTip(test) msg += translate( "BIM", "The objects below have a common property set but that property set doesn't contain all the needed properties:" ) + "\n\n" for o in self.culprits[test]: msg += o.Label + "\n" msg += "\n" + translate( "BIM", "Verify which properties a certain property set must contain on http://www.buildingsmart-tech.org/ifc/IFC4/Add2/html/annex/annex-b/alphabeticalorder_psets.htm" ) + "\n\n" msg += translate( "BIM", "To fix the property sets of these objects, use the IFC properties manager tool located under menu Manage -> Manage IFC Properties..." ) if msg: self.failed(test) else: self.passed(test) self.results[test] = msg QtGui.QApplication.restoreOverrideCursor()
def execute(self,obj): tol = 1 # tolerance for alignment. This is only visual, we can keep it low... ptol = 0.001 # tolerance for coincident points import math,Part,DraftGeomUtils,ArchCommands if len(obj.Pipes) < 2: return if len(obj.Pipes) > 3: FreeCAD.Console.PrintWarning(translate("Arch","Only the 3 first wires will be connected")+"\n") if obj.Radius.Value == 0: return wires = [] order = [] for o in obj.Pipes: wires.append(o.Proxy.getWire(o)) if wires[0].Vertexes[0].Point.sub(wires[1].Vertexes[0].Point).Length <= ptol: order = ["start","start"] point = wires[0].Vertexes[0].Point elif wires[0].Vertexes[0].Point.sub(wires[1].Vertexes[-1].Point).Length <= ptol: order = ["start","end"] point = wires[0].Vertexes[0].Point elif wires[0].Vertexes[-1].Point.sub(wires[1].Vertexes[-1].Point).Length <= ptol: order = ["end","end"] point = wires[0].Vertexes[-1].Point elif wires[0].Vertexes[-1].Point.sub(wires[1].Vertexes[0].Point).Length <= ptol: order = ["end","start"] point = wires[0].Vertexes[-1].Point else: FreeCAD.Console.PrintError(translate("Arch","Common vertex not found")+"\n") return if order[0] == "start": v1 = wires[0].Vertexes[1].Point.sub(wires[0].Vertexes[0].Point).normalize() else: v1 = wires[0].Vertexes[-2].Point.sub(wires[0].Vertexes[-1].Point).normalize() if order[1] == "start": v2 = wires[1].Vertexes[1].Point.sub(wires[1].Vertexes[0].Point).normalize() else: v2 = wires[1].Vertexes[-2].Point.sub(wires[1].Vertexes[-1].Point).normalize() p = obj.Pipes[0].Proxy.getProfile(obj.Pipes[0]) p = Part.Face(p) if len(obj.Pipes) == 2: if obj.ConnectorType != "Corner": obj.ConnectorType = "Corner" if round(v1.getAngle(v2),tol) in [0,round(math.pi,tol)]: FreeCAD.Console.PrintError(translate("Arch","Pipes are already aligned")+"\n") return normal = v2.cross(v1) offset = math.tan(math.pi/2-v1.getAngle(v2)/2)*obj.Radius.Value v1.multiply(offset) v2.multiply(offset) self.setOffset(obj.Pipes[0],order[0],offset) self.setOffset(obj.Pipes[1],order[1],offset) # find center perp = v1.cross(normal).normalize() perp.multiply(obj.Radius.Value) center = point.add(v1).add(perp) # move and rotate the profile to the first point delta = point.add(v1)-p.CenterOfMass p.translate(delta) vp = DraftGeomUtils.getNormal(p) rot = FreeCAD.Rotation(vp,v1) p.rotate(p.CenterOfMass,rot.Axis,math.degrees(rot.Angle)) sh = p.revolve(center,normal,math.degrees(math.pi-v1.getAngle(v2))) #sh = Part.makeCompound([sh]+[Part.Vertex(point),Part.Vertex(point.add(v1)),Part.Vertex(center),Part.Vertex(point.add(v2))]) else: if obj.ConnectorType != "Tee": obj.ConnectorType = "Tee" if wires[2].Vertexes[0].Point == point: order.append("start") elif wires[0].Vertexes[-1].Point == point: order.append("end") else: FreeCAD.Console.PrintError(translate("Arch","Common vertex not found")+"\n") if order[2] == "start": v3 = wires[2].Vertexes[1].Point.sub(wires[2].Vertexes[0].Point).normalize() else: v3 = wires[2].Vertexes[-2].Point.sub(wires[2].Vertexes[-1].Point).normalize() if round(v1.getAngle(v2),tol) in [0,round(math.pi,tol)]: pair = [v1,v2,v3] elif round(v1.getAngle(v3),tol) in [0,round(math.pi,tol)]: pair = [v1,v3,v2] elif round(v2.getAngle(v3),tol) in [0,round(math.pi,tol)]: pair = [v2,v3,v1] else: FreeCAD.Console.PrintError(translate("Arch","At least 2 pipes must align")+"\n") return offset = obj.Radius.Value v1.multiply(offset) v2.multiply(offset) v3.multiply(offset) self.setOffset(obj.Pipes[0],order[0],offset) self.setOffset(obj.Pipes[1],order[1],offset) self.setOffset(obj.Pipes[2],order[2],offset) normal = pair[0].cross(pair[2]) # move and rotate the profile to the first point delta = point.add(pair[0])-p.CenterOfMass p.translate(delta) vp = DraftGeomUtils.getNormal(p) rot = FreeCAD.Rotation(vp,pair[0]) p.rotate(p.CenterOfMass,rot.Axis,math.degrees(rot.Angle)) t1 = p.extrude(pair[1].multiply(2)) # move and rotate the profile to the second point delta = point.add(pair[2])-p.CenterOfMass p.translate(delta) vp = DraftGeomUtils.getNormal(p) rot = FreeCAD.Rotation(vp,pair[2]) p.rotate(p.CenterOfMass,rot.Axis,math.degrees(rot.Angle)) t2 = p.extrude(pair[2].negative().multiply(2)) # create a cut plane cp = Part.makePolygon([point,point.add(pair[0]),point.add(normal),point]) cp = Part.Face(cp) if cp.normalAt(0,0).getAngle(pair[2]) < math.pi/2: cp.reverse() cf, cv, invcv = ArchCommands.getCutVolume(cp,t2) t2 = t2.cut(cv) sh = t1.fuse(t2) obj.Shape = sh
def Activated(self): sel = FreeCADGui.Selection.getSelectionEx() if sel: obj = sel[0].Object if Draft.getType(obj) == "Structure": if len(sel) > 1: sk = sel[1].Object if sk.isDerivedFrom("Part::Feature"): if len(sk.Shape.Wires) == 1: # we have a base object and a sketch: create the rebar now FreeCAD.ActiveDocument.openTransaction( translate("Arch", "Create Rebar")) FreeCADGui.addModule("Arch") FreeCADGui.doCommand( "Arch.makeRebar(FreeCAD.ActiveDocument." + obj.Name + ",FreeCAD.ActiveDocument." + sk.Name + ")") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() return else: # we have only a base object: open the sketcher FreeCADGui.activateWorkbench("SketcherWorkbench") FreeCADGui.runCommand("Sketcher_NewSketch") FreeCAD.ArchObserver = ArchComponent.ArchSelectionObserver( obj, FreeCAD.ActiveDocument.Objects[-1], hide=False, nextCommand="Arch_Rebar") FreeCADGui.Selection.addObserver(FreeCAD.ArchObserver) return elif obj.isDerivedFrom("Part::Feature"): if len(obj.Shape.Wires) == 1: # we have only the sketch: extract the base object from it if hasattr(obj, "Support"): if obj.Support: if len(obj.Support) != 0: sup = obj.Support[0][0] else: print( "Arch: error: couldn't extract a base object" ) return FreeCAD.ActiveDocument.openTransaction( translate("Arch", "Create Rebar")) FreeCADGui.addModule("Arch") FreeCADGui.doCommand( "Arch.makeRebar(FreeCAD.ActiveDocument." + sup.Name + ",FreeCAD.ActiveDocument." + obj.Name + ")") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() return else: print( "Arch: error: couldn't extract a base object") return FreeCAD.Console.PrintMessage( translate("Arch", "Please select a base face on a structural object\n")) FreeCADGui.Control.showDialog(ArchComponent.SelectionTaskPanel()) FreeCAD.ArchObserver = ArchComponent.ArchSelectionObserver( nextCommand="Arch_Rebar") FreeCADGui.Selection.addObserver(FreeCAD.ArchObserver)