mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-11 06:18:09 +00:00
Fix #5544. Assign / add of objects with styles are now supported.
This commit is contained in:
@@ -210,12 +210,7 @@ class AssignClass(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
ifc_representation_class=self.ifc_representation_class,
|
ifc_representation_class=self.ifc_representation_class,
|
||||||
)
|
)
|
||||||
if self.should_add_representation and obj.data and len(obj.data.vertices):
|
if self.should_add_representation and obj.data and len(obj.data.vertices):
|
||||||
builder = ifcopenshell.util.shape_builder.ShapeBuilder(tool.Ifc.get())
|
representation = tool.Geometry.export_mesh_to_tessellation(obj, ifc_context)
|
||||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
|
||||||
verts = [v.co / unit_scale for v in obj.data.vertices]
|
|
||||||
faces = [p.vertices[:] for p in obj.data.polygons]
|
|
||||||
item = builder.mesh(verts, faces)
|
|
||||||
representation = builder.get_representation(ifc_context, [item])
|
|
||||||
ifcopenshell.api.geometry.assign_representation(tool.Ifc.get(), element, representation)
|
ifcopenshell.api.geometry.assign_representation(tool.Ifc.get(), element, representation)
|
||||||
bonsai.core.geometry.switch_representation(
|
bonsai.core.geometry.switch_representation(
|
||||||
tool.Ifc,
|
tool.Ifc,
|
||||||
@@ -373,16 +368,7 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
pass
|
pass
|
||||||
elif representation_template == "OBJ" and props.representation_obj:
|
elif representation_template == "OBJ" and props.representation_obj:
|
||||||
obj.matrix_world = props.representation_obj.matrix_world
|
obj.matrix_world = props.representation_obj.matrix_world
|
||||||
builder = ifcopenshell.util.shape_builder.ShapeBuilder(tool.Ifc.get())
|
representation = tool.Geometry.export_mesh_to_tessellation(props.representation_obj, ifc_context)
|
||||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
|
||||||
items = []
|
|
||||||
meshes = tool.Geometry.split_by_loose_parts(props.representation_obj)
|
|
||||||
for mesh in meshes:
|
|
||||||
verts = [v.co / unit_scale for v in mesh.vertices]
|
|
||||||
faces = [p.vertices[:] for p in mesh.polygons]
|
|
||||||
items.append(builder.mesh(verts, faces))
|
|
||||||
bpy.data.meshes.remove(mesh)
|
|
||||||
representation = builder.get_representation(ifc_context, items)
|
|
||||||
ifcopenshell.api.geometry.assign_representation(tool.Ifc.get(), element, representation)
|
ifcopenshell.api.geometry.assign_representation(tool.Ifc.get(), element, representation)
|
||||||
bonsai.core.geometry.switch_representation(
|
bonsai.core.geometry.switch_representation(
|
||||||
tool.Ifc,
|
tool.Ifc,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import multiprocessing
|
|||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
import ifcopenshell.api.grid
|
import ifcopenshell.api.grid
|
||||||
|
import ifcopenshell.api.style
|
||||||
import ifcopenshell.geom
|
import ifcopenshell.geom
|
||||||
import ifcopenshell.guid
|
import ifcopenshell.guid
|
||||||
import ifcopenshell.util.element
|
import ifcopenshell.util.element
|
||||||
@@ -1600,3 +1601,34 @@ class Geometry(bonsai.core.tool.Geometry):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def reload_representation_item_ids(cls, representation: ifcopenshell.entity_instance, data: bpy.types.Mesh) -> None:
|
def reload_representation_item_ids(cls, representation: ifcopenshell.entity_instance, data: bpy.types.Mesh) -> None:
|
||||||
data["ios_item_ids"] = [i["item"].id() for i in ifcopenshell.util.representation.resolve_items(representation)]
|
data["ios_item_ids"] = [i["item"].id() for i in ifcopenshell.util.representation.resolve_items(representation)]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def export_mesh_to_tessellation(cls, obj: bpy.types.Object, ifc_context) -> ifcopenshell.entity_instance:
|
||||||
|
builder = ifcopenshell.util.shape_builder.ShapeBuilder(tool.Ifc.get())
|
||||||
|
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||||
|
items = []
|
||||||
|
meshes = cls.split_by_loose_parts(obj)
|
||||||
|
for mesh in meshes:
|
||||||
|
verts = [v.co / unit_scale for v in mesh.vertices]
|
||||||
|
faces = [p.vertices[:] for p in mesh.polygons]
|
||||||
|
item = builder.mesh(verts, faces)
|
||||||
|
items.append(item)
|
||||||
|
material_index = mesh.polygons[0].material_index
|
||||||
|
if materials := list(mesh.materials):
|
||||||
|
material = materials[material_index]
|
||||||
|
if not (style := tool.Style.get_style(material)):
|
||||||
|
style = ifcopenshell.api.run("style.add_style", tool.Ifc.get(), name=material.name)
|
||||||
|
if material.use_nodes:
|
||||||
|
ifc_class = "IfcSurfaceStyleRendering"
|
||||||
|
attributes = tool.Style.get_surface_rendering_attributes(material)
|
||||||
|
else:
|
||||||
|
ifc_class = "IfcSurfaceStyleShading"
|
||||||
|
attributes = tool.Style.get_surface_shading_attributes(material)
|
||||||
|
ifcopenshell.api.style.add_surface_style(
|
||||||
|
tool.Ifc.get(), style=style, ifc_class=ifc_class, attributes=attributes
|
||||||
|
)
|
||||||
|
tool.Ifc.link(style, material)
|
||||||
|
material.use_fake_user = True
|
||||||
|
ifcopenshell.api.style.assign_item_style(tool.Ifc.get(), item=item, style=style)
|
||||||
|
bpy.data.meshes.remove(mesh)
|
||||||
|
return builder.get_representation(ifc_context, items)
|
||||||
|
|||||||
@@ -594,55 +594,9 @@ class Style(bonsai.core.tool.Style):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def assign_style_to_representation_item(
|
def assign_style_to_representation_item(
|
||||||
cls, representation_item: ifcopenshell.entity_instance, style: Optional[ifcopenshell.entity_instance] = None
|
cls, item: ifcopenshell.entity_instance, style: Optional[ifcopenshell.entity_instance] = None
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Assign specified style to a representation item and unassign all previously assigned styles."""
|
return ifcopenshell.api.style.assign_item_style(tool.Ifc.get(), item=item, style=style)
|
||||||
ifc_file = representation_item.file
|
|
||||||
if not (styled_item := next(iter(representation_item.StyledByItem), None)):
|
|
||||||
if style is None:
|
|
||||||
return
|
|
||||||
if ifc_file.schema == "IFC2X3":
|
|
||||||
style = ifc_file.create_entity("IfcPresentationStyleAssignment", (style,))
|
|
||||||
ifc_file.create_entity("IfcStyledItem", representation_item, (style,))
|
|
||||||
return
|
|
||||||
|
|
||||||
styled_item_styles = styled_item.Styles
|
|
||||||
if style and styled_item_styles == (style,):
|
|
||||||
return
|
|
||||||
|
|
||||||
if ifc_file.schema == "IFC4X3":
|
|
||||||
if style is None:
|
|
||||||
ifc_file.remove(styled_item)
|
|
||||||
return
|
|
||||||
styled_item.Styles = (style,)
|
|
||||||
return
|
|
||||||
|
|
||||||
# < IFC4X3
|
|
||||||
# Can't just remove a styled item or assign a style
|
|
||||||
# since we need to remove/change the possible style assignments.
|
|
||||||
assignment = None
|
|
||||||
for style_ in styled_item_styles:
|
|
||||||
if not style_.is_a("IfcPresentationStyleAssignment"):
|
|
||||||
continue
|
|
||||||
# Remove second assignment.
|
|
||||||
if style is None or assignment:
|
|
||||||
ifc_file.remove(style_)
|
|
||||||
else:
|
|
||||||
assignment = style_
|
|
||||||
if assignment.Styles != (style,):
|
|
||||||
assignment.Styles = (style,)
|
|
||||||
|
|
||||||
if style is None:
|
|
||||||
ifc_file.remove(styled_item)
|
|
||||||
return
|
|
||||||
|
|
||||||
if assignment:
|
|
||||||
if styled_item_styles == (assignment,):
|
|
||||||
return
|
|
||||||
styled_item.Styles = (assignment,)
|
|
||||||
return
|
|
||||||
|
|
||||||
styled_item.Styles = (style,)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_representation_item_style(
|
def get_representation_item_style(
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ from .. import wrap_usecases
|
|||||||
from .add_style import add_style
|
from .add_style import add_style
|
||||||
from .add_surface_style import add_surface_style
|
from .add_surface_style import add_surface_style
|
||||||
from .add_surface_textures import add_surface_textures
|
from .add_surface_textures import add_surface_textures
|
||||||
|
from .assign_item_style import assign_item_style
|
||||||
from .assign_material_style import assign_material_style
|
from .assign_material_style import assign_material_style
|
||||||
from .assign_representation_styles import assign_representation_styles
|
from .assign_representation_styles import assign_representation_styles
|
||||||
from .edit_presentation_style import edit_presentation_style
|
from .edit_presentation_style import edit_presentation_style
|
||||||
@@ -43,6 +44,7 @@ __all__ = [
|
|||||||
"add_style",
|
"add_style",
|
||||||
"add_surface_style",
|
"add_surface_style",
|
||||||
"add_surface_textures",
|
"add_surface_textures",
|
||||||
|
"assign_item_style",
|
||||||
"assign_material_style",
|
"assign_material_style",
|
||||||
"assign_representation_styles",
|
"assign_representation_styles",
|
||||||
"edit_presentation_style",
|
"edit_presentation_style",
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
# IfcOpenShell - IFC toolkit and geometry engine
|
||||||
|
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||||
|
#
|
||||||
|
# This file is part of IfcOpenShell.
|
||||||
|
#
|
||||||
|
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# IfcOpenShell is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
import ifcopenshell
|
||||||
|
from typing import Optional, Union
|
||||||
|
|
||||||
|
|
||||||
|
def assign_item_style(
|
||||||
|
file: ifcopenshell.file,
|
||||||
|
item: ifcopenshell.entity_instance,
|
||||||
|
style: Optional[ifcopenshell.entity_instance],
|
||||||
|
should_use_presentation_style_assignment: bool = False,
|
||||||
|
) -> Union[ifcopenshell.entity_instance, None]:
|
||||||
|
"""Assigns a style directly to a representation item
|
||||||
|
|
||||||
|
A style may either be assigned directly to an object's representation
|
||||||
|
items, or to a material which is then associated with the object. If both
|
||||||
|
exist, then the style assigned directly to the object's representation
|
||||||
|
takes precedence. It is recommended to use materials and assign styles to
|
||||||
|
materials. However, sometimes you may want to assign colours directly to
|
||||||
|
the object representation as an override. This API function provides that
|
||||||
|
capability.
|
||||||
|
|
||||||
|
If you want to assign styles to a material instead (recommended), then
|
||||||
|
please see ifcopenshell.api.style.assign_material_style.
|
||||||
|
|
||||||
|
:param item: The IfcRepresentationItem of the object
|
||||||
|
that you want to assign styles to.
|
||||||
|
:param style: A presentation style, typically IfcSurfaceStyle. None if you
|
||||||
|
want to remove an existing style from the item.
|
||||||
|
:return: Created or existing IfcStyledItem, or None if the style was removed.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code:: python
|
||||||
|
|
||||||
|
# A model context is needed to store 3D geometry
|
||||||
|
model3d = ifcopenshell.api.context.add_context(model, context_type="Model")
|
||||||
|
|
||||||
|
# Specifically, we want to store body geometry
|
||||||
|
body = ifcopenshell.api.context.add_context(model,
|
||||||
|
context_type="Model", context_identifier="Body", target_view="MODEL_VIEW", parent=model3d)
|
||||||
|
|
||||||
|
# Let's create a new wall. The wall does not have any geometry yet.
|
||||||
|
wall = ifcopenshell.api.root.create_entity(model, ifc_class="IfcWall")
|
||||||
|
|
||||||
|
# Let's use the "3D Body" representation we created earlier to add a
|
||||||
|
# new wall-like body geometry, 5 meters long, 3 meters high, and
|
||||||
|
# 200mm thick
|
||||||
|
representation = ifcopenshell.api.geometry.add_wall_representation(model,
|
||||||
|
context=body, length=5, height=3, thickness=0.2)
|
||||||
|
|
||||||
|
# Assign our new body geometry back to our wall
|
||||||
|
ifcopenshell.api.geometry.assign_representation(model,
|
||||||
|
product=wall, representation=representation)
|
||||||
|
|
||||||
|
# Place our wall at the origin
|
||||||
|
ifcopenshell.api.geometry.edit_object_placement(model, product=wall)
|
||||||
|
|
||||||
|
# Create a new surface style
|
||||||
|
style = ifcopenshell.api.style.add_style(model)
|
||||||
|
|
||||||
|
# Create a simple grey shading colour and transparency.
|
||||||
|
ifcopenshell.api.style.add_surface_style(model,
|
||||||
|
style=style, ifc_class="IfcSurfaceStyleShading", attributes={
|
||||||
|
"SurfaceColour": { "Name": None, "Red": 0.5, "Green": 0.5, "Blue": 0.5 },
|
||||||
|
"Transparency": 0., # 0 is opaque, 1 is transparent
|
||||||
|
})
|
||||||
|
|
||||||
|
# Now specifically our wall only will be coloured grey.
|
||||||
|
ifcopenshell.api.style.assign_representation_styles(model,
|
||||||
|
shape_representation=representation, styles=[style])
|
||||||
|
"""
|
||||||
|
if not (styled_item := next(iter(item.StyledByItem), None)):
|
||||||
|
if style is None:
|
||||||
|
return
|
||||||
|
if file.schema == "IFC2X3":
|
||||||
|
style = file.create_entity("IfcPresentationStyleAssignment", (style,))
|
||||||
|
return file.create_entity("IfcStyledItem", item, (style,))
|
||||||
|
|
||||||
|
styled_item_styles = styled_item.Styles
|
||||||
|
if style and styled_item_styles == (style,):
|
||||||
|
return styled_item
|
||||||
|
|
||||||
|
if file.schema == "IFC4X3":
|
||||||
|
if style is None:
|
||||||
|
file.remove(styled_item)
|
||||||
|
return
|
||||||
|
styled_item.Styles = (style,)
|
||||||
|
return styled_item
|
||||||
|
|
||||||
|
# < IFC4X3
|
||||||
|
# Can't just remove a styled item or assign a style
|
||||||
|
# since we need to remove/change the possible style assignments.
|
||||||
|
assignment = None
|
||||||
|
for style_ in styled_item_styles:
|
||||||
|
if not style_.is_a("IfcPresentationStyleAssignment"):
|
||||||
|
continue
|
||||||
|
# Remove second assignment.
|
||||||
|
if style is None or assignment:
|
||||||
|
file.remove(style_)
|
||||||
|
else:
|
||||||
|
assignment = style_
|
||||||
|
if assignment.Styles != (style,):
|
||||||
|
assignment.Styles = (style,)
|
||||||
|
|
||||||
|
if style is None:
|
||||||
|
file.remove(styled_item)
|
||||||
|
return
|
||||||
|
|
||||||
|
if assignment:
|
||||||
|
if styled_item_styles == (assignment,):
|
||||||
|
return styled_item
|
||||||
|
styled_item.Styles = (assignment,)
|
||||||
|
return styled_item
|
||||||
|
|
||||||
|
styled_item.Styles = (style,)
|
||||||
|
return styled_item
|
||||||
Reference in New Issue
Block a user