This commit is contained in:
Andrej730
2024-11-15 16:41:02 +05:00
parent 7f40491e41
commit dd0d0ed1af
4 changed files with 38 additions and 35 deletions
@@ -24,6 +24,7 @@ import ifcopenshell.util.attribute
import ifcopenshell.util.doc
import bonsai.tool as tool
from bonsai.bim.ifc import IfcStore
from typing import Any
def refresh():
@@ -49,7 +50,7 @@ class PsetTemplatesData:
cls.data["prop_templates"] = cls.prop_templates()
@classmethod
def primary_measure_type(cls):
def primary_measure_type(cls) -> list[tuple[str, str, str]]:
ifc_file = IfcStore.pset_template_file
if not ifc_file:
return []
@@ -61,7 +62,7 @@ class PsetTemplatesData:
]
@classmethod
def property_template_type(cls):
def property_template_type(cls) -> list[tuple[str, str, str]]:
ifc_file = IfcStore.pset_template_file
if not ifc_file:
return []
@@ -96,7 +97,7 @@ class PsetTemplatesData:
return [(str(t.id()), t.Name, "") for t in IfcStore.pset_template_file.by_type("IfcPropertySetTemplate")]
@classmethod
def pset_template(cls):
def pset_template(cls) -> dict[str, Any]:
props = bpy.context.scene.BIMPsetTemplateProperties
template_id = props.pset_templates
if not template_id:
@@ -109,7 +110,7 @@ class PsetTemplatesData:
return info
@classmethod
def prop_templates(cls):
def prop_templates(cls) -> list[dict[str, Any]]:
props = bpy.context.scene.BIMPsetTemplateProperties
template_id = props.pset_templates
if not template_id:
+16 -15
View File
@@ -22,7 +22,19 @@ import ifcopenshell.api
import ifcopenshell.util.date
import ifcopenshell.util.unit
import datetime
from typing import Any, Optional, Union
from typing import Any, Optional, Union, Literal, get_args
SUPPORTED_COLUMN = Literal[
"HIERARCHY",
"TYPE", # CREW, LABOR, EQUIPMENT, SUBCONTRACTOR, MATERIAL, PRODUCT.
"ACTIVITY/RESOURCE NAME",
"DESCRIPTION",
"COST",
"QUANTITY NAME",
"LABOR OUTPUT",
"EQUIPMENT OUTPUT",
]
class Csv2Ifc:
@@ -32,7 +44,7 @@ class Csv2Ifc:
Notes about format:
- empty rows are skipped.
- 'HIERARCHY' must be the first column.
- See SUPPORTED_COLUMNS below for the list of supported columns.
- See SUPPORTED_COLUMN above for the list of supported columns.
Example:
@@ -42,17 +54,6 @@ class Csv2Ifc:
csv2ifc.execute()
"""
SUPPORTED_COLUMNS = (
"HIERARCHY",
"TYPE", # CREW, LABOR, EQUIPMENT, SUBCONTRACTOR, MATERIAL, PRODUCT.
"ACTIVITY/RESOURCE NAME",
"DESCRIPTION",
"COST",
"QUANTITY NAME",
"LABOR OUTPUT",
"EQUIPMENT OUTPUT",
)
def __init__(self, csv: str, ifc_file: Optional[ifcopenshell.file] = None):
"""
:param csv: CSV filepath to load resources from.
@@ -78,7 +79,7 @@ class Csv2Ifc:
def parse_csv(self) -> None:
self.parents = {}
self.headers: dict[str, int] = {}
self.headers: dict[SUPPORTED_COLUMN, int] = {}
with open(self.csv, "r") as csv_file:
reader = csv.reader(csv_file)
for row in reader:
@@ -86,7 +87,7 @@ class Csv2Ifc:
if not row[0]:
continue
if row[0] == "HIERARCHY":
missing_columns = set(self.SUPPORTED_COLUMNS) - set(row)
missing_columns = set(get_args(SUPPORTED_COLUMN)) - set(row)
if missing_columns:
raise Exception(
f"Header is missing some of the required columns: {', '.join(missing_columns)}."
@@ -17,15 +17,16 @@
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
import ifcopenshell
import ifcopenshell.api.pset
import ifcopenshell.util.pset
from typing import Optional, Any
from typing import Optional, Any, Union
def edit_qto(
file: ifcopenshell.file,
qto: ifcopenshell.entity_instance,
name: Optional[str] = None,
properties: Optional[dict[str, Any]] = None,
properties: Optional[dict[str, Union[ifcopenshell.entity_instance, float, int]]] = None,
pset_template: Optional[ifcopenshell.entity_instance] = None,
) -> None:
"""Edits a quantity set and its quantities
@@ -40,10 +41,8 @@ def edit_qto(
It is not allowed to have None quantities in IFC.
:param qto: The IfcElementQuantity to edit.
:type qto: ifcopenshell.entity_instance
:param name: A new name for the quantity set. If no name is specified,
the quantity set name is not changed.
:type name: str, optional
:param properties: A dictionary of properties. The keys must be a string
of the name of the quantity. The data type of the value will be
determined by the quantity set template. If no quantity set
@@ -53,13 +52,11 @@ def edit_qto(
become IfcBoolean, and integers will become IfcInteger. If more
control is desired, you may explicitly specify IFC data objects
directly.
:type properties: dict
:param pset_template: If a quantity set template is provided, this will
be used to determine data types. If no user-defined template is
provided, the built-in buildingSMART templates will be loaded.
:type pset_template: ifcopenshell.entity_instance, optional
:return: None
:rtype: None
Example:
@@ -121,6 +118,9 @@ def edit_qto(
class Usecase:
file: ifcopenshell.file
settings: dict[str, Any]
def execute(self):
self.qto_idx = 5
if self.settings["qto"].is_a("IfcPhysicalComplexQuantity"):
@@ -132,22 +132,22 @@ class Usecase:
new_properties = self.add_new_properties()
self.extend_qto_with_new_properties(new_properties)
def update_qto_name(self):
def update_qto_name(self) -> None:
if self.settings["name"]:
self.settings["qto"].Name = self.settings["name"]
def load_qto_template(self):
def load_qto_template(self) -> None:
if self.settings["pset_template"]:
self.pset_template = self.settings["pset_template"]
else:
self.psetqto = ifcopenshell.util.pset.get_template(self.file.schema_identifier)
self.qto_template = self.psetqto.get_by_name(self.settings["qto"].Name)
def update_existing_properties(self):
def update_existing_properties(self) -> None:
for prop in self.settings["qto"][self.qto_idx] or []:
self.update_existing_property(prop)
def update_existing_property(self, prop):
def update_existing_property(self, prop: ifcopenshell.entity_instance) -> None:
if prop.Name not in self.settings["properties"]:
return
value = self.settings["properties"][prop.Name]
@@ -162,7 +162,7 @@ class Usecase:
prop[3] = float(value)
del self.settings["properties"][name]
def add_new_properties(self):
def add_new_properties(self) -> list[ifcopenshell.entity_instance]:
properties = []
for name, value in self.settings["properties"].items():
if value is None:
@@ -184,12 +184,12 @@ class Usecase:
)
return properties
def extend_qto_with_new_properties(self, new_properties):
def extend_qto_with_new_properties(self, new_properties: list[ifcopenshell.entity_instance]) -> None:
props = list(self.settings["qto"][self.qto_idx]) if self.settings["qto"][self.qto_idx] else []
props.extend(new_properties)
self.settings["qto"][self.qto_idx] = props
def get_canonical_property_type(self, name, value):
def get_canonical_property_type(self, name: str, value: Union[ifcopenshell.entity_instance, float, int]) -> str:
if isinstance(value, ifcopenshell.entity_instance):
result = value.is_a().replace("Ifc", "").replace("Measure", "")
# Sigh, IFC inconsistencies
@@ -205,7 +205,8 @@ class Usecase:
return prop_template.TemplateType[2:].lower().capitalize()
return "Length"
def get_primary_measure_type(self, name, previous_value=None):
# TODO: unused code.
def get_primary_measure_type(self, name: str, previous_value: Optional[Any] = None) -> str:
if not self.qto_template:
return previous_value.is_a() if previous_value else "IfcLabel"
for prop_template in self.qto_template.HasPropertyTemplates:
@@ -271,7 +271,7 @@ def get_quantity(
if quantity[0] != name:
continue
if quantity.is_a("IfcPhysicalSimpleQuantity"):
# 3 IfcPhysicalSimpleQuantity.Unit
# 3 IfcPhysicalSimpleQuantity.XXXValue
result = quantity[3]
elif quantity.is_a("IfcPhysicalComplexQuantity"):
data = {k: v for k, v in quantity.get_info().items() if v is not None and k != "Name"}
@@ -299,7 +299,7 @@ def get_quantities(
# 0 IfcPhysicalQuantity.Name
quantity_name = quantity[0]
if quantity.is_a("IfcPhysicalSimpleQuantity"):
# 3 IfcPhysicalSimpleQuantity.Unit
# 3 IfcPhysicalSimpleQuantity.XXXValue
results[quantity_name] = quantity[3]
if verbose:
results[quantity_name] = {