From b2637897f5f419b10d3c311aeba8cb17e72838f6 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Thu, 18 Jul 2013 12:59:17 -0300 Subject: [PATCH] 0000982: Arch Space object A new Arch Space object that can be created from a solid shape or from several boundary faces, or a mix of both --- src/Mod/Arch/ArchCommands.py | 54 +++++++------ src/Mod/Arch/ArchComponent.py | 2 +- src/Mod/Arch/ArchSpace.py | 138 ++++++++++++++++++++++++++++------ src/Mod/Draft/Draft.py | 4 +- 4 files changed, 151 insertions(+), 47 deletions(-) diff --git a/src/Mod/Arch/ArchCommands.py b/src/Mod/Arch/ArchCommands.py index 3155fa68e..a0c340b79 100644 --- a/src/Mod/Arch/ArchCommands.py +++ b/src/Mod/Arch/ArchCommands.py @@ -571,17 +571,22 @@ class _CommandAdd: def Activated(self): sel = FreeCADGui.Selection.getSelection() - FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Grouping"))) - if not mergeCells(sel): - host = sel.pop() - ss = "[" - for o in sel: - if len(ss) > 1: - ss += "," - ss += "FreeCAD.ActiveDocument."+o.Name - ss += "]" + if Draft.getType(sel[-1]) == "Space": + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Add space boundary"))) FreeCADGui.doCommand("import Arch") - FreeCADGui.doCommand("Arch.addComponents("+ss+",FreeCAD.ActiveDocument."+host.Name+")") + FreeCADGui.doCommand("Arch.addSpaceBoundaries( FreeCAD.ActiveDocument."+sel[-1].Name+", FreeCADGui.Selection.getSelectionEx() )") + else: + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Grouping"))) + if not mergeCells(sel): + 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.addComponents("+ss+",FreeCAD.ActiveDocument."+host.Name+")") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() @@ -601,20 +606,25 @@ class _CommandRemove: def Activated(self): sel = FreeCADGui.Selection.getSelection() - FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Ungrouping"))) - if (Draft.getType(sel[-1]) in ["Wall","Structure"]) and (len(sel) > 1): - host = sel.pop() - ss = "[" - for o in sel: - if len(ss) > 1: - ss += "," - ss += "FreeCAD.ActiveDocument."+o.Name - ss += "]" + if Draft.getType(sel[-1]) == "Space": + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Remove space boundary"))) FreeCADGui.doCommand("import Arch") - FreeCADGui.doCommand("Arch.removeComponents("+ss+",FreeCAD.ActiveDocument."+host.Name+")") + FreeCADGui.doCommand("Arch.removeSpaceBoundaries( FreeCAD.ActiveDocument."+sel[-1].Name+", FreeCADGui.Selection.getSelection() )") else: - FreeCADGui.doCommand("import Arch") - FreeCADGui.doCommand("Arch.removeComponents(Arch.ActiveDocument."+sel[-1].Name+")") + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Ungrouping"))) + if (Draft.getType(sel[-1]) in ["Wall","Structure"]) 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(Arch.ActiveDocument."+sel[-1].Name+")") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() diff --git a/src/Mod/Arch/ArchComponent.py b/src/Mod/Arch/ArchComponent.py index 73fc1d574..23dac1ffd 100644 --- a/src/Mod/Arch/ArchComponent.py +++ b/src/Mod/Arch/ArchComponent.py @@ -409,7 +409,7 @@ class ViewProviderComponent: vobj.Proxy = self self.Object = vobj.Object - def updateData(self,vobj,prop): + def updateData(self,obj,prop): return def onChanged(self,vobj,prop): diff --git a/src/Mod/Arch/ArchSpace.py b/src/Mod/Arch/ArchSpace.py index 685f0160d..c7468bdeb 100644 --- a/src/Mod/Arch/ArchSpace.py +++ b/src/Mod/Arch/ArchSpace.py @@ -21,7 +21,7 @@ #* * #*************************************************************************** -import FreeCAD,FreeCADGui,ArchComponent,ArchCommands,math +import FreeCAD,FreeCADGui,ArchComponent,ArchCommands,math,Draft from DraftTools import translate from PyQt4 import QtCore @@ -40,13 +40,25 @@ def makeSpace(objects): obj.Base = objects[0] objects[0].ViewObject.hide() else: - obj.Proxy.addSubobjects(objects) + obj.Proxy.addSubobjects(obj,objects) -def addSpaceBoundary(space,subobjects): - """addSpaceBoundary(space,subobjects): adds the given subobjects to the given space""" +def addSpaceBoundaries(space,subobjects): + """addSpaceBoundaries(space,subobjects): adds the given subobjects to the given space""" import Draft if Draft.getType(space) == "Space": space.Proxy.addSubobjects(space,subobjects) + +def removeSpaceBoundaries(space,objects): + """removeSpaceBoundaries(space,objects): removes the given objects from the given spaces boundaries""" + import Draft + if Draft.getType(space) == "Space": + bounds = space.Boundaries + for o in objects: + for b in bounds: + if o.Name == b[0].Name: + bounds.remove(b) + break + space.Boundaries = bounds class _CommandSpace: "the Arch Space command definition" @@ -65,7 +77,10 @@ class _CommandSpace: def Activated(self): FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Space"))) FreeCADGui.doCommand("import Arch") - FreeCADGui.doCommand("Arch.makeSpace(FreeCADGui.Selection.getSelection())") + if len(FreeCADGui.Selection.getSelection()) == 1: + FreeCADGui.doCommand("Arch.makeSpace(FreeCADGui.Selection.getSelection())") + else: + FreeCADGui.doCommand("Arch.makeSpace(FreeCADGui.Selection.getSelectionEx())") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() @@ -84,32 +99,30 @@ class _Space(ArchComponent.Component): self.getShape(obj) def onChanged(self,obj,prop): - print prop if prop in ["Boundaries","Base"]: self.getShape(obj) def addSubobjects(self,obj,subobjects): "adds subobjects to this space" - objs = [] + objs = obj.Boundaries for o in subobjects: - print o if isinstance(o,tuple) or isinstance(o,list): - objs.append(tuple(o)) + if o[0].Name != obj.Name: + objs.append(tuple(o)) else: for el in o.SubElementNames: if "Face" in el: - print "adding ",el - objs.append((o.Object,el)) - print "boundaries to add: ",objs + if o.Object.Name != obj.Name: + objs.append((o.Object,el)) obj.Boundaries = objs def getShape(self,obj): - "computes a shape" + "computes a shape from a base shape and/or bounday faces" import Part shape = None faces = [] - print "starting compute" + #print "starting compute" # 1: if we have a base shape, we use it if obj.Base: @@ -119,7 +132,7 @@ class _Space(ArchComponent.Component): # 2: if not, add all bounding boxes of considered objects and build a first shape if shape: - print "got shape from base object" + #print "got shape from base object" bb = shape.BoundBox else: bb = None @@ -132,7 +145,7 @@ class _Space(ArchComponent.Component): if not bb: return shape = Part.makeBox(bb.XLength,bb.YLength,bb.ZLength,FreeCAD.Vector(bb.XMin,bb.YMin,bb.ZMin)) - print "created shape from boundbox" + #print "created shape from boundbox" # 3: identifing boundary faces goodfaces = [] @@ -141,9 +154,9 @@ class _Space(ArchComponent.Component): if "Face" in b[1]: fn = int(b[1][4:])-1 faces.append(b[0].Shape.Faces[fn]) - print "adding face ",fn," of object ",b[0].Name + #print "adding face ",fn," of object ",b[0].Name - print "total: ", len(faces), " faces" + #print "total: ", len(faces), " faces" # 4: get cutvolumes from faces cutvolumes = [] @@ -152,22 +165,37 @@ class _Space(ArchComponent.Component): f.reverse() cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(f,shape) if cutvolume: - print "generated 1 cutvolume" + #print "generated 1 cutvolume" cutvolumes.append(cutvolume.copy()) #Part.show(cutvolume) for v in cutvolumes: - print "cutting" + #print "cutting" shape = shape.cut(v) # 5: get the final shape if shape: if shape.Solids: - print "setting objects shape" + #print "setting objects shape" shape = shape.Solids[0] obj.Shape = shape return - print "something went wrong, bailing out" + print "Arch: error computing space boundary" + + def getArea(self,obj): + "returns the horizontal area at the center of the space" + import Part,DraftGeomUtils + try: + pl = Part.makePlane(1,1) + sh = obj.Shape.copy() + cutplane,v1,v2 = ArchCommands.getCutVolume(pl,sh) + e = sh.section(cutplane) + e = DraftGeomUtils.sortEdges(e.Edges) + w = Part.Wire(e) + f = Part.Face(w) + return round(f.Area,Draft.getParam("dimPrecision")) + except: + return 0 class _ViewProviderSpace(ArchComponent.ViewProviderComponent): @@ -177,6 +205,12 @@ class _ViewProviderSpace(ArchComponent.ViewProviderComponent): vobj.LineWidth = 1 vobj.LineColor = (1.0,0.0,0.0,1.0) vobj.DrawStyle = "Dotted" + vobj.addProperty("App::PropertyString","Override","Base", + "Text override. Use $area to insert the area") + vobj.addProperty("App::PropertyColor","TextColor","Base", + "The color of the area text") + vobj.TextColor = (1.0,0.0,0.0,1.0) + vobj.Override = "$area m2" ArchComponent.ViewProviderComponent.__init__(self,vobj) def getIcon(self): @@ -189,5 +223,65 @@ class _ViewProviderSpace(ArchComponent.ViewProviderComponent): else: return [] + def setDisplayMode(self,mode): + if mode == "Detailed": + self.setAnnotation(True) + return "Flat Lines" + else: + self.setAnnotation(False) + return mode + + def getArea(self,obj): + "returns a formatted area text" + area = str(obj.Proxy.getArea(obj)) + if obj.ViewObject.Override: + text = obj.ViewObject.Override + area = text.replace("$area",str(area)) + return str(area) + + def setAnnotation(self,recreate=True): + if hasattr(self,"Object"): + if hasattr(self,"area"): + if self.area: + self.Object.ViewObject.Annotation.removeChild(self.area) + self.area = None + self.coords = None + self.anno = None + if recreate: + area = self.getArea(self.Object) + if area: + from pivy import coin + import SketcherGui + self.area = coin.SoSeparator() + self.coords = coin.SoTransform() + if self.Object.Shape: + if not self.Object.Shape.isNull(): + c = self.Object.Shape.CenterOfMass + self.coords.translation.setValue([c.x,c.y,c.z]) + self.anno = coin.SoType.fromName("SoDatumLabel").createInstance() + self.anno.string.setValue(area) + self.anno.datumtype.setValue(6) + color = coin.SbVec3f(self.Object.ViewObject.TextColor[:3]) + self.anno.textColor.setValue(color) + self.area.addChild(self.coords) + self.area.addChild(self.anno) + self.Object.ViewObject.Annotation.addChild(self.area) + + def updateData(self,obj,prop): + if prop == "Shape": + if hasattr(self,"area"): + if self.area: + area = self.getArea(obj) + self.anno.string.setValue(area) + if not obj.Shape.isNull(): + c = obj.Shape.CenterOfMass + self.coords.translation.setValue([c.x,c.y,c.z]) + + def onChanged(self,vobj,prop): + if prop in ["Override","TextColor"]: + if vobj.DisplayMode == "Detailed": + self.setAnnotation(True) + return + FreeCADGui.addCommand('Arch_Space',_CommandSpace()) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index e7db49a3d..0914c7cd1 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -2574,7 +2574,7 @@ class _ViewProviderDimension(_ViewProviderDraft): obj.addProperty("App::PropertyColor","LineColor","Base","Line color") obj.addProperty("App::PropertyLength","ExtLines","Base","Ext lines") obj.addProperty("App::PropertyVector","TextPosition","Base","The position of the text. Leave (0,0,0) for automatic position") - obj.addProperty("App::PropertyString","Override","Base","Text override. Use 'dim' to insert the dimension length") + obj.addProperty("App::PropertyString","Override","Base","Text override. Use $dim to insert the dimension length") obj.FontSize=getParam("textheight") obj.FontName=getParam("textfont") obj.ExtLines=0.3 @@ -2735,7 +2735,7 @@ class _ViewProviderDimension(_ViewProviderDraft): dtext = "%."+str(dtext)+"f" dtext = (dtext % p3.sub(p2).Length) if text: - text = text.replace("dim",dtext) + text = text.replace("$dim",dtext) else: text = dtext if hasattr(self,"text"):