stbkit 0.1.0a9.dev1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- stbkit/__main__.py +10 -0
- stbkit/api/__init__.py +48 -0
- stbkit/api/experimental/__init__.py +19 -0
- stbkit/api/experimental/repository/__init__.py +30 -0
- stbkit/api/py.typed +0 -0
- stbkit/api/stb_latest.py +7 -0
- stbkit/api/stb_v2_0_2.py +11 -0
- stbkit/api/stb_v2_1_1.py +9 -0
- stbkit/cli/__init__.py +17 -0
- stbkit/cli/_internal/cli_main.py +114 -0
- stbkit/cli/_internal/common.py +126 -0
- stbkit/cli/_internal/constants_exit_code.py +59 -0
- stbkit/cli/_internal/converter.py +693 -0
- stbkit/cli/_internal/diff.py +213 -0
- stbkit/cli/_internal/entry_points.py +25 -0
- stbkit/cli/_internal/global_parent.py +70 -0
- stbkit/cli/_internal/show_versions.py +36 -0
- stbkit/cli/_internal/validate.py +310 -0
- stbkit/cli/commands/convert.py +16 -0
- stbkit/cli/commands/diff.py +16 -0
- stbkit/cli/commands/validate.py +16 -0
- stbkit/cli/py.typed +0 -0
- stbkit/tools/__init__.py +12 -0
- stbkit/tools/_internal/__init__.py +5 -0
- stbkit/tools/_internal/constants.py +21 -0
- stbkit/tools/_internal/data_model/building_geometry.py +1208 -0
- stbkit/tools/_internal/data_model/building_geometry_web.py +106 -0
- stbkit/tools/_internal/data_model/element_data.py +93 -0
- stbkit/tools/_internal/data_model/ifc_data/entity_data.py +67 -0
- stbkit/tools/_internal/data_model/ifc_data/entity_names.py +32 -0
- stbkit/tools/_internal/data_model/shape_data.py +1089 -0
- stbkit/tools/_internal/diff/__init__.py +5 -0
- stbkit/tools/_internal/diff/common.py +50 -0
- stbkit/tools/_internal/diff/diff_xml.py +796 -0
- stbkit/tools/_internal/matrix.py +51 -0
- stbkit/tools/_internal/optional_dependencies/__init__.py +5 -0
- stbkit/tools/_internal/optional_dependencies/ifc_common.py +28 -0
- stbkit/tools/_internal/optional_dependencies/ifc_exporter/ifc_entity_exporter.py +473 -0
- stbkit/tools/_internal/optional_dependencies/ifc_exporter/ifc_profile_exporter.py +267 -0
- stbkit/tools/_internal/optional_dependencies/ifc_exporter/ifc_representation_exporter.py +178 -0
- stbkit/tools/_internal/optional_dependencies/ifc_pipeline.py +133 -0
- stbkit/tools/_internal/optional_dependencies/ifc_to_building_geometry.py +64 -0
- stbkit/tools/_internal/stb_io.py +116 -0
- stbkit/tools/_internal/stb_repair/_common.py +24 -0
- stbkit/tools/_internal/stb_repair/_stb_repair.py +197 -0
- stbkit/tools/_internal/stb_repair/_stb_v2_0_2_repair.py +53 -0
- stbkit/tools/_internal/stb_repair/_stb_v2_1_0_repair.py +109 -0
- stbkit/tools/_internal/stb_repair/_stb_v2_1_1_repair.py +109 -0
- stbkit/tools/_internal/studio_report.py +49 -0
- stbkit/tools/_internal/utils/atomic_writer.py +57 -0
- stbkit/tools/_internal/utils/float_rounding.py +49 -0
- stbkit/tools/_internal/utils/girder_utils.py +91 -0
- stbkit/tools/_internal/utils/guid_utils.py +30 -0
- stbkit/tools/_internal/utils/mesh_utils.py +1305 -0
- stbkit/tools/_internal/utils/node_utils.py +50 -0
- stbkit/tools/_internal/utils/unit_utils.py +23 -0
- stbkit/tools/_internal/vectors.py +222 -0
- stbkit/tools/converters/__init__.py +39 -0
- stbkit/tools/converters/_internal/__init__.py +5 -0
- stbkit/tools/converters/_internal/building_geometry_to_ply_text.py +32 -0
- stbkit/tools/converters/_internal/coord_converter.py +151 -0
- stbkit/tools/converters/_internal/element_data_to_building_geometry.py +549 -0
- stbkit/tools/converters/_internal/ifc_to_ply_text.py +21 -0
- stbkit/tools/converters/_internal/name_converter.py +23 -0
- stbkit/tools/converters/_internal/pipeline/__init__.py +5 -0
- stbkit/tools/converters/_internal/pipeline/data.py +188 -0
- stbkit/tools/converters/_internal/pipeline/execution.py +569 -0
- stbkit/tools/converters/_internal/pipeline/ply_pipeline.py +52 -0
- stbkit/tools/converters/_internal/pipeline/stb_pipeline.py +226 -0
- stbkit/tools/converters/_internal/pipeline/stb_pipeline_latest.py +39 -0
- stbkit/tools/converters/_internal/pipeline/step.py +139 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/__init__.py +17 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/_stb_latest_to_element_data.py +186 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/member/member_footing.py +49 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/member/member_line.py +533 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/member/member_pile.py +100 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/member/member_plane.py +103 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/open.py +70 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/section/sec.py +214 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/section/sec_beam_rc.py +67 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/section/sec_beam_s.py +97 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/section/sec_beam_src.py +28 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/section/sec_brace_s.py +49 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/section/sec_column_cft.py +217 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/section/sec_column_rc.py +41 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/section/sec_column_s.py +127 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/section/sec_column_src.py +173 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/section/sec_foundation.py +225 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/section/sec_parapet_rc.py +53 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/section/sec_pile_rc.py +106 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/section/sec_pile_s.py +100 -0
- stbkit/tools/converters/_internal/stb_latest_to_element_data/section/sec_steel.py +432 -0
- stbkit/tools/converters/_internal/stb_to_building_geometry.py +44 -0
- stbkit/tools/converters/_internal/stb_to_ifc_data/__init__.py +5 -0
- stbkit/tools/converters/_internal/stb_to_ifc_data/_stb_to_ifc_data.py +59 -0
- stbkit/tools/converters/_internal/stb_to_ifc_data/convert_option.py +22 -0
- stbkit/tools/converters/_internal/stb_to_ply_text.py +22 -0
- stbkit/tools/py.typed +0 -0
- stbkit/tools/upgrade/__init__.py +13 -0
- stbkit/tools/upgrade/_internal/__init__.py +5 -0
- stbkit/tools/upgrade/_internal/common.py +205 -0
- stbkit/tools/upgrade/_internal/upgrade.py +228 -0
- stbkit/tools/upgrade/_internal/v2_0_2_to_v2_1_0/__init__.py +60 -0
- stbkit/tools/upgrade/_internal/v2_0_2_to_v2_1_0/hook_funcs/hook_common.py +62 -0
- stbkit/tools/upgrade/_internal/v2_0_2_to_v2_1_0/hook_funcs/hook_joint_beam_shape_h.py +44 -0
- stbkit/tools/upgrade/_internal/v2_0_2_to_v2_1_0/hook_funcs/hook_sec_pile_rc.py +101 -0
- stbkit/tools/upgrade/_internal/v2_0_2_to_v2_1_0/hook_funcs/hook_sec_pile_s.py +78 -0
- stbkit/tools/upgrade/_internal/v2_0_2_to_v2_1_0/hook_funcs/hook_sec_slab_deck.py +56 -0
- stbkit/tools/upgrade/_internal/v2_0_2_to_v2_1_0/hook_funcs/hook_sec_slab_rc.py +128 -0
- stbkit/tools/upgrade/_internal/v2_0_2_to_v2_1_0/hook_funcs/post_girder.py +126 -0
- stbkit/tools/upgrade/_internal/v2_0_2_to_v2_1_0/hook_funcs/post_open.py +110 -0
- stbkit/tools/upgrade/_internal/v2_0_2_to_v2_1_0/hook_funcs/post_sec_beam_rc.py +227 -0
- stbkit/tools/upgrade/_internal/v2_0_2_to_v2_1_0/hook_funcs/post_sec_beam_s.py +1153 -0
- stbkit/tools/upgrade/_internal/v2_0_2_to_v2_1_0/hooks.py +22 -0
- stbkit/tools/upgrade/_internal/v2_0_2_to_v2_1_0/post.py +42 -0
- stbkit/tools/upgrade/_internal/v2_0_2_to_v2_1_0/tables.py +99 -0
- stbkit/tools/upgrade/_internal/v2_1_0_to_v2_1_1/__init__.py +58 -0
- stbkit/tools/upgrade/_internal/v2_1_0_to_v2_1_1/hooks.py +32 -0
- stbkit/tools/upgrade/_internal/v2_1_0_to_v2_1_1/tables.py +56 -0
- stbkit-0.1.0a9.dev1.dist-info/METADATA +196 -0
- stbkit-0.1.0a9.dev1.dist-info/RECORD +125 -0
- stbkit-0.1.0a9.dev1.dist-info/WHEEL +5 -0
- stbkit-0.1.0a9.dev1.dist-info/entry_points.txt +2 -0
- stbkit-0.1.0a9.dev1.dist-info/licenses/LICENSE +373 -0
- stbkit-0.1.0a9.dev1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Copyright 2026 TAISEI CORPORATION
|
|
2
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
4
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
5
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
|
|
9
|
+
from .vectors import Vector3d
|
|
10
|
+
|
|
11
|
+
type _Matrix4x4Tuple = tuple[
|
|
12
|
+
tuple[float, float, float, float],
|
|
13
|
+
tuple[float, float, float, float],
|
|
14
|
+
tuple[float, float, float, float],
|
|
15
|
+
tuple[float, float, float, float],
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True, slots=True)
|
|
20
|
+
class RotationMatrix:
|
|
21
|
+
"""回転行列
|
|
22
|
+
x_axis,y_axis,z_axisは正規直行基底"""
|
|
23
|
+
|
|
24
|
+
origin: Vector3d
|
|
25
|
+
x_axis: Vector3d
|
|
26
|
+
y_axis: Vector3d
|
|
27
|
+
z_axis: Vector3d
|
|
28
|
+
|
|
29
|
+
def to_global_point(self, point: Vector3d) -> Vector3d:
|
|
30
|
+
return (
|
|
31
|
+
self.origin
|
|
32
|
+
+ point.x * self.x_axis
|
|
33
|
+
+ point.y * self.y_axis
|
|
34
|
+
+ point.z * self.z_axis
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def to_local_point(self, point: Vector3d) -> Vector3d:
|
|
38
|
+
delta: Vector3d = point - self.origin
|
|
39
|
+
return Vector3d(
|
|
40
|
+
delta.dot(self.x_axis),
|
|
41
|
+
delta.dot(self.y_axis),
|
|
42
|
+
delta.dot(self.z_axis),
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
def to_matrix_tuple(self) -> _Matrix4x4Tuple:
|
|
46
|
+
return (
|
|
47
|
+
(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.origin.x),
|
|
48
|
+
(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.origin.y),
|
|
49
|
+
(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.origin.z),
|
|
50
|
+
(0.0, 0.0, 0.0, 1.0),
|
|
51
|
+
)
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Copyright 2025-2026 TAISEI CORPORATION
|
|
2
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
4
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
5
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Copyright 2026 TAISEI CORPORATION
|
|
2
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
4
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
5
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
6
|
+
|
|
7
|
+
from typing import Never
|
|
8
|
+
|
|
9
|
+
_IFCOPENSHELL_IMPORT_ERROR_MESSAGE = (
|
|
10
|
+
"ifcopenshellがインストールされていません。IFCファイルの機能を利用するにはifcopenshellをインストールしてください。\n"
|
|
11
|
+
"インストール方法: \npip install ifcopenshell\n"
|
|
12
|
+
"または\npip install stbkit[ifc]"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def raise_import_error(e: ImportError) -> Never:
|
|
17
|
+
if e.name == "ifcopenshell" or (
|
|
18
|
+
e.name is not None and e.name.startswith("ifcopenshell.")
|
|
19
|
+
):
|
|
20
|
+
raise ImportError(_IFCOPENSHELL_IMPORT_ERROR_MESSAGE) from e
|
|
21
|
+
raise ImportError(f"予期しないImportErrorが発生しました: {e}") from e
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def ensure_ifcopenshell() -> None:
|
|
25
|
+
try:
|
|
26
|
+
import ifcopenshell # noqa: F401
|
|
27
|
+
except ImportError as e:
|
|
28
|
+
raise_import_error(e)
|
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
# Copyright 2025-2026 TAISEI CORPORATION
|
|
2
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
4
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
5
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
6
|
+
|
|
7
|
+
from typing import Protocol
|
|
8
|
+
from uuid import UUID
|
|
9
|
+
|
|
10
|
+
import ifcopenshell.api.aggregate
|
|
11
|
+
import ifcopenshell.api.context
|
|
12
|
+
import ifcopenshell.api.geometry
|
|
13
|
+
import ifcopenshell.api.project
|
|
14
|
+
import ifcopenshell.api.root
|
|
15
|
+
import ifcopenshell.api.unit
|
|
16
|
+
import ifcopenshell.file
|
|
17
|
+
import numpy as np
|
|
18
|
+
from ifcopenshell import entity_instance
|
|
19
|
+
from numpy.typing import NDArray
|
|
20
|
+
from stbkit.core._internal.transform.guid_tools import generate_uuid
|
|
21
|
+
from stbkit.core.stb_exceptions import ZeroLengthMemberError
|
|
22
|
+
from stbkit.core.stb_reporting import Code, Phase, Reporter, get_reporter
|
|
23
|
+
|
|
24
|
+
from ....converters._internal import coord_converter
|
|
25
|
+
from ...constants import UNKNOWN_ELEMENT_SIZE_MM
|
|
26
|
+
from ...data_model.element_data import (
|
|
27
|
+
ElementLine,
|
|
28
|
+
ElementLineSrc,
|
|
29
|
+
ElementPlane,
|
|
30
|
+
ElementType,
|
|
31
|
+
)
|
|
32
|
+
from ...data_model.ifc_data.entity_data import (
|
|
33
|
+
IfcBuilding,
|
|
34
|
+
IfcBuildingStorey,
|
|
35
|
+
IfcModel,
|
|
36
|
+
IfcProject,
|
|
37
|
+
IfcSite,
|
|
38
|
+
)
|
|
39
|
+
from ...data_model.ifc_data.entity_names import EntityName
|
|
40
|
+
from ...matrix import RotationMatrix
|
|
41
|
+
from ...utils.float_rounding import round_float
|
|
42
|
+
from ...utils.guid_utils import to_ifc_guid
|
|
43
|
+
from ...vectors import Vector2d, Vector3d
|
|
44
|
+
from .ifc_representation_exporter import IfcRepresentationExporter
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _rotation_matrix_to_ndarray(
|
|
48
|
+
matrix: RotationMatrix,
|
|
49
|
+
*,
|
|
50
|
+
round_digits: int | None,
|
|
51
|
+
round_digits_mm: int | None,
|
|
52
|
+
) -> NDArray[np.float64]:
|
|
53
|
+
result: NDArray[np.float64] = np.array(matrix.to_matrix_tuple(), dtype=np.float64)
|
|
54
|
+
if result.shape != (4, 4):
|
|
55
|
+
raise AssertionError(f"4x4行列ではありません: {result.shape}")
|
|
56
|
+
if round_digits is None and round_digits_mm is None:
|
|
57
|
+
return result
|
|
58
|
+
rounded: NDArray[np.float64] = result.copy()
|
|
59
|
+
if round_digits is not None:
|
|
60
|
+
for i in range(3):
|
|
61
|
+
for j in range(3):
|
|
62
|
+
rounded[i, j] = round_float(
|
|
63
|
+
rounded[i, j],
|
|
64
|
+
round_digits=round_digits,
|
|
65
|
+
)
|
|
66
|
+
if round_digits_mm is not None:
|
|
67
|
+
round_digits_m: int = round_digits_mm + 3
|
|
68
|
+
rounded[0, 3] = round_float(rounded[0, 3], round_digits=round_digits_m)
|
|
69
|
+
rounded[1, 3] = round_float(rounded[1, 3], round_digits=round_digits_m)
|
|
70
|
+
rounded[2, 3] = round_float(rounded[2, 3], round_digits=round_digits_m)
|
|
71
|
+
return rounded
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class _HasGuid(Protocol):
|
|
75
|
+
guid: UUID | None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _unit_sort_key(unit: entity_instance) -> tuple[str, str]:
|
|
79
|
+
"""単位を固定順序へ並べるためのkey"""
|
|
80
|
+
return (unit.is_a(), str(getattr(unit, "UnitType", "")))
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _set_guid(ifc_entity: entity_instance, obj: _HasGuid) -> None:
|
|
84
|
+
if obj.guid is None:
|
|
85
|
+
obj.guid = generate_uuid()
|
|
86
|
+
if obj.guid:
|
|
87
|
+
ifc_entity.GlobalId = to_ifc_guid(obj.guid)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class IfcEntityExporter:
|
|
91
|
+
def __init__(
|
|
92
|
+
self,
|
|
93
|
+
*,
|
|
94
|
+
model: ifcopenshell.file | None = None,
|
|
95
|
+
reporter: Reporter | None = None,
|
|
96
|
+
round_digits: int | None = None,
|
|
97
|
+
round_digits_mm: int | None = None,
|
|
98
|
+
) -> None:
|
|
99
|
+
self._model: ifcopenshell.file | None = model
|
|
100
|
+
self._body: entity_instance | None = None
|
|
101
|
+
self._round_digits: int | None = round_digits
|
|
102
|
+
self._round_digits_mm: int | None = round_digits_mm
|
|
103
|
+
self.reporter: Reporter = reporter or get_reporter()
|
|
104
|
+
self.representation_exporter: IfcRepresentationExporter = (
|
|
105
|
+
IfcRepresentationExporter(
|
|
106
|
+
model,
|
|
107
|
+
reporter=self.reporter,
|
|
108
|
+
round_digits_mm=round_digits_mm,
|
|
109
|
+
)
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def model(self) -> ifcopenshell.file:
|
|
114
|
+
if self._model is None:
|
|
115
|
+
raise AssertionError("modelが初期化されていません")
|
|
116
|
+
return self._model
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def body(self) -> entity_instance:
|
|
120
|
+
if self._body is None:
|
|
121
|
+
raise AssertionError("bodyが初期化されていません")
|
|
122
|
+
return self._body
|
|
123
|
+
|
|
124
|
+
@body.setter
|
|
125
|
+
def body(self, value: entity_instance) -> None:
|
|
126
|
+
self._body = value
|
|
127
|
+
self.representation_exporter.body = value
|
|
128
|
+
|
|
129
|
+
def create_entity_plane_element(
|
|
130
|
+
self,
|
|
131
|
+
plane_element: ElementPlane,
|
|
132
|
+
) -> entity_instance:
|
|
133
|
+
if not plane_element.points:
|
|
134
|
+
raise AssertionError(f"{plane_element.name}にpointsが設定されていません")
|
|
135
|
+
if len(plane_element.points) < 3:
|
|
136
|
+
raise AssertionError(f"{plane_element.name}のpointsの数が3以下です")
|
|
137
|
+
if plane_element.element_type is None:
|
|
138
|
+
raise AssertionError(
|
|
139
|
+
f"{plane_element.name}にelement_typeが設定されていません"
|
|
140
|
+
)
|
|
141
|
+
plate_element: entity_instance = ifcopenshell.api.root.create_entity(
|
|
142
|
+
self.model,
|
|
143
|
+
ifc_class=IfcEntityExporter.to_entity_name(
|
|
144
|
+
plane_element.element_type
|
|
145
|
+
).value,
|
|
146
|
+
name=plane_element.name,
|
|
147
|
+
)
|
|
148
|
+
_set_guid(plate_element, plane_element)
|
|
149
|
+
thickness: float | None = plane_element.thickness
|
|
150
|
+
if thickness is None:
|
|
151
|
+
self.reporter.warning(
|
|
152
|
+
f"要素[{plane_element.name}]にthicknessが設定されていないため、厚さ{UNKNOWN_ELEMENT_SIZE_MM}mmで出力します。",
|
|
153
|
+
code=Code.UNKNOWN_SHAPE,
|
|
154
|
+
phase=Phase.CONVERT_IFC,
|
|
155
|
+
)
|
|
156
|
+
thickness = UNKNOWN_ELEMENT_SIZE_MM
|
|
157
|
+
|
|
158
|
+
representation = self.representation_exporter.get_plate_representation(
|
|
159
|
+
thickness=thickness,
|
|
160
|
+
opens=plane_element.opens,
|
|
161
|
+
points=plane_element.points,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
ifcopenshell.api.geometry.assign_representation(
|
|
165
|
+
self.model, product=plate_element, representation=representation
|
|
166
|
+
)
|
|
167
|
+
matrix = _rotation_matrix_to_ndarray(
|
|
168
|
+
coord_converter.rotation_matrix_plate(
|
|
169
|
+
[p.mm_to_m() for p in plane_element.points]
|
|
170
|
+
),
|
|
171
|
+
round_digits=self._round_digits,
|
|
172
|
+
round_digits_mm=self._round_digits_mm,
|
|
173
|
+
)
|
|
174
|
+
ifcopenshell.api.geometry.edit_object_placement(
|
|
175
|
+
self.model, product=plate_element, matrix=matrix
|
|
176
|
+
)
|
|
177
|
+
return plate_element
|
|
178
|
+
|
|
179
|
+
def create_entity_element_line(
|
|
180
|
+
self,
|
|
181
|
+
element_line: ElementLine,
|
|
182
|
+
) -> entity_instance | None:
|
|
183
|
+
if not element_line.lengths:
|
|
184
|
+
self.reporter.warning(
|
|
185
|
+
f"要素[{element_line.name}]にlengthsが設定されていないため、IFCエクスポートをスキップしました。",
|
|
186
|
+
code=Code.ZERO_LENGTH_MEMBER,
|
|
187
|
+
phase=Phase.CONVERT_IFC,
|
|
188
|
+
)
|
|
189
|
+
return None
|
|
190
|
+
if not element_line.point_start:
|
|
191
|
+
raise AssertionError(
|
|
192
|
+
f"{element_line.name}にpoint_startが設定されていません"
|
|
193
|
+
)
|
|
194
|
+
if not element_line.point_end:
|
|
195
|
+
raise AssertionError(f"{element_line.name}にpoint_endが設定されていません")
|
|
196
|
+
if element_line.element_type is None:
|
|
197
|
+
raise AssertionError(
|
|
198
|
+
f"{element_line.name}にelement_typeが設定されていません"
|
|
199
|
+
)
|
|
200
|
+
line_element: entity_instance = ifcopenshell.api.root.create_entity(
|
|
201
|
+
self.model,
|
|
202
|
+
ifc_class=IfcEntityExporter.to_entity_name(element_line.element_type).value,
|
|
203
|
+
name=element_line.name,
|
|
204
|
+
)
|
|
205
|
+
_set_guid(line_element, element_line)
|
|
206
|
+
point_start: Vector3d = element_line.point_start
|
|
207
|
+
point_end: Vector3d = element_line.point_end
|
|
208
|
+
if element_line.shapes:
|
|
209
|
+
representation = self.representation_exporter.get_line_representation(
|
|
210
|
+
shapes=element_line.shapes,
|
|
211
|
+
axis_position=element_line.axis_position,
|
|
212
|
+
lengths=element_line.lengths,
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
if self.representation_exporter.is_extrusion(element_line.shapes):
|
|
216
|
+
offset: Vector2d = Vector2d.zero() - element_line.shapes[
|
|
217
|
+
0
|
|
218
|
+
].start.get_position_point(element_line.axis_position)
|
|
219
|
+
if element_line.shapes[0].start.offset:
|
|
220
|
+
offset += element_line.shapes[0].start.offset
|
|
221
|
+
_, vy, vz = coord_converter.axis_vector_by_element_type(
|
|
222
|
+
element_line.point_start,
|
|
223
|
+
element_line.point_end,
|
|
224
|
+
element_line.angle,
|
|
225
|
+
element_line.element_type,
|
|
226
|
+
)
|
|
227
|
+
point_start += offset.x * vy + offset.y * vz
|
|
228
|
+
point_end += offset.x * vy + offset.y * vz
|
|
229
|
+
|
|
230
|
+
else:
|
|
231
|
+
representation = (
|
|
232
|
+
self.representation_exporter.get_line_unknown_representation(
|
|
233
|
+
element_line.lengths
|
|
234
|
+
)
|
|
235
|
+
)
|
|
236
|
+
ifcopenshell.api.geometry.assign_representation(
|
|
237
|
+
self.model, product=line_element, representation=representation
|
|
238
|
+
)
|
|
239
|
+
matrix = _rotation_matrix_to_ndarray(
|
|
240
|
+
coord_converter.rotation_matrix_by_element_type(
|
|
241
|
+
point_start.mm_to_m(),
|
|
242
|
+
point_end.mm_to_m(),
|
|
243
|
+
element_line.angle,
|
|
244
|
+
element_line.element_type,
|
|
245
|
+
),
|
|
246
|
+
round_digits=self._round_digits,
|
|
247
|
+
round_digits_mm=self._round_digits_mm,
|
|
248
|
+
)
|
|
249
|
+
ifcopenshell.api.geometry.edit_object_placement(
|
|
250
|
+
self.model, product=line_element, matrix=matrix
|
|
251
|
+
)
|
|
252
|
+
return line_element
|
|
253
|
+
|
|
254
|
+
def create_entity_element_line_src(
|
|
255
|
+
self,
|
|
256
|
+
line_element_src: ElementLineSrc,
|
|
257
|
+
) -> entity_instance:
|
|
258
|
+
element_assembly: entity_instance = ifcopenshell.api.root.create_entity(
|
|
259
|
+
self.model,
|
|
260
|
+
ifc_class=EntityName.IFC_ELEMENT_ASSEMBLY.value,
|
|
261
|
+
name=line_element_src.name,
|
|
262
|
+
)
|
|
263
|
+
_set_guid(element_assembly, line_element_src)
|
|
264
|
+
|
|
265
|
+
items: list[entity_instance] = []
|
|
266
|
+
if line_element_src.steel:
|
|
267
|
+
item_steel: entity_instance | None = self.create_entity_element_line(
|
|
268
|
+
line_element_src.steel
|
|
269
|
+
)
|
|
270
|
+
if item_steel is not None:
|
|
271
|
+
items.append(item_steel)
|
|
272
|
+
if line_element_src.rc:
|
|
273
|
+
item_rc: entity_instance | None = self.create_entity_element_line(
|
|
274
|
+
line_element_src.rc
|
|
275
|
+
)
|
|
276
|
+
if item_rc is not None:
|
|
277
|
+
items.append(item_rc)
|
|
278
|
+
# ifcopenshellのassign_objectは呼ぶたびに集合演算を行うため処理時間がかかり順序も安定しなくなる。
|
|
279
|
+
# そのため、参照関係はここで1度だけ作る。
|
|
280
|
+
if items:
|
|
281
|
+
self.model.create_entity(
|
|
282
|
+
EntityName.IFC_REL_AGGREGATES.value,
|
|
283
|
+
GlobalId=to_ifc_guid(generate_uuid()),
|
|
284
|
+
RelatingObject=element_assembly,
|
|
285
|
+
RelatedObjects=items,
|
|
286
|
+
)
|
|
287
|
+
return element_assembly
|
|
288
|
+
|
|
289
|
+
def create_entity_element(
|
|
290
|
+
self,
|
|
291
|
+
element: ElementLine | ElementPlane | ElementLineSrc,
|
|
292
|
+
) -> entity_instance | None:
|
|
293
|
+
try:
|
|
294
|
+
match element:
|
|
295
|
+
case ElementLine() as line_element:
|
|
296
|
+
return self.create_entity_element_line(line_element)
|
|
297
|
+
case ElementPlane() as plane_element:
|
|
298
|
+
return self.create_entity_plane_element(plane_element)
|
|
299
|
+
case ElementLineSrc() as line_element_src:
|
|
300
|
+
return self.create_entity_element_line_src(line_element_src)
|
|
301
|
+
case _:
|
|
302
|
+
raise AssertionError(f"不明な要素タイプです: {type(element)}")
|
|
303
|
+
except ZeroLengthMemberError:
|
|
304
|
+
self.reporter.warning(
|
|
305
|
+
f"要素'{element.name}'の始端と終端が同じ位置のため、IFCエクスポートをスキップしました。",
|
|
306
|
+
code=Code.ZERO_LENGTH_MEMBER,
|
|
307
|
+
phase=Phase.CONVERT_IFC,
|
|
308
|
+
)
|
|
309
|
+
return None
|
|
310
|
+
|
|
311
|
+
def create_entity_building_storey(
|
|
312
|
+
self,
|
|
313
|
+
ifc_building_storey: IfcBuildingStorey,
|
|
314
|
+
) -> entity_instance:
|
|
315
|
+
building_storey: entity_instance = ifcopenshell.api.root.create_entity(
|
|
316
|
+
self.model,
|
|
317
|
+
ifc_class=EntityName.IFC_BUILDING_STOREY.value,
|
|
318
|
+
name=ifc_building_storey.name,
|
|
319
|
+
)
|
|
320
|
+
_set_guid(building_storey, ifc_building_storey)
|
|
321
|
+
n_element: int = len(ifc_building_storey.elements)
|
|
322
|
+
self.reporter.info(
|
|
323
|
+
message=f"---要素のIFCエンティティ変換処理({n_element}件)---",
|
|
324
|
+
code=Code.PROGRESS_INFO,
|
|
325
|
+
phase=Phase.CONVERT_IFC,
|
|
326
|
+
)
|
|
327
|
+
elements: list[entity_instance] = []
|
|
328
|
+
batch_size: int = 1000
|
|
329
|
+
for i, element in enumerate(ifc_building_storey.elements, 1):
|
|
330
|
+
e = self.create_entity_element(element)
|
|
331
|
+
if e is not None:
|
|
332
|
+
elements.append(e)
|
|
333
|
+
if i % batch_size == 0 or i == n_element:
|
|
334
|
+
self.reporter.info(
|
|
335
|
+
message=f"---要素のIFCエンティティ変換処理({i}/{n_element}件)---",
|
|
336
|
+
code=Code.PROGRESS_INFO,
|
|
337
|
+
phase=Phase.CONVERT_IFC,
|
|
338
|
+
)
|
|
339
|
+
n_element = len(elements)
|
|
340
|
+
self.reporter.info(
|
|
341
|
+
message=f"---要素のIFCエンティティ配置処理({n_element}件)---",
|
|
342
|
+
code=Code.PROGRESS_INFO,
|
|
343
|
+
phase=Phase.CONVERT_IFC,
|
|
344
|
+
)
|
|
345
|
+
# ifcopenshellのassign_containerは、呼ぶたびに集合演算を行うため処理時間がかかり順序も安定しなくなる。
|
|
346
|
+
# そのため、参照関係はここで1度だけ作る。
|
|
347
|
+
if elements:
|
|
348
|
+
self.model.create_entity(
|
|
349
|
+
EntityName.IFC_REL_CONTAINED_IN_SPATIAL_STRUCTURE.value,
|
|
350
|
+
GlobalId=to_ifc_guid(generate_uuid()),
|
|
351
|
+
RelatedElements=elements,
|
|
352
|
+
RelatingStructure=building_storey,
|
|
353
|
+
)
|
|
354
|
+
return building_storey
|
|
355
|
+
|
|
356
|
+
def create_entity_ifc_building(self, ifc_building: IfcBuilding) -> entity_instance:
|
|
357
|
+
building: entity_instance = ifcopenshell.api.root.create_entity(
|
|
358
|
+
self.model,
|
|
359
|
+
ifc_class=EntityName.IFC_BUILDING.value,
|
|
360
|
+
name=ifc_building.name,
|
|
361
|
+
)
|
|
362
|
+
_set_guid(building, ifc_building)
|
|
363
|
+
building_storeys: list[entity_instance] = [
|
|
364
|
+
self.create_entity_building_storey(building_storey)
|
|
365
|
+
for building_storey in ifc_building.building_storeys
|
|
366
|
+
]
|
|
367
|
+
rel: entity_instance | None = ifcopenshell.api.aggregate.assign_object(
|
|
368
|
+
self.model, relating_object=building, products=building_storeys
|
|
369
|
+
)
|
|
370
|
+
if rel is not None:
|
|
371
|
+
rel.GlobalId = to_ifc_guid(generate_uuid())
|
|
372
|
+
return building
|
|
373
|
+
|
|
374
|
+
def create_entity_ifc_site(self, ifc_site: IfcSite) -> entity_instance:
|
|
375
|
+
site: entity_instance = ifcopenshell.api.root.create_entity(
|
|
376
|
+
self.model, ifc_class=EntityName.IFC_SITE.value, name=ifc_site.name
|
|
377
|
+
)
|
|
378
|
+
if not ifc_site.building:
|
|
379
|
+
raise AssertionError("buildingが設定されていません")
|
|
380
|
+
building: entity_instance = self.create_entity_ifc_building(ifc_site.building)
|
|
381
|
+
_set_guid(site, ifc_site)
|
|
382
|
+
rel: entity_instance | None = ifcopenshell.api.aggregate.assign_object(
|
|
383
|
+
self.model, relating_object=site, products=[building]
|
|
384
|
+
)
|
|
385
|
+
if rel is not None:
|
|
386
|
+
rel.GlobalId = to_ifc_guid(generate_uuid())
|
|
387
|
+
return site
|
|
388
|
+
|
|
389
|
+
def create_entity_project(self, ifc_project: IfcProject) -> entity_instance:
|
|
390
|
+
project: entity_instance = ifcopenshell.api.root.create_entity(
|
|
391
|
+
self.model, ifc_class=EntityName.IFC_PROJECT.value, name=ifc_project.name
|
|
392
|
+
)
|
|
393
|
+
_set_guid(project, ifc_project)
|
|
394
|
+
ifcopenshell.api.unit.assign_unit(self.model)
|
|
395
|
+
# assign_unitはsetを経由するため並びが実行ごとに変わるため、順序を固定する
|
|
396
|
+
units = project.UnitsInContext
|
|
397
|
+
if units is not None:
|
|
398
|
+
units.Units = sorted(units.Units, key=_unit_sort_key)
|
|
399
|
+
context: entity_instance = ifcopenshell.api.context.add_context(
|
|
400
|
+
self.model, context_type="Model"
|
|
401
|
+
)
|
|
402
|
+
self.body = ifcopenshell.api.context.add_context(
|
|
403
|
+
self.model,
|
|
404
|
+
context_type="Model",
|
|
405
|
+
context_identifier="Body",
|
|
406
|
+
target_view="MODEL_VIEW",
|
|
407
|
+
parent=context,
|
|
408
|
+
)
|
|
409
|
+
if not ifc_project.site:
|
|
410
|
+
raise AssertionError("siteが設定されていません")
|
|
411
|
+
site: entity_instance = self.create_entity_ifc_site(ifc_project.site)
|
|
412
|
+
rel: entity_instance | None = ifcopenshell.api.aggregate.assign_object(
|
|
413
|
+
self.model, relating_object=project, products=[site]
|
|
414
|
+
)
|
|
415
|
+
if rel is not None:
|
|
416
|
+
rel.GlobalId = to_ifc_guid(generate_uuid())
|
|
417
|
+
return project
|
|
418
|
+
|
|
419
|
+
@staticmethod
|
|
420
|
+
def ifc_model_to_file(
|
|
421
|
+
ifc_model: IfcModel,
|
|
422
|
+
*,
|
|
423
|
+
reporter: Reporter,
|
|
424
|
+
round_digits: int | None = None,
|
|
425
|
+
round_digits_mm: int | None = None,
|
|
426
|
+
) -> ifcopenshell.file:
|
|
427
|
+
reporter.info(
|
|
428
|
+
"---IFCジオメトリデータ->IFC Entityデータ変換処理開始---",
|
|
429
|
+
code=Code.PROGRESS_INFO,
|
|
430
|
+
phase=Phase.CONVERT_IFC,
|
|
431
|
+
)
|
|
432
|
+
model: ifcopenshell.file = ifcopenshell.api.project.create_file()
|
|
433
|
+
exporter: IfcEntityExporter = IfcEntityExporter(
|
|
434
|
+
model=model,
|
|
435
|
+
reporter=reporter,
|
|
436
|
+
round_digits=round_digits,
|
|
437
|
+
round_digits_mm=round_digits_mm,
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
if not ifc_model.project:
|
|
441
|
+
raise AssertionError("projectが設定されていません")
|
|
442
|
+
exporter.create_entity_project(ifc_model.project)
|
|
443
|
+
reporter.info(
|
|
444
|
+
"---IFCジオメトリデータ->IFC Entityデータ変換処理終了---",
|
|
445
|
+
code=Code.PROGRESS_INFO,
|
|
446
|
+
phase=Phase.CONVERT_IFC,
|
|
447
|
+
)
|
|
448
|
+
return model
|
|
449
|
+
|
|
450
|
+
@staticmethod
|
|
451
|
+
def to_entity_name(element_type: ElementType) -> EntityName:
|
|
452
|
+
match element_type:
|
|
453
|
+
case (
|
|
454
|
+
ElementType.GIRDER
|
|
455
|
+
| ElementType.BEAM
|
|
456
|
+
| ElementType.STRIP_FOOTING
|
|
457
|
+
| ElementType.PARAPET
|
|
458
|
+
):
|
|
459
|
+
return EntityName.IFC_BEAM
|
|
460
|
+
case ElementType.COLUMN | ElementType.POST | ElementType.FOUNDATION_COLUMN:
|
|
461
|
+
return EntityName.IFC_COLUMN
|
|
462
|
+
case ElementType.BRACE:
|
|
463
|
+
return EntityName.IFC_MEMBER
|
|
464
|
+
case ElementType.WALL:
|
|
465
|
+
return EntityName.IFC_WALL
|
|
466
|
+
case ElementType.SLAB:
|
|
467
|
+
return EntityName.IFC_SLAB
|
|
468
|
+
case ElementType.FOOTING:
|
|
469
|
+
return EntityName.IFC_FOOTING
|
|
470
|
+
case ElementType.PILE:
|
|
471
|
+
return EntityName.IFC_PILE
|
|
472
|
+
case _:
|
|
473
|
+
raise AssertionError(f"不明なElementTypeです: {element_type}")
|