mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
First attempt at ripping out agnostic code into ifcopenshell.api namespace. See #1399.
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import ifcopenshell
|
||||
from ifcopenshell.api.owner.api import create_owner_history
|
||||
from ifcopenshell.api.owner.api import update_owner_history
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": None,
|
||||
"relating_object": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
decomposes = None
|
||||
if self.settings["product"].Decomposes:
|
||||
decomposes = self.settings["product"].Decomposes[0]
|
||||
|
||||
is_decomposed_by = None
|
||||
for rel in self.settings["relating_object"].IsDecomposedBy:
|
||||
if rel.is_a("IfcRelAggregates"):
|
||||
is_decomposed_by = rel
|
||||
break
|
||||
|
||||
if decomposes and decomposes == is_decomposed_by:
|
||||
return
|
||||
|
||||
if decomposes:
|
||||
related_objects = list(decomposes.RelatedObjects)
|
||||
related_objects.remove(self.settings["product"])
|
||||
if related_objects:
|
||||
decomposes.RelatedObjects = related_objects
|
||||
update_owner_history(decomposes)
|
||||
else:
|
||||
self.file.remove(decomposes)
|
||||
|
||||
if is_decomposed_by:
|
||||
related_objects = list(is_decomposed_by.RelatedObjects)
|
||||
related_objects.append(self.settings["product"])
|
||||
is_decomposed_by.RelatedObjects = related_objects
|
||||
update_owner_history(is_decomposed_by)
|
||||
else:
|
||||
is_decomposed_by = self.file.create_entity(
|
||||
"IfcRelAggregates",
|
||||
**{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"OwnerHistory": create_owner_history(),
|
||||
"RelatedObjects": [self.settings["product"]],
|
||||
"RelatingObject": self.settings["relating_object"],
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
class Data:
|
||||
products = {}
|
||||
|
||||
@classmethod
|
||||
def purge(cls):
|
||||
cls.products = {}
|
||||
|
||||
@classmethod
|
||||
def load(cls, file, product_id):
|
||||
if not file:
|
||||
return
|
||||
product = file.by_id(product_id)
|
||||
if product.Decomposes and product.Decomposes[0].is_a("IfcRelAggregates"):
|
||||
obj = product.Decomposes[0].RelatingObject
|
||||
cls.products[product_id] = {"type": obj.is_a(), "Name": obj.Name, "id": int(obj.id())}
|
||||
else:
|
||||
cls.products[product_id] = {"type": None, "Name": None, "id": None}
|
||||
@@ -0,0 +1,48 @@
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.attribute
|
||||
|
||||
|
||||
class Data:
|
||||
products = {}
|
||||
|
||||
@classmethod
|
||||
def purge(cls):
|
||||
cls.products = {}
|
||||
|
||||
@classmethod
|
||||
def load(cls, file, product_id):
|
||||
if not file:
|
||||
return
|
||||
product = file.by_id(product_id)
|
||||
schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(file.schema)
|
||||
cls.products[product_id] = []
|
||||
declaration = schema.declaration_by_name(product.is_a())
|
||||
for attribute in declaration.all_attributes():
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
value = getattr(product, attribute.name())
|
||||
list_type = None
|
||||
enum_items = ()
|
||||
|
||||
if isinstance(data_type, tuple):
|
||||
list_type = data_type[1]
|
||||
data_type = data_type[0]
|
||||
|
||||
if data_type in ["entity", "list", "string", "enum"]:
|
||||
value = None if value is None else str(value)
|
||||
elif data_type == "float":
|
||||
value = None if value is None else float(value)
|
||||
elif data_type == "integer":
|
||||
value = None if value is None else int(value)
|
||||
|
||||
if data_type == "enum":
|
||||
enum_items = ifcopenshell.util.attribute.get_enum_items(attribute)
|
||||
|
||||
cls.products[product_id].append({
|
||||
"name": attribute.name(),
|
||||
"value": value,
|
||||
"type": data_type,
|
||||
"enum_items": enum_items,
|
||||
"list_type": list_type,
|
||||
"is_optional": attribute.optional(),
|
||||
"is_null": getattr(product, attribute.name()) is None
|
||||
})
|
||||
@@ -0,0 +1,18 @@
|
||||
from ifcopenshell.api.owner.api import update_owner_history
|
||||
|
||||
|
||||
class Usecase():
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": None,
|
||||
"attributes": {}
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["product"], name, value)
|
||||
if hasattr(self.settings["product"], "OwnerHistory"):
|
||||
update_owner_history(self.settings["product"])
|
||||
@@ -0,0 +1,39 @@
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.schema
|
||||
import ifcopenshell.util.date
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"classification": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
edition_date = None
|
||||
if self.settings["classification"].EditionDate:
|
||||
edition_date = ifcopenshell.util.date.ifc2datetime(self.settings["classification"].EditionDate)
|
||||
self.settings["classification"].EditionDate = None
|
||||
|
||||
migrator = ifcopenshell.util.schema.Migrator()
|
||||
result = migrator.migrate(self.settings["classification"], self.file)
|
||||
|
||||
# TODO: should auto date migration be part of the migrator?
|
||||
if self.file.schema == "IFC2X3" and edition_date:
|
||||
result.EditionDate = ifcopenshell.util.date.datetime2ifc(edition_date, "IfcCalendarDate")
|
||||
else:
|
||||
result.EditionDate = ifcopenshell.util.date.datetime2ifc(edition_date, "IfcDate")
|
||||
|
||||
self.file.create_entity("IfcRelAssociatesClassification", **{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"RelatedObjects": [self.file.by_type("IfcProject")[0]],
|
||||
"RelatingClassification": result
|
||||
})
|
||||
return # See bug #1272
|
||||
try:
|
||||
result = self.file.add(self.settings["classification"])
|
||||
except:
|
||||
migrator = ifcopenshell.util.schema.Migrator()
|
||||
result = migrator.migrate(self.settings["classification"], self.file)
|
||||
@@ -0,0 +1,63 @@
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.schema
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": None,
|
||||
"reference": None,
|
||||
"classification": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
relating_classification = None
|
||||
|
||||
if hasattr(self.settings["reference"], "ItemReference"):
|
||||
identification = self.settings["reference"].ItemReference # IFC2X3
|
||||
else:
|
||||
identification = self.settings["reference"].Identification
|
||||
|
||||
for reference in self.file.by_type("IfcClassificationReference"):
|
||||
if self.file.schema == "IFC2X3":
|
||||
if reference.ItemReference == identification:
|
||||
relating_classification = reference
|
||||
break
|
||||
else:
|
||||
if reference.Identification == identification:
|
||||
relating_classification = reference
|
||||
break
|
||||
|
||||
if relating_classification:
|
||||
association = self.get_association(relating_classification)
|
||||
related_objects = set(association.RelatedObjects)
|
||||
related_objects.add(self.settings["product"])
|
||||
association.RelatedObjects = list(related_objects)
|
||||
return
|
||||
|
||||
migrator = ifcopenshell.util.schema.Migrator()
|
||||
# This removal patch is to support a lightweight classification
|
||||
old_referenced_source = self.settings["reference"].ReferencedSource
|
||||
self.settings["reference"].ReferencedSource = None
|
||||
relating_classification = migrator.migrate(self.settings["reference"], self.file)
|
||||
relating_classification.ReferencedSource = self.settings["classification"]
|
||||
self.settings["reference"].ReferencedSource = old_referenced_source
|
||||
self.file.create_entity(
|
||||
"IfcRelAssociatesClassification",
|
||||
**{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"RelatedObjects": [self.settings["product"]],
|
||||
"RelatingClassification": relating_classification,
|
||||
}
|
||||
)
|
||||
|
||||
def get_association(self, reference):
|
||||
if self.file.schema == "IFC2X3":
|
||||
for association in self.file.by_type("IfcRelAssociatesClassification"):
|
||||
if association.RelatingClassification == reference:
|
||||
return association
|
||||
elif reference.ClassificationRefForObjects:
|
||||
return reference.ClassificationRefForObjects[0]
|
||||
@@ -0,0 +1,76 @@
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.date
|
||||
|
||||
|
||||
class Data:
|
||||
is_loaded = False
|
||||
products = {}
|
||||
classifications = {}
|
||||
references = {}
|
||||
library_file = None
|
||||
library_classifications = {}
|
||||
library_references = {}
|
||||
|
||||
@classmethod
|
||||
def purge(cls):
|
||||
cls.is_loaded = False
|
||||
cls.products = {}
|
||||
cls.classifications = {}
|
||||
cls.references = {}
|
||||
cls.library_file = None
|
||||
cls.library_classifications = {}
|
||||
cls.library_references = {}
|
||||
|
||||
@classmethod
|
||||
def load(cls, file, product_id=None):
|
||||
cls._file = file
|
||||
if not cls._file:
|
||||
return
|
||||
if product_id:
|
||||
return cls.load_product_classifications(product_id)
|
||||
cls.load_classifications()
|
||||
cls.load_references()
|
||||
cls.is_loaded = True
|
||||
|
||||
@classmethod
|
||||
def load_product_classifications(cls, product_id):
|
||||
product = cls._file.by_id(product_id)
|
||||
cls.products[product_id] = []
|
||||
if not product.HasAssociations:
|
||||
return
|
||||
for association in product.HasAssociations:
|
||||
if association.is_a("IfcRelAssociatesClassification"):
|
||||
cls.products[product_id].append(association.RelatingClassification.id())
|
||||
|
||||
@classmethod
|
||||
def load_classifications(cls):
|
||||
cls.classifications = {}
|
||||
for classification in cls._file.by_type("IfcClassification"):
|
||||
data = classification.get_info()
|
||||
if cls._file.schema == "IFC2X3" and data["EditionDate"]:
|
||||
data["EditionDate"] = ifcopenshell.util.date(data.EditionDate).isoformat()
|
||||
cls.classifications[classification.id()] = data
|
||||
|
||||
@classmethod
|
||||
def load_references(cls):
|
||||
cls.references = {}
|
||||
for reference in cls._file.by_type("IfcClassificationReference"):
|
||||
data = reference.get_info()
|
||||
if reference.ReferencedSource:
|
||||
#data["ReferencedSource"] = cls.get_referenced_source(reference.ReferencedSource)
|
||||
data["ReferencedSource"] = reference.ReferencedSource.id()
|
||||
cls.references[reference.id()] = data
|
||||
|
||||
@classmethod
|
||||
def get_referenced_source(cls, reference):
|
||||
if reference.is_a("IfcClassification"):
|
||||
return reference
|
||||
elif reference.is_a("IfcClassificationReference") and reference.ReferencedSource:
|
||||
return cls.get_referenced_source(reference.ReferencedSource)
|
||||
|
||||
@classmethod
|
||||
def load_library(cls, filepath):
|
||||
cls.library_file = ifcopenshell.open(filepath)
|
||||
cls.library_classifications = {}
|
||||
for classification in cls.library_file.by_type("IfcClassification"):
|
||||
cls.library_classifications[classification.id()] = classification.Name
|
||||
@@ -0,0 +1,13 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"classification": None,
|
||||
"attributes": {}
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["classification"], name, value)
|
||||
@@ -0,0 +1,13 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"reference": None,
|
||||
"attributes": {}
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["reference"], name, value)
|
||||
@@ -0,0 +1,24 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"classification": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
references = self.get_references(self.settings["classification"])
|
||||
for reference in references:
|
||||
self.file.remove(reference)
|
||||
self.file.remove(self.settings["classification"])
|
||||
for rel in self.file.by_type("IfcRelAssociatesClassification"):
|
||||
if not rel.RelatingClassification:
|
||||
self.file.remove(rel)
|
||||
|
||||
def get_references(self, classification):
|
||||
results = []
|
||||
if not classification.HasReferences:
|
||||
return results
|
||||
for reference in classification.HasReferences:
|
||||
results.append(reference)
|
||||
results.extend(self.get_references(reference))
|
||||
return results
|
||||
@@ -0,0 +1,28 @@
|
||||
import ifcopenshell.util.schema
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"reference": None, "product": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
total_related_objects = 0
|
||||
for association in self.file.by_type("IfcRelAssociatesClassification"):
|
||||
if association.RelatingClassification == self.settings["reference"] and association.RelatedObjects:
|
||||
total_related_objects += len(association.RelatedObjects)
|
||||
related_objects = list(association.RelatedObjects)
|
||||
try:
|
||||
related_objects.remove(self.settings["product"])
|
||||
except:
|
||||
continue
|
||||
if len(related_objects):
|
||||
association.RelatedObjects = related_objects
|
||||
else:
|
||||
self.file.remove(association)
|
||||
|
||||
# TODO: we only handle lightweight classifications here
|
||||
if total_related_objects == 1:
|
||||
self.file.remove(self.settings["reference"])
|
||||
@@ -0,0 +1,15 @@
|
||||
import ifcopenshell
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings={}):
|
||||
self.file = file
|
||||
self.settings = {}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
return self.file.create_entity("IfcObjective", **{
|
||||
"Name": "Unnamed",
|
||||
"ConstraintGrade": "NOTDEFINED",
|
||||
"ObjectiveQualifier": "NOTDEFINED"
|
||||
})
|
||||
@@ -0,0 +1,28 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": None,
|
||||
"constraint": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
rel = self.get_constraint_rel()
|
||||
related_objects = set(rel.RelatedObjects) if rel.RelatedObjects else set()
|
||||
related_objects.add(self.settings["product"])
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
|
||||
def get_constraint_rel(self):
|
||||
for rel in self.file.by_type("IfcRelAssociatesConstraint"):
|
||||
if rel.RelatingConstraint == self.settings["constraint"]:
|
||||
return rel
|
||||
return self.file.create_entity("IfcRelAssociatesConstraint", **{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
# TODO: owner history
|
||||
"RelatingConstraint": self.settings["constraint"]
|
||||
})
|
||||
@@ -0,0 +1,48 @@
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.date
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class Data:
|
||||
is_loaded = False
|
||||
products = {}
|
||||
objectives = {}
|
||||
|
||||
@classmethod
|
||||
def purge(cls):
|
||||
cls.is_loaded = False
|
||||
cls.products = {}
|
||||
cls.objectives = {}
|
||||
|
||||
@classmethod
|
||||
def load(cls, file, product_id=None):
|
||||
cls._file = file
|
||||
if not cls._file:
|
||||
return
|
||||
if product_id:
|
||||
return cls.load_product(product_id)
|
||||
cls.load_objectives()
|
||||
cls.is_loaded = True
|
||||
|
||||
@classmethod
|
||||
def load_product(cls, product_id):
|
||||
product = cls._file.by_id(product_id)
|
||||
cls.products[product_id] = []
|
||||
if not product.HasAssociations:
|
||||
return
|
||||
for association in product.HasAssociations:
|
||||
if association.is_a("IfcRelAssociatesConstraint"):
|
||||
if not association.RelatingConstraint.is_a("IfcObjective"):
|
||||
continue # not yet implemented
|
||||
cls.products[product_id].append(association.RelatingConstraint.id())
|
||||
|
||||
@classmethod
|
||||
def load_objectives(cls):
|
||||
cls.objectives = {}
|
||||
for constraint in cls._file.by_type("IfcObjective"):
|
||||
data = constraint.get_info()
|
||||
if cls._file.schema == "IFC2X3":
|
||||
for attribute in ["CreationTime"]:
|
||||
if data[attribute]:
|
||||
data[attribute] = ifcopenshell.util.date.ifc2datetime(data[attribute]).isoformat()
|
||||
cls.objectives[constraint.id()] = data
|
||||
@@ -0,0 +1,13 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"objective": None,
|
||||
"attributes": {}
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["objective"], name, value)
|
||||
@@ -0,0 +1,12 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"constraint": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
self.file.remove(self.settings["constraint"])
|
||||
for rel in self.file.by_type("IfcRelAssociatesConstraint"):
|
||||
if not rel.RelatingConstraint:
|
||||
self.file.remove(rel)
|
||||
@@ -0,0 +1,17 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": None,
|
||||
"constraint": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for rel in self.settings["product"].HasAssociations:
|
||||
if rel.is_a("IfcRelAssociatesConstraint") and rel.RelatingConstraint == self.settings["constraint"]:
|
||||
self.file.remove(rel)
|
||||
@@ -0,0 +1,45 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"context": None,
|
||||
"subcontext": None,
|
||||
"target_view": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
parent = [
|
||||
c
|
||||
for c in self.file.by_type("IfcGeometricRepresentationContext")
|
||||
if c.ContextType == self.settings["context"]
|
||||
]
|
||||
if not parent:
|
||||
self.create_origin()
|
||||
if self.settings["context"] == "Plan":
|
||||
context = self.file.createIfcGeometricRepresentationContext(None, "Plan", 2, 1.0e-05, self.origin)
|
||||
else:
|
||||
context = self.file.createIfcGeometricRepresentationContext(None, "Model", 3, 1.0e-05, self.origin)
|
||||
project = self.file.by_type("IfcProject")[0]
|
||||
if project.RepresentationContexts:
|
||||
contexts = list(project.RepresentationContexts)
|
||||
else:
|
||||
contexts = []
|
||||
contexts.append(context)
|
||||
project.RepresentationContexts = contexts
|
||||
return context
|
||||
parent = parent[0]
|
||||
return self.file.create_entity("IfcGeometricRepresentationSubContext", **{
|
||||
"ContextIdentifier": self.settings["subcontext"],
|
||||
"ContextType": self.settings["context"],
|
||||
"ParentContext": parent,
|
||||
"TargetView": self.settings["target_view"],
|
||||
})
|
||||
|
||||
def create_origin(self):
|
||||
self.origin = self.file.createIfcAxis2Placement3D(
|
||||
self.file.createIfcCartesianPoint((0.0, 0.0, 0.0)),
|
||||
self.file.createIfcDirection((0.0, 0.0, 1.0)),
|
||||
self.file.createIfcDirection((1.0, 0.0, 0.0)),
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
class Data:
|
||||
is_loaded = False
|
||||
contexts = {}
|
||||
|
||||
@classmethod
|
||||
def purge(cls):
|
||||
cls.is_loaded = False
|
||||
cls.contexts = {}
|
||||
|
||||
@classmethod
|
||||
def load(cls, file):
|
||||
if not file:
|
||||
return
|
||||
cls.contexts = {}
|
||||
for context in file.by_type("IfcGeometricRepresentationContext", include_subtypes=False):
|
||||
subcontexts = {}
|
||||
for subcontext in context.HasSubContexts:
|
||||
subcontexts[int(subcontext.id())] = {
|
||||
"ContextType": subcontext.ContextType,
|
||||
"ContextIdentifier": subcontext.ContextIdentifier,
|
||||
"TargetView": subcontext.TargetView,
|
||||
}
|
||||
cls.contexts[int(context.id())] = {
|
||||
"ContextType": context.ContextType,
|
||||
"HasSubContexts": subcontexts
|
||||
}
|
||||
cls.is_loaded = True
|
||||
@@ -0,0 +1,12 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"context": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
# TODO: this is a light remove only
|
||||
for subcontext in self.settings["context"].HasSubContexts:
|
||||
self.file.remove(subcontext)
|
||||
self.file.remove(self.settings["context"])
|
||||
@@ -0,0 +1,15 @@
|
||||
import ifcopenshell
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings={}):
|
||||
self.file = file
|
||||
self.settings = {}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
id_attribute = "DocumentId" if self.file.schema == "IFC2X3" else "Identification"
|
||||
return self.file.create_entity("IfcDocumentInformation", **{
|
||||
id_attribute: ifcopenshell.guid.new(),
|
||||
"Name": "Unnamed"
|
||||
})
|
||||
@@ -0,0 +1,14 @@
|
||||
import ifcopenshell
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings={}):
|
||||
self.file = file
|
||||
self.settings = {}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
id_attribute = "ItemReference" if self.file.schema == "IFC2X3" else "Identification"
|
||||
return self.file.create_entity("IfcDocumentReference", **{
|
||||
id_attribute: ifcopenshell.guid.new()
|
||||
})
|
||||
@@ -0,0 +1,41 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": None,
|
||||
"document": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
rel = self.get_document_rel()
|
||||
related_objects = set(rel.RelatedObjects) if rel.RelatedObjects else set()
|
||||
related_objects.add(self.settings["product"])
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
|
||||
def get_document_rel(self):
|
||||
if self.file.schema == "IFC2X3":
|
||||
for rel in self.file.by_type("IfcRelAssociatesDocument"):
|
||||
if rel.RelatingDocument == self.settings["document"]:
|
||||
return rel
|
||||
else:
|
||||
if (
|
||||
hasattr(self.settings["document"], "DocumentRefForObjects")
|
||||
and self.settings["document"].DocumentRefForObjects
|
||||
):
|
||||
return self.settings["document"].DocumentRefForObjects[0]
|
||||
elif (
|
||||
hasattr(self.settings["document"], "DocumentInfoForObjects")
|
||||
and self.settings["document"].DocumentInfoForObjects
|
||||
):
|
||||
return self.settings["document"].DocumentInfoForObjects[0]
|
||||
|
||||
return self.file.create_entity("IfcRelAssociatesDocument", **{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
# TODO: owner history
|
||||
"RelatingDocument": self.settings["document"]
|
||||
})
|
||||
@@ -0,0 +1,65 @@
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.date
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class Data:
|
||||
is_loaded = False
|
||||
products = {}
|
||||
references = {}
|
||||
information = {}
|
||||
|
||||
@classmethod
|
||||
def purge(cls):
|
||||
cls.is_loaded = False
|
||||
cls.products = {}
|
||||
cls.references = {}
|
||||
cls.information = {}
|
||||
|
||||
@classmethod
|
||||
def load(cls, file, product_id=None):
|
||||
cls._file = file
|
||||
if not cls._file:
|
||||
return
|
||||
if product_id:
|
||||
return cls.load_product(product_id)
|
||||
cls.load_references()
|
||||
cls.load_information()
|
||||
cls.is_loaded = True
|
||||
|
||||
@classmethod
|
||||
def load_product(cls, product_id):
|
||||
product = cls._file.by_id(product_id)
|
||||
cls.products[product_id] = []
|
||||
if not product.HasAssociations:
|
||||
return
|
||||
for association in product.HasAssociations:
|
||||
if association.is_a("IfcRelAssociatesDocument"):
|
||||
cls.products[product_id].append(association.RelatingDocument.id())
|
||||
|
||||
@classmethod
|
||||
def load_information(cls):
|
||||
cls.information = {}
|
||||
for information in cls._file.by_type("IfcDocumentInformation"):
|
||||
data = information.get_info()
|
||||
if cls._file.schema == "IFC2X3":
|
||||
for attribute in ["CreationTime", "LastRevisionTime", "ValidFrom", "ValidUntil"]:
|
||||
if data[attribute]:
|
||||
data[attribute] = ifcopenshell.util.date.ifc2datetime(data[attribute]).isoformat()
|
||||
if data["ElectronicFormat"]:
|
||||
data["ElectronicFormat"] = "{}/{}".format(
|
||||
information.ElectronicFormat.MimeContentType, information.ElectronicFormat.MimeSubtype
|
||||
)
|
||||
cls.information[information.id()] = data
|
||||
|
||||
@classmethod
|
||||
def load_references(cls):
|
||||
cls.references = {}
|
||||
for reference in cls._file.by_type("IfcDocumentReference"):
|
||||
data = reference.get_info()
|
||||
if cls._file.schema == "IFC2X3":
|
||||
if reference.ReferenceToDocument:
|
||||
data["ReferencedDocument"] = reference.ReferenceToDocument[0].id()
|
||||
elif reference.ReferencedDocument:
|
||||
data["ReferencedDocument"] = reference.ReferencedDocument.id()
|
||||
cls.references[reference.id()] = data
|
||||
@@ -0,0 +1,13 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"information": None,
|
||||
"attributes": {}
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["information"], name, value)
|
||||
@@ -0,0 +1,13 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"reference": None,
|
||||
"attributes": {}
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["reference"], name, value)
|
||||
@@ -0,0 +1,12 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"document": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
self.file.remove(self.settings["document"])
|
||||
for rel in self.file.by_type("IfcRelAssociatesDocument"):
|
||||
if not rel.RelatingDocument:
|
||||
self.file.remove(rel)
|
||||
@@ -0,0 +1,17 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": None,
|
||||
"document": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for rel in self.settings["product"].HasAssociations:
|
||||
if rel.is_a("IfcRelAssociatesDocument") and rel.RelatingDocument == self.settings["document"]:
|
||||
self.file.remove(rel)
|
||||
@@ -0,0 +1,451 @@
|
||||
import bpy
|
||||
import bmesh
|
||||
import ifcopenshell.util.unit
|
||||
from mathutils import Vector
|
||||
from blenderbim.bim.module.geometry.helper import Helper
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
# TODO: This usecase currently depends on Blender's data model
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
"blender_object": None, # This is (currently) a Blender object, hence this depends on Blender now
|
||||
"geometry": None, # This is (currently) a Blender data object, hence this depends on Blender now
|
||||
"coordinate_offset": None, # Optionally apply a vector offset to all coordinates
|
||||
"total_items": 1, # How many representation items to create
|
||||
"unit_scale": None, # A scale factor to apply for all vectors in case the unit is different
|
||||
"should_force_faceted_brep": False, # If we should force faceted breps for meshes
|
||||
"should_force_triangulation": False, # If we should force triangulation for meshes
|
||||
"is_wireframe": False, # If the geometry is a wireframe
|
||||
"is_curve": False, # If the geometry is a Blender curve
|
||||
"is_point_cloud": False, # If the geometry is a point cloud
|
||||
# Possible IFC representation classes:
|
||||
# IfcExtrudedAreaSolid/IfcRectangleProfileDef
|
||||
# IfcExtrudedAreaSolid/IfcCircleProfileDef
|
||||
# IfcExtrudedAreaSolid/IfcArbitraryClosedProfileDef
|
||||
# IfcExtrudedAreaSolid/IfcArbitraryProfileDef
|
||||
"ifc_representation_class": None, # Whether to cast a mesh into a particular class
|
||||
}
|
||||
self.ifc_vertices = []
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
if isinstance(self.settings["geometry"], bpy.types.Mesh):
|
||||
self.evaluate_geometry()
|
||||
if self.settings["unit_scale"] is None:
|
||||
self.settings["unit_scale"] = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
if self.settings["context"].ContextType == "Model":
|
||||
return self.create_model_representation()
|
||||
elif self.settings["context"].ContextType == "Plan":
|
||||
return self.create_plan_representation()
|
||||
return self.create_variable_representation()
|
||||
|
||||
def evaluate_geometry(self):
|
||||
self.boolean_modifiers = []
|
||||
for modifier in self.settings["blender_object"].modifiers:
|
||||
if not modifier.type == "BOOLEAN":
|
||||
continue
|
||||
modifier_data = {}
|
||||
for name in ["operation", "operand_type", "object", "solver", "use_self"]:
|
||||
modifier_data[name] = getattr(modifier, name)
|
||||
self.boolean_modifiers.append(modifier_data)
|
||||
self.settings["blender_object"].modifiers.remove(modifier)
|
||||
|
||||
if self.settings["should_force_triangulation"]:
|
||||
mesh = self.settings["blender_object"].evaluated_get(bpy.context.evaluated_depsgraph_get()).to_mesh()
|
||||
bm = bmesh.new()
|
||||
bm.from_mesh(mesh)
|
||||
bmesh.ops.triangulate(bm, faces=bm.faces)
|
||||
bm.to_mesh(mesh)
|
||||
bm.free()
|
||||
del bm
|
||||
self.settings["geometry"] = mesh
|
||||
else:
|
||||
self.settings["geometry"] = (
|
||||
self.settings["blender_object"].evaluated_get(bpy.context.evaluated_depsgraph_get()).to_mesh()
|
||||
)
|
||||
|
||||
for modifier in self.boolean_modifiers:
|
||||
new = self.settings["blender_object"].modifiers.new("IfcOpeningElement", "BOOLEAN")
|
||||
for key, value in modifier.items():
|
||||
setattr(new, key, value)
|
||||
|
||||
def create_model_representation(self):
|
||||
if self.settings["context"].is_a() == "IfcGeometricRepresentationContext":
|
||||
return self.create_variable_representation()
|
||||
if self.settings["context"].ContextIdentifier == "Annotation":
|
||||
return self.create_geometric_set_representation()
|
||||
elif self.settings["context"].ContextIdentifier == "Axis":
|
||||
return self.create_curve3d_representation()
|
||||
elif self.settings["context"].ContextIdentifier == "Body":
|
||||
return self.create_variable_representation()
|
||||
elif self.settings["context"].ContextIdentifier == "Box":
|
||||
return self.create_box_representation()
|
||||
elif self.settings["context"].ContextIdentifier == "Clearance":
|
||||
return self.create_variable_representation()
|
||||
elif self.settings["context"].ContextIdentifier == "CoG":
|
||||
return self.create_cog_representation()
|
||||
elif self.settings["context"].ContextIdentifier == "FootPrint":
|
||||
return self.create_variable_representation()
|
||||
elif self.settings["context"].ContextIdentifier == "Reference":
|
||||
if self.settings["context"].TargetView == "GRAPH_VIEW":
|
||||
return self.create_structural_reference_representation()
|
||||
elif self.settings["context"].ContextIdentifier == "Profile":
|
||||
return self.create_curve3d_representation()
|
||||
elif self.settings["context"].ContextIdentifier == "SurveyPoints":
|
||||
return self.create_geometric_curve_set_representation()
|
||||
|
||||
def create_plan_representation(self):
|
||||
if self.settings["context"].ContextIdentifier == "Annotation":
|
||||
if isinstance(self.settings["geometry"], bpy.types.TextCurve):
|
||||
return self.create_text_representation()
|
||||
shape_representation = self.create_geometric_curve_set_representation(is_2d=True)
|
||||
shape_representation.RepresentationType = "Annotation2D"
|
||||
return shape_representation
|
||||
elif self.settings["context"].ContextIdentifier == "Axis":
|
||||
return self.create_curve2d_representation()
|
||||
elif self.settings["context"].ContextIdentifier == "Body":
|
||||
pass
|
||||
elif self.settings["context"].ContextIdentifier == "Box":
|
||||
pass
|
||||
elif self.settings["context"].ContextIdentifier == "Clearance":
|
||||
pass
|
||||
elif self.settings["context"].ContextIdentifier == "CoG":
|
||||
pass
|
||||
elif self.settings["context"].ContextIdentifier == "FootPrint":
|
||||
if self.settings["context"].TargetView in ["PLAN_VIEW", "REFLECTED_PLAN_VIEW"]:
|
||||
return self.create_geometric_curve_set_representation(is_2d=True)
|
||||
elif self.settings["context"].ContextIdentifier == "Reference":
|
||||
pass
|
||||
elif self.settings["context"].ContextIdentifier == "Profile":
|
||||
pass
|
||||
elif self.settings["context"].ContextIdentifier == "SurveyPoints":
|
||||
pass
|
||||
|
||||
def create_variable_representation(self):
|
||||
if self.settings["is_wireframe"]:
|
||||
return self.create_wireframe_representation()
|
||||
elif self.settings["is_curve"]:
|
||||
return self.create_curve_representation()
|
||||
elif self.settings["is_point_cloud"]:
|
||||
return self.create_point_cloud_representation()
|
||||
elif isinstance(self.settings["geometry"], bpy.types.Camera):
|
||||
return self.create_camera_block_representation()
|
||||
elif self.settings["ifc_representation_class"] == "IfcExtrudedAreaSolid/IfcRectangleProfileDef":
|
||||
return self.create_rectangle_extrusion_representation()
|
||||
elif self.settings["ifc_representation_class"] == "IfcExtrudedAreaSolid/IfcCircleProfileDef":
|
||||
return self.create_circle_extrusion_representation()
|
||||
elif self.settings["ifc_representation_class"] == "IfcExtrudedAreaSolid/IfcArbitraryClosedProfileDef":
|
||||
return self.create_arbitrary_extrusion_representation()
|
||||
elif self.settings["ifc_representation_class"] == "IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids":
|
||||
return self.create_arbitrary_void_extrusion_representation()
|
||||
return self.create_mesh_representation()
|
||||
|
||||
def create_camera_block_representation(self):
|
||||
raster_x = self.settings["geometry"].BIMCameraProperties.raster_x
|
||||
raster_y = self.settings["geometry"].BIMCameraProperties.raster_y
|
||||
|
||||
if self.is_camera_landscape():
|
||||
width = self.settings["geometry"].ortho_scale
|
||||
height = width / raster_x * raster_y
|
||||
else:
|
||||
height = self.settings["geometry"].ortho_scale
|
||||
width = height / raster_y * raster_x
|
||||
|
||||
block = self.file.create_entity(
|
||||
"IfcBlock",
|
||||
**{
|
||||
"Position": self.file.createIfcAxis2Placement3D(
|
||||
self.create_cartesian_point(-width / 2, -height / 2, -self.settings["geometry"].clip_end)
|
||||
),
|
||||
"XLength": self.convert_si_to_unit(width),
|
||||
"YLength": self.convert_si_to_unit(height),
|
||||
"ZLength": self.convert_si_to_unit(self.settings["geometry"].clip_end),
|
||||
}
|
||||
)
|
||||
|
||||
return self.file.createIfcShapeRepresentation(
|
||||
self.settings["context"],
|
||||
self.settings["context"].ContextIdentifier,
|
||||
"CSG",
|
||||
[self.file.createIfcCsgSolid(block)],
|
||||
)
|
||||
|
||||
def is_camera_landscape(self):
|
||||
return (
|
||||
self.settings["geometry"].BIMCameraProperties.raster_x
|
||||
> self.settings["geometry"].BIMCameraProperties.raster_y
|
||||
)
|
||||
|
||||
def create_curve3d_representation(self):
|
||||
return self.file.createIfcShapeRepresentation(
|
||||
self.settings["context"],
|
||||
self.settings["context"].ContextIdentifier,
|
||||
"Curve3D",
|
||||
self.create_curves(),
|
||||
)
|
||||
|
||||
def create_curves(self, is_2d=False):
|
||||
if isinstance(self.settings["geometry"], bpy.types.Mesh):
|
||||
if self.file.schema == "IFC2X3":
|
||||
return self.create_curves_from_mesh_ifc2x3(is_2d=is_2d)
|
||||
else:
|
||||
return self.create_curves_from_mesh(is_2d=is_2d)
|
||||
elif isinstance(self.settings["geometry"], bpy.types.Curve):
|
||||
return self.create_curves_from_curve(is_2d=is_2d)
|
||||
|
||||
def create_curves_from_mesh(self, is_2d=False):
|
||||
curves = []
|
||||
points = self.create_cartesian_point_list_from_vertices(self.settings["geometry"].vertices, is_2d=is_2d)
|
||||
edge_loops = []
|
||||
previous_edge = None
|
||||
edge_loop = []
|
||||
for edge in self.settings["geometry"].edges:
|
||||
if (Vector(points.CoordList[edge.vertices[0]]) - Vector(points.CoordList[edge.vertices[1]])).length < 0.001:
|
||||
# Maybe we should warn the user to weld vertices in this scenario?
|
||||
continue
|
||||
elif previous_edge is None:
|
||||
edge_loop = [self.file.createIfcLineIndex((edge.vertices[0] + 1, edge.vertices[1] + 1))]
|
||||
elif edge.vertices[0] == previous_edge.vertices[1]:
|
||||
edge_loop.append(self.file.createIfcLineIndex((edge.vertices[0] + 1, edge.vertices[1] + 1)))
|
||||
else:
|
||||
edge_loops.append(edge_loop)
|
||||
edge_loop = [self.file.createIfcLineIndex((edge.vertices[0] + 1, edge.vertices[1] + 1))]
|
||||
previous_edge = edge
|
||||
edge_loops.append(edge_loop)
|
||||
for edge_loop in edge_loops:
|
||||
curves.append(self.file.createIfcIndexedPolyCurve(points, edge_loop))
|
||||
return curves
|
||||
|
||||
def create_curves_from_mesh_ifc2x3(self, is_2d=False):
|
||||
curves = []
|
||||
points = [
|
||||
self.create_cartesian_point(v.co.x, v.co.y, v.co.z if is_2d else None)
|
||||
for v in self.settings["geometry"].vertices
|
||||
]
|
||||
coord_list = [p.Coordinates for p in points]
|
||||
edge_loops = []
|
||||
previous_edge = None
|
||||
edge_loop = []
|
||||
for edge in self.settings["geometry"].edges:
|
||||
if (Vector(coord_list[edge.vertices[0]]) - Vector(coord_list[edge.vertices[1]])).length < 0.001:
|
||||
# Maybe we should warn the user to weld vertices in this scenario?
|
||||
continue
|
||||
elif previous_edge is None:
|
||||
edge_loop = [edge.vertices]
|
||||
elif edge.vertices[0] == previous_edge.vertices[1]:
|
||||
edge_loop.append(edge.vertices)
|
||||
else:
|
||||
edge_loops.append(edge_loop)
|
||||
edge_loop = [edge.vertices]
|
||||
previous_edge = edge
|
||||
edge_loops.append(edge_loop)
|
||||
for edge_loop in edge_loops:
|
||||
loop_points = [points[p[0]] for p in edge_loop]
|
||||
loop_points.append(points[edge_loop[-1][1]])
|
||||
curves.append(self.file.createIfcPolyline(loop_points))
|
||||
return curves
|
||||
|
||||
def create_curves_from_curve(self, is_2d=False):
|
||||
results = []
|
||||
for spline in self.settings["geometry"].splines:
|
||||
# TODO: support interpolated curves, not just polylines
|
||||
points = []
|
||||
for point in spline.bezier_points:
|
||||
if is_2d:
|
||||
points.append(self.create_cartesian_point(point.co.x, point.co.y))
|
||||
else:
|
||||
points.append(self.create_cartesian_point(point.co.x, point.co.y, point.co.z))
|
||||
for point in spline.points:
|
||||
if is_2d:
|
||||
points.append(self.create_cartesian_point(point.co.x, point.co.y))
|
||||
else:
|
||||
points.append(self.create_cartesian_point(point.co.x, point.co.y, point.co.z))
|
||||
if spline.use_cyclic_u:
|
||||
points.append(points[0])
|
||||
results.append(self.file.createIfcPolyline(points))
|
||||
return results
|
||||
|
||||
def create_rectangle_extrusion_representation(self):
|
||||
helper = Helper(self.file)
|
||||
indices = helper.auto_detect_rectangle_profile_extruded_area_solid(self.settings["geometry"])
|
||||
profile_def = helper.create_rectangle_profile_def(self.settings["geometry"], indices["profile"])
|
||||
item = helper.create_extruded_area_solid(self.settings["geometry"], indices["extrusion"], profile_def)
|
||||
return self.file.createIfcShapeRepresentation(
|
||||
self.settings["context"],
|
||||
self.settings["context"].ContextIdentifier,
|
||||
"SweptSolid",
|
||||
[item],
|
||||
)
|
||||
|
||||
def create_circle_extrusion_representation(self):
|
||||
helper = Helper(self.file)
|
||||
indices = helper.auto_detect_circle_profile_extruded_area_solid(self.settings["geometry"])
|
||||
profile_def = helper.create_circle_profile_def(self.settings["geometry"], indices["profile"])
|
||||
item = helper.create_extruded_area_solid(self.settings["geometry"], indices["extrusion"], profile_def)
|
||||
return self.file.createIfcShapeRepresentation(
|
||||
self.settings["context"],
|
||||
self.settings["context"].ContextIdentifier,
|
||||
"SweptSolid",
|
||||
[item],
|
||||
)
|
||||
|
||||
def create_arbitrary_extrusion_representation(self):
|
||||
helper = Helper(self.file)
|
||||
indices = helper.auto_detect_arbitrary_closed_profile_extruded_area_solid(self.settings["geometry"])
|
||||
profile_def = helper.create_arbitrary_closed_profile_def(self.settings["geometry"], indices["profile"])
|
||||
item = helper.create_extruded_area_solid(self.settings["geometry"], indices["extrusion"], profile_def)
|
||||
return self.file.createIfcShapeRepresentation(
|
||||
self.settings["context"],
|
||||
self.settings["context"].ContextIdentifier,
|
||||
"SweptSolid",
|
||||
[item],
|
||||
)
|
||||
|
||||
def create_arbitrary_void_extrusion_representation(self):
|
||||
helper = Helper(self.file)
|
||||
indices = helper.auto_detect_arbitrary_profile_with_voids_extruded_area_solid(self.settings["geometry"])
|
||||
profile_def = helper.create_arbitrary_profile_def_with_voids(
|
||||
self.settings["geometry"], indices["profile"], indices["inner_curves"]
|
||||
)
|
||||
item = helper.create_extruded_area_solid(self.settings["geometry"], indices["extrusion"], profile_def)
|
||||
return self.file.createIfcShapeRepresentation(
|
||||
self.settings["context"],
|
||||
self.settings["context"].ContextIdentifier,
|
||||
"SweptSolid",
|
||||
[item],
|
||||
)
|
||||
|
||||
def create_mesh_representation(self):
|
||||
if self.file.schema == "IFC2X3" or self.settings["should_force_faceted_brep"]:
|
||||
return self.create_faceted_brep()
|
||||
return self.create_polygonal_face_set()
|
||||
|
||||
def create_faceted_brep(self):
|
||||
self.create_vertices()
|
||||
ifc_raw_items = [None] * self.settings["total_items"]
|
||||
for i, value in enumerate(ifc_raw_items):
|
||||
ifc_raw_items[i] = []
|
||||
for polygon in self.settings["geometry"].polygons:
|
||||
ifc_raw_items[polygon.material_index % self.settings["total_items"]].append(
|
||||
self.file.createIfcFace(
|
||||
[
|
||||
self.file.createIfcFaceOuterBound(
|
||||
self.file.createIfcPolyLoop([self.ifc_vertices[vertice] for vertice in polygon.vertices]),
|
||||
True,
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
# TODO: May not actually be a closed shell, but who checks anyway?
|
||||
items = [self.file.createIfcFacetedBrep(self.file.createIfcClosedShell(i)) for i in ifc_raw_items if i]
|
||||
return self.file.createIfcShapeRepresentation(
|
||||
self.settings["context"],
|
||||
self.settings["context"].ContextIdentifier,
|
||||
"Brep",
|
||||
items,
|
||||
)
|
||||
|
||||
def create_polygonal_face_set(self):
|
||||
ifc_raw_items = [None] * self.settings["total_items"]
|
||||
for i, value in enumerate(ifc_raw_items):
|
||||
ifc_raw_items[i] = []
|
||||
for polygon in self.settings["geometry"].polygons:
|
||||
ifc_raw_items[polygon.material_index % self.settings["total_items"]].append(
|
||||
self.file.createIfcIndexedPolygonalFace([v + 1 for v in polygon.vertices])
|
||||
)
|
||||
coordinates = self.file.createIfcCartesianPointList3D(
|
||||
[self.convert_si_to_unit(v.co) for v in self.settings["geometry"].vertices]
|
||||
)
|
||||
items = [self.file.createIfcPolygonalFaceSet(coordinates, None, i) for i in ifc_raw_items if i]
|
||||
return self.file.createIfcShapeRepresentation(
|
||||
self.settings["context"],
|
||||
self.settings["context"].ContextIdentifier,
|
||||
"Tessellation",
|
||||
items,
|
||||
)
|
||||
|
||||
def create_vertices(self, is_2d=False):
|
||||
if is_2d:
|
||||
for v in self.settings["geometry"].vertices:
|
||||
co = self.convert_si_to_unit(v.co)
|
||||
self.ifc_vertices.append(self.file.createIfcCartesianPoint((co[0], co[1])))
|
||||
return
|
||||
self.ifc_vertices.extend(
|
||||
[
|
||||
self.file.createIfcCartesianPoint(self.convert_si_to_unit(v.co))
|
||||
for v in self.settings["geometry"].vertices
|
||||
]
|
||||
)
|
||||
|
||||
def create_cartesian_point(self, x, y, z=None):
|
||||
x = self.convert_si_to_unit(x)
|
||||
y = self.convert_si_to_unit(y)
|
||||
if z is None:
|
||||
return self.file.createIfcCartesianPoint((x, y))
|
||||
z = self.convert_si_to_unit(z)
|
||||
return self.file.createIfcCartesianPoint((x, y, z))
|
||||
|
||||
def create_cartesian_point_list_from_vertices(self, vertices, is_2d=False):
|
||||
if is_2d:
|
||||
return self.file.createIfcCartesianPointList2D([self.convert_si_to_unit(v.co.xy) for v in vertices])
|
||||
return self.file.createIfcCartesianPointList3D([self.convert_si_to_unit(v.co) for v in vertices])
|
||||
|
||||
def convert_si_to_unit(self, co):
|
||||
if self.settings["coordinate_offset"]:
|
||||
return (co / self.settings["unit_scale"]) + self.settings["coordinate_offset"]
|
||||
return co / self.settings["unit_scale"]
|
||||
|
||||
def create_geometric_curve_set_representation(self, is_2d=False):
|
||||
geometric_curve_set = self.file.createIfcGeometricCurveSet(self.create_curves(is_2d=is_2d))
|
||||
return self.file.createIfcShapeRepresentation(
|
||||
self.settings["context"],
|
||||
self.settings["context"].ContextIdentifier,
|
||||
"GeometricCurveSet",
|
||||
[geometric_curve_set],
|
||||
)
|
||||
|
||||
def create_box_representation(self):
|
||||
obj = self.settings["blender_object"]
|
||||
bounding_box = self.file.createIfcBoundingBox(
|
||||
self.create_cartesian_point(obj.bound_box[0][0], obj.bound_box[0][1], obj.bound_box[0][2]),
|
||||
self.convert_si_to_unit(obj.dimensions[0]),
|
||||
self.convert_si_to_unit(obj.dimensions[1]),
|
||||
self.convert_si_to_unit(obj.dimensions[2]),
|
||||
)
|
||||
return self.file.createIfcShapeRepresentation(
|
||||
self.settings["context"],
|
||||
self.settings["context"].ContextIdentifier,
|
||||
"BoundingBox",
|
||||
[bounding_box],
|
||||
)
|
||||
|
||||
def create_structural_reference_representation(self):
|
||||
if self.settings["blender_object"].type == "EMPTY":
|
||||
return self.file.createIfcTopologyRepresentation(
|
||||
self.settings["context"],
|
||||
self.settings["context"].ContextIdentifier,
|
||||
"Vertex",
|
||||
[self.create_vertex_point(Vector((0, 0, 0)))],
|
||||
)
|
||||
return self.file.createIfcTopologyRepresentation(
|
||||
self.settings["context"],
|
||||
self.settings["context"].ContextIdentifier,
|
||||
"Edge",
|
||||
[self.create_edge()],
|
||||
)
|
||||
|
||||
def create_vertex_point(self, point):
|
||||
return self.file.createIfcVertexPoint(self.create_cartesian_point(point.x, point.y, point.z))
|
||||
|
||||
def create_edge(self):
|
||||
if hasattr(self.settings["geometry"], "splines"):
|
||||
points = self.get_spline_points(self.settings["geometry"].splines[0])
|
||||
else:
|
||||
points = self.settings["geometry"].vertices
|
||||
if not points:
|
||||
return
|
||||
return self.file.createIfcEdge(self.create_vertex_point(points[0].co), self.create_vertex_point(points[1].co))
|
||||
@@ -0,0 +1,34 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"product": None, "representation": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
if self.settings["product"].is_a("IfcProduct"):
|
||||
definition = self.settings["product"].Representation
|
||||
if not definition:
|
||||
definition = self.file.createIfcProductDefinitionShape()
|
||||
self.settings["product"].Representation = definition
|
||||
representations = list(definition.Representations) if definition.Representations else []
|
||||
representations.append(self.settings["representation"])
|
||||
definition.Representations = representations
|
||||
elif self.settings["product"].is_a("IfcTypeProduct"):
|
||||
if self.settings["product"].RepresentationMaps:
|
||||
maps = list(self.settings["product"].RepresentationMaps)
|
||||
else:
|
||||
maps = []
|
||||
self.zero = self.file.createIfcCartesianPoint((0.0, 0.0, 0.0))
|
||||
self.x_axis = self.file.createIfcDirection((1.0, 0.0, 0.0))
|
||||
self.z_axis = self.file.createIfcDirection((0.0, 0.0, 1.0))
|
||||
maps.append(
|
||||
self.file.create_entity(
|
||||
"IfcRepresentationMap",
|
||||
**{
|
||||
"MappingOrigin": self.file.createIfcAxis2Placement3D(self.zero, self.z_axis, self.x_axis),
|
||||
"MappedRepresentation": self.settings["representation"],
|
||||
}
|
||||
)
|
||||
)
|
||||
self.settings["product"].RepresentationMaps = maps
|
||||
@@ -0,0 +1,31 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"shape_representation": None,
|
||||
"styles": [],
|
||||
"should_use_presentation_style_assignment": False,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
if not self.settings["styles"]:
|
||||
return []
|
||||
self.results = []
|
||||
for element in self.file.traverse(self.settings["shape_representation"]):
|
||||
if not element.is_a("IfcShapeRepresentation"):
|
||||
continue
|
||||
for item in element.Items:
|
||||
if not item.is_a("IfcGeometricRepresentationItem"):
|
||||
continue
|
||||
style = self.settings["styles"].pop(0)
|
||||
name = style.Name
|
||||
if self.file.schema == "IFC2X3" or self.settings["should_use_presentation_style_assignment"]:
|
||||
style = self.file.createIfcPresentationStyleAssignment([style])
|
||||
self.results.append(
|
||||
self.file.createIfcStyledItem(
|
||||
item, [style], name
|
||||
)
|
||||
)
|
||||
return self.results
|
||||
@@ -0,0 +1,36 @@
|
||||
class Data:
|
||||
products = {}
|
||||
representations = {}
|
||||
|
||||
@classmethod
|
||||
def purge(cls):
|
||||
cls.products = {}
|
||||
cls.representations = {}
|
||||
|
||||
@classmethod
|
||||
def load(cls, file, product_id):
|
||||
if not file:
|
||||
return
|
||||
cls.products[product_id] = []
|
||||
product = file.by_id(product_id)
|
||||
representations = []
|
||||
if product.is_a("IfcProduct"):
|
||||
if product.Representation:
|
||||
representations = product.Representation.Representations
|
||||
else:
|
||||
representations = []
|
||||
elif product.is_a("IfcTypeProduct"):
|
||||
representations = [rm.MappedRepresentation for rm in product.RepresentationMaps or []]
|
||||
for representation in representations:
|
||||
c = representation.ContextOfItems
|
||||
rep_id = int(representation.id())
|
||||
cls.representations[rep_id] = {
|
||||
"RepresentationIdentifier": representation.RepresentationIdentifier,
|
||||
"RepresentationType": representation.RepresentationType,
|
||||
"ContextOfItems": {
|
||||
"ContextType": c.ContextType,
|
||||
"ContextIdentifier": c.ContextIdentifier,
|
||||
"TargetView": c.TargetView if c.is_a("IfcGeometricRepresentationSubContext") else "",
|
||||
}
|
||||
}
|
||||
cls.products[product_id].append(rep_id)
|
||||
@@ -0,0 +1,90 @@
|
||||
import numpy as np
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.placement
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"product": None, "matrix": np.eye(4)}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
if not hasattr(self.settings["product"], "ObjectPlacement"):
|
||||
return
|
||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
|
||||
dependent_objects = []
|
||||
if self.settings["product"].ObjectPlacement:
|
||||
for referenced_placement in self.settings["product"].ObjectPlacement.ReferencedByPlacements:
|
||||
for placed_obj in referenced_placement.PlacesObject:
|
||||
dependent_objects.append(
|
||||
{
|
||||
"product": placed_obj,
|
||||
"matrix": ifcopenshell.util.placement.get_local_placement(referenced_placement),
|
||||
}
|
||||
)
|
||||
|
||||
placement_rel_to = None
|
||||
if hasattr(self.settings["product"], "ContainedInStructure") and self.settings["product"].ContainedInStructure:
|
||||
placement_rel_to = self.settings["product"].ContainedInStructure[0].RelatingStructure.ObjectPlacement
|
||||
elif hasattr(self.settings["product"], "Decomposes") and self.settings["product"].Decomposes:
|
||||
relating_object = self.settings["product"].Decomposes[0].RelatingObject
|
||||
placement_rel_to = relating_object.ObjectPlacement if hasattr(relating_object, "ObjectPlacement") else None
|
||||
|
||||
placement = self.file.createIfcLocalPlacement(placement_rel_to, self.get_relative_placement(placement_rel_to))
|
||||
if self.settings["product"].ObjectPlacement:
|
||||
for inverse in self.file.get_inverse(self.settings["product"]):
|
||||
ifcopenshell.util.element.replace_attribute(
|
||||
inverse, self.settings["product"].ObjectPlacement, placement
|
||||
)
|
||||
old = self.settings["product"].ObjectPlacement
|
||||
old.PlacementRelTo = None
|
||||
self.settings["product"].ObjectPlacement = None
|
||||
if not self.file.get_inverse(old):
|
||||
ifcopenshell.util.element.remove_deep(self.file, old)
|
||||
self.settings["product"].ObjectPlacement = placement
|
||||
|
||||
for settings in dependent_objects:
|
||||
self.settings = settings
|
||||
self.execute()
|
||||
|
||||
return placement
|
||||
|
||||
def get_relative_placement(self, placement_rel_to):
|
||||
if placement_rel_to:
|
||||
relating_object_matrix = ifcopenshell.util.placement.get_local_placement(placement_rel_to)
|
||||
relating_object_matrix[0][3] = self.convert_unit_to_si(relating_object_matrix[0][3])
|
||||
relating_object_matrix[1][3] = self.convert_unit_to_si(relating_object_matrix[1][3])
|
||||
relating_object_matrix[2][3] = self.convert_unit_to_si(relating_object_matrix[2][3])
|
||||
else:
|
||||
relating_object_matrix = np.eye(4)
|
||||
m = self.settings["matrix"]
|
||||
x = np.array((m[0][0], m[1][0], m[2][0]))
|
||||
z = np.array((m[0][2], m[1][2], m[2][2]))
|
||||
o = np.array((m[0][3], m[1][3], m[2][3]))
|
||||
object_matrix = ifcopenshell.util.placement.a2p(o, z, x)
|
||||
relative_placement_matrix = np.linalg.inv(relating_object_matrix) @ object_matrix
|
||||
return self.create_ifc_axis_2_placement_3d(
|
||||
relative_placement_matrix[:, 3][0:3],
|
||||
relative_placement_matrix[:, 2][0:3],
|
||||
relative_placement_matrix[:, 0][0:3],
|
||||
)
|
||||
|
||||
def create_ifc_axis_2_placement_3d(self, point, up, forward):
|
||||
return self.file.createIfcAxis2Placement3D(
|
||||
self.create_cartesian_point(point),
|
||||
self.file.createIfcDirection(up.tolist()),
|
||||
self.file.createIfcDirection(forward.tolist()),
|
||||
)
|
||||
|
||||
def create_cartesian_point(self, co):
|
||||
co = self.convert_si_to_unit(co)
|
||||
return self.file.createIfcCartesianPoint(co.tolist())
|
||||
|
||||
def convert_si_to_unit(self, co):
|
||||
return co / self.unit_scale
|
||||
|
||||
def convert_unit_to_si(self, co):
|
||||
return co * self.unit_scale
|
||||
@@ -0,0 +1,35 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"representation": None}
|
||||
self.ifc_vertices = []
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
mapping_source = self.get_mapping_source()
|
||||
|
||||
if not mapping_source:
|
||||
return
|
||||
|
||||
zero = self.file.createIfcCartesianPoint((0.0, 0.0, 0.0))
|
||||
x_axis = self.file.createIfcDirection((1.0, 0.0, 0.0))
|
||||
y_axis = self.file.createIfcDirection((0.0, 1.0, 0.0))
|
||||
z_axis = self.file.createIfcDirection((0.0, 0.0, 1.0))
|
||||
|
||||
mapping_target = self.file.createIfcCartesianTransformationOperator3D(x_axis, y_axis, zero, 1, z_axis)
|
||||
mapped_item = self.file.createIfcMappedItem(mapping_source, mapping_target)
|
||||
return self.file.create_entity(
|
||||
"IfcShapeRepresentation",
|
||||
**{
|
||||
"ContextOfItems": self.settings["representation"].ContextOfItems,
|
||||
"RepresentationIdentifier": self.settings["representation"].RepresentationIdentifier,
|
||||
"RepresentationType": "MappedRepresentation",
|
||||
"Items": [mapped_item],
|
||||
}
|
||||
)
|
||||
|
||||
def get_mapping_source(self):
|
||||
for inverse in self.file.get_inverse(self.settings["representation"]):
|
||||
if inverse.is_a("IfcRepresentationMap"):
|
||||
return inverse
|
||||
@@ -0,0 +1,43 @@
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"representation": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
if self.settings["representation"].RepresentationType == "MappedRepresentation":
|
||||
return self.remove_mapped_representation_portion_only()
|
||||
return self.remove_entire_representation_tree()
|
||||
|
||||
def remove_mapped_representation_portion_only(self):
|
||||
dummy_context = self.file.create_entity("IfcRepresentationContext")
|
||||
dummy_representation_map = self.file.createIfcRepresentationMap()
|
||||
self.settings["representation"].ContextOfItems = dummy_context
|
||||
for item in self.settings["representation"].Items:
|
||||
item.MappingSource = dummy_representation_map
|
||||
ifcopenshell.util.element.remove_deep(self.file, self.settings["representation"])
|
||||
|
||||
def remove_entire_representation_tree(self):
|
||||
dummy_context = self.file.create_entity("IfcRepresentationContext")
|
||||
for subelement in self.file.traverse(self.settings["representation"]):
|
||||
if subelement.is_a("IfcRepresentationItem") and subelement.StyledByItem:
|
||||
[self.file.remove(s) for s in subelement.StyledByItem]
|
||||
elif subelement.is_a("IfcRepresentation"):
|
||||
subelement.ContextOfItems = dummy_context
|
||||
self.purge_representation_inverses(subelement)
|
||||
self.purge_representation_inverses(self.settings["representation"])
|
||||
ifcopenshell.util.element.remove_deep(self.file, self.settings["representation"])
|
||||
|
||||
def purge_representation_inverses(self, element):
|
||||
for inverse in self.file.get_inverse(element):
|
||||
if inverse.is_a("IfcPresentationLayerAssignment"):
|
||||
assigned_items = set(inverse.AssignedItems)
|
||||
if len(assigned_items) == 1:
|
||||
self.file.remove(inverse)
|
||||
else:
|
||||
assigned_items.remove(element)
|
||||
inverse.AssignedItems = list(assigned_items)
|
||||
@@ -0,0 +1,56 @@
|
||||
import ifcopenshell.api.geometry.remove_representation as remove_representation
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"product": None, "representation": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
if self.settings["product"].is_a("IfcProduct"):
|
||||
self.unassign_product_representation(self.settings["product"], self.settings["representation"])
|
||||
elif self.settings["product"].is_a("IfcTypeProduct"):
|
||||
self.unassign_type_representation()
|
||||
|
||||
def unassign_product_representation(self, product, representation):
|
||||
representations = list(product.Representation.Representations or [])
|
||||
if representation not in representations:
|
||||
return
|
||||
representations.remove(representation)
|
||||
if not representations:
|
||||
self.file.remove(product.Representation)
|
||||
else:
|
||||
product.Representation.Representations = representations
|
||||
|
||||
def unassign_type_representation(self):
|
||||
for representation_map in self.settings["product"].RepresentationMaps or []:
|
||||
if representation_map.MappedRepresentation == self.settings["representation"]:
|
||||
self.unassign_products_using_mapped_representation(representation_map)
|
||||
self.remove_representation_map_only(representation_map)
|
||||
break
|
||||
self.settings["product"].RepresentationMaps = self.settings["product"].RepresentationMaps or None
|
||||
|
||||
def remove_representation_map_only(self, representation_map):
|
||||
dummy_representation = self.file.createIfcShapeRepresentation()
|
||||
representation_map.MappedRepresentation = dummy_representation
|
||||
ifcopenshell.util.element.remove_deep(self.file, representation_map)
|
||||
self.file.remove(representation_map)
|
||||
|
||||
def unassign_products_using_mapped_representation(self, representation_map):
|
||||
mapped_representations = []
|
||||
just_representations = []
|
||||
for map_usage in representation_map.MapUsage or []:
|
||||
for inverse in self.file.get_inverse(map_usage):
|
||||
if not inverse.is_a("IfcShapeRepresentation"):
|
||||
continue
|
||||
for definition in inverse.OfProductRepresentation or []:
|
||||
for product in definition.ShapeOfProduct or []:
|
||||
mapped_representations.append({"product": product, "representation": inverse})
|
||||
just_representations.append(inverse)
|
||||
for item in mapped_representations:
|
||||
self.unassign_product_representation(item["product"], item["representation"])
|
||||
for representation in just_representations:
|
||||
remove_representation.Usecase(self.file, {"representation": representation}).execute()
|
||||
@@ -0,0 +1,20 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
|
||||
def execute(self):
|
||||
source_crs = None
|
||||
for context in self.file.by_type("IfcGeometricRepresentationContext", include_subtypes=False):
|
||||
if context.ContextType == "Model":
|
||||
source_crs = context
|
||||
break
|
||||
if not source_crs:
|
||||
return
|
||||
projected_crs = self.file.create_entity("IfcProjectedCRS", **{"Name": ""})
|
||||
self.file.create_entity("IfcMapConversion", **{
|
||||
"SourceCRS": source_crs,
|
||||
"TargetCRS": projected_crs,
|
||||
"Eastings": 0,
|
||||
"Northings": 0,
|
||||
"OrthogonalHeight": 0,
|
||||
})
|
||||
@@ -0,0 +1,31 @@
|
||||
class Data:
|
||||
is_loaded = False
|
||||
map_conversion = {}
|
||||
projected_crs = {}
|
||||
|
||||
@classmethod
|
||||
def purge(cls):
|
||||
cls.is_loaded = False
|
||||
cls.map_conversion = {}
|
||||
cls.projected_crs = {}
|
||||
|
||||
@classmethod
|
||||
def load(cls, file):
|
||||
if not file:
|
||||
return
|
||||
cls.map_conversion = {}
|
||||
cls.projected_crs = {}
|
||||
if file.schema == "IFC2X3":
|
||||
return
|
||||
for context in file.by_type("IfcGeometricRepresentationContext", include_subtypes=False):
|
||||
if not context.HasCoordinateOperation:
|
||||
continue
|
||||
map_conversion = context.HasCoordinateOperation[0]
|
||||
cls.map_conversion = map_conversion.get_info()
|
||||
cls.map_conversion["SourceCRS"] = cls.map_conversion["SourceCRS"].id()
|
||||
cls.map_conversion["TargetCRS"] = cls.map_conversion["TargetCRS"].id()
|
||||
cls.projected_crs = map_conversion.TargetCRS.get_info()
|
||||
if cls.projected_crs["MapUnit"]:
|
||||
cls.projected_crs["MapUnit"] = map_conversion.TargetCRS.MapUnit.get_info()
|
||||
break
|
||||
cls.is_loaded = True
|
||||
@@ -0,0 +1,52 @@
|
||||
import ifcopenshell.util.unit
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"map_conversion": {},
|
||||
"projected_crs": {},
|
||||
"map_unit": "",
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
map_conversion = self.file.by_type("IfcMapConversion")[0]
|
||||
projected_crs = self.file.by_type("IfcProjectedCRS")[0]
|
||||
for name, value in self.settings["map_conversion"].items():
|
||||
setattr(map_conversion, name, value)
|
||||
for name, value in self.settings["projected_crs"].items():
|
||||
setattr(projected_crs, name, value)
|
||||
self.remove_existing_map_unit(projected_crs)
|
||||
self.set_map_unit(projected_crs)
|
||||
|
||||
def remove_existing_map_unit(self, projected_crs):
|
||||
if projected_crs.MapUnit and len(self.file.get_inverse(projected_crs.MapUnit)) == 1:
|
||||
# TODO: go deeper for conversion units
|
||||
self.file.remove(projected_crs.MapUnit)
|
||||
|
||||
def set_map_unit(self, projected_crs):
|
||||
if not self.settings["map_unit"]:
|
||||
return
|
||||
|
||||
if "METRE" in self.settings["map_unit"]:
|
||||
projected_crs.MapUnit = self.file.createIfcSIUnit(
|
||||
None,
|
||||
"LENGTHUNIT",
|
||||
ifcopenshell.util.unit.get_prefix(self.settings["map_unit"]),
|
||||
ifcopenshell.util.unit.get_unit_name(self.settings["map_unit"]),
|
||||
)
|
||||
return
|
||||
|
||||
value_component = self.file.create_entity(
|
||||
"IfcReal", **{"wrappedValue": ifcopenshell.util.unit.si_conversions[self.settings["map_unit"]]}
|
||||
)
|
||||
si_unit = self.file.createIfcSIUnit(None, "LENGTHUNIT", None, "METRE")
|
||||
projected_crs.MapUnit = self.file.createIfcConversionBasedUnit(
|
||||
self.file.createIfcDimensionalExponents(1, 0, 0, 0, 0, 0, 0),
|
||||
"LENGTHUNIT",
|
||||
self.settings["map_unit"],
|
||||
self.file.createIfcMeasureWithUnit(value_component, si_unit),
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
|
||||
def execute(self):
|
||||
map_conversion = self.file.by_type("IfcMapConversion")[0]
|
||||
projected_crs = self.file.by_type("IfcProjectedCRS")[0]
|
||||
if projected_crs.MapUnit and len(self.file.get_inverse(projected_crs.MapUnit)) == 1:
|
||||
# TODO: go deeper for conversion units
|
||||
self.file.remove(projected_crs.MapUnit)
|
||||
self.file.remove(projected_crs)
|
||||
self.file.remove(map_conversion)
|
||||
@@ -0,0 +1,44 @@
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.unit
|
||||
import ifcopenshell.util.placement
|
||||
from mathutils import Matrix # For now, we depend on Blender
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"AxisCurve": None, # A Blender object
|
||||
"grid_axis": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
if self.settings["grid_axis"].AxisCurve:
|
||||
ifcopenshell.util.element.remove_deep(self.file, self.settings["grid_axis"].AxisCurve)
|
||||
|
||||
self.settings["unit_scale"] = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
grid = [i for i in self.file.get_inverse(self.settings["grid_axis"]) if i.is_a("IfcGrid")][0]
|
||||
points = [
|
||||
Matrix(ifcopenshell.util.placement.get_local_placement(grid.ObjectPlacement)).inverted()
|
||||
@ (self.settings["AxisCurve"].matrix_world @ v.co)
|
||||
for v in self.settings["AxisCurve"].data.vertices[0:2]
|
||||
]
|
||||
self.settings["grid_axis"].AxisCurve = self.file.createIfcPolyline(
|
||||
[
|
||||
self.create_cartesian_point(points[0][0], points[0][1], points[0][2]),
|
||||
self.create_cartesian_point(points[1][0], points[1][1], points[1][2]),
|
||||
]
|
||||
)
|
||||
|
||||
def create_cartesian_point(self, x, y, z=None):
|
||||
x = self.convert_si_to_unit(x)
|
||||
y = self.convert_si_to_unit(y)
|
||||
if z is None:
|
||||
return self.file.createIfcCartesianPoint((x, y))
|
||||
z = self.convert_si_to_unit(z)
|
||||
return self.file.createIfcCartesianPoint((x, y, z))
|
||||
|
||||
def convert_si_to_unit(self, co):
|
||||
return co / self.settings["unit_scale"]
|
||||
@@ -0,0 +1,21 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"AxisTag": "A",
|
||||
"SameSense": True,
|
||||
"UVWAxes": "UAxes", # Choose which axes
|
||||
"Grid": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
element = self.file.create_entity("IfcGridAxis", **{
|
||||
"AxisTag": self.settings["AxisTag"],
|
||||
"SameSense": self.settings["SameSense"]
|
||||
})
|
||||
axes = list(getattr(self.settings["Grid"], self.settings["UVWAxes"]) or [])
|
||||
axes.append(element)
|
||||
setattr(self.settings["Grid"], self.settings["UVWAxes"], axes)
|
||||
return element
|
||||
@@ -0,0 +1,17 @@
|
||||
import ifcopenshell
|
||||
from ifcopenshell.api.owner.api import create_owner_history
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings={}):
|
||||
self.file = file
|
||||
self.settings = {}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
return self.file.create_entity("IfcGroup", **{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"OwnerHistory": create_owner_history(),
|
||||
"Name": "Unnamed"
|
||||
})
|
||||
@@ -0,0 +1,28 @@
|
||||
import ifcopenshell
|
||||
from ifcopenshell.api.owner.api import create_owner_history
|
||||
from ifcopenshell.api.owner.api import update_owner_history
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": None,
|
||||
"group": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
if not self.settings["group"].IsGroupedBy:
|
||||
return self.file.create_entity("IfcRelAssignsToGroup", **{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"OwnerHistory": create_owner_history(),
|
||||
"RelatedObjects": [self.settings["product"]],
|
||||
"RelatingGroup": self.settings["group"]
|
||||
})
|
||||
rel = self.settings["group"].IsGroupedBy[0]
|
||||
related_objects = set(rel.RelatedObjects) or set()
|
||||
related_objects.add(self.settings["product"])
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
update_owner_history(rel)
|
||||
@@ -0,0 +1,24 @@
|
||||
class Data:
|
||||
is_loaded = False
|
||||
products = {}
|
||||
groups = {}
|
||||
|
||||
@classmethod
|
||||
def purge(cls):
|
||||
cls.is_loaded = False
|
||||
cls.products = {}
|
||||
cls.groups = {}
|
||||
|
||||
@classmethod
|
||||
def load(cls, file):
|
||||
cls.products = {}
|
||||
cls.groups = {}
|
||||
for group in file.by_type("IfcGroup", include_subtypes=False):
|
||||
if group.IsGroupedBy:
|
||||
for rel in group.IsGroupedBy:
|
||||
for product in rel.RelatedObjects:
|
||||
cls.products.setdefault(product.id(), []).append(group.id())
|
||||
data = group.get_info()
|
||||
del data["OwnerHistory"]
|
||||
cls.groups[group.id()] = data
|
||||
cls.is_loaded=True
|
||||
@@ -0,0 +1,13 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"group": None,
|
||||
"attributes": {}
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["group"], name, value)
|
||||
@@ -0,0 +1,11 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"group": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for rel in self.settings["group"].IsGroupedBy or []:
|
||||
self.file.remove(rel)
|
||||
self.file.remove(self.settings["group"])
|
||||
@@ -0,0 +1,25 @@
|
||||
import ifcopenshell
|
||||
from ifcopenshell.api.owner.api import update_owner_history
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": None,
|
||||
"group": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
if not self.settings["group"].IsGroupedBy:
|
||||
return
|
||||
rel = self.settings["group"].IsGroupedBy[0]
|
||||
related_objects = set(rel.RelatedObjects) or set()
|
||||
related_objects.remove(self.settings["product"])
|
||||
if len(related_objects):
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
update_owner_history(rel)
|
||||
else:
|
||||
self.file.remove(rel)
|
||||
@@ -0,0 +1,11 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings={}):
|
||||
self.file = file
|
||||
self.settings = {}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
return self.file.create_entity("IfcPresentationLayerAssignment", **{
|
||||
"Name": "Unnamed"
|
||||
})
|
||||
@@ -0,0 +1,17 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"item": None,
|
||||
"layer": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
assigned_items = set(self.settings["layer"].AssignedItems) or set()
|
||||
assigned_items.add(self.settings["item"])
|
||||
self.settings["layer"].AssignedItems = list(assigned_items)
|
||||
@@ -0,0 +1,35 @@
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.date
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class Data:
|
||||
is_loaded = False
|
||||
items = {}
|
||||
layers = {}
|
||||
|
||||
@classmethod
|
||||
def purge(cls):
|
||||
cls.is_loaded = False
|
||||
cls.items = {}
|
||||
cls.layers = {}
|
||||
|
||||
@classmethod
|
||||
def load(cls, file):
|
||||
cls._file = file
|
||||
if not cls._file:
|
||||
return
|
||||
cls.load_layers()
|
||||
cls.is_loaded = True
|
||||
|
||||
@classmethod
|
||||
def load_layers(cls):
|
||||
cls.layers = {}
|
||||
cls.items = {}
|
||||
for layer in cls._file.by_type("IfcPresentationLayerAssignment"):
|
||||
data = layer.get_info()
|
||||
if layer.AssignedItems:
|
||||
for item in layer.AssignedItems:
|
||||
cls.items.setdefault(item.id(), []).append(layer.id())
|
||||
del data["AssignedItems"]
|
||||
cls.layers[layer.id()] = data
|
||||
@@ -0,0 +1,13 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"layer": None,
|
||||
"attributes": {}
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["layer"], name, value)
|
||||
@@ -0,0 +1,9 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"layer": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
self.file.remove(self.settings["layer"])
|
||||
@@ -0,0 +1,17 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"item": None,
|
||||
"layer": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
assigned_items = set(self.settings["layer"].AssignedItems) or set()
|
||||
assigned_items.remove(self.settings["item"])
|
||||
self.settings["layer"].AssignedItems = list(assigned_items)
|
||||
@@ -0,0 +1,16 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"constituent_set": None, "material": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
constituents = list(self.settings["constituent_set"].MaterialConstituents or [])
|
||||
constituent = self.file.create_entity("IfcMaterialConstituent", **{"Material": self.settings["material"]})
|
||||
constituents.append(constituent)
|
||||
self.settings["constituent_set"].MaterialConstituents = constituents
|
||||
return constituent
|
||||
@@ -0,0 +1,19 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"layer_set": None, "material": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
layers = list(self.settings["layer_set"].MaterialLayers or [])
|
||||
layer = self.file.create_entity("IfcMaterialLayer", **{
|
||||
"Material": self.settings["material"],
|
||||
"LayerThickness": 0.
|
||||
})
|
||||
layers.append(layer)
|
||||
self.settings["layer_set"].MaterialLayers = layers
|
||||
return layer
|
||||
@@ -0,0 +1,14 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"material_list": None, "material": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
materials = list(self.settings["material_list"].Materials or [])
|
||||
materials.append(self.settings["material"])
|
||||
self.settings["material_list"].Materials = materials
|
||||
@@ -0,0 +1,12 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"Name": "Unnamed"}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
return self.file.create_entity("IfcMaterial", **{"Name": self.settings["Name"] or "Unnamed"})
|
||||
@@ -0,0 +1,67 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"product": None, "type": "IfcMaterial", "material": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
if self.settings["type"] == "IfcMaterial":
|
||||
self.assign_ifc_material()
|
||||
elif self.settings["type"] == "IfcMaterialConstituentSet":
|
||||
material_set = self.file.create_entity(self.settings["type"])
|
||||
self.create_material_association(material_set)
|
||||
elif self.settings["type"] == "IfcMaterialLayerSet":
|
||||
material_set = self.file.create_entity(self.settings["type"])
|
||||
self.create_material_association(material_set)
|
||||
elif self.settings["type"] == "IfcMaterialLayerSetUsage":
|
||||
material_set = self.file.create_entity("IfcMaterialLayerSet")
|
||||
material_set_usage = self.create_layer_set_usage(material_set)
|
||||
self.create_material_association(material_set_usage)
|
||||
elif self.settings["type"] == "IfcMaterialProfileSet":
|
||||
material_set = self.file.create_entity(self.settings["type"])
|
||||
self.create_material_association(material_set)
|
||||
elif self.settings["type"] == "IfcMaterialList":
|
||||
material_set = self.file.create_entity(self.settings["type"])
|
||||
material_set.Materials = [self.settings["material"]]
|
||||
self.create_material_association(material_set)
|
||||
|
||||
def create_layer_set_usage(self, material_set):
|
||||
return self.file.create_entity("IfcMaterialLayerSetUsage", **{
|
||||
"ForLayerSet": material_set,
|
||||
"LayerSetDirection": "AXIS2" if self.settings["product"].is_a("IfcWall") else "AXIS3",
|
||||
"DirectionSense": "POSITIVE",
|
||||
"OffsetFromReferenceLine": 0
|
||||
})
|
||||
|
||||
def assign_ifc_material(self):
|
||||
rel = self.get_rel_associates_material(self.settings["material"])
|
||||
if not rel:
|
||||
return self.create_material_association(self.settings["material"])
|
||||
related_objects = list(rel.RelatedObjects)
|
||||
related_objects.append(self.settings["product"])
|
||||
rel.RelatedObjects = related_objects
|
||||
|
||||
def create_material_association(self, relating_material):
|
||||
return self.file.create_entity(
|
||||
"IfcRelAssociatesMaterial",
|
||||
**{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"RelatedObjects": [self.settings["product"]],
|
||||
"RelatingMaterial": relating_material,
|
||||
}
|
||||
)
|
||||
|
||||
def get_rel_associates_material(self, material):
|
||||
if self.file.schema == "IFC2X3":
|
||||
rel = [
|
||||
r
|
||||
for r in self.file.by_type("IfcRelAssociatesMaterial")
|
||||
if r.RelatingMaterial == self.settings["material"]
|
||||
]
|
||||
return rel[0] if rel else None
|
||||
if self.settings["material"].AssociatedTo:
|
||||
return self.settings["material"].AssociatedTo[0]
|
||||
@@ -0,0 +1,114 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Data:
|
||||
is_loaded = False
|
||||
materials = {}
|
||||
constituent_sets = {}
|
||||
constituents = {}
|
||||
layer_sets = {}
|
||||
layers = {}
|
||||
profile_sets = {}
|
||||
profiles = {}
|
||||
lists = {}
|
||||
products = {}
|
||||
_file = None
|
||||
|
||||
@classmethod
|
||||
def purge(cls):
|
||||
cls.is_loaded = False
|
||||
cls.materials = {}
|
||||
cls.constituent_sets = {}
|
||||
cls.constituents = {}
|
||||
cls.layer_set_usages = {}
|
||||
cls.layer_sets = {}
|
||||
cls.layers = {}
|
||||
cls.profile_sets = {}
|
||||
cls.profiles = {}
|
||||
cls.lists = {}
|
||||
cls.products = {}
|
||||
cls._file = None
|
||||
|
||||
@classmethod
|
||||
def load(cls, file, product_id=None):
|
||||
cls._file = file
|
||||
if not cls._file:
|
||||
return
|
||||
if product_id:
|
||||
return cls.load_product_material(product_id)
|
||||
cls.load_materials()
|
||||
cls.load_constituents()
|
||||
cls.load_layers()
|
||||
cls.load_layer_usages()
|
||||
cls.load_profiles()
|
||||
cls.load_lists()
|
||||
cls.is_loaded = True
|
||||
|
||||
@classmethod
|
||||
def load_materials(cls):
|
||||
cls.materials = {}
|
||||
cls.load_element("IfcMaterial", cls.materials)
|
||||
|
||||
@classmethod
|
||||
def load_constituents(cls):
|
||||
cls.constituent_sets = {}
|
||||
cls.constituents = {}
|
||||
cls.load_element("IfcMaterialConstituent", cls.constituents)
|
||||
cls.load_element("IfcMaterialConstituentSet", cls.constituent_sets)
|
||||
|
||||
@classmethod
|
||||
def load_layers(cls):
|
||||
cls.layer_sets = {}
|
||||
cls.layers = {}
|
||||
cls.load_element("IfcMaterialLayer", cls.layers)
|
||||
cls.load_element("IfcMaterialLayerSet", cls.layer_sets)
|
||||
|
||||
@classmethod
|
||||
def load_layer_usages(cls):
|
||||
cls.layer_set_usages = {}
|
||||
cls.load_element("IfcMaterialLayerSetUsage", cls.layer_set_usages)
|
||||
|
||||
@classmethod
|
||||
def load_profiles(cls):
|
||||
cls.profile_sets = {}
|
||||
cls.profiles = {}
|
||||
cls.load_element("IfcMaterialProfile", cls.profiles)
|
||||
cls.load_element("IfcMaterialProfileSet", cls.profile_sets)
|
||||
|
||||
@classmethod
|
||||
def load_lists(cls):
|
||||
cls.lists = {}
|
||||
cls.load_element("IfcMaterialList", cls.lists)
|
||||
|
||||
@classmethod
|
||||
def load_product_material(cls, product_id):
|
||||
cls.products[product_id] = {}
|
||||
for association in cls._file.by_id(product_id).HasAssociations:
|
||||
if association.is_a("IfcRelAssociatesMaterial"):
|
||||
cls.load_association(association, product_id)
|
||||
|
||||
@classmethod
|
||||
def load_element(cls, ifc_class, to_dict):
|
||||
try:
|
||||
elements = cls._file.by_type(ifc_class)
|
||||
except:
|
||||
return
|
||||
for element in elements:
|
||||
to_dict[element.id()] = cls.get_simple_info(element)
|
||||
|
||||
@classmethod
|
||||
def get_simple_info(cls, element):
|
||||
info = element.get_info()
|
||||
for key, value in info.items():
|
||||
if isinstance(value, ifcopenshell.entity_instance):
|
||||
info[key] = value.id()
|
||||
elif isinstance(value, tuple) and value and isinstance(value[0], ifcopenshell.entity_instance):
|
||||
info[key] = [v.id() for v in value]
|
||||
return info
|
||||
|
||||
@classmethod
|
||||
def load_association(cls, association, product_id):
|
||||
material_select = association.RelatingMaterial
|
||||
if material_select.is_a("IfcMaterialProfileSetUsage"): # TODO: implement usages
|
||||
material_select = material_select.ForProfileSet
|
||||
cls.products[product_id] = {"type": material_select.is_a(), "id": material_select.id()}
|
||||
@@ -0,0 +1,13 @@
|
||||
class Usecase():
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"element": None,
|
||||
"attributes": {}
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["element"], name, value)
|
||||
@@ -0,0 +1,15 @@
|
||||
class Usecase():
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"constituent": None,
|
||||
"attributes": {},
|
||||
"material": None
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["constituent"], name, value)
|
||||
self.settings["constituent"].Material = self.settings["material"]
|
||||
@@ -0,0 +1,15 @@
|
||||
class Usecase():
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"layer": None,
|
||||
"attributes": {},
|
||||
"material": None
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["layer"], name, value)
|
||||
self.settings["layer"].Material = self.settings["material"]
|
||||
@@ -0,0 +1,15 @@
|
||||
class Usecase():
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"profile": None,
|
||||
"attributes": {},
|
||||
"material": None
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["profile"], name, value)
|
||||
self.settings["profile"].Material = self.settings["material"]
|
||||
@@ -0,0 +1,12 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"constituent": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
self.file.remove(self.settings["constituent"])
|
||||
@@ -0,0 +1,12 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"layer": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
self.file.remove(self.settings["layer"])
|
||||
@@ -0,0 +1,13 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"material_list": None, "material": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
materials = [m for m in self.settings["material_list"].Materials if m != self.settings["material"]]
|
||||
self.settings["material_list"].Materials = materials
|
||||
@@ -0,0 +1,23 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"material": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
inverse_elements = self.file.get_inverse(self.settings["material"])
|
||||
self.file.remove(self.settings["material"])
|
||||
# TODO: this is probably not robust enough
|
||||
for inverse in inverse_elements:
|
||||
if inverse.is_a("IfcMaterialConstituent"):
|
||||
self.file.remove(inverse)
|
||||
elif inverse.is_a("IfcMaterialLayer"):
|
||||
self.file.remove(inverse)
|
||||
elif inverse.is_a("IfcMaterialProfile"):
|
||||
self.file.remove(inverse)
|
||||
elif inverse.is_a("IfcRelAssociatesMaterial"):
|
||||
self.file.remove(inverse)
|
||||
@@ -0,0 +1,19 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"material_set": None, "old_index": 0, "new_index": 0}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
if self.settings["material_set"].is_a("IfcMaterialConstituentSet"):
|
||||
set_name = "MaterialConstituents"
|
||||
elif self.settings["material_set"].is_a("IfcMaterialLayerSet"):
|
||||
set_name = "MaterialLayers"
|
||||
elif self.settings["material_set"].is_a("IfcMaterialProfileSet"):
|
||||
set_name = "MaterialProfiles"
|
||||
elif self.settings["material_set"].is_a("IfcMaterialList"):
|
||||
set_name = "Materials"
|
||||
items = list(getattr(self.settings["material_set"], set_name) or [])
|
||||
items.insert(self.settings["new_index"], items.pop(self.settings["old_index"]))
|
||||
setattr(self.settings["material_set"], set_name, items)
|
||||
@@ -0,0 +1,14 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"product": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for association in self.settings["product"].HasAssociations:
|
||||
if association.is_a("IfcRelAssociatesMaterial"):
|
||||
self.file.remove(association)
|
||||
@@ -0,0 +1,11 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"assigned_object": None, "ifc_class": "IfcPostalAddress"}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
addresses = list(self.settings["assigned_object"].Addresses) if self.settings["assigned_object"].Addresses else []
|
||||
addresses.append(self.file.create_entity(self.settings["ifc_class"], "OFFICE"))
|
||||
self.settings["assigned_object"].Addresses = addresses
|
||||
@@ -0,0 +1,6 @@
|
||||
class Usecase:
|
||||
def __init__(self, file):
|
||||
self.file = file
|
||||
|
||||
def execute(self):
|
||||
self.file.createIfcOrganization("APTR", "Aperture Science")
|
||||
@@ -0,0 +1,6 @@
|
||||
class Usecase:
|
||||
def __init__(self, file):
|
||||
self.file = file
|
||||
|
||||
def execute(self):
|
||||
self.file.createIfcPerson("HSeldon", "Seldon", "Hari")
|
||||
@@ -0,0 +1,11 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"assigned_object": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
roles = list(self.settings["assigned_object"].Roles) if self.settings["assigned_object"].Roles else []
|
||||
roles.append(self.file.createIfcActorRole("ARCHITECT"))
|
||||
self.settings["assigned_object"].Roles = roles
|
||||
@@ -0,0 +1,62 @@
|
||||
import bpy
|
||||
import time
|
||||
import addon_utils
|
||||
import ifcopenshell.api.owner.create_owner_history as create_owner_history_usecase
|
||||
import ifcopenshell.api.owner.update_owner_history as update_owner_history_usecase
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
def update_owner_history(element, change_action=None):
|
||||
if not element.OwnerHistory:
|
||||
element.OwnerHistory = create_owner_history()
|
||||
return
|
||||
file = IfcStore.get_file()
|
||||
return update_owner_history_usecase.Usecase(
|
||||
file,
|
||||
{
|
||||
"element": element,
|
||||
"person": file.by_id(int(bpy.context.scene.BIMOwnerProperties.user_person)),
|
||||
"organisation": file.by_id(int(bpy.context.scene.BIMOwnerProperties.user_organisation)),
|
||||
"ApplicationIdentifier": "BlenderBIM",
|
||||
"ApplicationFullName": "BlenderBIM Add-on",
|
||||
"Version": get_application_version(),
|
||||
"ChangeAction": change_action or "MODIFIED",
|
||||
},
|
||||
).execute()
|
||||
|
||||
|
||||
def create_owner_history(change_action=None):
|
||||
file = IfcStore.get_file()
|
||||
|
||||
if (
|
||||
not bpy.context.scene.BIMOwnerProperties.user_person
|
||||
or not bpy.context.scene.BIMOwnerProperties.user_organisation
|
||||
):
|
||||
if file.schema == "IFC2X3":
|
||||
assert False, "A person and organisation is required in IFC2X3."
|
||||
return None
|
||||
|
||||
return create_owner_history_usecase.Usecase(
|
||||
file,
|
||||
{
|
||||
"person": file.by_id(int(bpy.context.scene.BIMOwnerProperties.user_person)),
|
||||
"organisation": file.by_id(int(bpy.context.scene.BIMOwnerProperties.user_organisation)),
|
||||
"ApplicationIdentifier": "BlenderBIM",
|
||||
"ApplicationFullName": "BlenderBIM Add-on",
|
||||
"Version": get_application_version(),
|
||||
"ChangeAction": change_action or "ADDED",
|
||||
},
|
||||
).execute()
|
||||
|
||||
|
||||
def get_application_version():
|
||||
return ".".join(
|
||||
[
|
||||
str(x)
|
||||
for x in [
|
||||
addon.bl_info.get("version", (-1, -1, -1))
|
||||
for addon in addon_utils.modules()
|
||||
if addon.bl_info["name"] == "BlenderBIM"
|
||||
][0]
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,101 @@
|
||||
import time
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"person": None,
|
||||
"organisation": None,
|
||||
"ApplicationIdentifier": "",
|
||||
"ApplicationFullName": "",
|
||||
"Version": "",
|
||||
"ChangeAction": "NOTDEFINED",
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
user = self.get_user()
|
||||
application = self.get_application()
|
||||
return self.file.create_entity(
|
||||
"IfcOwnerHistory",
|
||||
**{
|
||||
"OwningUser": user,
|
||||
"OwningApplication": application,
|
||||
"State": "READWRITE",
|
||||
"ChangeAction": self.settings["ChangeAction"],
|
||||
"LastModifiedDate": int(time.time()),
|
||||
"LastModifyingUser": user,
|
||||
"LastModifyingApplication": application,
|
||||
"CreationDate": int(time.time()),
|
||||
},
|
||||
)
|
||||
|
||||
def get_user(self):
|
||||
for element in self.file.by_type("IfcPersonAndOrganization"):
|
||||
if (
|
||||
element.ThePerson == self.settings["person"]
|
||||
and element.TheOrganization == self.settings["organisation"]
|
||||
):
|
||||
return element
|
||||
return self.file.create_entity(
|
||||
"IfcPersonAndOrganization",
|
||||
**{"ThePerson": self.settings["person"], "TheOrganization": self.settings["organisation"]},
|
||||
)
|
||||
|
||||
def get_application(self):
|
||||
for element in self.file.by_type("IfcApplication"):
|
||||
if element.ApplicationIdentifier == self.settings["ApplicationIdentifier"]:
|
||||
return element
|
||||
return self.file.create_entity(
|
||||
"IfcApplication",
|
||||
**{
|
||||
"ApplicationDeveloper": self.get_application_organisation(),
|
||||
"Version": self.settings["Version"],
|
||||
"ApplicationFullName": self.settings["ApplicationFullName"],
|
||||
"ApplicationIdentifier": self.settings["ApplicationIdentifier"],
|
||||
},
|
||||
)
|
||||
|
||||
def get_application_organisation(self):
|
||||
return self.file.create_entity(
|
||||
"IfcOrganization",
|
||||
**{
|
||||
"Name": "IfcOpenShell",
|
||||
"Description": "IfcOpenShell is an open source (LGPL) software library that helps users and software developers to work with the IFC file format.",
|
||||
"Roles": [
|
||||
self.file.create_entity("IfcActorRole", **{"Role": "USERDEFINED", "UserDefinedRole": "CONTRIBUTOR"})
|
||||
],
|
||||
"Addresses": [
|
||||
self.file.create_entity(
|
||||
"IfcTelecomAddress",
|
||||
**{
|
||||
"Purpose": "USERDEFINED",
|
||||
"UserDefinedPurpose": "WEBPAGE",
|
||||
"Description": "The main webpage of the software collection.",
|
||||
"WWWHomePageURL": "https://ifcopenshell.org",
|
||||
},
|
||||
),
|
||||
self.file.create_entity(
|
||||
"IfcTelecomAddress",
|
||||
**{
|
||||
"Purpose": "USERDEFINED",
|
||||
"UserDefinedPurpose": "WEBPAGE",
|
||||
"Description": "The BlenderBIM Add-on webpage of the software collection.",
|
||||
"WWWHomePageURL": "https://blenderbim.org",
|
||||
},
|
||||
),
|
||||
self.file.create_entity(
|
||||
"IfcTelecomAddress",
|
||||
**{
|
||||
"Purpose": "USERDEFINED",
|
||||
"UserDefinedPurpose": "REPOSITORY",
|
||||
"Description": "The source code repository of the software collection.",
|
||||
"WWWHomePageURL": "https://github.com/IfcOpenShell/IfcOpenShell.git",
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,65 @@
|
||||
class Data:
|
||||
is_loaded = False
|
||||
people = {}
|
||||
organisations = {}
|
||||
addresses = {}
|
||||
roles = {}
|
||||
|
||||
@classmethod
|
||||
def purge(cls):
|
||||
cls.is_loaded = False
|
||||
cls.people = {}
|
||||
cls.organisations = {}
|
||||
cls.addresses = {}
|
||||
cls.roles = {}
|
||||
|
||||
@classmethod
|
||||
def load(cls, file):
|
||||
if not file:
|
||||
return
|
||||
cls.people = {}
|
||||
cls.organisations = {}
|
||||
cls.addresses = {}
|
||||
cls.roles = {}
|
||||
for person in file.by_type("IfcPerson"):
|
||||
data = person.get_info()
|
||||
data["is_engaged"] = bool(person.EngagedIn)
|
||||
cls.people[person.id()] = data
|
||||
|
||||
roles = []
|
||||
if data["Roles"]:
|
||||
for role in data["Roles"]:
|
||||
roles.append(role.id())
|
||||
data["Roles"] = roles
|
||||
|
||||
addresses = []
|
||||
if data["Addresses"]:
|
||||
for address in data["Addresses"]:
|
||||
addresses.append(address.id())
|
||||
data["Addresses"] = addresses
|
||||
|
||||
for organisation in file.by_type("IfcOrganization"):
|
||||
data = organisation.get_info()
|
||||
data["is_engaged"] = (
|
||||
bool(organisation.IsRelatedBy) or bool(organisation.Relates) or bool(organisation.Engages)
|
||||
)
|
||||
cls.organisations[organisation.id()] = data
|
||||
|
||||
roles = []
|
||||
if data["Roles"]:
|
||||
for role in data["Roles"]:
|
||||
roles.append(role.id())
|
||||
data["Roles"] = roles
|
||||
|
||||
addresses = []
|
||||
if data["Addresses"]:
|
||||
for address in data["Addresses"]:
|
||||
addresses.append(address.id())
|
||||
data["Addresses"] = addresses
|
||||
|
||||
for address in file.by_type("IfcAddress"):
|
||||
cls.addresses[address.id()] = address.get_info()
|
||||
|
||||
for role in file.by_type("IfcActorRole"):
|
||||
cls.roles[role.id()] = role.get_info()
|
||||
cls.is_loaded = True
|
||||
@@ -0,0 +1,13 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"address": None,
|
||||
"attributes": {}
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["address"], name, value)
|
||||
@@ -0,0 +1,13 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"organisation": None,
|
||||
"attributes": {}
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["organisation"], name, value)
|
||||
@@ -0,0 +1,13 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"person": None,
|
||||
"attributes": {}
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["person"], name, value)
|
||||
@@ -0,0 +1,13 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"role": None,
|
||||
"attributes": {}
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["role"], name, value)
|
||||
@@ -0,0 +1,9 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"address": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
self.file.remove(self.settings["address"])
|
||||
@@ -0,0 +1,9 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"organisation": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
self.file.remove(self.settings["organisation"])
|
||||
@@ -0,0 +1,9 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"person": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
self.file.remove(self.settings["person"])
|
||||
@@ -0,0 +1,9 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"role": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
self.file.remove(self.settings["role"])
|
||||
@@ -0,0 +1,99 @@
|
||||
import time
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"OwnerHistory": None,
|
||||
"person": None,
|
||||
"organisation": None,
|
||||
"ApplicationIdentifier": "",
|
||||
"ApplicationFullName": "",
|
||||
"Version": "",
|
||||
"ChangeAction": "NOTDEFINED",
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
if len(self.file.get_inverse(self.settings["element"].OwnerHistory)) > 1:
|
||||
old_history = self.settings["element"].OwnerHistory
|
||||
self.settings["element"].OwnerHistory = self.file.create_entity("IfcOwnerHistory")
|
||||
for i, attribute in enumerate(old_history):
|
||||
self.settings["element"].OwnerHistory[i] = attribute
|
||||
user = self.get_user()
|
||||
application = self.get_application()
|
||||
self.settings["element"].OwnerHistory.ChangeAction = self.settings["ChangeAction"]
|
||||
self.settings["element"].OwnerHistory.LastModifiedDate = int(time.time())
|
||||
self.settings["element"].OwnerHistory.LastModifyingUser = user
|
||||
self.settings["element"].OwnerHistory.LastModifyingApplication = application
|
||||
return self.settings["OwnerHistory"]
|
||||
|
||||
def get_user(self):
|
||||
for element in self.file.by_type("IfcPersonAndOrganization"):
|
||||
if (
|
||||
element.ThePerson == self.settings["person"]
|
||||
and element.TheOrganization == self.settings["organisation"]
|
||||
):
|
||||
return element
|
||||
return self.file.create_entity(
|
||||
"IfcPersonAndOrganization",
|
||||
**{"ThePerson": self.settings["person"], "TheOrganization": self.settings["organisation"]},
|
||||
)
|
||||
|
||||
def get_application(self):
|
||||
for element in self.file.by_type("IfcApplication"):
|
||||
if element.ApplicationIdentifier == self.settings["ApplicationIdentifier"]:
|
||||
return element
|
||||
return self.file.create_entity(
|
||||
"IfcApplication",
|
||||
**{
|
||||
"ApplicationDeveloper": self.get_application_organisation(),
|
||||
"Version": self.settings["Version"],
|
||||
"ApplicationFullName": self.settings["ApplicationFullName"],
|
||||
"ApplicationIdentifier": self.settings["ApplicationIdentifier"],
|
||||
},
|
||||
)
|
||||
|
||||
def get_application_organisation(self):
|
||||
return self.file.create_entity(
|
||||
"IfcOrganization",
|
||||
**{
|
||||
"Name": "IfcOpenShell",
|
||||
"Description": "IfcOpenShell is an open source (LGPL) software library that helps users and software developers to work with the IFC file format.",
|
||||
"Roles": [
|
||||
self.file.create_entity("IfcActorRole", **{"Role": "USERDEFINED", "UserDefinedRole": "CONTRIBUTOR"})
|
||||
],
|
||||
"Addresses": [
|
||||
self.file.create_entity(
|
||||
"IfcTelecomAddress",
|
||||
**{
|
||||
"Purpose": "USERDEFINED",
|
||||
"UserDefinedPurpose": "WEBPAGE",
|
||||
"Description": "The main webpage of the software collection.",
|
||||
"WWWHomePageURL": "https://ifcopenshell.org",
|
||||
},
|
||||
),
|
||||
self.file.create_entity(
|
||||
"IfcTelecomAddress",
|
||||
**{
|
||||
"Purpose": "USERDEFINED",
|
||||
"UserDefinedPurpose": "WEBPAGE",
|
||||
"Description": "The BlenderBIM Add-on webpage of the software collection.",
|
||||
"WWWHomePageURL": "https://blenderbim.org",
|
||||
},
|
||||
),
|
||||
self.file.create_entity(
|
||||
"IfcTelecomAddress",
|
||||
**{
|
||||
"Purpose": "USERDEFINED",
|
||||
"UserDefinedPurpose": "REPOSITORY",
|
||||
"Description": "The source code repository of the software collection.",
|
||||
"WWWHomePageURL": "https://github.com/IfcOpenShell/IfcOpenShell.git",
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,25 @@
|
||||
import datetime
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, settings=None):
|
||||
self.settings = {"version": "IFC4"}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
self.file = ifcopenshell.file(schema=self.settings["version"])
|
||||
# TODO: add all metadata, pending bug #747
|
||||
self.file.wrapped_data.header.file_name.name = "/dev/null" # Hehehe
|
||||
self.file.wrapped_data.header.file_name.time_stamp = (
|
||||
datetime.datetime.utcnow()
|
||||
.replace(tzinfo=datetime.timezone.utc)
|
||||
.astimezone()
|
||||
.replace(microsecond=0)
|
||||
.isoformat()
|
||||
)
|
||||
self.file.wrapped_data.header.file_name.preprocessor_version = "IfcOpenShell {}".format(ifcopenshell.version)
|
||||
self.file.wrapped_data.header.file_name.originating_system = "IfcOpenShell {}".format(ifcopenshell.version)
|
||||
self.file.wrapped_data.header.file_name.authorization = "Nobody"
|
||||
return self.file
|
||||
@@ -0,0 +1,40 @@
|
||||
import ifcopenshell
|
||||
import blenderbim.bim.schema # TODO: refactor
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"product": None, "Name": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
if self.settings["product"].is_a("IfcObject"):
|
||||
pset = self.file.create_entity(
|
||||
"IfcPropertySet", **{"GlobalId": ifcopenshell.guid.new(), "Name": self.settings["Name"]}
|
||||
)
|
||||
self.file.create_entity(
|
||||
"IfcRelDefinesByProperties",
|
||||
**{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
# TODO: owner history
|
||||
"RelatedObjects": [self.settings["product"]],
|
||||
"RelatingPropertyDefinition": pset,
|
||||
}
|
||||
)
|
||||
elif self.settings["product"].is_a("IfcTypeObject"):
|
||||
pset = self.file.create_entity(
|
||||
"IfcPropertySet", **{"GlobalId": ifcopenshell.guid.new(), "Name": self.settings["Name"]}
|
||||
)
|
||||
has_property_sets = list(self.settings["product"].HasPropertySets)
|
||||
has_property_sets.append(pset)
|
||||
self.settings["product"].HasPropertySets = has_property_sets
|
||||
elif self.settings["product"].is_a("IfcMaterialDefinition"):
|
||||
pset = self.file.create_entity(
|
||||
"IfcMaterialProperties",
|
||||
**{
|
||||
"Name": self.settings["Name"],
|
||||
"Material": self.settings["product"],
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,25 @@
|
||||
import ifcopenshell
|
||||
import blenderbim.bim.schema # TODO: refactor
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"product": None, "Name": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
if self.settings["product"].is_a("IfcObject"):
|
||||
qto = self.file.create_entity(
|
||||
"IfcElementQuantity", **{"GlobalId": ifcopenshell.guid.new(), "Name": self.settings["Name"]}
|
||||
)
|
||||
self.file.create_entity(
|
||||
"IfcRelDefinesByProperties",
|
||||
**{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
# TODO: owner history
|
||||
"RelatedObjects": [self.settings["product"]],
|
||||
"RelatingPropertyDefinition": qto,
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,190 @@
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.attribute
|
||||
import blenderbim.bim.schema # TODO: refactor elsewhere
|
||||
|
||||
|
||||
class Data:
|
||||
products = {}
|
||||
psets = {}
|
||||
qtos = {}
|
||||
|
||||
@classmethod
|
||||
def purge(cls):
|
||||
cls.products = {}
|
||||
cls.psets = {}
|
||||
cls.qtos = {}
|
||||
|
||||
@classmethod
|
||||
def load(cls, file, product_id):
|
||||
cls._file = file
|
||||
cls._schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(file.schema)
|
||||
if not file:
|
||||
return
|
||||
product = file.by_id(product_id)
|
||||
cls.products[product_id] = {"psets": set(), "qtos": set()}
|
||||
if product.is_a("IfcElementType"):
|
||||
cls.add_type_product_psets(product, product_id)
|
||||
elif product.is_a("IfcMaterialDefinition"):
|
||||
cls.add_material_psets(product, product_id)
|
||||
else:
|
||||
cls.add_product_psets(product, product_id)
|
||||
|
||||
@classmethod
|
||||
def add_type_product_psets(cls, product, product_id):
|
||||
if not hasattr(product, "HasPropertySets") or not product.HasPropertySets:
|
||||
return # TODO
|
||||
for definition in product.HasPropertySets:
|
||||
if definition.is_a("IfcPropertySet"):
|
||||
cls.add_pset(definition, product_id)
|
||||
|
||||
@classmethod
|
||||
def add_material_psets(cls, product, product_id):
|
||||
if not product.HasProperties:
|
||||
return
|
||||
for pset in product.HasProperties:
|
||||
cls.add_pset(pset, product_id)
|
||||
|
||||
@classmethod
|
||||
def add_product_psets(cls, product, product_id):
|
||||
if not hasattr(product, "IsDefinedBy") or not product.IsDefinedBy:
|
||||
return
|
||||
for definition in product.IsDefinedBy:
|
||||
if not definition.is_a("IfcRelDefinesByProperties"):
|
||||
continue
|
||||
if definition.RelatingPropertyDefinition.is_a("IfcPropertySet"):
|
||||
cls.add_pset(definition.RelatingPropertyDefinition, product_id)
|
||||
elif definition.RelatingPropertyDefinition.is_a("IfcElementQuantity"):
|
||||
cls.add_qto(definition.RelatingPropertyDefinition, product_id)
|
||||
|
||||
@classmethod
|
||||
def add_pset(cls, pset, product_id):
|
||||
new_pset = {
|
||||
"Name": pset.Name,
|
||||
"is_expanded": True,
|
||||
"Properties": cls.get_properties_from_template(pset.Name) or [],
|
||||
}
|
||||
cls.products[product_id]["psets"].add(int(pset.id()))
|
||||
cls.psets[int(pset.id())] = new_pset
|
||||
try:
|
||||
if hasattr(pset, "HasProperties"):
|
||||
props = pset.HasProperties
|
||||
elif hasattr(pset, "Properties"): # For IfcMaterialProperties
|
||||
props = pset.Properties
|
||||
except:
|
||||
return # I've seen ArchiCAD produce invalid IFCs with empty data
|
||||
# Invalid IFC, but some vendors like Solidworks do this so we accomodate it
|
||||
if not props:
|
||||
return
|
||||
for prop in props:
|
||||
if prop.is_a("IfcPropertySingleValue") and prop.NominalValue:
|
||||
has_existing_prop = False
|
||||
for existing_prop in new_pset["Properties"]:
|
||||
if existing_prop["Name"] == prop.Name:
|
||||
if prop.NominalValue is None:
|
||||
existing_prop["value"] = None
|
||||
elif existing_prop["type"] == "string":
|
||||
existing_prop["value"] = str(prop.NominalValue.wrappedValue)
|
||||
elif existing_prop["type"] == "float":
|
||||
existing_prop["value"] = float(prop.NominalValue.wrappedValue)
|
||||
elif existing_prop["type"] == "integer":
|
||||
existing_prop["value"] = int(prop.NominalValue.wrappedValue)
|
||||
elif existing_prop["type"] == "boolean":
|
||||
existing_prop["value"] = bool(prop.NominalValue.wrappedValue)
|
||||
elif existing_prop["type"] == "enum":
|
||||
existing_prop["value"] = str(prop.NominalValue.wrappedValue)
|
||||
existing_prop["is_null"] = prop.NominalValue.wrappedValue is None
|
||||
has_existing_prop = True
|
||||
break
|
||||
if not has_existing_prop:
|
||||
value = prop.NominalValue.wrappedValue
|
||||
if isinstance(value, str):
|
||||
data_type = "string"
|
||||
elif isinstance(value, float):
|
||||
data_type = "float"
|
||||
elif isinstance(value, bool):
|
||||
data_type = "boolean"
|
||||
elif isinstance(value, int):
|
||||
data_type = "integer"
|
||||
else:
|
||||
data_type = "string"
|
||||
value = str(value)
|
||||
new_pset["Properties"].append(
|
||||
{
|
||||
"Name": prop.Name,
|
||||
"value": value,
|
||||
"type": data_type,
|
||||
"enum_items": [],
|
||||
"is_null": prop.NominalValue.wrappedValue is None,
|
||||
}
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def add_qto(cls, qto, product_id):
|
||||
new_qto = {
|
||||
"Name": qto.Name,
|
||||
"is_expanded": True,
|
||||
"Properties": cls.get_properties_from_template(qto.Name) or [],
|
||||
}
|
||||
cls.products[product_id]["qtos"].add(int(qto.id()))
|
||||
cls.qtos[int(qto.id())] = new_qto
|
||||
for prop in qto.Quantities or []:
|
||||
if prop.is_a("IfcPhysicalSimpleQuantity"):
|
||||
value = prop[3]
|
||||
has_existing_prop = False
|
||||
for existing_prop in new_qto["Properties"]:
|
||||
if existing_prop["Name"] == prop.Name:
|
||||
existing_prop["value"] = float(value)
|
||||
existing_prop["is_null"] = value is None
|
||||
has_existing_prop = True
|
||||
break
|
||||
if not has_existing_prop:
|
||||
new_qto["Properties"].append(
|
||||
{
|
||||
"Name": prop.Name,
|
||||
"value": float(value),
|
||||
"type": "float",
|
||||
"enum_items": [],
|
||||
"is_null": value is None,
|
||||
}
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_properties_from_template(cls, name):
|
||||
template = blenderbim.bim.schema.ifc.psetqto.get_by_name(name)
|
||||
if not template:
|
||||
return
|
||||
properties = []
|
||||
for prop_template in template.HasPropertyTemplates:
|
||||
if not prop_template.is_a("IfcSimplePropertyTemplate"):
|
||||
continue # Other types not yet supported
|
||||
enum_items = []
|
||||
|
||||
if prop_template.TemplateType == "P_SINGLEVALUE":
|
||||
try:
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(
|
||||
cls._schema.declaration_by_name(prop_template.PrimaryMeasureType or "IfcLabel")
|
||||
)
|
||||
except:
|
||||
# TODO: Occurs if the data type is something that exists in IFC4 and not in IFC2X3. To fully fix
|
||||
# this we need to generate the IFC2X3 pset template definitions.
|
||||
continue
|
||||
elif prop_template.TemplateType == "P_ENUMERATEDVALUE":
|
||||
data_type = "enum"
|
||||
enum_items = [v.wrappedValue for v in prop_template.Enumerators.EnumerationValues]
|
||||
elif prop_template.TemplateType in ["Q_LENGTH", "Q_AREA", "Q_VOLUME", "Q_WEIGHT", "Q_TIME"]:
|
||||
data_type = "float"
|
||||
elif prop_template.TemplateType == "Q_COUNT":
|
||||
data_type = "integer"
|
||||
else:
|
||||
continue # Other types not yet supported
|
||||
|
||||
properties.append(
|
||||
{
|
||||
"Name": prop_template.Name,
|
||||
"value": None,
|
||||
"type": data_type,
|
||||
"enum_items": enum_items,
|
||||
"is_null": True,
|
||||
}
|
||||
)
|
||||
return properties
|
||||
@@ -0,0 +1,75 @@
|
||||
import blenderbim.bim.schema # TODO: refactor
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"pset": None, "Name": None, "Properties": {}}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
self.update_pset_name()
|
||||
self.load_pset_template()
|
||||
self.update_existing_properties()
|
||||
new_properties = self.add_new_properties()
|
||||
self.extend_pset_with_new_properties(new_properties)
|
||||
|
||||
def update_pset_name(self):
|
||||
if self.settings["Name"]:
|
||||
self.settings["pset"].Name = self.settings["Name"]
|
||||
|
||||
def load_pset_template(self):
|
||||
self.pset_template = blenderbim.bim.schema.ifc.psetqto.get_by_name(self.settings["pset"].Name)
|
||||
|
||||
def update_existing_properties(self):
|
||||
for prop in self.get_properties():
|
||||
self.update_existing_property(prop)
|
||||
|
||||
def update_existing_property(self, prop):
|
||||
if prop.Name not in self.settings["Properties"]:
|
||||
return
|
||||
value = self.settings["Properties"][prop.Name]
|
||||
if value is None:
|
||||
prop.NominalValue = None
|
||||
else:
|
||||
primary_measure_type = self.get_primary_measure_type(prop.Name, previous_value=prop.NominalValue)
|
||||
prop.NominalValue = self.file.create_entity(primary_measure_type, value)
|
||||
del self.settings["Properties"][prop.Name]
|
||||
|
||||
def add_new_properties(self):
|
||||
properties = []
|
||||
for name, value in self.settings["Properties"].items():
|
||||
if value is None:
|
||||
continue
|
||||
primary_measure_type = self.get_primary_measure_type(name)
|
||||
properties.append(
|
||||
self.file.create_entity(
|
||||
"IfcPropertySingleValue",
|
||||
**{"Name": name, "NominalValue": self.file.create_entity(primary_measure_type, value)},
|
||||
)
|
||||
)
|
||||
return properties
|
||||
|
||||
def extend_pset_with_new_properties(self, new_properties):
|
||||
props = list(self.get_properties())
|
||||
props.extend(new_properties)
|
||||
if hasattr(self.settings["pset"], "HasProperties"):
|
||||
self.settings["pset"].HasProperties = props
|
||||
elif hasattr(self.settings["pset"], "Properties"):
|
||||
self.settings["pset"].Properties = props
|
||||
|
||||
def get_properties(self):
|
||||
if hasattr(self.settings["pset"], "HasProperties"):
|
||||
return self.settings["pset"].HasProperties or []
|
||||
elif hasattr(self.settings["pset"], "Properties"): # For IfcMaterialProperties
|
||||
return self.settings["pset"].Properties or []
|
||||
|
||||
def get_primary_measure_type(self, name, previous_value=None):
|
||||
if not self.pset_template:
|
||||
return previous_value.is_a() if previous_value else "IfcLabel"
|
||||
for prop_template in self.pset_template.HasPropertyTemplates:
|
||||
if prop_template.Name != name:
|
||||
continue
|
||||
return prop_template.PrimaryMeasureType or "IfcLabel"
|
||||
return previous_value.is_a() if previous_value else "IfcLabel"
|
||||
@@ -0,0 +1,72 @@
|
||||
import blenderbim.bim.schema # TODO: refactor
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"qto": None, "Name": None, "Properties": {}}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
self.update_qto_name()
|
||||
self.load_qto_template()
|
||||
self.update_existing_properties()
|
||||
new_properties = self.add_new_properties()
|
||||
self.extend_qto_with_new_properties(new_properties)
|
||||
|
||||
def update_qto_name(self):
|
||||
if self.settings["Name"]:
|
||||
self.settings["qto"].Name = self.settings["Name"]
|
||||
|
||||
def load_qto_template(self):
|
||||
self.qto_template = blenderbim.bim.schema.ifc.psetqto.get_by_name(self.settings["qto"].Name)
|
||||
|
||||
def update_existing_properties(self):
|
||||
for prop in self.settings["qto"].Quantities or []:
|
||||
self.update_existing_property(prop)
|
||||
|
||||
def update_existing_property(self, prop):
|
||||
if prop.Name not in self.settings["Properties"]:
|
||||
return
|
||||
value = self.settings["Properties"][prop.Name]
|
||||
if prop.is_a("IfcPhysicalSimpleQuantity"):
|
||||
prop[3] = float(value) if value else None
|
||||
del self.settings["Properties"][prop.Name]
|
||||
|
||||
def add_new_properties(self):
|
||||
properties = []
|
||||
for name, value in self.settings["Properties"].items():
|
||||
if value is None:
|
||||
continue
|
||||
property_type = self.get_canonical_property_type(name)
|
||||
properties.append(
|
||||
self.file.create_entity(
|
||||
"IfcQuantity{}".format(property_type),
|
||||
**{"Name": name, "{}Value".format(property_type): value},
|
||||
)
|
||||
)
|
||||
return properties
|
||||
|
||||
def extend_qto_with_new_properties(self, new_properties):
|
||||
props = list(self.settings["qto"].Quantities) if self.settings["qto"].Quantities else []
|
||||
props.extend(new_properties)
|
||||
self.settings["qto"].Quantities = props
|
||||
|
||||
def get_canonical_property_type(self, name):
|
||||
if not self.qto_template:
|
||||
return "Length"
|
||||
for prop_template in self.qto_template.HasPropertyTemplates:
|
||||
if prop_template.Name != name:
|
||||
continue
|
||||
return prop_template.TemplateType[2:].lower().capitalize()
|
||||
return "Length"
|
||||
|
||||
def get_primary_measure_type(self, name, previous_value=None):
|
||||
if not self.qto_template:
|
||||
return previous_value.is_a() if previous_value else "IfcLabel"
|
||||
for prop_template in self.qto_template.HasPropertyTemplates:
|
||||
if prop_template.Name != name:
|
||||
continue
|
||||
return prop_template.PrimaryMeasureType or "IfcLabel"
|
||||
return previous_value.is_a() if previous_value else "IfcLabel"
|
||||
@@ -0,0 +1,27 @@
|
||||
import blenderbim.bim.schema # TODO: refactor
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"product": None, "pset": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
to_purge = []
|
||||
should_remove_pset = True
|
||||
for inverse in self.file.get_inverse(self.settings["pset"]):
|
||||
if inverse.is_a("IfcRelDefinesByProperties"):
|
||||
if not inverse.RelatedObjects or len(inverse.RelatedObjects) == 1:
|
||||
to_purge.append(inverse)
|
||||
else:
|
||||
related_objects = list(inverse.RelatedObjects)
|
||||
related_objects.remove(self.settings["product"])
|
||||
inverse.RelatedObjects = related_objects
|
||||
should_remove_pset = False
|
||||
if should_remove_pset:
|
||||
self.file.remove(self.settings["pset"])
|
||||
for element in to_purge:
|
||||
self.file.remove(element)
|
||||
# TODO: implement deep purging
|
||||
@@ -0,0 +1,22 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings={}):
|
||||
self.file = file
|
||||
self.settings = {"pset_template": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
prop_template = self.file.create_entity("IfcSimplePropertyTemplate", **{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"Name": "NewProperty",
|
||||
"PrimaryMeasureType": "IfcLabel",
|
||||
"TemplateType": "P_SINGLEVALUE",
|
||||
"AccessState": "READWRITE"
|
||||
})
|
||||
has_property_templates = list(self.settings["pset_template"].HasPropertyTemplates or [])
|
||||
has_property_templates.append(prop_template)
|
||||
self.settings["pset_template"].HasPropertyTemplates = has_property_templates
|
||||
return prop_template
|
||||
@@ -0,0 +1,17 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings={}):
|
||||
self.file = file
|
||||
self.settings = {}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
self.file.create_entity("IfcPropertySetTemplate", **{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"Name": "New_Pset",
|
||||
"TemplateType": "PSET_TYPEDRIVENONLY",
|
||||
"ApplicableEntity": "IfcTypeObject"
|
||||
})
|
||||
@@ -0,0 +1,34 @@
|
||||
class Data:
|
||||
is_loaded = False
|
||||
pset_templates = {}
|
||||
prop_templates = {}
|
||||
|
||||
@classmethod
|
||||
def purge(cls):
|
||||
cls.is_loaded = False
|
||||
cls.pset_templates = {}
|
||||
cls.prop_templates = {}
|
||||
|
||||
@classmethod
|
||||
def load(cls, file):
|
||||
cls._file = file
|
||||
|
||||
cls.pset_templates = {}
|
||||
cls.prop_templates = {}
|
||||
|
||||
for pset_template in cls._file.by_type("IfcPropertySetTemplate"):
|
||||
data = pset_template.get_info()
|
||||
data["HasPropertyTemplates"] = [e.id() for e in pset_template.HasPropertyTemplates or []]
|
||||
if "OwnerHistory" in data:
|
||||
del data["OwnerHistory"]
|
||||
cls.pset_templates[pset_template.id()] = data
|
||||
|
||||
for prop_template in cls._file.by_type("IfcSimplePropertyTemplate"):
|
||||
data = prop_template.get_info()
|
||||
cls.prop_templates[prop_template.id()] = {
|
||||
"GlobalId": data["GlobalId"],
|
||||
"Name": data["Name"],
|
||||
"Description": data["Description"],
|
||||
"PrimaryMeasureType": data["PrimaryMeasureType"]
|
||||
}
|
||||
cls.is_loaded = True
|
||||
@@ -0,0 +1,10 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"prop_template": None, "attributes": {}}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["prop_template"], name, value)
|
||||
@@ -0,0 +1,10 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {"pset_template": None, "attributes": {}}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["pset_template"], name, value)
|
||||
@@ -0,0 +1,21 @@
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"prop_template": None
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for inverse in self.file.get_inverse(self.settings["prop_template"]):
|
||||
if len(inverse.HasPropertyTemplates) == 1:
|
||||
inverse.HasPropertyTemplates = []
|
||||
else:
|
||||
has_property_templates = list(inverse.HasPropertyTemplates)
|
||||
has_property_templates.remove(self.settings["prop_template"])
|
||||
inverse.HasPropertyTemplates = has_property_templates
|
||||
ifcopenshell.util.element.remove_deep(self.file, self.settings["prop_template"])
|
||||
@@ -0,0 +1,14 @@
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, settings=None):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"pset_template": None
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
ifcopenshell.util.element.remove_deep(self.file, self.settings["pset_template"])
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user