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,549 @@
|
|
|
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
|
+
import uuid
|
|
8
|
+
from collections.abc import Sequence
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from uuid import UUID
|
|
11
|
+
|
|
12
|
+
from stbkit.core.stb_reporting import Code, Phase, Reporter
|
|
13
|
+
|
|
14
|
+
from stbkit.tools._internal.vectors import Vector2d, Vector3d
|
|
15
|
+
|
|
16
|
+
from ..._internal.data_model.building_geometry import (
|
|
17
|
+
BuildingGeometry,
|
|
18
|
+
ElementFlags,
|
|
19
|
+
ElementKind,
|
|
20
|
+
SurfaceLoopType,
|
|
21
|
+
)
|
|
22
|
+
from ..._internal.data_model.element_data import (
|
|
23
|
+
ElementData,
|
|
24
|
+
ElementLine,
|
|
25
|
+
ElementLineSrc,
|
|
26
|
+
ElementPlane,
|
|
27
|
+
ElementType,
|
|
28
|
+
Node,
|
|
29
|
+
)
|
|
30
|
+
from ..._internal.data_model.shape_data import Shape, ShapePair, ShapePosition
|
|
31
|
+
from ..._internal.utils.mesh_utils import create_mesh
|
|
32
|
+
from .coord_converter import (
|
|
33
|
+
axis_vector_plate,
|
|
34
|
+
to_global_coord,
|
|
35
|
+
to_global_coord_plate,
|
|
36
|
+
to_plate_element_coord,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class _LocalMesh:
|
|
42
|
+
vertices: list[Vector3d] = field(default_factory=list)
|
|
43
|
+
faces: list[Sequence[int]] = field(default_factory=list)
|
|
44
|
+
|
|
45
|
+
def add_vertices_and_faces(
|
|
46
|
+
self, vertices: Sequence[Vector3d], faces: Sequence[Sequence[int]]
|
|
47
|
+
) -> None:
|
|
48
|
+
offset: int = len(self.vertices)
|
|
49
|
+
self.vertices.extend(vertices)
|
|
50
|
+
for face in faces:
|
|
51
|
+
self.faces.append([f + offset for f in face])
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def create_local_line_meshes(
|
|
55
|
+
shapes: Sequence[ShapePair],
|
|
56
|
+
axis_position: ShapePosition,
|
|
57
|
+
lengths: Sequence[float],
|
|
58
|
+
) -> list[_LocalMesh]:
|
|
59
|
+
if not shapes:
|
|
60
|
+
raise AssertionError("形状が設定されていません")
|
|
61
|
+
if len(shapes) != len(lengths):
|
|
62
|
+
raise AssertionError("形状と長さの数が異なります")
|
|
63
|
+
|
|
64
|
+
meshes: list[_LocalMesh] = []
|
|
65
|
+
start_length = 0.0
|
|
66
|
+
for shape, length in zip(shapes, lengths, strict=True):
|
|
67
|
+
shape_end: Shape = shape.end if shape.end else shape.start
|
|
68
|
+
start_point2ds: list[Vector2d] = (
|
|
69
|
+
shape.start.get_out_point2ds_with_rotate_and_offset()
|
|
70
|
+
)
|
|
71
|
+
end_point2ds: list[Vector2d] = (
|
|
72
|
+
shape_end.get_out_point2ds_with_rotate_and_offset()
|
|
73
|
+
)
|
|
74
|
+
start_in_point2ds: list[Vector2d] | None = (
|
|
75
|
+
shape.start.get_in_point2ds_with_rotate_and_offset()
|
|
76
|
+
)
|
|
77
|
+
end_in_point2ds: list[Vector2d] | None = (
|
|
78
|
+
shape_end.get_in_point2ds_with_rotate_and_offset()
|
|
79
|
+
)
|
|
80
|
+
index_start: int = 0
|
|
81
|
+
index_end: int = index_start + len(start_point2ds)
|
|
82
|
+
if axis_position != ShapePosition.CENTER_CENTER:
|
|
83
|
+
offset_start: Vector2d = shape.start.get_position_point(axis_position)
|
|
84
|
+
start_point2ds = [point - offset_start for point in start_point2ds]
|
|
85
|
+
offset_end: Vector2d = shape_end.get_position_point(axis_position)
|
|
86
|
+
end_point2ds = [point - offset_end for point in end_point2ds]
|
|
87
|
+
|
|
88
|
+
if len(start_point2ds) != len(end_point2ds):
|
|
89
|
+
raise AssertionError("断面のStartとEndの頂点数が異なります")
|
|
90
|
+
|
|
91
|
+
n: int = len(start_point2ds)
|
|
92
|
+
vertices: list[Vector3d] = [
|
|
93
|
+
point.to_vector3d(start_length) for point in start_point2ds
|
|
94
|
+
]
|
|
95
|
+
vertices.extend(
|
|
96
|
+
point.to_vector3d(start_length + length) for point in end_point2ds
|
|
97
|
+
)
|
|
98
|
+
faces: list[Sequence[int]] = []
|
|
99
|
+
if (
|
|
100
|
+
start_in_point2ds
|
|
101
|
+
and end_in_point2ds
|
|
102
|
+
and len(start_in_point2ds) == len(end_in_point2ds)
|
|
103
|
+
and len(start_point2ds) == len(start_in_point2ds)
|
|
104
|
+
):
|
|
105
|
+
vertices.extend(
|
|
106
|
+
point.to_vector3d(start_length) for point in start_in_point2ds
|
|
107
|
+
)
|
|
108
|
+
vertices.extend(
|
|
109
|
+
point.to_vector3d(start_length + length) for point in end_in_point2ds
|
|
110
|
+
)
|
|
111
|
+
index_in_start: int = index_end + len(end_point2ds)
|
|
112
|
+
index_in_end: int = index_in_start + len(start_in_point2ds)
|
|
113
|
+
for i in range(len(start_in_point2ds)):
|
|
114
|
+
faces.append(
|
|
115
|
+
[
|
|
116
|
+
(i + 1) % n + index_in_start,
|
|
117
|
+
i + index_in_start,
|
|
118
|
+
i + index_in_end,
|
|
119
|
+
(i + 1) % n + index_in_end,
|
|
120
|
+
]
|
|
121
|
+
)
|
|
122
|
+
faces.append(
|
|
123
|
+
[
|
|
124
|
+
i + index_start,
|
|
125
|
+
(i + 1) % n + index_start,
|
|
126
|
+
(i + 1) % n + index_in_start,
|
|
127
|
+
i + index_in_start,
|
|
128
|
+
]
|
|
129
|
+
)
|
|
130
|
+
faces.append(
|
|
131
|
+
[
|
|
132
|
+
(i + 1) % n + index_end,
|
|
133
|
+
i + index_end,
|
|
134
|
+
i + index_in_end,
|
|
135
|
+
(i + 1) % n + index_in_end,
|
|
136
|
+
]
|
|
137
|
+
)
|
|
138
|
+
else:
|
|
139
|
+
faces.append(list(range(n)))
|
|
140
|
+
faces.append(list(range(2 * n - 1, n - 1, -1)))
|
|
141
|
+
|
|
142
|
+
for i in range(n):
|
|
143
|
+
faces.append(
|
|
144
|
+
[
|
|
145
|
+
i,
|
|
146
|
+
(i + 1) % n,
|
|
147
|
+
(i + 1) % n + n,
|
|
148
|
+
i + n,
|
|
149
|
+
]
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
meshes.append(_LocalMesh(vertices=vertices, faces=faces))
|
|
153
|
+
start_length += length
|
|
154
|
+
|
|
155
|
+
return meshes
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _triangulate_faces(mesh: _LocalMesh) -> _LocalMesh:
|
|
159
|
+
result_vertices: list[Vector3d] = list(mesh.vertices)
|
|
160
|
+
result_faces: list[Sequence[int]] = []
|
|
161
|
+
|
|
162
|
+
for face in mesh.faces:
|
|
163
|
+
match len(face):
|
|
164
|
+
case 0 | 1 | 2:
|
|
165
|
+
raise ValueError("頂点数が3未満の面は三角形分割できません")
|
|
166
|
+
case 3:
|
|
167
|
+
result_faces.append(list(face))
|
|
168
|
+
case _:
|
|
169
|
+
face_vertices: list[Vector3d] = [mesh.vertices[index] for index in face]
|
|
170
|
+
face_vertices_element: list[Vector2d] = [
|
|
171
|
+
Vector2d(v.x, v.y) for v in to_plate_element_coord(face_vertices)
|
|
172
|
+
]
|
|
173
|
+
_, new_faces, _, _ = create_mesh(face_vertices_element)
|
|
174
|
+
result_faces.extend(new_faces)
|
|
175
|
+
return _LocalMesh(vertices=result_vertices, faces=result_faces)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def element_line_to_element_mesh(
|
|
179
|
+
element: ElementLine, *, allow_polygons: bool, reporter: Reporter
|
|
180
|
+
) -> _LocalMesh | None:
|
|
181
|
+
if not element.shapes or not element.point_start or not element.point_end:
|
|
182
|
+
reporter.error(
|
|
183
|
+
"形状が設定されていません",
|
|
184
|
+
code=Code.UNKNOWN_SHAPE,
|
|
185
|
+
phase=Phase.CONVERT_GEOMETRY,
|
|
186
|
+
)
|
|
187
|
+
return None
|
|
188
|
+
if not element.element_type:
|
|
189
|
+
reporter.error(
|
|
190
|
+
"要素タイプが設定されていません",
|
|
191
|
+
code=Code.UNKNOWN_SHAPE,
|
|
192
|
+
phase=Phase.CONVERT_GEOMETRY,
|
|
193
|
+
)
|
|
194
|
+
return None
|
|
195
|
+
if len(element.shapes) != len(element.lengths):
|
|
196
|
+
reporter.error(
|
|
197
|
+
"形状と長さの数が異なります",
|
|
198
|
+
code=Code.UNKNOWN_SHAPE,
|
|
199
|
+
phase=Phase.CONVERT_GEOMETRY,
|
|
200
|
+
)
|
|
201
|
+
return None
|
|
202
|
+
local_meshes: list[_LocalMesh] = create_local_line_meshes(
|
|
203
|
+
element.shapes,
|
|
204
|
+
element.axis_position,
|
|
205
|
+
element.lengths,
|
|
206
|
+
)
|
|
207
|
+
mesh: _LocalMesh = _LocalMesh()
|
|
208
|
+
for local_mesh in local_meshes:
|
|
209
|
+
global_vertices: list[Vector3d] = to_global_coord(
|
|
210
|
+
local_mesh.vertices,
|
|
211
|
+
element.point_start,
|
|
212
|
+
element.point_end,
|
|
213
|
+
element.angle,
|
|
214
|
+
element.element_type,
|
|
215
|
+
)
|
|
216
|
+
mesh.add_vertices_and_faces(
|
|
217
|
+
[point.mm_to_m() for point in global_vertices],
|
|
218
|
+
local_mesh.faces,
|
|
219
|
+
)
|
|
220
|
+
if allow_polygons:
|
|
221
|
+
return mesh
|
|
222
|
+
|
|
223
|
+
try:
|
|
224
|
+
return _triangulate_faces(mesh)
|
|
225
|
+
except ValueError as e:
|
|
226
|
+
reporter.error(
|
|
227
|
+
f"線要素の多角形の三角形分割に失敗しました: {e}",
|
|
228
|
+
code=Code.UNEXPECTED_ERROR,
|
|
229
|
+
phase=Phase.CONVERT_GEOMETRY,
|
|
230
|
+
)
|
|
231
|
+
return None
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def element_line_src_to_element_meshes(
|
|
235
|
+
element: ElementLineSrc, *, allow_polygons: bool, reporter: Reporter
|
|
236
|
+
) -> tuple[_LocalMesh | None, _LocalMesh | None]:
|
|
237
|
+
if element.rc is None or element.steel is None:
|
|
238
|
+
reporter.error(
|
|
239
|
+
"RCまたはS形状が設定されていません",
|
|
240
|
+
code=Code.UNKNOWN_SHAPE,
|
|
241
|
+
phase=Phase.CONVERT_GEOMETRY,
|
|
242
|
+
)
|
|
243
|
+
return None, None
|
|
244
|
+
mesh_rc: _LocalMesh | None = element_line_to_element_mesh(
|
|
245
|
+
element.rc, allow_polygons=allow_polygons, reporter=reporter
|
|
246
|
+
)
|
|
247
|
+
mesh_s: _LocalMesh | None = element_line_to_element_mesh(
|
|
248
|
+
element.steel, allow_polygons=allow_polygons, reporter=reporter
|
|
249
|
+
)
|
|
250
|
+
return mesh_rc, mesh_s
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def element_plane_to_element_mesh(
|
|
254
|
+
element: ElementPlane, *, allow_polygons: bool, reporter: Reporter
|
|
255
|
+
) -> _LocalMesh | None:
|
|
256
|
+
if not element.points:
|
|
257
|
+
raise AssertionError("要素の頂点が設定されていません")
|
|
258
|
+
thickness: float = element.thickness if element.thickness else 10
|
|
259
|
+
# 表面
|
|
260
|
+
out_points2d: list[Vector2d] = [
|
|
261
|
+
Vector2d(v.x, v.y) for v in to_plate_element_coord(element.points)
|
|
262
|
+
]
|
|
263
|
+
in_points2d: list[list[Vector2d]] = element.opens or []
|
|
264
|
+
try:
|
|
265
|
+
vertices2d, faces, new_out_points, new_in_points = create_mesh(
|
|
266
|
+
out_points2d, in_points2d
|
|
267
|
+
)
|
|
268
|
+
except ValueError as e:
|
|
269
|
+
reporter.error(
|
|
270
|
+
f"平面要素のメッシュ化に失敗しました: {e}",
|
|
271
|
+
code=Code.UNEXPECTED_ERROR,
|
|
272
|
+
phase=Phase.CONVERT_GEOMETRY,
|
|
273
|
+
)
|
|
274
|
+
return None
|
|
275
|
+
mesh: _LocalMesh = _LocalMesh()
|
|
276
|
+
vertices3d: list[Vector3d] = to_global_coord_plate(
|
|
277
|
+
[v.to_vector3d(z=thickness) for v in vertices2d], element.points
|
|
278
|
+
)
|
|
279
|
+
mesh.add_vertices_and_faces([v.mm_to_m() for v in vertices3d], faces)
|
|
280
|
+
# 裏面
|
|
281
|
+
faces_rev = [list(reversed(face)) for face in faces]
|
|
282
|
+
vertices3d_back: list[Vector3d] = to_global_coord_plate(
|
|
283
|
+
[v.to_vector3d(z=0.0) for v in vertices2d], element.points
|
|
284
|
+
)
|
|
285
|
+
mesh.add_vertices_and_faces(
|
|
286
|
+
[v.mm_to_m() for v in vertices3d_back],
|
|
287
|
+
faces_rev,
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
_vx, _vy, _vz = axis_vector_plate(element.points)
|
|
291
|
+
|
|
292
|
+
# 側面
|
|
293
|
+
side_faces: list[list[int]] = (
|
|
294
|
+
[[0, 1, 2, 3]] if allow_polygons else [[0, 1, 2], [0, 2, 3]]
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
if new_out_points is not None:
|
|
298
|
+
if len(new_out_points) == 1:
|
|
299
|
+
out_points2d = new_out_points[0]
|
|
300
|
+
else:
|
|
301
|
+
raise NotImplementedError("未実装です")
|
|
302
|
+
if new_in_points is not None:
|
|
303
|
+
in_points2d = new_in_points
|
|
304
|
+
# 側面内側
|
|
305
|
+
for tmp_in_point2ds in in_points2d:
|
|
306
|
+
tmp_in_point2ds = tmp_in_point2ds + [tmp_in_point2ds[0]]
|
|
307
|
+
for i in range(len(tmp_in_point2ds) - 1):
|
|
308
|
+
p0 = tmp_in_point2ds[i]
|
|
309
|
+
p1 = tmp_in_point2ds[i + 1]
|
|
310
|
+
p0_3d_top = to_global_coord_plate(
|
|
311
|
+
[p0.to_vector3d(z=thickness)], element.points
|
|
312
|
+
)[0]
|
|
313
|
+
p1_3d_top = to_global_coord_plate(
|
|
314
|
+
[p1.to_vector3d(z=thickness)], element.points
|
|
315
|
+
)[0]
|
|
316
|
+
p0_3d_bottom = to_global_coord_plate(
|
|
317
|
+
[p0.to_vector3d(z=0.0)], element.points
|
|
318
|
+
)[0]
|
|
319
|
+
p1_3d_bottom = to_global_coord_plate(
|
|
320
|
+
[p1.to_vector3d(z=0.0)], element.points
|
|
321
|
+
)[0]
|
|
322
|
+
mesh.add_vertices_and_faces(
|
|
323
|
+
[
|
|
324
|
+
p0_3d_top.mm_to_m(),
|
|
325
|
+
p1_3d_top.mm_to_m(),
|
|
326
|
+
p1_3d_bottom.mm_to_m(),
|
|
327
|
+
p0_3d_bottom.mm_to_m(),
|
|
328
|
+
],
|
|
329
|
+
side_faces,
|
|
330
|
+
)
|
|
331
|
+
# 側面外側
|
|
332
|
+
out_points2d = out_points2d + [out_points2d[0]]
|
|
333
|
+
for i in range(len(out_points2d) - 1):
|
|
334
|
+
p0 = out_points2d[i]
|
|
335
|
+
p1 = out_points2d[i + 1]
|
|
336
|
+
p0_3d_top = to_global_coord_plate(
|
|
337
|
+
[p0.to_vector3d(z=thickness)], element.points
|
|
338
|
+
)[0]
|
|
339
|
+
p1_3d_top = to_global_coord_plate(
|
|
340
|
+
[p1.to_vector3d(z=thickness)], element.points
|
|
341
|
+
)[0]
|
|
342
|
+
p0_3d_bottom = to_global_coord_plate([p0.to_vector3d(z=0.0)], element.points)[0]
|
|
343
|
+
p1_3d_bottom = to_global_coord_plate([p1.to_vector3d(z=0.0)], element.points)[0]
|
|
344
|
+
mesh.add_vertices_and_faces(
|
|
345
|
+
[
|
|
346
|
+
p0_3d_top.mm_to_m(),
|
|
347
|
+
p1_3d_top.mm_to_m(),
|
|
348
|
+
p1_3d_bottom.mm_to_m(),
|
|
349
|
+
p0_3d_bottom.mm_to_m(),
|
|
350
|
+
],
|
|
351
|
+
side_faces,
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
return mesh
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def _get_element_source_type(
|
|
358
|
+
element: ElementLine | ElementLineSrc | ElementPlane,
|
|
359
|
+
) -> str:
|
|
360
|
+
path: str | None = element.path
|
|
361
|
+
if path:
|
|
362
|
+
source_type = path.rsplit("/", 1)[-1].partition("[")[0]
|
|
363
|
+
if source_type:
|
|
364
|
+
return source_type
|
|
365
|
+
|
|
366
|
+
element_type: ElementType | None = element.element_type
|
|
367
|
+
return element_type.value if element_type is not None else ""
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def _element_kind_from_type(element_type: ElementType | None) -> ElementKind:
|
|
371
|
+
if element_type is None:
|
|
372
|
+
return ElementKind.OTHER
|
|
373
|
+
return ElementKind[element_type.name]
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
_OFFSET_AXIS_TYPES: frozenset[ElementType] = frozenset(
|
|
377
|
+
{
|
|
378
|
+
ElementType.PILE,
|
|
379
|
+
ElementType.FOUNDATION_COLUMN,
|
|
380
|
+
ElementType.FOOTING,
|
|
381
|
+
ElementType.PARAPET,
|
|
382
|
+
}
|
|
383
|
+
)
|
|
384
|
+
"""Line描画の際にoffsetを考慮しないと見えない部材
|
|
385
|
+
- 杭は基準節点が1つのため、1つの柱に複数の杭がある場合offsetで表現しないと重なって見えない
|
|
386
|
+
- 基礎柱、フーチングは基準節点が1つであり、点になってしまうため、offsetした位置で表現する
|
|
387
|
+
- パラペットは基本的に梁と節点がかぶるため、重なってしまうのでoffsetで表現する
|
|
388
|
+
"""
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def _line_points(
|
|
392
|
+
element: ElementLine | ElementLineSrc,
|
|
393
|
+
node_infos: dict[int, Node],
|
|
394
|
+
) -> tuple[Vector3d, Vector3d] | None:
|
|
395
|
+
node_ids: list[int] = element.node_ids
|
|
396
|
+
if element.element_type not in _OFFSET_AXIS_TYPES and len(node_ids) == 2:
|
|
397
|
+
node_start: Node | None = node_infos.get(node_ids[0])
|
|
398
|
+
node_end: Node | None = node_infos.get(node_ids[1])
|
|
399
|
+
if node_start is not None and node_end is not None:
|
|
400
|
+
return node_start.position, node_end.position
|
|
401
|
+
line: ElementLine | None = (
|
|
402
|
+
element
|
|
403
|
+
if isinstance(element, ElementLine)
|
|
404
|
+
else (element.rc if element.rc is not None else element.steel)
|
|
405
|
+
)
|
|
406
|
+
if line is None or line.point_start is None or line.point_end is None:
|
|
407
|
+
return None
|
|
408
|
+
return line.point_start, line.point_end
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def _plane_points(
|
|
412
|
+
element: ElementPlane,
|
|
413
|
+
) -> list[tuple[SurfaceLoopType, list[Vector3d]]] | None:
|
|
414
|
+
node_points: list[Vector3d] | None = element.node_points
|
|
415
|
+
if node_points is None or len(node_points) < 3:
|
|
416
|
+
return None
|
|
417
|
+
|
|
418
|
+
loops: list[tuple[SurfaceLoopType, list[Vector3d]]] = [
|
|
419
|
+
(SurfaceLoopType.OUTER, [point.mm_to_m() for point in node_points])
|
|
420
|
+
]
|
|
421
|
+
for open_point2ds in element.opens:
|
|
422
|
+
if len(open_point2ds) < 3:
|
|
423
|
+
continue
|
|
424
|
+
open_point3ds: list[Vector3d] = to_global_coord_plate(
|
|
425
|
+
[point.to_vector3d(z=0.0) for point in open_point2ds],
|
|
426
|
+
node_points,
|
|
427
|
+
)
|
|
428
|
+
loops.append(
|
|
429
|
+
(SurfaceLoopType.HOLE, [point.mm_to_m() for point in open_point3ds])
|
|
430
|
+
)
|
|
431
|
+
return loops
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def _add_element_info(
|
|
435
|
+
geom: BuildingGeometry,
|
|
436
|
+
element_index: int,
|
|
437
|
+
element: ElementLine | ElementLineSrc | ElementPlane,
|
|
438
|
+
node_infos: dict[int, Node],
|
|
439
|
+
node_indices: dict[int, int],
|
|
440
|
+
) -> None:
|
|
441
|
+
node_relation: list[int] = [
|
|
442
|
+
node_indices[node_id] for node_id in element.node_ids if node_id in node_indices
|
|
443
|
+
]
|
|
444
|
+
if node_relation:
|
|
445
|
+
geom.set_element_nodes(element_index, node_relation)
|
|
446
|
+
|
|
447
|
+
if isinstance(element, ElementPlane):
|
|
448
|
+
loops = _plane_points(element)
|
|
449
|
+
if loops is not None:
|
|
450
|
+
geom.add_element_plane_shape(element_index, loops)
|
|
451
|
+
return
|
|
452
|
+
|
|
453
|
+
axis_points = _line_points(element, node_infos)
|
|
454
|
+
if axis_points is not None:
|
|
455
|
+
point_start, point_end = axis_points
|
|
456
|
+
geom.add_element_line_shape(
|
|
457
|
+
element_index,
|
|
458
|
+
start=point_start.mm_to_m(),
|
|
459
|
+
end=point_end.mm_to_m(),
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
def element_data_to_building_geometry(
|
|
464
|
+
elements: ElementData,
|
|
465
|
+
*,
|
|
466
|
+
allow_polygons: bool,
|
|
467
|
+
reporter: Reporter,
|
|
468
|
+
node_infos: dict[int, Node] | None = None,
|
|
469
|
+
) -> BuildingGeometry:
|
|
470
|
+
|
|
471
|
+
geom: BuildingGeometry = BuildingGeometry()
|
|
472
|
+
node_indices: dict[int, int] = {}
|
|
473
|
+
if node_infos is not None:
|
|
474
|
+
node_indices = {
|
|
475
|
+
node_id: geom.add_node(
|
|
476
|
+
node.position.mm_to_m(),
|
|
477
|
+
source_id=str(node_id),
|
|
478
|
+
guid=node.guid,
|
|
479
|
+
xpath=node.xpath,
|
|
480
|
+
)
|
|
481
|
+
for node_id, node in node_infos.items()
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
for element in elements:
|
|
485
|
+
path: str | None = element.path
|
|
486
|
+
guid: UUID = element.guid if element.guid else uuid.uuid4()
|
|
487
|
+
element_kind: ElementKind = _element_kind_from_type(element.element_type)
|
|
488
|
+
|
|
489
|
+
source_type: str = _get_element_source_type(element)
|
|
490
|
+
# SRCのクリック検出は外側のRCで行う。そのためRCを先に登録する。
|
|
491
|
+
is_composite: bool = isinstance(element, ElementLineSrc)
|
|
492
|
+
index: int = geom.add_element(
|
|
493
|
+
kind=element_kind,
|
|
494
|
+
guid=guid,
|
|
495
|
+
xpath=path,
|
|
496
|
+
name=element.name,
|
|
497
|
+
source_type=source_type,
|
|
498
|
+
flags=(
|
|
499
|
+
ElementFlags.IS_COMPOSITE_CONCRETE
|
|
500
|
+
if is_composite
|
|
501
|
+
else ElementFlags.NONE
|
|
502
|
+
),
|
|
503
|
+
)
|
|
504
|
+
if node_infos is not None:
|
|
505
|
+
_add_element_info(
|
|
506
|
+
geom,
|
|
507
|
+
index,
|
|
508
|
+
element,
|
|
509
|
+
node_infos,
|
|
510
|
+
node_indices,
|
|
511
|
+
)
|
|
512
|
+
match element:
|
|
513
|
+
case ElementLineSrc():
|
|
514
|
+
mesh_rc, mesh_s = element_line_src_to_element_meshes(
|
|
515
|
+
element,
|
|
516
|
+
allow_polygons=allow_polygons,
|
|
517
|
+
reporter=reporter,
|
|
518
|
+
)
|
|
519
|
+
if mesh_rc:
|
|
520
|
+
geom.add_element_mesh(index, mesh_rc.vertices, mesh_rc.faces)
|
|
521
|
+
if mesh_s:
|
|
522
|
+
# SはRCと同じGUID・XPathを持つ別要素とする。
|
|
523
|
+
# 節点関連はRCにのみ持たせて二重描画を防ぐ
|
|
524
|
+
steel_index: int = geom.add_element(
|
|
525
|
+
kind=element_kind,
|
|
526
|
+
guid=guid,
|
|
527
|
+
xpath=path,
|
|
528
|
+
name=element.name,
|
|
529
|
+
source_type=source_type,
|
|
530
|
+
flags=ElementFlags.IS_COMPOSITE_STEEL,
|
|
531
|
+
)
|
|
532
|
+
geom.add_element_mesh(steel_index, mesh_s.vertices, mesh_s.faces)
|
|
533
|
+
case ElementLine():
|
|
534
|
+
mesh: _LocalMesh | None = element_line_to_element_mesh(
|
|
535
|
+
element,
|
|
536
|
+
allow_polygons=allow_polygons,
|
|
537
|
+
reporter=reporter,
|
|
538
|
+
)
|
|
539
|
+
if mesh:
|
|
540
|
+
geom.add_element_mesh(index, mesh.vertices, mesh.faces)
|
|
541
|
+
case ElementPlane():
|
|
542
|
+
mesh = element_plane_to_element_mesh(
|
|
543
|
+
element,
|
|
544
|
+
allow_polygons=allow_polygons,
|
|
545
|
+
reporter=reporter,
|
|
546
|
+
)
|
|
547
|
+
if mesh:
|
|
548
|
+
geom.add_element_mesh(index, mesh.vertices, mesh.faces)
|
|
549
|
+
return geom
|
|
@@ -0,0 +1,21 @@
|
|
|
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 TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
from ..._internal.data_model.building_geometry import BuildingGeometry
|
|
10
|
+
from ..._internal.optional_dependencies.ifc_to_building_geometry import (
|
|
11
|
+
ifc_to_building_geometry,
|
|
12
|
+
)
|
|
13
|
+
from .building_geometry_to_ply_text import building_geometry_to_ply_text
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
import ifcopenshell.file
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def ifc_to_ply_text(ifc_file: "ifcopenshell.file") -> str:
|
|
20
|
+
geom: BuildingGeometry = ifc_to_building_geometry(ifc_file)
|
|
21
|
+
return building_geometry_to_ply_text(geom)
|
|
@@ -0,0 +1,23 @@
|
|
|
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 stbkit.core._internal.name_converter import private_field_name
|
|
8
|
+
from stbkit.core.data_model.common import StBridgeElement
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def stb_element_to_ifc_name(stb_element: StBridgeElement) -> str:
|
|
12
|
+
result: list[str] = []
|
|
13
|
+
p_name_id: str = private_field_name("id")
|
|
14
|
+
if hasattr(stb_element, p_name_id):
|
|
15
|
+
id = getattr(stb_element, p_name_id)
|
|
16
|
+
if id:
|
|
17
|
+
result.append(str(id))
|
|
18
|
+
p_name_name: str = private_field_name("name")
|
|
19
|
+
if hasattr(stb_element, p_name_name):
|
|
20
|
+
name = getattr(stb_element, p_name_name)
|
|
21
|
+
if name:
|
|
22
|
+
result.append(str(name))
|
|
23
|
+
return "_".join(result)
|
|
@@ -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/.
|