|
17 | 17 | # along with IfcFM. If not, see <http://www.gnu.org/licenses/>. |
18 | 18 |
|
19 | 19 | import ifcopenshell |
| 20 | +import ifcopenshell.geom |
20 | 21 | import ifcopenshell.util.classification |
21 | 22 | import ifcopenshell.util.date |
22 | 23 | import ifcopenshell.util.element |
23 | 24 | import ifcopenshell.util.fm |
24 | 25 | import ifcopenshell.util.placement |
| 26 | +import ifcopenshell.util.shape |
25 | 27 | import ifcopenshell.util.system |
26 | | -from typing import Any, Union, Optional |
| 28 | +from ifcopenshell.util.shape_builder import np_matrix_to_euler |
| 29 | +from typing import Any, Union, Optional, Generator |
27 | 30 |
|
28 | 31 |
|
29 | 32 | # The original BIMServer plugin has a function called ifcToCOBie: |
@@ -163,7 +166,7 @@ def get_documents( |
163 | 166 |
|
164 | 167 |
|
165 | 168 | def get_attributes(ifc_file: ifcopenshell.file) -> list[dict[str, Any]]: |
166 | | - results = [] |
| 169 | + results: list[dict[str, Any]] = [] |
167 | 170 | history = get_history(ifc_file) |
168 | 171 | created_by = get_email_from_history(history) if history else None |
169 | 172 | 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_ |
850 | 853 | } |
851 | 854 |
|
852 | 855 |
|
853 | | -def get_attribute_data( |
854 | | - ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance |
855 | | -) -> ifcopenshell.entity_instance: |
| 856 | +def pass_category_elements_as_data(ifc_file: ifcopenshell.file, element: dict[str, Any]) -> dict[str, Any]: |
856 | 857 | return element |
857 | 858 |
|
858 | 859 |
|
| 860 | +def get_coordinate_elements(ifc_file: ifcopenshell.file) -> list[dict[str, Any]]: |
| 861 | + elements = get_floors(ifc_file) + get_spaces(ifc_file) |
| 862 | + results: list[dict[str, Any]] = [] |
| 863 | + for element in elements: |
| 864 | + for data in get_coordinate_data_(element): |
| 865 | + results.append(data) |
| 866 | + return results |
| 867 | + |
| 868 | + |
| 869 | +def get_coordinate_data_(element: ifcopenshell.entity_instance) -> Generator[dict[str, Any], None, None]: |
| 870 | + M_TRANSLATION = (slice(0, 3), 3) |
| 871 | + element_name = val(element.Name) |
| 872 | + element_class = element.is_a() |
| 873 | + |
| 874 | + base_data = { |
| 875 | + "CreatedBy": get_created_by(element), |
| 876 | + "CreatedOn": get_created_on(element), |
| 877 | + "RowName": element_name, |
| 878 | + "ExtSystem": "IfcFm", |
| 879 | + "ExtObject": element_class, |
| 880 | + "ExtIdentifier": element.GlobalId, |
| 881 | + } |
| 882 | + |
| 883 | + if element_class == "IfcBuildingStorey": |
| 884 | + matrix = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement) |
| 885 | + categories = ("points",) |
| 886 | + rotation = np_matrix_to_euler(matrix) |
| 887 | + translation = matrix[M_TRANSLATION] |
| 888 | + # Rotation axes as explained in https://www.nibs.org/nbims/v3/cobie. |
| 889 | + points_data = { |
| 890 | + "Name": element_name, |
| 891 | + "Category": "point", |
| 892 | + "SheetName": "Floor", |
| 893 | + "CoordinateXAxis": translation[0], |
| 894 | + "CoordinateYAxis": translation[1], |
| 895 | + "CoordinateZAxis": translation[2], |
| 896 | + "ClockwiseRotation": rotation[2] * 180, |
| 897 | + "ElevationalRotation": rotation[0] * 180, |
| 898 | + "YawRotation": rotation[1] * 180, |
| 899 | + } |
| 900 | + yield base_data | points_data |
| 901 | + return |
| 902 | + |
| 903 | + # IfcSpaces. |
| 904 | + if element.Representation is None: |
| 905 | + return |
| 906 | + |
| 907 | + settings = ifcopenshell.geom.settings() |
| 908 | + shape: ifcopenshell.geom.ShapeElementType |
| 909 | + shape = ifcopenshell.geom.create_shape(settings, element) |
| 910 | + verts = ifcopenshell.util.shape.get_shape_vertices(shape, shape.geometry) |
| 911 | + categories = ("box-lowerleft", "box-upperright") |
| 912 | + bbox = ifcopenshell.util.shape.get_bbox(verts) |
| 913 | + base_data = base_data | { |
| 914 | + "Category": "point", |
| 915 | + "SheetName": "Space", |
| 916 | + # Spaces don't need rotation as box points are already in world space. |
| 917 | + "ClockwiseRotation": None, |
| 918 | + "ElevationalRotation": None, |
| 919 | + "YawRotation": None, |
| 920 | + } |
| 921 | + for category, point in zip(categories, bbox): |
| 922 | + box_point_data = { |
| 923 | + "Name": element_name + category, |
| 924 | + "CoordinateXAxis": point[0], |
| 925 | + "CoordinateYAxis": point[1], |
| 926 | + "CoordinateZAxis": point[2], |
| 927 | + } |
| 928 | + yield base_data | box_point_data |
| 929 | + |
| 930 | + |
859 | 931 | def get_unit_type_name(ifc_file: ifcopenshell.file, unit_type: str) -> Union[str, None]: |
860 | 932 | for unit in ifc_file.by_type("IfcUnitAssignment")[0].Units: |
861 | 933 | if unit.is_a("IfcNamedUnit") and unit.UnitType == unit_type: |
@@ -936,6 +1008,7 @@ def get_facility_parent( |
936 | 1008 |
|
937 | 1009 |
|
938 | 1010 | def val(x: Any) -> Any: |
| 1011 | + """Replace n/a and empty strings with `None`.""" |
939 | 1012 | return x if x not in ("", "n/a") else None |
940 | 1013 |
|
941 | 1014 |
|
@@ -1428,7 +1501,31 @@ def get_sheet_name(element: ifcopenshell.entity_instance) -> Union[str, None]: |
1428 | 1501 | "colours": "ririiirreeeoo", |
1429 | 1502 | "sort": [{"name": "Category", "order": "ASC"}, {"name": "Name", "order": "ASC"}], |
1430 | 1503 | "get_category_elements": get_attributes, |
1431 | | - "get_element_data": get_attribute_data, |
| 1504 | + "get_element_data": pass_category_elements_as_data, |
| 1505 | + }, |
| 1506 | + "Coordinate": { |
| 1507 | + "keys": ["Name", "SheetName", "RowName"], |
| 1508 | + "headers": ( |
| 1509 | + "Name", |
| 1510 | + "CreatedBy", |
| 1511 | + "CreatedOn", |
| 1512 | + "Category", |
| 1513 | + "SheetName", |
| 1514 | + "RowName", |
| 1515 | + "CoordinateXAxis", |
| 1516 | + "CoordinateYAxis", |
| 1517 | + "CoordinateZAxis", |
| 1518 | + "ExtSystem", |
| 1519 | + "ExtObject", |
| 1520 | + "ExtIdentifier", |
| 1521 | + "ClockwiseRotation", |
| 1522 | + "ElevationalRotation", |
| 1523 | + "YawRotation", |
| 1524 | + ), |
| 1525 | + "colours": "ririiirrreeerrr", |
| 1526 | + "sort": [{"name": "Category", "order": "ASC"}, {"name": "Name", "order": "ASC"}], |
| 1527 | + "get_category_elements": get_coordinate_elements, |
| 1528 | + "get_element_data": pass_category_elements_as_data, |
1432 | 1529 | }, |
1433 | 1530 | }, |
1434 | 1531 | } |
0 commit comments