From 4acf8e09dca051fd42445fb96a7e6639ef695e48 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Wed, 15 Jun 2016 21:17:44 -0300 Subject: [PATCH] Arch: misc improvements and bugfixes * Allow mesh-based windows (with non-solid shape) to pass through * Allow precast elements to be clones * Structure elements now display a different icon when thry are clones * Arch clones now get the same placements as their cloned object on create * Fixed the bad export of clones to IFC * Recoded the Site/Building/Floor IFC export to be more flexible --- src/Mod/Arch/ArchComponent.py | 10 +- src/Mod/Arch/ArchPrecast.py | 27 +- src/Mod/Arch/ArchStructure.py | 3 + src/Mod/Arch/ArchWindow.py | 8 +- src/Mod/Arch/Resources/Arch.qrc | 1 + .../Resources/icons/Arch_Structure_Clone.svg | 288 ++++++++++++++++++ src/Mod/Arch/importIFC.py | 92 ++++-- src/Mod/Draft/Draft.py | 1 + 8 files changed, 402 insertions(+), 28 deletions(-) create mode 100644 src/Mod/Arch/Resources/icons/Arch_Structure_Clone.svg diff --git a/src/Mod/Arch/ArchComponent.py b/src/Mod/Arch/ArchComponent.py index c0e2e0887..91dfd7646 100644 --- a/src/Mod/Arch/ArchComponent.py +++ b/src/Mod/Arch/ArchComponent.py @@ -645,7 +645,7 @@ class Component: print "Arch: unable to cut object ",o.Name, " from ", obj.Name return base - def applyShape(self,obj,shape,placement): + 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(): @@ -662,8 +662,16 @@ class Component: obj.Placement = placement else: FreeCAD.Console.PrintWarning(obj.Label + " " + translate("Arch","has no solid")+"\n") + if allownosolid: + obj.Shape = shape + if not placement.isNull(): + obj.Placement = placement else: FreeCAD.Console.PrintWarning(obj.Label + " " + translate("Arch","has an invalid shape")+"\n") + if allowinvalid: + obj.Shape = shape + if not placement.isNull(): + obj.Placement = placement else: FreeCAD.Console.PrintWarning(obj.Label + " " + translate("Arch","has a null shape")+"\n") diff --git a/src/Mod/Arch/ArchPrecast.py b/src/Mod/Arch/ArchPrecast.py index af0a118d6..7fd758208 100644 --- a/src/Mod/Arch/ArchPrecast.py +++ b/src/Mod/Arch/ArchPrecast.py @@ -52,6 +52,11 @@ class _Precast(ArchComponent.Component): def getExtrusionVector(self,obj,noplacement=True): return FreeCAD.Vector() + + def execute(self,obj): + + if self.clone(obj): + return class _PrecastBeam(_Precast): @@ -68,6 +73,9 @@ class _PrecastBeam(_Precast): obj.Role = ["Beam"] def execute(self,obj): + + if self.clone(obj): + return pl = obj.Placement length = obj.Length.Value @@ -168,6 +176,9 @@ class _PrecastIbeam(_Precast): obj.Role = ["Beam"] def execute(self,obj): + + if self.clone(obj): + return pl = obj.Placement length = obj.Length.Value @@ -220,6 +231,9 @@ class _PrecastPillar(_Precast): obj.Role = ["Column"] def execute(self,obj): + + if self.clone(obj): + return pl = obj.Placement length = obj.Length.Value @@ -336,6 +350,9 @@ class _PrecastPanel(_Precast): obj.Role = ["Plate"] def execute(self,obj): + + if self.clone(obj): + return pl = obj.Placement length = obj.Length.Value @@ -432,6 +449,9 @@ class _PrecastSlab(_Precast): obj.SlabType = ["Champagne","Hat"] def execute(self,obj): + + if self.clone(obj): + return pl = obj.Placement slabtype = obj.SlabType @@ -514,6 +534,9 @@ class _ViewProviderPrecast(ArchComponent.ViewProviderComponent): def getIcon(self): import Arch_rc + if hasattr(self,"Object"): + if self.Object.CloneOf: + return ":/icons/Arch_Structure_Clone.svg" return ":/icons/Arch_Structure_Tree.svg" def setEdit(self,vobj,mode): @@ -535,8 +558,8 @@ class _ViewProviderPrecast(ArchComponent.ViewProviderComponent): import FreeCADGui if hasattr(self,"dentd"): self.Object.Dents = self.dentd.getValues() + del self.dentd FreeCADGui.Control.closeDialog() - del self.dentd return False @@ -1042,7 +1065,7 @@ class _DentsTaskPanel: return l -def makePrecast(precasttype,length=0,width=0,height=0,slabtype="",chamfer=0,dentlength=0,dentwidth=0,dentheight=0,dents=[],base=0,holenumber=0,holemajor=0,holeminor=0,holespacing=0,groovenumber=0,groovedepth=0,grooveheight=0,groovespacing=0): +def makePrecast(precasttype=None,length=0,width=0,height=0,slabtype="",chamfer=0,dentlength=0,dentwidth=0,dentheight=0,dents=[],base=0,holenumber=0,holemajor=0,holeminor=0,holespacing=0,groovenumber=0,groovedepth=0,grooveheight=0,groovespacing=0): "creates one of the precast objects in the current document" diff --git a/src/Mod/Arch/ArchStructure.py b/src/Mod/Arch/ArchStructure.py index 666faa3de..a551f1014 100644 --- a/src/Mod/Arch/ArchStructure.py +++ b/src/Mod/Arch/ArchStructure.py @@ -504,6 +504,9 @@ class _ViewProviderStructure(ArchComponent.ViewProviderComponent): def getIcon(self): import Arch_rc + if hasattr(self,"Object"): + if self.Object.CloneOf: + return ":/icons/Arch_Structure_Clone.svg" return ":/icons/Arch_Structure_Tree.svg" def updateData(self,obj,prop): diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py index f33cc691e..c23b6115b 100644 --- a/src/Mod/Arch/ArchWindow.py +++ b/src/Mod/Arch/ArchWindow.py @@ -716,8 +716,7 @@ class _Window(ArchComponent.Component): base = self.processSubShapes(obj,base) if base: if not base.isNull(): - if base.Solids: - self.applyShape(obj,base,pl) + self.applyShape(obj,base,pl,allowinvalid=True,allownosolid=True) def getSubVolume(self,obj,plac=None): "returns a subvolume for cutting in a base object" @@ -746,7 +745,10 @@ class _Window(ArchComponent.Component): width = max(b.XLength,b.YLength,b.ZLength) if not width: if Draft.isClone(obj,"Window"): - orig = obj.Objects[0] + if hasattr(obj,"CloneOf"): + orig = obj.CloneOf + else: + orig = obj.Objects[0] if orig.Base: base = orig.Base if hasattr(orig,"HoleDepth"): diff --git a/src/Mod/Arch/Resources/Arch.qrc b/src/Mod/Arch/Resources/Arch.qrc index 054d7e637..fbad062aa 100644 --- a/src/Mod/Arch/Resources/Arch.qrc +++ b/src/Mod/Arch/Resources/Arch.qrc @@ -21,6 +21,7 @@ icons/Arch_SectionPlane_Tree.svg icons/Arch_Site_Tree.svg icons/Arch_Structure_Tree.svg + icons/Arch_Structure_Clone.svg icons/Arch_Window_Tree.svg icons/Arch_Axis.svg icons/Arch_Axis_Tree.svg diff --git a/src/Mod/Arch/Resources/icons/Arch_Structure_Clone.svg b/src/Mod/Arch/Resources/icons/Arch_Structure_Clone.svg new file mode 100644 index 000000000..3b9f2659c --- /dev/null +++ b/src/Mod/Arch/Resources/icons/Arch_Structure_Clone.svg @@ -0,0 +1,288 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py index d29a7cb92..f8468ec6d 100644 --- a/src/Mod/Arch/importIFC.py +++ b/src/Mod/Arch/importIFC.py @@ -1116,32 +1116,75 @@ def export(exportList,filename): sites = [] buildings = [] floors = [] + treated = [] + for floor in Draft.getObjectsOfType(objectslist,"Floor"): + objs = Draft.getGroupContents(floor,walls=True) + objs = Arch.pruneIncluded(objs) + children = [] + for c in objs: + if c.Name in products.keys(): + if not (c.Name in treated): + children.append(products[c.Name]) + f = products[floor.Name] + if children: + ifcfile.createIfcRelContainedInSpatialStructure(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'StoreyLink','',children,f) + floors.append(floor.Name) + for c in children: + if not (c.Name in treated): + treated.append(c.Name) + for building in Draft.getObjectsOfType(objectslist,"Building"): + objs = Draft.getGroupContents(building,walls=True) + objs = Arch.pruneIncluded(objs) + children = [] + childfloors = [] + for c in objs: + if c.Name in products.keys(): + if Draft.getType(c) == "Floor": + childfloors.append(products[c.Name]) + elif not (c.Name in treated): + children.append(products[c.Name]) + b = products[building.Name] + if children: + ifcfile.createIfcRelContainedInSpatialStructure(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'BuildingLink','',children,b) + if childfloors: + ifcfile.createIfcRelAggregates(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'BuildingLink','',b,childfloors) + buildings.append(b) + for c in children+childfloors: + if not (c.Name in treated): + treated.append(c.Name) for site in Draft.getObjectsOfType(objectslist,"Site"): - for building in Draft.getObjectsOfType(site.Group,"Building"): - for floor in Draft.getObjectsOfType(building.Group,"Floor"): - children = Draft.getGroupContents(floor,walls=True) - children = Arch.pruneIncluded(children) - children = [products[c.Name] for c in children if c.Name in products.keys()] - floor = products[floor.Name] - ifcfile.createIfcRelContainedInSpatialStructure(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'StoreyLink','',children,floor) - floors.append(floor) - building = products[building.Name] - if floors: - ifcfile.createIfcRelAggregates(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'BuildingLink','',building,floors) - buildings.append(building) - site = products[site.Name] - if buildings: - ifcfile.createIfcRelAggregates(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'SiteLink','',site,buildings) - sites.append(site) + objs = Draft.getGroupContents(site,walls=True) + objs = Arch.pruneIncluded(objs) + children = [] + childbuildings = [] + for c in objs: + if c.Name in products.keys(): + if Draft.getType(c) == "Building": + childbuildings.append(products[c.Name]) + elif not (c.Name in treated): + children.append(products[c.Name]) + s = products[site.Name] + if children: + ifcfile.createIfcRelContainedInSpatialStructure(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'BuildingLink','',children,s) + sites.append(s) + for c in children+childbuildings: + if not (c.Name in treated): + treated.append(c.Name) if not sites: - if DEBUG: print "adding default site" + if DEBUG: print "No site found. Adding default site" sites = [ifcfile.createIfcSite(ifcopenshell.guid.compress(uuid.uuid1().hex),history,"Default Site",'',None,None,None,None,"ELEMENT",None,None,None,None,None)] ifcfile.createIfcRelAggregates(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'ProjectLink','',project,sites) if not buildings: - if DEBUG: print "adding default building" + if DEBUG: print "No building found. Adding default building" buildings = [ifcfile.createIfcBuilding(ifcopenshell.guid.compress(uuid.uuid1().hex),history,"Default Building",'',None,None,None,None,"ELEMENT",None,None,None)] - ifcfile.createIfcRelAggregates(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'SiteLink','',sites[0],buildings) - ifcfile.createIfcRelContainedInSpatialStructure(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'BuildingLink','',products.values(),buildings[0]) + ifcfile.createIfcRelAggregates(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'SiteLink','',sites[0],buildings) + untreated = [] + for p in products.values(): + if not(p.Name) in treated: + if p.Name != buildings[0].Name: + untreated.append(p) + if untreated: + ifcfile.createIfcRelContainedInSpatialStructure(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'BuildingLink','',untreated,buildings[0]) # materials materials = {} @@ -1383,6 +1426,11 @@ def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tess dataset = fcshape.Shells if DEBUG: print "Warning! object contains no solids" + # if this is a clone, place back the shapes in null position + if tostore: + for shape in dataset: + shape.Placement = FreeCAD.Placement() + # new ifcopenshell serializer from ifcopenshell import geom if hasattr(geom,"serialise") and obj.isDerivedFrom("Part::Feature") and SERIALIZE: @@ -1477,7 +1525,7 @@ def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tess ovc = ifcfile.createIfcCartesianPoint((0.0,0.0,0.0)) gpl = ifcfile.createIfcAxis2Placement3D(ovc,zvc,xvc) repmap = ifcfile.createIfcRepresentationMap(gpl,subrep) - pla = FreeCAD.ActiveDocument.getObject(k).Placement + pla = FreeCAD.ActiveDocument.getObject(tostore).Placement axis1 = ifcfile.createIfcDirection(tuple(pla.Rotation.multVec(FreeCAD.Vector(1,0,0)))) axis2 = ifcfile.createIfcDirection(tuple(pla.Rotation.multVec(FreeCAD.Vector(0,1,0)))) origin = ifcfile.createIfcCartesianPoint(tuple(FreeCAD.Vector(pla.Base).multiply(0.001))) @@ -1485,7 +1533,7 @@ def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tess transf = ifcfile.createIfcCartesianTransformationOperator3D(axis1,axis2,origin,1.0,axis3) mapitem = ifcfile.createIfcMappedItem(repmap,transf) shapes = [mapitem] - sharedobjects[k] = repmap + sharedobjects[tostore] = repmap solidType = "MappedRepresentation" # set surface style diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 138bbdc82..6e77a2e73 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -2477,6 +2477,7 @@ def clone(obj,delta=None): base = getCloneBase(obj[0]) cl.Label = prefix + base.Label cl.CloneOf = base + cl.Placement = obj[0].Placement return cl else: cl = FreeCAD.ActiveDocument.addObject("Part::AttachableObjectPython","Clone")