179 lines
7.8 KiB
Python
179 lines
7.8 KiB
Python
import Arch, ArchIFC, math
|
|
|
|
class ProjectImporter:
|
|
def __init__(self, file, objects):
|
|
self.file = file
|
|
self.objects = objects
|
|
|
|
def execute(self):
|
|
self.project = self.file.by_type("IfcProject")[0]
|
|
self.object = Arch.makeProject()
|
|
self.objects[self.project.id()] = self.object
|
|
self.setAttributes()
|
|
self.setComplexAttributes()
|
|
|
|
def setAttributes(self):
|
|
for property in self.object.PropertiesList:
|
|
if hasattr(self.project, property) and getattr(self.project, property):
|
|
setattr(self.object, property, getattr(self.project, property))
|
|
|
|
def setComplexAttributes(self):
|
|
try:
|
|
mapConversion = self.project.RepresentationContexts[0].HasCoordinateOperation[0]
|
|
|
|
data = self.extractTargetCRSData(mapConversion.TargetCRS)
|
|
data.update(self.extractMapConversionData(mapConversion))
|
|
ArchIFC.IfcRoot.setObjIfcComplexAttributeValue(self, self.object, "RepresentationContexts", data)
|
|
except:
|
|
# This scenario occurs validly in IFC2X3, as the mapConversion does
|
|
# not exist
|
|
return
|
|
|
|
def extractTargetCRSData(self, targetCRS):
|
|
mappings = {
|
|
"name": "Name",
|
|
"description": "Description",
|
|
"geodetic_datum": "GeodeticDatum",
|
|
"vertical_datum": "VerticalDatum",
|
|
"map_projection": "MapProjection",
|
|
"map_zone": "MapZone"
|
|
}
|
|
data = {}
|
|
for attributeName, ifcName in mappings.items():
|
|
data[attributeName] = str(getattr(targetCRS, ifcName))
|
|
|
|
if targetCRS.MapUnit.Prefix:
|
|
data["map_unit"] = targetCRS.MapUnit.Prefix.title() + targetCRS.MapUnit.Name.lower()
|
|
else:
|
|
data["map_unit"] = targetCRS.MapUnit.Name.title()
|
|
|
|
return data
|
|
|
|
def extractMapConversionData(self, mapConversion):
|
|
mappings = {
|
|
"eastings": "Eastings",
|
|
"northings": "Northings",
|
|
"orthogonal_height": "OrthogonalHeight",
|
|
"x_axis_abscissa": "XAxisAbscissa",
|
|
"x_axis_ordinate": "XAxisOrdinate",
|
|
"scale": "Scale"
|
|
}
|
|
data = {}
|
|
for attributeName, ifcName in mappings.items():
|
|
data[attributeName] = str(getattr(mapConversion, ifcName))
|
|
|
|
data["true_north"] = str(self.calculateTrueNorthAngle(
|
|
mapConversion.XAxisAbscissa, mapConversion.XAxisOrdinate))
|
|
return data
|
|
|
|
def calculateTrueNorthAngle(self, x, y):
|
|
return round(math.degrees(math.atan2(y, x)) - 90, 6)
|
|
|
|
|
|
|
|
def buildRelationships(ifcfile,root_element):
|
|
"""Builds different tables from an IFC file"""
|
|
|
|
# building relations tables
|
|
# TODO use inverse attributes, see https://forum.freecadweb.org/viewtopic.php?f=39&t=37892
|
|
# done for properties
|
|
|
|
objects = {} # { id:object, ... }
|
|
prodrepr = {} # product/representations table
|
|
additions = {} # { host:[child,...], ... }
|
|
groups = {} # { host:[child,...], ... } # used in structural IFC
|
|
subtractions = [] # [ [opening,host], ... ]
|
|
colors = {} # { id:(r,g,b) }
|
|
shapes = {} # { id:shaoe } only used for merge mode
|
|
structshapes = {} # { id:shaoe } only used for merge mode
|
|
mattable = {} # { objid:matid }
|
|
sharedobjects = {} # { representationmapid:object }
|
|
parametrics = [] # a list of imported objects whose parametric relationships need processing after all objects have been created
|
|
profiles = {} # to store reused extrusion profiles {ifcid:fcobj,...}
|
|
style_material_id = {} # { style_entity_id: material_id) }
|
|
|
|
# gather easy entity types
|
|
sites = ifcfile.by_type("IfcSite")
|
|
buildings = ifcfile.by_type("IfcBuilding")
|
|
floors = ifcfile.by_type("IfcBuildingStorey")
|
|
products = ifcfile.by_type(root_element)
|
|
openings = ifcfile.by_type("IfcOpeningElement")
|
|
annotations = ifcfile.by_type("IfcAnnotation")
|
|
materials = ifcfile.by_type("IfcMaterial")
|
|
|
|
for r in ifcfile.by_type("IfcRelContainedInSpatialStructure"):
|
|
additions.setdefault(r.RelatingStructure.id(),[]).extend([e.id() for e in r.RelatedElements])
|
|
for r in ifcfile.by_type("IfcRelAggregates"):
|
|
additions.setdefault(r.RelatingObject.id(),[]).extend([e.id() for e in r.RelatedObjects])
|
|
for r in ifcfile.by_type("IfcRelAssignsToGroup"):
|
|
groups.setdefault(r.RelatingGroup.id(),[]).extend([e.id() for e in r.RelatedObjects])
|
|
for r in ifcfile.by_type("IfcRelVoidsElement"):
|
|
subtractions.append([r.RelatedOpeningElement.id(), r.RelatingBuildingElement.id()])
|
|
for r in ifcfile.by_type("IfcRelAssociatesMaterial"):
|
|
for o in r.RelatedObjects:
|
|
if r.RelatingMaterial.is_a("IfcMaterial"):
|
|
mattable[o.id()] = r.RelatingMaterial.id()
|
|
elif r.RelatingMaterial.is_a("IfcMaterialLayer"):
|
|
mattable[o.id()] = r.RelatingMaterial.Material.id()
|
|
elif r.RelatingMaterial.is_a("IfcMaterialLayerSet"):
|
|
mattable[o.id()] = r.RelatingMaterial.MaterialLayers[0].Material.id()
|
|
elif r.RelatingMaterial.is_a("IfcMaterialLayerSetUsage"):
|
|
mattable[o.id()] = r.RelatingMaterial.ForLayerSet.MaterialLayers[0].Material.id()
|
|
for p in ifcfile.by_type("IfcProduct"):
|
|
if hasattr(p,"Representation"):
|
|
if p.Representation:
|
|
for it in p.Representation.Representations:
|
|
for it1 in it.Items:
|
|
prodrepr.setdefault(p.id(),[]).append(it1.id())
|
|
if it1.is_a("IfcBooleanResult"):
|
|
prodrepr.setdefault(p.id(),[]).append(it1.FirstOperand.id())
|
|
elif it.Items[0].is_a("IfcMappedItem"):
|
|
prodrepr.setdefault(p.id(),[]).append(it1.MappingSource.MappedRepresentation.id())
|
|
if it1.MappingSource.MappedRepresentation.is_a("IfcShapeRepresentation"):
|
|
for it2 in it1.MappingSource.MappedRepresentation.Items:
|
|
prodrepr.setdefault(p.id(),[]).append(it2.id())
|
|
# colors
|
|
style_color_rgb = {} # { style_entity_id: (r,g,b) }
|
|
for r in ifcfile.by_type("IfcStyledItem"):
|
|
if r.Styles:
|
|
if r.Styles[0].is_a("IfcPresentationStyleAssignment"):
|
|
for style1 in r.Styles[0].Styles:
|
|
if style1.is_a("IfcSurfaceStyle"):
|
|
for style2 in style1.Styles:
|
|
if style2.is_a("IfcSurfaceStyleRendering"):
|
|
if style2.SurfaceColour:
|
|
c = style2.SurfaceColour
|
|
style_color_rgb[r.id()] = (c.Red,c.Green,c.Blue)
|
|
# Nova
|
|
if r.Item:
|
|
for p in prodrepr.keys():
|
|
if r.Item.id() in prodrepr[p]:
|
|
style_material_id[r.id()] = p
|
|
|
|
# Allplan, ArchiCAD
|
|
for m in ifcfile.by_type("IfcMaterialDefinitionRepresentation"):
|
|
for it in m.Representations:
|
|
if it.Items:
|
|
style_material_id[it.Items[0].id()] = m.RepresentedMaterial.id()
|
|
|
|
# create colors out of style_color_rgb and style_material_id
|
|
for k in style_material_id:
|
|
if k in style_color_rgb:
|
|
colors[style_material_id[k]] = style_color_rgb[k]
|
|
|
|
# remove any leftover annotations from products
|
|
tp = []
|
|
for product in products:
|
|
if product.is_a("IfcGrid") and not (product in annotations):
|
|
annotations.append(product)
|
|
elif not (product in annotations):
|
|
tp.append(product)
|
|
products = sorted(tp,key=lambda prod: prod.id())
|
|
|
|
return objects,prodrepr,additions,groups,subtractions,colors,shapes, \
|
|
structshapes,mattable,sharedobjects,parametrics,profiles, \
|
|
sites,buildings,floors,products,openings,annotations,materials, \
|
|
style_material_id
|
|
|
|
|