Arch: Added option to references to fuse the base objects by material
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user