mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-13 02:47:48 +00:00
typing
This commit is contained in:
@@ -55,10 +55,10 @@ def name_callback(obj: Union[bpy.types.Object, bpy.types.Material], data: str) -
|
||||
return
|
||||
|
||||
if isinstance(obj, bpy.types.Material):
|
||||
props = obj.BIMStyleProperties
|
||||
props = tool.Style.get_material_style_props(obj)
|
||||
if ifc_definition_id := props.ifc_definition_id:
|
||||
if props.is_renaming:
|
||||
props.is_renmaing = False
|
||||
props.is_renaming = False
|
||||
return
|
||||
tool.Ifc.get().by_id(ifc_definition_id).Name = obj.name
|
||||
refresh_ui_data()
|
||||
|
||||
@@ -265,7 +265,8 @@ class IfcStore:
|
||||
IfcStore.guid_map[global_id] = obj
|
||||
|
||||
if element.is_a("IfcSurfaceStyle"):
|
||||
obj.BIMStyleProperties.ifc_definition_id = element.id()
|
||||
props = tool.Style.get_material_style_props(obj)
|
||||
props.ifc_definition_id = element.id()
|
||||
else:
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
props.ifc_definition_id = element.id()
|
||||
@@ -406,7 +407,8 @@ class IfcStore:
|
||||
@staticmethod
|
||||
def purge_blender_ifc_data(obj: IFC_CONNECTED_TYPE) -> None:
|
||||
if isinstance(obj, bpy.types.Material):
|
||||
obj.BIMStyleProperties.ifc_definition_id = 0
|
||||
props = tool.Style.get_material_style_props(obj)
|
||||
props.ifc_definition_id = 0
|
||||
else: # bpy.types.Object
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
props.ifc_definition_id = 0
|
||||
|
||||
@@ -86,7 +86,7 @@ class MaterialCreator:
|
||||
|
||||
def load_existing_materials(self) -> None:
|
||||
for material in bpy.data.materials:
|
||||
if ifc_definition_id := material.BIMStyleProperties.ifc_definition_id:
|
||||
if ifc_definition_id := tool.Blender.get_ifc_definition_id(material):
|
||||
self.styles[ifc_definition_id] = material
|
||||
|
||||
def parse_element_type_material_styles(self, element: ifcopenshell.entity_instance) -> None:
|
||||
@@ -964,10 +964,11 @@ class IfcImporter:
|
||||
self.material_creator.styles[style.id()] = blender_material
|
||||
|
||||
style_elements = tool.Style.get_style_elements(blender_material)
|
||||
props = tool.Style.get_material_style_props(blender_material)
|
||||
if tool.Style.has_blender_external_style(style_elements):
|
||||
blender_material.BIMStyleProperties.active_style_type = "External"
|
||||
props.active_style_type = "External"
|
||||
else:
|
||||
blender_material.BIMStyleProperties.active_style_type = "Shading"
|
||||
props.active_style_type = "Shading"
|
||||
|
||||
def place_objects_in_collections(self) -> None:
|
||||
for ifc_definition_id, obj in self.added_data.items():
|
||||
|
||||
@@ -3353,7 +3353,8 @@ class AddReferenceImage(bpy.types.Operator, tool.Ifc.Operator):
|
||||
obj.material_slots[0].material = material
|
||||
bpy.ops.bim.add_style()
|
||||
|
||||
style = ifc_file.by_id(material.BIMStyleProperties.ifc_definition_id)
|
||||
style = tool.Ifc.get_entity(material)
|
||||
assert style
|
||||
tool.Style.assign_style_to_object(style, obj)
|
||||
|
||||
# TODO: IfcSurfaceStyleRendering is unnecessary here, added it only because
|
||||
|
||||
@@ -1019,7 +1019,7 @@ class EnableEditingExtrusionAxis(bpy.types.Operator, tool.Ifc.Operator):
|
||||
position = Matrix()
|
||||
|
||||
direction = Vector(extrusion.ExtrudedDirection.DirectionRatios).normalized()
|
||||
tool.Model.import_axis([Vector((0, 0, 0)), direction * extrusion.Depth], obj=obj, position=position)
|
||||
tool.Model.import_axis((Vector((0, 0, 0)), direction * extrusion.Depth), obj=obj, position=position)
|
||||
|
||||
bpy.ops.object.mode_set(mode="EDIT")
|
||||
ProfileDecorator.install(context, exit_edit_mode_callback=lambda: disable_editing_extrusion_axis(context))
|
||||
|
||||
@@ -97,9 +97,8 @@ class BlenderMaterialStyleData:
|
||||
material = obj.active_material
|
||||
if not material:
|
||||
return False
|
||||
props = material.BIMStyleProperties
|
||||
style_id = props.ifc_definition_id
|
||||
style = tool.Ifc.get_entity_by_id(style_id)
|
||||
|
||||
style = tool.Ifc.get_entity(material)
|
||||
if not style:
|
||||
return False
|
||||
|
||||
|
||||
@@ -118,8 +118,7 @@ class UnlinkStyle(bpy.types.Operator, tool.Ifc.Operator):
|
||||
# Don't check blender_material and style_id as this operator is only called from UI.
|
||||
assert isinstance(self.blender_material, str) # Type checker.
|
||||
material = bpy.data.materials[self.blender_material]
|
||||
style_id = material.BIMStyleProperties.ifc_definition_id
|
||||
style = tool.Ifc.get_entity_by_id(style_id)
|
||||
style = tool.Ifc.get_entity(material)
|
||||
|
||||
# Material is linked to a style from a different project.
|
||||
if not style or tool.Ifc.get_object(style) != material:
|
||||
@@ -221,18 +220,25 @@ class UpdateCurrentStyle(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
style = tool.Ifc.get().by_id(self.style_id)
|
||||
material = tool.Ifc.get_object(style)
|
||||
current_style_type = material.BIMStyleProperties.active_style_type
|
||||
msprops = tool.Style.get_material_style_props(material)
|
||||
current_style_type = msprops.active_style_type
|
||||
|
||||
if self.update_all:
|
||||
sprops = tool.Style.get_style_props()
|
||||
sprops.active_style_type = current_style_type
|
||||
return {"FINISHED"}
|
||||
|
||||
updated_materials = set()
|
||||
updated_materials: set[bpy.types.Material] = set()
|
||||
for obj in context.selected_objects:
|
||||
if not isinstance(obj.data, (bpy.types.Mesh, bpy.types.Curve)):
|
||||
continue
|
||||
for mat in obj.data.materials:
|
||||
if mat and mat not in updated_materials and mat.BIMStyleProperties.ifc_definition_id != 0:
|
||||
mat.BIMStyleProperties.active_style_type = current_style_type
|
||||
if (
|
||||
mat
|
||||
and mat not in updated_materials
|
||||
and (msprops_ := tool.Style.get_material_style_props(mat)).ifc_definition_id != 0
|
||||
):
|
||||
msprops_.active_style_type = current_style_type
|
||||
updated_materials.add(mat)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -755,7 +761,8 @@ class EnableEditingSurfaceStyle(bpy.types.Operator):
|
||||
bonsai.bim.helper.import_attributes2(surface_style or self.ifc_class, attributes, callback)
|
||||
|
||||
material = tool.Ifc.get_object(style)
|
||||
active_style_type = material.BIMStyleProperties.active_style_type
|
||||
msprops = tool.Style.get_material_style_props(material)
|
||||
active_style_type = msprops.active_style_type
|
||||
if self.ifc_class == "IfcExternallyDefinedSurfaceStyle" and active_style_type != "External":
|
||||
if tool.Style.has_blender_external_style(style_elements):
|
||||
tool.Style.switch_shading(material, "External")
|
||||
@@ -803,9 +810,10 @@ class EditSurfaceStyle(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
# restore selected style type
|
||||
material = tool.Ifc.get_object(self.style)
|
||||
material.BIMStyleProperties.active_style_type = material.BIMStyleProperties.active_style_type
|
||||
msprops = tool.Style.get_material_style_props(material)
|
||||
msprops.active_style_type = msprops.active_style_type
|
||||
|
||||
def edit_existing_style(self):
|
||||
def edit_existing_style(self) -> None:
|
||||
ifc_file = tool.Ifc.get()
|
||||
material = tool.Ifc.get_object(self.style)
|
||||
assert self.surface_style
|
||||
@@ -867,7 +875,7 @@ class EditSurfaceStyle(bpy.types.Operator, tool.Ifc.Operator):
|
||||
attributes=bonsai.bim.helper.export_attributes(attributes),
|
||||
)
|
||||
|
||||
def add_new_style(self):
|
||||
def add_new_style(self) -> None:
|
||||
material = tool.Ifc.get_object(self.style)
|
||||
if self.props.is_editing_class == "IfcSurfaceStyleShading":
|
||||
surface_style = ifcopenshell.api.run(
|
||||
@@ -911,13 +919,13 @@ class EditSurfaceStyle(bpy.types.Operator, tool.Ifc.Operator):
|
||||
attributes=bonsai.bim.helper.export_attributes(attributes),
|
||||
)
|
||||
|
||||
def get_shading_attributes(self):
|
||||
def get_shading_attributes(self) -> dict[str, Any]:
|
||||
return {
|
||||
"SurfaceColour": self.color_to_dict(self.props.surface_colour),
|
||||
"Transparency": self.props.transparency or None,
|
||||
}
|
||||
|
||||
def get_rendering_attributes(self):
|
||||
def get_rendering_attributes(self) -> dict[str, Any]:
|
||||
if self.props.is_diffuse_colour_null:
|
||||
diffuse_colour = None
|
||||
elif self.props.diffuse_colour_class == "IfcColourRgb":
|
||||
@@ -961,7 +969,7 @@ class EditSurfaceStyle(bpy.types.Operator, tool.Ifc.Operator):
|
||||
textures.append(texture_data)
|
||||
return textures
|
||||
|
||||
def color_to_dict(self, x):
|
||||
def color_to_dict(self, x: tuple[float, float, float]) -> dict[str, Any]:
|
||||
return {"Red": x[0], "Green": x[1], "Blue": x[2]}
|
||||
|
||||
|
||||
|
||||
@@ -39,13 +39,13 @@ from typing import Literal, Union, TYPE_CHECKING, get_args
|
||||
_ = gettext.gettext
|
||||
|
||||
|
||||
def get_style_types(self, context):
|
||||
def get_style_types(self: "BIMStylesProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
|
||||
if not StylesData.is_loaded:
|
||||
StylesData.load()
|
||||
return StylesData.data["style_types"]
|
||||
|
||||
|
||||
def get_reflectance_methods(self, context):
|
||||
def get_reflectance_methods(self: "BIMStylesProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
|
||||
if not StylesData.is_loaded:
|
||||
StylesData.load()
|
||||
return StylesData.data["reflectance_methods"]
|
||||
@@ -77,6 +77,16 @@ class Style(PropertyGroup):
|
||||
type=bpy.types.Material,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
ifc_definition_id: int
|
||||
total_elements: int
|
||||
style_classes: bpy.types.bpy_prop_collection_idprop[StrProperty]
|
||||
has_surface_colour: bool
|
||||
surface_colour: tuple[float, float, float]
|
||||
has_diffuse_colour: bool
|
||||
diffuse_colour: tuple[float, float, float]
|
||||
blender_material: Union[bpy.types.Material, None]
|
||||
|
||||
|
||||
STYLE_TYPES = [
|
||||
("Shading", "Shading", ""),
|
||||
@@ -86,7 +96,7 @@ STYLE_TYPES = [
|
||||
|
||||
def update_shading_styles(self: "BIMStylesProperties", context: bpy.types.Context) -> None:
|
||||
for mat in bpy.data.materials:
|
||||
if mat.BIMStyleProperties.ifc_definition_id == 0:
|
||||
if tool.Blender.get_ifc_definition_id(mat) == 0:
|
||||
continue
|
||||
tool.Style.change_current_style_type(mat, self.active_style_type)
|
||||
|
||||
@@ -111,7 +121,9 @@ UV_MODES = [
|
||||
("Camera", "Camera", _("UV from position coordinate in camera space")),
|
||||
]
|
||||
|
||||
|
||||
TextureMapMode = Literal[
|
||||
"DIFFUSE", "NORMAL", "METALLICROUGHNESS", "SPECULAR", "SHININESS", "EMISSIVE", "OCCLUSION", "AMBIENT"
|
||||
]
|
||||
TEXTURE_MAPS_MODS = (
|
||||
("DIFFUSE", "DIFFUSE", ""),
|
||||
("NORMAL", "NORMAL", ""),
|
||||
@@ -129,6 +141,10 @@ class Texture(PropertyGroup):
|
||||
# NOTE: subtype `FILE_PATH` is not used to avoid .blend relative paths
|
||||
path: StringProperty(name="Texture Path", update=update_shader_graph)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
mode: TextureMapMode
|
||||
path: str
|
||||
|
||||
|
||||
class ColourRgb(PropertyGroup):
|
||||
name: StringProperty()
|
||||
@@ -136,6 +152,10 @@ class ColourRgb(PropertyGroup):
|
||||
# not exposed in the UI, here just to preserve the data
|
||||
color_name: StringProperty(name="Color Name")
|
||||
|
||||
if TYPE_CHECKING:
|
||||
color_value: tuple[float, float, float]
|
||||
color_name: str
|
||||
|
||||
# to fit blender.bim.helper.export_attributes
|
||||
def get_value(self):
|
||||
return {
|
||||
|
||||
@@ -16,11 +16,16 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import annotations
|
||||
import bpy
|
||||
import bonsai.bim.helper
|
||||
import bonsai.tool as tool
|
||||
from bpy.types import Panel, UIList
|
||||
from bonsai.bim.module.style.data import StylesData, BlenderMaterialStyleData
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bonsai.bim.module.style.prop import BIMStylesProperties, Style
|
||||
|
||||
|
||||
class BIM_PT_styles(Panel):
|
||||
@@ -94,7 +99,8 @@ class BIM_PT_styles(Panel):
|
||||
if active_style:
|
||||
row = self.layout.row(align=True)
|
||||
if material := style.blender_material:
|
||||
row.prop(material.BIMStyleProperties, "active_style_type", icon="SHADING_RENDERED", text="")
|
||||
msprops = tool.Style.get_material_style_props(material)
|
||||
row.prop(msprops, "active_style_type", icon="SHADING_RENDERED", text="")
|
||||
op = row.operator("bim.update_current_style", icon="FILE_REFRESH", text="")
|
||||
op.style_id = style.ifc_definition_id
|
||||
|
||||
@@ -255,11 +261,19 @@ class BIM_PT_styles(Panel):
|
||||
|
||||
|
||||
class BIM_UL_styles(UIList):
|
||||
def draw_item(self, context, layout: bpy.types.UILayout, data, item, icon, active_data, active_property):
|
||||
def draw_item(
|
||||
self,
|
||||
context,
|
||||
layout: bpy.types.UILayout,
|
||||
data: BIMStylesProperties,
|
||||
item: Style,
|
||||
icon,
|
||||
active_data,
|
||||
active_property,
|
||||
):
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
props = tool.Style.get_style_props()
|
||||
if item.ifc_definition_id == props.is_editing_style:
|
||||
if item.ifc_definition_id == data.is_editing_style:
|
||||
row.label(text="", icon="GREASEPENCIL")
|
||||
row.prop(item, "name", text="", emboss=False)
|
||||
if item.has_surface_colour:
|
||||
@@ -295,7 +309,7 @@ class BIM_PT_style(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return bool(tool.Ifc.get() and (material := context.material) and material.BIMStyleProperties.ifc_definition_id)
|
||||
return bool(tool.Ifc.get() and (material := context.material) and tool.Blender.get_ifc_definition_id(material))
|
||||
|
||||
def draw(self, context):
|
||||
# NOTE: this UI is needed only to indicate whether blender material is linked to IFC
|
||||
@@ -305,10 +319,11 @@ class BIM_PT_style(Panel):
|
||||
BlenderMaterialStyleData.load()
|
||||
|
||||
material = context.material
|
||||
style_id = material.BIMStyleProperties.ifc_definition_id
|
||||
assert material
|
||||
style_id = tool.Blender.get_ifc_definition_id(material)
|
||||
row = self.layout.row(align=True)
|
||||
|
||||
if style_id and not BlenderMaterialStyleData.data["is_linked_to_style"]:
|
||||
if not BlenderMaterialStyleData.data["is_linked_to_style"]:
|
||||
row.label(text="Material has linked IFC from a different project.")
|
||||
op = row.operator("bim.unlink_style", icon="UNLINKED", text="")
|
||||
op.blender_material = material.name
|
||||
|
||||
@@ -1601,5 +1601,7 @@ class Blender(bonsai.core.tool.Blender):
|
||||
return obj.BIMObjectProperties
|
||||
|
||||
@classmethod
|
||||
def get_ifc_definition_id(cls, obj: bpy.types.Object) -> int:
|
||||
return tool.Blender.get_object_bim_props(obj).ifc_definition_id
|
||||
def get_ifc_definition_id(cls, obj: IFC_CONNECTED_TYPE) -> int:
|
||||
if isinstance(obj, bpy.types.Object):
|
||||
return tool.Blender.get_object_bim_props(obj).ifc_definition_id
|
||||
return tool.Style.get_material_style_props(obj).ifc_definition_id
|
||||
|
||||
@@ -639,7 +639,7 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
@classmethod
|
||||
def get_object_materials_without_styles(cls, obj: bpy.types.Object) -> list[bpy.types.Material]:
|
||||
return [
|
||||
s.material for s in obj.material_slots if s.material and not s.material.BIMStyleProperties.ifc_definition_id
|
||||
s.material for s in obj.material_slots if s.material and not tool.Blender.get_ifc_definition_id(s.material)
|
||||
]
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -110,7 +110,7 @@ class Ifc(bonsai.core.tool.Ifc):
|
||||
if isinstance(obj, bpy.types.Object):
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
elif isinstance(obj, bpy.types.Material):
|
||||
props = obj.BIMStyleProperties
|
||||
props = tool.Style.get_material_style_props(obj)
|
||||
else:
|
||||
props = tool.Geometry.get_mesh_props(obj)
|
||||
|
||||
|
||||
@@ -293,8 +293,19 @@ class Model(bonsai.core.tool.Model):
|
||||
else:
|
||||
break
|
||||
|
||||
unit_scale: float
|
||||
vertices: list[Vector]
|
||||
edges: list[Sequence[int]]
|
||||
arcs: list[Sequence[int]]
|
||||
circles: list[Sequence[int]]
|
||||
|
||||
@classmethod
|
||||
def import_axis(cls, axis, obj=None, position=None):
|
||||
def import_axis(
|
||||
cls,
|
||||
axis: Union[ifcopenshell.entity_instance, tuple[Vector, Vector]],
|
||||
obj=None,
|
||||
position: Optional[Matrix] = None,
|
||||
) -> bpy.types.Object:
|
||||
cls.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
|
||||
if position is None:
|
||||
@@ -305,7 +316,7 @@ class Model(bonsai.core.tool.Model):
|
||||
cls.arcs = []
|
||||
cls.circles = []
|
||||
|
||||
if isinstance(axis, list):
|
||||
if isinstance(axis, tuple):
|
||||
cls.vertices.extend(
|
||||
[
|
||||
position @ Vector(cls.convert_unit_to_si(axis[0])).to_3d(),
|
||||
@@ -478,7 +489,7 @@ class Model(bonsai.core.tool.Model):
|
||||
@classmethod
|
||||
def convert_curve_to_mesh(
|
||||
cls,
|
||||
obj: bpy.types.Object,
|
||||
obj: Union[bpy.types.Object, None], # Unused argument.
|
||||
position: Matrix,
|
||||
curve: ifcopenshell.entity_instance,
|
||||
x_angle: Optional[float] = None,
|
||||
@@ -1624,7 +1635,7 @@ class Model(bonsai.core.tool.Model):
|
||||
loop_edges = list(bm.edges)
|
||||
|
||||
# Create loops from edges
|
||||
loops = []
|
||||
loops: list[list[bmesh.types.BMEdge]] = []
|
||||
while loop_edges:
|
||||
edge = loop_edges.pop()
|
||||
loop = [edge]
|
||||
@@ -1645,19 +1656,19 @@ class Model(bonsai.core.tool.Model):
|
||||
|
||||
tmp = ifcopenshell.file(schema=tool.Ifc.get().schema)
|
||||
|
||||
def is_in_group(v, group_name):
|
||||
def is_in_group(v: bmesh.types.BMVert, group_name: str) -> bool:
|
||||
for group_index in groups[group_name]:
|
||||
if group_index in v[deform_layer]:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_group_index(v, group_name):
|
||||
def get_group_index(v: bmesh.types.BMVert, group_name: str) -> Union[int, None]:
|
||||
for group_index in groups[group_name]:
|
||||
if group_index in v[deform_layer]:
|
||||
return group_index
|
||||
|
||||
# Convert all loops into IFC curves
|
||||
curves = []
|
||||
curves: list[ifcopenshell.entity_instance] = []
|
||||
for loop in loops:
|
||||
|
||||
if len(loop) == 1 and all([is_in_group(v, "IFCCIRCLE") for v in loop[0].verts]):
|
||||
@@ -1670,7 +1681,7 @@ class Model(bonsai.core.tool.Model):
|
||||
tmp.createIfcCircle(tmp.createIfcAxis2Placement2D(tmp.createIfcCartesianPoint(list(mid))), radius)
|
||||
)
|
||||
else:
|
||||
loop_verts = []
|
||||
loop_verts: list[bmesh.types.BMVert] = []
|
||||
for i, edge in enumerate(loop):
|
||||
if i == 0 and len(loop) == 1:
|
||||
loop_verts.append(edge.verts[0])
|
||||
@@ -1746,7 +1757,7 @@ class Model(bonsai.core.tool.Model):
|
||||
curves.append(tmp.createIfcIndexedPolyCurve(points))
|
||||
|
||||
# Sort IFC curves into either closed, or closed with void profile defs
|
||||
profile_defs = []
|
||||
profile_defs: list[ifcopenshell.entity_instance] = []
|
||||
settings = ifcopenshell.geom.settings()
|
||||
settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
|
||||
|
||||
|
||||
@@ -418,8 +418,8 @@ class Root(bonsai.core.tool.Root):
|
||||
"""Rename material without triggerring name callback and unnecessary writing to IFC."""
|
||||
if material.name == name:
|
||||
return
|
||||
props = material.BIMStyleProperties
|
||||
props.is_renaming = True
|
||||
msprops = tool.Style.get_material_style_props(material)
|
||||
msprops.is_renaming = True
|
||||
material.name = name # The handler will trigger, and reset is_renaming to False.
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -162,14 +162,14 @@ class Style(bonsai.core.tool.Style):
|
||||
cls, blender_material_or_style: Union[bpy.types.Material, ifcopenshell.entity_instance]
|
||||
) -> dict[str, ifcopenshell.entity_instance]:
|
||||
if isinstance(blender_material_or_style, bpy.types.Material):
|
||||
if not (ifc_definition_id := blender_material_or_style.BIMStyleProperties.ifc_definition_id):
|
||||
style = tool.Ifc.get_entity(blender_material_or_style)
|
||||
if not style:
|
||||
return {}
|
||||
style = tool.Ifc.get().by_id(ifc_definition_id)
|
||||
else:
|
||||
style = blender_material_or_style
|
||||
style_elements = {}
|
||||
for style in style.Styles:
|
||||
style_elements[style.is_a()] = style
|
||||
for style_ in style.Styles:
|
||||
style_elements[style_.is_a()] = style_
|
||||
return style_elements
|
||||
|
||||
@classmethod
|
||||
@@ -305,7 +305,7 @@ class Style(bonsai.core.tool.Style):
|
||||
return next((l.from_node for l in input_pin.links if l.from_node.type == of_type), None)
|
||||
return next((l.from_node for l in input_pin.links), None)
|
||||
|
||||
props = obj.BIMStyleProperties
|
||||
props = tool.Style.get_material_style_props(obj)
|
||||
transparency = 1 - obj.diffuse_color[3]
|
||||
diffuse_color = obj.diffuse_color
|
||||
viewport_color = color_to_ifc_format(obj.diffuse_color)
|
||||
@@ -487,16 +487,14 @@ class Style(bonsai.core.tool.Style):
|
||||
|
||||
@classmethod
|
||||
def get_surface_shading_style(cls, obj: bpy.types.Material) -> Union[ifcopenshell.entity_instance, None]:
|
||||
if ifc_definition_id := obj.BIMStyleProperties.ifc_definition_id:
|
||||
style = tool.Ifc.get().by_id(ifc_definition_id)
|
||||
if style := tool.Ifc.get_entity(obj):
|
||||
items = [s for s in style.Styles if s.is_a() == "IfcSurfaceStyleShading"]
|
||||
if items:
|
||||
return items[0]
|
||||
|
||||
@classmethod
|
||||
def get_surface_texture_style(cls, obj: bpy.types.Material) -> Union[ifcopenshell.entity_instance, None]:
|
||||
if ifc_definition_id := obj.BIMStyleProperties.ifc_definition_id:
|
||||
style = tool.Ifc.get().by_id(ifc_definition_id)
|
||||
if style := tool.Ifc.get_entity(obj):
|
||||
items = [s for s in style.Styles if s.is_a("IfcSurfaceStyleWithTextures")]
|
||||
if items:
|
||||
return items[0]
|
||||
@@ -581,7 +579,8 @@ class Style(bonsai.core.tool.Style):
|
||||
|
||||
@classmethod
|
||||
def change_current_style_type(cls, blender_material: bpy.types.Material, style_type: str) -> None:
|
||||
blender_material.BIMStyleProperties.active_style_type = style_type
|
||||
props = cls.get_material_style_props(blender_material)
|
||||
props.active_style_type = style_type
|
||||
|
||||
@classmethod
|
||||
def get_styled_items(cls, style: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
|
||||
@@ -632,7 +631,8 @@ class Style(bonsai.core.tool.Style):
|
||||
|
||||
@classmethod
|
||||
def reload_material_from_ifc(cls, blender_material: bpy.types.Material) -> None:
|
||||
blender_material.BIMStyleProperties.active_style_type = blender_material.BIMStyleProperties.active_style_type
|
||||
props = cls.get_material_style_props(blender_material)
|
||||
props.active_style_type = props.active_style_type
|
||||
|
||||
@classmethod
|
||||
def switch_shading(cls, blender_material: bpy.types.Material, style_type: StyleType) -> None:
|
||||
|
||||
@@ -911,14 +911,14 @@ def the_material_name_is_not_an_ifc_material(name):
|
||||
@then(parsers.parse('the material "{name}" is an IFC style'))
|
||||
def the_material_name_is_an_ifc_style(name):
|
||||
obj = the_material_name_exists(name)
|
||||
ifc_definition_id = obj.BIMStyleProperties.ifc_definition_id
|
||||
ifc_definition_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
assert ifc_definition_id != 0, f"The material {obj} has a style ID of {ifc_definition_id}"
|
||||
|
||||
|
||||
@then(parsers.parse('the material "{name}" is not an IFC style'))
|
||||
def the_material_name_is_not_an_ifc_style(name):
|
||||
obj = the_material_name_exists(name)
|
||||
ifc_definition_id = obj.BIMStyleProperties.ifc_definition_id
|
||||
ifc_definition_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
assert ifc_definition_id == 0, f"The material {obj} has a style ID of {ifc_definition_id}"
|
||||
|
||||
|
||||
|
||||
@@ -891,11 +891,12 @@ class TestAddReferenceImage(NewFile):
|
||||
assert tool.Cad.are_vectors_equal(obj.dimensions, Vector((3.53982, 2.0, 0.0)))
|
||||
|
||||
material = obj.active_material
|
||||
assert material
|
||||
assert material.name == "image"
|
||||
assert material.BIMStyleProperties.ifc_definition_id != 0
|
||||
assert tool.Blender.get_ifc_definition_id(material) != 0
|
||||
|
||||
ifc_file = tool.Ifc.get()
|
||||
style = ifc_file.by_id(material.BIMStyleProperties.ifc_definition_id)
|
||||
style = tool.Ifc.get_entity(material)
|
||||
assert style
|
||||
styled_items = set(tool.Style.get_styled_items(style))
|
||||
representation_items = set(tool.Geometry.get_active_representation(obj).Items)
|
||||
assert styled_items == representation_items
|
||||
|
||||
@@ -112,7 +112,8 @@ class TestGetObjectMaterialsWithoutStyles(NewFile):
|
||||
material1 = bpy.data.materials.new("Material")
|
||||
material2 = bpy.data.materials.new("Material")
|
||||
material3 = bpy.data.materials.new("Material")
|
||||
material3.BIMStyleProperties.ifc_definition_id = 1
|
||||
props = tool.Style.get_material_style_props(material3)
|
||||
props.ifc_definition_id = 1
|
||||
obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
|
||||
obj.data.materials.append(material1)
|
||||
obj.data.materials.append(material2)
|
||||
@@ -307,7 +308,7 @@ class TestRecordObjectMaterials(NewFile):
|
||||
tool.Ifc.set(ifc)
|
||||
style = ifc.createIfcSurfaceStyle()
|
||||
material = bpy.data.materials.new("Material")
|
||||
material.BIMStyleProperties.ifc_definition_id = style.id()
|
||||
tool.Ifc.link(style, material)
|
||||
obj.data.materials.append(material)
|
||||
subject.record_object_materials(obj)
|
||||
assert tool.Geometry.get_mesh_props(obj.data).material_checksum == str([style.id()])
|
||||
|
||||
@@ -462,7 +462,7 @@ class TestApplyIfcMaterialChanges(NewFile):
|
||||
def get_used_styles(self, obj: bpy.types.Object) -> set[ifcopenshell.entity_instance]:
|
||||
ifc_file = tool.Ifc.get()
|
||||
return {
|
||||
ifc_file.by_id(s.material.BIMStyleProperties.ifc_definition_id) for s in obj.material_slots if s.material
|
||||
ifc_file.by_id(tool.Blender.get_ifc_definition_id(s.material)) for s in obj.material_slots if s.material
|
||||
}
|
||||
|
||||
def get_mesh(self, obj: bpy.types.Object) -> bpy.types.Mesh:
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api.project
|
||||
import ifcopenshell.api.root
|
||||
import ifcopenshell.api.unit
|
||||
import bonsai.core.tool
|
||||
import bonsai.tool as tool
|
||||
from test.bim.bootstrap import NewFile
|
||||
|
||||
@@ -308,7 +308,8 @@ class TestGetSurfaceRenderingStyle(NewFile):
|
||||
style_item = tool.Ifc.get().createIfcSurfaceStyleRendering()
|
||||
style = tool.Ifc.get().createIfcSurfaceStyle(Styles=[style_item])
|
||||
obj = bpy.data.materials.new("Material")
|
||||
obj.BIMStyleProperties.ifc_definition_id = style.id()
|
||||
props = tool.Style.get_material_style_props(obj)
|
||||
props.ifc_definition_id = style.id()
|
||||
assert subject.get_surface_rendering_style(obj) == style_item
|
||||
|
||||
|
||||
@@ -347,7 +348,7 @@ class TestGetSurfaceShadingStyle(NewFile):
|
||||
style_item = tool.Ifc.get().createIfcSurfaceStyleShading()
|
||||
style = tool.Ifc.get().createIfcSurfaceStyle(Styles=[style_item])
|
||||
obj = bpy.data.materials.new("Material")
|
||||
obj.BIMStyleProperties.ifc_definition_id = style.id()
|
||||
tool.Ifc.link(style, obj)
|
||||
assert subject.get_surface_shading_style(obj) == style_item
|
||||
|
||||
def test_do_not_get_rendering_styles(self):
|
||||
@@ -355,7 +356,7 @@ class TestGetSurfaceShadingStyle(NewFile):
|
||||
style_item = tool.Ifc.get().createIfcSurfaceStyleRendering()
|
||||
style = tool.Ifc.get().createIfcSurfaceStyle(Styles=[style_item])
|
||||
obj = bpy.data.materials.new("Material")
|
||||
obj.BIMStyleProperties.ifc_definition_id = style.id()
|
||||
tool.Ifc.link(style, obj)
|
||||
assert subject.get_surface_shading_style(obj) is None
|
||||
|
||||
|
||||
@@ -365,7 +366,7 @@ class TestGetSurfaceTextureStyle(NewFile):
|
||||
style_item = tool.Ifc.get().createIfcSurfaceStyleWithTextures()
|
||||
style = tool.Ifc.get().createIfcSurfaceStyle(Styles=[style_item])
|
||||
obj = bpy.data.materials.new("Material")
|
||||
obj.BIMStyleProperties.ifc_definition_id = style.id()
|
||||
tool.Ifc.link(style, obj)
|
||||
assert subject.get_surface_texture_style(obj) == style_item
|
||||
|
||||
|
||||
|
||||
@@ -21,159 +21,203 @@ import ifcopenshell.util.element
|
||||
import ifcopenshell.util.shape
|
||||
import ifcopenshell.util.unit
|
||||
from ifcopenshell.util.data import Clipping
|
||||
from typing import Any, Union, Optional, Literal
|
||||
from typing import Any, Union, Optional, Literal, get_args
|
||||
|
||||
VECTOR_3D = tuple[float, float, float]
|
||||
CardinalPointNumeric = Literal[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
|
||||
CardinalPointString = Literal[
|
||||
"bottom left",
|
||||
"bottom centre",
|
||||
"bottom right",
|
||||
"mid-depth left",
|
||||
"mid-depth centre",
|
||||
"mid-depth right",
|
||||
"top left",
|
||||
"top centre",
|
||||
"top right",
|
||||
"geometric centroid",
|
||||
"bottom in line with the geometric centroid",
|
||||
"left in line with the geometric centroid",
|
||||
"right in line with the geometric centroid",
|
||||
"top in line with the geometric centroid",
|
||||
"shear centre",
|
||||
"bottom in line with the shear centre",
|
||||
"left in line with the shear centre",
|
||||
"right in line with the shear centre",
|
||||
"top in line with the shear centre",
|
||||
]
|
||||
CARDINAL_POINT_VALUES: tuple[CardinalPointString, ...] = get_args(CardinalPointString)
|
||||
CardinalPoint = Union[CardinalPointNumeric, CardinalPointString]
|
||||
|
||||
|
||||
def add_profile_representation(
|
||||
file: ifcopenshell.file,
|
||||
# IfcGeometricRepresentationContext
|
||||
context: ifcopenshell.entity_instance,
|
||||
profile: ifcopenshell.entity_instance,
|
||||
# in meters
|
||||
depth: float = 1.0,
|
||||
cardinal_point: Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] = 5,
|
||||
# A list of planes that define clipping half space solids
|
||||
# Planes are defined either by Clipping objects
|
||||
# or by dictionaries of arguments for `Clipping.parse`
|
||||
# TODO: None makes more sense as default value?
|
||||
cardinal_point: Union[CardinalPoint, None] = 5,
|
||||
clippings: Optional[list[Union[Clipping, dict[str, Any]]]] = None,
|
||||
placement_zx_axes: tuple[Union[VECTOR_3D, None], Union[VECTOR_3D, None]] = (None, None),
|
||||
) -> ifcopenshell.entity_instance:
|
||||
"""Add profile representation.
|
||||
|
||||
:param context: The IfcGeometricRepresentationContext for the representation,
|
||||
only Model/Body/MODEL_VIEW type of representations are currently supported.
|
||||
:param profile: The IfcProfileDef to extrude.
|
||||
:param depth: The depth of the extrusion in meters.
|
||||
:param cardinal_point: The cardinal point of the profile.
|
||||
:param clippings: A list of planes that define clipping half space solids.
|
||||
Planes are defined either by Clipping objects
|
||||
or by dictionaries of arguments for `Clipping.parse`.
|
||||
:param placement_zx_axes: A tuple of two vectors that define the placement of the profile.
|
||||
The first vector is the Z axis, the second vector is the X axis.
|
||||
:return: IfcShapeRepresentation.
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {
|
||||
"context": context,
|
||||
"profile": profile,
|
||||
"depth": depth,
|
||||
"cardinal_point": cardinal_point,
|
||||
"clippings": clippings if clippings is not None else [],
|
||||
"placement_zx_axes": placement_zx_axes,
|
||||
}
|
||||
return usecase.execute()
|
||||
clippings = clippings if clippings is not None else []
|
||||
return usecase.execute(context, profile, depth, cardinal_point, clippings, placement_zx_axes)
|
||||
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
settings: dict[str, Any]
|
||||
clippings: list[Clipping]
|
||||
|
||||
def execute(self):
|
||||
self.settings["unit_scale"] = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
self.settings["clippings"] = [Clipping.parse(c) for c in self.settings["clippings"]]
|
||||
return self.file.createIfcShapeRepresentation(
|
||||
self.settings["context"],
|
||||
self.settings["context"].ContextIdentifier,
|
||||
"Clipping" if self.settings["clippings"] else "SweptSolid",
|
||||
def execute(
|
||||
self,
|
||||
context: ifcopenshell.entity_instance,
|
||||
profile: ifcopenshell.entity_instance,
|
||||
depth: float,
|
||||
cardinal_point: Union[CardinalPoint, None],
|
||||
clippings: list[Union[Clipping, dict[str, Any]]],
|
||||
placement_zx_axes: tuple[Union[VECTOR_3D, None], Union[VECTOR_3D, None]],
|
||||
) -> ifcopenshell.entity_instance:
|
||||
if isinstance(cardinal_point, int):
|
||||
cardinal_point = CARDINAL_POINT_VALUES[cardinal_point - 1]
|
||||
|
||||
self.cardinal_point = cardinal_point
|
||||
self.profile = profile
|
||||
self.clippings = [Clipping.parse(c) for c in clippings]
|
||||
self.depth = depth
|
||||
self.placement_zx_axes = placement_zx_axes
|
||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
return self.file.create_entity(
|
||||
"IfcShapeRepresentation",
|
||||
context,
|
||||
context.ContextIdentifier,
|
||||
"Clipping" if self.clippings else "SweptSolid",
|
||||
[self.create_item()],
|
||||
)
|
||||
|
||||
def create_item(self):
|
||||
def create_item(self) -> ifcopenshell.entity_instance:
|
||||
point = self.get_point()
|
||||
placement = self.file.createIfcAxis2Placement3D(
|
||||
point,
|
||||
self.file.createIfcDirection(self.settings["placement_zx_axes"][0] or (0.0, 0.0, 1.0)),
|
||||
self.file.createIfcDirection(self.settings["placement_zx_axes"][1] or (1.0, 0.0, 0.0)),
|
||||
self.file.create_entity("IfcDirection", self.placement_zx_axes[0] or (0.0, 0.0, 1.0)),
|
||||
self.file.create_entity("IfcDirection", self.placement_zx_axes[1] or (1.0, 0.0, 0.0)),
|
||||
)
|
||||
extrusion = self.file.createIfcExtrudedAreaSolid(
|
||||
self.settings["profile"],
|
||||
extrusion = self.file.create_entity(
|
||||
"IfcExtrudedAreaSolid",
|
||||
self.profile,
|
||||
placement,
|
||||
self.file.createIfcDirection((0.0, 0.0, 1.0)),
|
||||
self.convert_si_to_unit(self.settings["depth"]),
|
||||
self.convert_si_to_unit(self.depth),
|
||||
)
|
||||
if self.settings["clippings"]:
|
||||
if self.clippings:
|
||||
return self.apply_clippings(extrusion)
|
||||
return extrusion
|
||||
|
||||
def apply_clippings(self, first_operand):
|
||||
while self.settings["clippings"]:
|
||||
clipping = self.settings["clippings"].pop()
|
||||
def apply_clippings(self, first_operand: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
|
||||
while self.clippings:
|
||||
clipping = self.clippings.pop()
|
||||
if isinstance(clipping, ifcopenshell.entity_instance):
|
||||
new = ifcopenshell.util.element.copy(self.file, clipping)
|
||||
new.FirstOperand = first_operand
|
||||
first_operand = new
|
||||
else: # Clipping
|
||||
first_operand = clipping.apply(self.file, first_operand, self.settings["unit_scale"])
|
||||
first_operand = clipping.apply(self.file, first_operand, self.unit_scale)
|
||||
return first_operand
|
||||
|
||||
def convert_si_to_unit(self, co):
|
||||
return co / self.settings["unit_scale"]
|
||||
def convert_si_to_unit(self, co: float) -> float:
|
||||
return co / self.unit_scale
|
||||
|
||||
def get_point(self):
|
||||
if not self.settings["cardinal_point"]:
|
||||
def get_point(self) -> ifcopenshell.entity_instance:
|
||||
if not self.cardinal_point:
|
||||
return self.file.createIfcCartesianPoint((0.0, 0.0, 0.0))
|
||||
elif self.settings["cardinal_point"] == 1:
|
||||
elif self.cardinal_point == "bottom left":
|
||||
return self.file.createIfcCartesianPoint((-self.get_x() / 2, self.get_y() / 2, 0.0))
|
||||
elif self.settings["cardinal_point"] == 2:
|
||||
elif self.cardinal_point == "bottom centre":
|
||||
return self.file.createIfcCartesianPoint((0.0, self.get_y() / 2, 0.0))
|
||||
elif self.settings["cardinal_point"] == 3:
|
||||
elif self.cardinal_point == "bottom right":
|
||||
return self.file.createIfcCartesianPoint((self.get_x() / 2, self.get_y() / 2, 0.0))
|
||||
elif self.settings["cardinal_point"] == 4:
|
||||
elif self.cardinal_point == "mid-depth left":
|
||||
return self.file.createIfcCartesianPoint((-self.get_x() / 2, 0.0, 0.0))
|
||||
elif self.settings["cardinal_point"] == 5:
|
||||
elif self.cardinal_point == "mid-depth centre":
|
||||
return self.file.createIfcCartesianPoint((0.0, 0.0, 0.0))
|
||||
elif self.settings["cardinal_point"] == 6:
|
||||
elif self.cardinal_point == "mid-depth right":
|
||||
return self.file.createIfcCartesianPoint((self.get_x() / 2, 0.0, 0.0))
|
||||
elif self.settings["cardinal_point"] == 7:
|
||||
elif self.cardinal_point == "top left":
|
||||
return self.file.createIfcCartesianPoint((-self.get_x() / 2, -self.get_y() / 2, 0.0))
|
||||
elif self.settings["cardinal_point"] == 8:
|
||||
elif self.cardinal_point == "top centre":
|
||||
return self.file.createIfcCartesianPoint((0.0, -self.get_y() / 2, 0.0))
|
||||
elif self.settings["cardinal_point"] == 9:
|
||||
elif self.cardinal_point == "top right":
|
||||
return self.file.createIfcCartesianPoint((self.get_x() / 2, -self.get_y() / 2, 0.0))
|
||||
# TODO other cardinal points
|
||||
return self.file.createIfcCartesianPoint((0.0, 0.0, 0.0))
|
||||
|
||||
def get_x(self):
|
||||
if self.settings["profile"].is_a("IfcAsymmetricIShapeProfileDef"):
|
||||
return self.settings["profile"].OverallWidth
|
||||
elif self.settings["profile"].is_a("IfcCShapeProfileDef"):
|
||||
return self.settings["profile"].Width
|
||||
elif self.settings["profile"].is_a("IfcCircleProfileDef"):
|
||||
return self.settings["profile"].Radius * 2
|
||||
elif self.settings["profile"].is_a("IfcEllipseProfileDef"):
|
||||
return self.settings["profile"].SemiAxis1 * 2
|
||||
elif self.settings["profile"].is_a("IfcIShapeProfileDef"):
|
||||
return self.settings["profile"].OverallWidth
|
||||
elif self.settings["profile"].is_a("IfcLShapeProfileDef"):
|
||||
return self.settings["profile"].Width
|
||||
elif self.settings["profile"].is_a("IfcRectangleProfileDef"):
|
||||
return self.settings["profile"].XDim
|
||||
elif self.settings["profile"].is_a("IfcTShapeProfileDef"):
|
||||
return self.settings["profile"].FlangeWidth
|
||||
elif self.settings["profile"].is_a("IfcUShapeProfileDef"):
|
||||
return self.settings["profile"].FlangeWidth
|
||||
elif self.settings["profile"].is_a("IfcZShapeProfileDef"):
|
||||
return (self.settings["profile"].FlangeWidth * 2) - self.settings["profile"].WebThickness
|
||||
def get_x(self) -> float:
|
||||
if self.profile.is_a("IfcAsymmetricIShapeProfileDef"):
|
||||
return self.profile.OverallWidth
|
||||
elif self.profile.is_a("IfcCShapeProfileDef"):
|
||||
return self.profile.Width
|
||||
elif self.profile.is_a("IfcCircleProfileDef"):
|
||||
return self.profile.Radius * 2
|
||||
elif self.profile.is_a("IfcEllipseProfileDef"):
|
||||
return self.profile.SemiAxis1 * 2
|
||||
elif self.profile.is_a("IfcIShapeProfileDef"):
|
||||
return self.profile.OverallWidth
|
||||
elif self.profile.is_a("IfcLShapeProfileDef"):
|
||||
return self.profile.Width
|
||||
elif self.profile.is_a("IfcRectangleProfileDef"):
|
||||
return self.profile.XDim
|
||||
elif self.profile.is_a("IfcTShapeProfileDef"):
|
||||
return self.profile.FlangeWidth
|
||||
elif self.profile.is_a("IfcUShapeProfileDef"):
|
||||
return self.profile.FlangeWidth
|
||||
elif self.profile.is_a("IfcZShapeProfileDef"):
|
||||
return (self.profile.FlangeWidth * 2) - self.profile.WebThickness
|
||||
else:
|
||||
settings = ifcopenshell.geom.settings()
|
||||
settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
|
||||
shape = ifcopenshell.geom.create_shape(settings, self.settings["profile"])
|
||||
shape = ifcopenshell.geom.create_shape(settings, self.profile)
|
||||
return self.convert_si_to_unit(ifcopenshell.util.shape.get_x(shape))
|
||||
return 0.0
|
||||
|
||||
def get_y(self):
|
||||
if self.settings["profile"].is_a("IfcAsymmetricIShapeProfileDef"):
|
||||
return self.settings["profile"].OverallDepth
|
||||
elif self.settings["profile"].is_a("IfcCShapeProfileDef"):
|
||||
return self.settings["profile"].Depth
|
||||
elif self.settings["profile"].is_a("IfcCircleProfileDef"):
|
||||
return self.settings["profile"].Radius * 2
|
||||
elif self.settings["profile"].is_a("IfcEllipseProfileDef"):
|
||||
return self.settings["profile"].SemiAxis2 * 2
|
||||
elif self.settings["profile"].is_a("IfcIShapeProfileDef"):
|
||||
return self.settings["profile"].OverallDepth
|
||||
elif self.settings["profile"].is_a("IfcLShapeProfileDef"):
|
||||
return self.settings["profile"].Depth
|
||||
elif self.settings["profile"].is_a("IfcRectangleProfileDef"):
|
||||
return self.settings["profile"].YDim
|
||||
elif self.settings["profile"].is_a("IfcTShapeProfileDef"):
|
||||
return self.settings["profile"].Depth
|
||||
elif self.settings["profile"].is_a("IfcUShapeProfileDef"):
|
||||
return self.settings["profile"].Depth
|
||||
elif self.settings["profile"].is_a("IfcZShapeProfileDef"):
|
||||
return self.settings["profile"].Depth
|
||||
def get_y(self) -> float:
|
||||
if self.profile.is_a("IfcAsymmetricIShapeProfileDef"):
|
||||
return self.profile.OverallDepth
|
||||
elif self.profile.is_a("IfcCShapeProfileDef"):
|
||||
return self.profile.Depth
|
||||
elif self.profile.is_a("IfcCircleProfileDef"):
|
||||
return self.profile.Radius * 2
|
||||
elif self.profile.is_a("IfcEllipseProfileDef"):
|
||||
return self.profile.SemiAxis2 * 2
|
||||
elif self.profile.is_a("IfcIShapeProfileDef"):
|
||||
return self.profile.OverallDepth
|
||||
elif self.profile.is_a("IfcLShapeProfileDef"):
|
||||
return self.profile.Depth
|
||||
elif self.profile.is_a("IfcRectangleProfileDef"):
|
||||
return self.profile.YDim
|
||||
elif self.profile.is_a("IfcTShapeProfileDef"):
|
||||
return self.profile.Depth
|
||||
elif self.profile.is_a("IfcUShapeProfileDef"):
|
||||
return self.profile.Depth
|
||||
elif self.profile.is_a("IfcZShapeProfileDef"):
|
||||
return self.profile.Depth
|
||||
else:
|
||||
settings = ifcopenshell.geom.settings()
|
||||
settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
|
||||
shape = ifcopenshell.geom.create_shape(settings, self.settings["profile"])
|
||||
shape = ifcopenshell.geom.create_shape(settings, self.profile)
|
||||
return self.convert_si_to_unit(ifcopenshell.util.shape.get_y(shape))
|
||||
return 0.0
|
||||
|
||||
@@ -149,6 +149,8 @@ class Usecase:
|
||||
self.settings_2d.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
|
||||
shape = ifcopenshell.geom.create_shape(self.settings_2d, dummy_solid)
|
||||
|
||||
# NOTE: points do not need unit conversion
|
||||
# as dummy file is inherently using project units.
|
||||
if self.cardinal_point == 1:
|
||||
return self.get_bottom_left(shape)
|
||||
elif self.cardinal_point == 2:
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import annotations
|
||||
import numpy as np
|
||||
import ifcopenshell
|
||||
from typing import Any, Union
|
||||
@@ -30,7 +31,9 @@ class Clipping:
|
||||
operand_type: str = "IfcHalfSpaceSolid"
|
||||
|
||||
@classmethod
|
||||
def parse(cls, raw_data: Any) -> Union[ifcopenshell.entity_instance, "Clipping", None]:
|
||||
def parse(
|
||||
cls, raw_data: Union[ifcopenshell.entity_instance, Clipping, dict[str, Any]]
|
||||
) -> Union[ifcopenshell.entity_instance, Clipping]:
|
||||
"""Parse various formats into a clipping object
|
||||
|
||||
`raw_data` can be either:
|
||||
|
||||
@@ -20,6 +20,7 @@ import test.bootstrap
|
||||
import ifcopenshell.api.root
|
||||
import ifcopenshell.api.context
|
||||
import ifcopenshell.api.geometry
|
||||
import ifcopenshell.util.shape_builder
|
||||
|
||||
|
||||
class TestAddShapeAspect(test.bootstrap.IFC4):
|
||||
|
||||
Reference in New Issue
Block a user