cobie24 - implement Coordinate tab #5926

This commit is contained in:
Andrej730
2025-01-13 13:22:26 +05:00
parent a968b61d02
commit 5c0a7af830
2 changed files with 106 additions and 9 deletions
+3 -3
View File
@@ -49,6 +49,7 @@ __version__ = version = "0.0.0"
ParserPreset = Literal["basic", "cobie24", "cobie24legacy"]
GetElementDataCallBack = Callable[[ifcopenshell.file, ifcopenshell.entity_instance], dict[str, Any]]
_parser_presets_configs = {}
@@ -69,9 +70,7 @@ def get_presets_configs() -> dict[ParserPreset, dict[str, Any]]:
class Parser:
config: dict[str, Any]
categories: defaultdict[str, dict[str, Any]]
get_custom_element_data: dict[
str, Union[Callable[[ifcopenshell.file, ifcopenshell.entity_instance], dict[str, Any]], dict[str, Any]]
]
get_custom_element_data: dict[str, Union[GetElementDataCallBack, dict[str, Any]]]
duplicate_keys: list[tuple[dict[str, Any], dict[str, Any]]]
def __init__(self, preset: Union[str, ParserPreset, dict[str, Any]] = "basic"):
@@ -93,6 +92,7 @@ class Parser:
def parse(self, ifc_file: ifcopenshell.file, name=None):
for category_name, category_config in self.config["categories"].items():
for element in category_config["get_category_elements"](ifc_file):
get_element_data: Union[GetElementDataCallBack, dict[str, Any]]
get_element_data = category_config["get_element_data"]
if isinstance(get_element_data, dict):
+103 -6
View File
@@ -17,13 +17,16 @@
# along with IfcFM. If not, see <http://www.gnu.org/licenses/>.
import ifcopenshell
import ifcopenshell.geom
import ifcopenshell.util.classification
import ifcopenshell.util.date
import ifcopenshell.util.element
import ifcopenshell.util.fm
import ifcopenshell.util.placement
import ifcopenshell.util.shape
import ifcopenshell.util.system
from typing import Any, Union, Optional
from ifcopenshell.util.shape_builder import np_matrix_to_euler
from typing import Any, Union, Optional, Generator
# The original BIMServer plugin has a function called ifcToCOBie:
@@ -163,7 +166,7 @@ def get_documents(
def get_attributes(ifc_file: ifcopenshell.file) -> list[dict[str, Any]]:
results = []
results: list[dict[str, Any]] = []
history = get_history(ifc_file)
created_by = get_email_from_history(history) if history else None
created_on = ifcopenshell.util.date.ifc2datetime(history.CreationDate).isoformat() if history else None
@@ -850,12 +853,81 @@ def get_document_data(ifc_file: ifcopenshell.file, element: ifcopenshell.entity_
}
def get_attribute_data(
ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance
) -> ifcopenshell.entity_instance:
def pass_category_elements_as_data(ifc_file: ifcopenshell.file, element: dict[str, Any]) -> dict[str, Any]:
return element
def get_coordinate_elements(ifc_file: ifcopenshell.file) -> list[dict[str, Any]]:
elements = get_floors(ifc_file) + get_spaces(ifc_file)
results: list[dict[str, Any]] = []
for element in elements:
for data in get_coordinate_data_(element):
results.append(data)
return results
def get_coordinate_data_(element: ifcopenshell.entity_instance) -> Generator[dict[str, Any], None, None]:
M_TRANSLATION = (slice(0, 3), 3)
element_name = val(element.Name)
element_class = element.is_a()
base_data = {
"CreatedBy": get_created_by(element),
"CreatedOn": get_created_on(element),
"RowName": element_name,
"ExtSystem": "IfcFm",
"ExtObject": element_class,
"ExtIdentifier": element.GlobalId,
}
if element_class == "IfcBuildingStorey":
matrix = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement)
categories = ("points",)
rotation = np_matrix_to_euler(matrix)
translation = matrix[M_TRANSLATION]
# Rotation axes as explained in https://www.nibs.org/nbims/v3/cobie.
points_data = {
"Name": element_name,
"Category": "point",
"SheetName": "Floor",
"CoordinateXAxis": translation[0],
"CoordinateYAxis": translation[1],
"CoordinateZAxis": translation[2],
"ClockwiseRotation": rotation[2] * 180,
"ElevationalRotation": rotation[0] * 180,
"YawRotation": rotation[1] * 180,
}
yield base_data | points_data
return
# IfcSpaces.
if element.Representation is None:
return
settings = ifcopenshell.geom.settings()
shape: ifcopenshell.geom.ShapeElementType
shape = ifcopenshell.geom.create_shape(settings, element)
verts = ifcopenshell.util.shape.get_shape_vertices(shape, shape.geometry)
categories = ("box-lowerleft", "box-upperright")
bbox = ifcopenshell.util.shape.get_bbox(verts)
base_data = base_data | {
"Category": "point",
"SheetName": "Space",
# Spaces don't need rotation as box points are already in world space.
"ClockwiseRotation": None,
"ElevationalRotation": None,
"YawRotation": None,
}
for category, point in zip(categories, bbox):
box_point_data = {
"Name": element_name + category,
"CoordinateXAxis": point[0],
"CoordinateYAxis": point[1],
"CoordinateZAxis": point[2],
}
yield base_data | box_point_data
def get_unit_type_name(ifc_file: ifcopenshell.file, unit_type: str) -> Union[str, None]:
for unit in ifc_file.by_type("IfcUnitAssignment")[0].Units:
if unit.is_a("IfcNamedUnit") and unit.UnitType == unit_type:
@@ -936,6 +1008,7 @@ def get_facility_parent(
def val(x: Any) -> Any:
"""Replace n/a and empty strings with `None`."""
return x if x not in ("", "n/a") else None
@@ -1428,7 +1501,31 @@ config = {
"colours": "ririiirreeeoo",
"sort": [{"name": "Category", "order": "ASC"}, {"name": "Name", "order": "ASC"}],
"get_category_elements": get_attributes,
"get_element_data": get_attribute_data,
"get_element_data": pass_category_elements_as_data,
},
"Coordinate": {
"keys": ["Name", "SheetName", "RowName"],
"headers": (
"Name",
"CreatedBy",
"CreatedOn",
"Category",
"SheetName",
"RowName",
"CoordinateXAxis",
"CoordinateYAxis",
"CoordinateZAxis",
"ExtSystem",
"ExtObject",
"ExtIdentifier",
"ClockwiseRotation",
"ElevationalRotation",
"YawRotation",
),
"colours": "ririiirrreeerrr",
"sort": [{"name": "Category", "order": "ASC"}, {"name": "Name", "order": "ASC"}],
"get_category_elements": get_coordinate_elements,
"get_element_data": pass_category_elements_as_data,
},
},
}