Arch: Added option to references to fuse the base objects by material

This commit is contained in:
Yorik van Havre
2021-09-02 12:21:29 +02:00
parent 68b328fd4c
commit 91dde33ef2
2 changed files with 103 additions and 23 deletions

View File

@@ -348,6 +348,11 @@ class BuildingPart(ArchIFC.IfcProduct):
if not "SavedInventor" in pl:
obj.addProperty("App::PropertyFileIncluded","SavedInventor","BuildingPart",QT_TRANSLATE_NOOP("App::Property","This property stores an inventor representation for this object"))
obj.setEditorMode("SavedInventor",2)
if not "OnlySolids" in pl:
obj.addProperty("App::PropertyBool","OnlySolids","BuildingPart",QT_TRANSLATE_NOOP("App::Property","If true, only solids will be collected by this object when referenced from other files"))
obj.OnlySolids = True
if not "MaterialsTable" in pl:
obj.addProperty("App::PropertyMap","MaterialsTable","BuildingPart",QT_TRANSLATE_NOOP("App::Property","A MaterialName:SolidIndexesList map that relates material names with solid indexes to be used when referencing this object from other files"))
self.Type = "BuildingPart"
@@ -412,17 +417,21 @@ class BuildingPart(ArchIFC.IfcProduct):
def execute(self,obj):
# gather all the child shapes into a compound
shapes = self.getShapes(obj)
shapes,materialstable = self.getShapes(obj)
if shapes:
f = []
for s in shapes:
f.extend(s.Faces)
#print("faces before compound:",len(f))
import Part
obj.Shape = Part.makeCompound(f)
#print("faces after compound:",len(obj.Shape.Faces))
#print("recomputing ",obj.Label)
if obj.OnlySolids:
f = []
for s in shapes:
f.extend(s.Solids)
#print("faces before compound:",len(f))
obj.Shape = Part.makeCompound(f)
#print("faces after compound:",len(obj.Shape.Faces))
#print("recomputing ",obj.Label)
else:
obj.Shape = Part.makeCompound(shapes)
obj.Area = self.getArea(obj)
obj.MaterialsTable = materialstable
def getArea(self,obj):
@@ -440,11 +449,22 @@ class BuildingPart(ArchIFC.IfcProduct):
"recursively get the shapes of objects inside this BuildingPart"
shapes = []
solidindex = 0
materialstable = {}
for child in Draft.get_group_contents(obj):
if not Draft.get_type(child) in ["Space"]:
if hasattr(child,'Shape'):
shapes.extend(child.Shape.Faces)
return shapes
if hasattr(child,'Shape') and child.Shape:
shapes.append(child.Shape)
for solid in child.Shape.Solids:
matname = "Undefined"
if hasattr(child,"Material") and child.Material:
matname = child.Material.Name
if matname in materialstable:
materialstable[matname] = materialstable[matname]+","+str(solidindex)
else:
materialstable[matname] = str(solidindex)
solidindex += 1
return shapes,materialstable
def getSpaces(self,obj):
@@ -651,13 +671,14 @@ class ViewProviderBuildingPart:
colors = []
for child in Draft.get_group_contents(obj):
if hasattr(child,'Shape') and (hasattr(child.ViewObject,"DiffuseColor") or hasattr(child.ViewObject,"ShapeColor")):
if hasattr(child.ViewObject,"DiffuseColor") and len(child.ViewObject.DiffuseColor) == len(child.Shape.Faces):
colors.extend(child.ViewObject.DiffuseColor)
else:
c = child.ViewObject.ShapeColor[:3]+(child.ViewObject.Transparency/100.0,)
for i in range(len(child.Shape.Faces)):
colors.append(c)
if not Draft.get_type(child) in ["Space"]:
if hasattr(child,'Shape') and (hasattr(child.ViewObject,"DiffuseColor") or hasattr(child.ViewObject,"ShapeColor")):
if hasattr(child.ViewObject,"DiffuseColor") and len(child.ViewObject.DiffuseColor) == len(child.Shape.Faces):
colors.extend(child.ViewObject.DiffuseColor)
else:
c = child.ViewObject.ShapeColor[:3]+(child.ViewObject.Transparency/100.0,)
for i in range(len(child.Shape.Faces)):
colors.append(c)
return colors
def onChanged(self,vobj,prop):

View File

@@ -102,6 +102,8 @@ class ArchReference:
obj.ReferenceMode = "Transient"
obj.removeProperty("TransientReference")
FreeCAD.Console.PrintMessage("Upgrading "+obj.Label+" TransientReference property to ReferenceMode\n")
if not "FuseArch" in pl:
obj.addProperty("App::PropertyBool","FuseArch", "Reference", QT_TRANSLATE_NOOP("App::Property","Fuse objects of same material"))
self.Type = "Reference"
def onDocumentRestored(self,obj):
@@ -158,11 +160,9 @@ class ArchReference:
f = zdoc.open(self.parts[obj.Part][1])
shapedata = f.read()
f.close()
import Part
shape = Part.Shape()
if sys.version_info.major >= 3:
shapedata = shapedata.decode("utf8")
shape.importBrepFromString(shapedata)
shape = self.cleanShape(shapedata,obj,self.parts[obj.Part][2])
obj.Shape = shape
if not pl.isIdentity():
obj.Placement = pl
@@ -170,6 +170,51 @@ class ArchReference:
print("Part not found in file")
self.reload = False
def cleanShape(self,shapedata,obj,materials):
"cleans the imported shape"
import Part
shape = Part.Shape()
shape.importBrepFromString(shapedata)
if obj.FuseArch and materials:
# separate lone edges
shapes = []
for edge in shape.Edges:
found = False
for solid in shape.Solids:
if found:
break
for soledge in solid.Edges:
if found:
break
if edge.hashCode() == soledge.hashCode():
found = True
break
else:
shapes.append(edge)
print("solids:",len(shape.Solids),"mattable:",materials)
for key,solindexes in materials.items():
if key == "Undefined":
# do not join objects with no defined material
for solindex in [int(i) for i in solindexes.split(",")]:
shapes.append(shape.Solids[solindex])
else:
fusion = None
for solindex in [int(i) for i in solindexes.split(",")]:
if not fusion:
fusion = shape.Solids[solindex]
else:
fusion = fusion.fuse(shape.Solids[solindex])
if fusion:
shapes.append(fusion)
shape = Part.makeCompound(shapes)
try:
shape = shape.removeSplitter()
except:
print(obj.Label,": error removing splitter")
return shape
def getFile(self,obj,filename=None):
"gets a valid file, if possible"
@@ -206,6 +251,7 @@ class ArchReference:
"returns a list of Part-based objects in a FCStd file"
parts = {}
materials = {}
filename = self.getFile(obj,filename)
if not filename:
return parts
@@ -214,6 +260,7 @@ class ArchReference:
name = None
label = None
part = None
materials = {}
writemode = False
for line in docf:
if sys.version_info.major >= 3:
@@ -236,11 +283,23 @@ class ArchReference:
if n:
part = n[0]
writemode = False
if name and label and part:
parts[name] = [label,part]
elif "<Property name=\"MaterialsTable\" type=\"App::PropertyMap\"" in line:
writemode = True
elif writemode and "<Item key=" in line:
n = re.findall('key=\"(.*?)\"',line)
v = re.findall('value=\"(.*?)\"',line)
if n and v:
materials[n[0]] = v[0]
elif writemode and "</Map>" in line:
writemode = False
elif "</Object>" in line:
if name and label and part:
parts[name] = [label,part,materials]
name = None
label = None
part = None
materials = {}
writemode = False
return parts
def getColors(self,obj):