mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
See #5972. Boolean operands are now loaded in item editing mode and are editable.
This commit is contained in:
@@ -36,15 +36,18 @@ class ItemDecorator:
|
||||
if cls.is_installed:
|
||||
cls.uninstall()
|
||||
obj_is_selected = {}
|
||||
obj_is_boolean = {}
|
||||
objs = {}
|
||||
for item_obj in context.scene.BIMGeometryProperties.item_objs:
|
||||
if obj := item_obj.obj:
|
||||
objs[obj.name] = cls.get_obj_data(obj)
|
||||
obj_is_selected[obj.name] = obj.select_get()
|
||||
obj_is_boolean[obj.name] = item_obj.is_boolean
|
||||
|
||||
handler = cls()
|
||||
handler.objs = objs
|
||||
handler.obj_is_selected = obj_is_selected
|
||||
handler.obj_is_boolean = obj_is_boolean
|
||||
cls.handlers.append(SpaceView3D.draw_handler_add(handler.draw_text, (context,), "WINDOW", "POST_PIXEL"))
|
||||
cls.handlers.append(SpaceView3D.draw_handler_add(handler.draw, (context,), "WINDOW", "POST_VIEW"))
|
||||
cls.is_installed = True
|
||||
@@ -138,7 +141,7 @@ class ItemDecorator:
|
||||
self.line_shader.bind() # required to be able to change uniforms of the shader
|
||||
# POLYLINE_UNIFORM_COLOR specific uniforms
|
||||
self.line_shader.uniform_float("viewportSize", (context.region.width, context.region.height))
|
||||
self.line_shader.uniform_float("lineWidth", 1.0)
|
||||
self.line_shader.uniform_float("lineWidth", 2.0)
|
||||
|
||||
# general shader
|
||||
self.shader = gpu.shader.from_builtin("UNIFORM_COLOR")
|
||||
@@ -154,6 +157,9 @@ class ItemDecorator:
|
||||
continue
|
||||
self.draw_batch("LINES", data["verts"], selected_elements_color, data["edges"])
|
||||
self.draw_batch("TRIS", data["verts"], transparent_color(selected_elements_color), data["tris"])
|
||||
else:
|
||||
self.draw_batch("LINES", data["verts"], decorator_color_background, data["edges"])
|
||||
elif self.obj_is_boolean[obj_name]:
|
||||
self.draw_batch("LINES", data["verts"], special_elements_color, data["edges"])
|
||||
self.draw_batch("TRIS", data["verts"], transparent_color(special_elements_color), data["tris"])
|
||||
else:
|
||||
self.draw_batch("LINES", data["verts"], transparent_color(unselected_elements_color, alpha=0.2), data["edges"])
|
||||
self.draw_batch("TRIS", data["verts"], transparent_color(special_elements_color), data["tris"])
|
||||
|
||||
@@ -2694,8 +2694,19 @@ class ImportRepresentationItems(bpy.types.Operator, tool.Ifc.Operator):
|
||||
data = obj.data
|
||||
assert data
|
||||
item_ids = data["ios_item_ids"] if "ios_item_ids" in data else data["ios_edges_item_ids"]
|
||||
for item_id in set(item_ids):
|
||||
queue = list(set(item_ids))
|
||||
processed_ids = set()
|
||||
boolean_ids = set()
|
||||
while queue:
|
||||
item_id = queue.pop()
|
||||
if item_id in processed_ids:
|
||||
continue # In theory, an item can be used multiple times (e.g. in a boolean stack).
|
||||
item = tool.Ifc.get().by_id(item_id)
|
||||
if item.is_a("IfcBooleanResult"):
|
||||
queue.append(item.FirstOperand.id())
|
||||
queue.append(item.SecondOperand.id())
|
||||
boolean_ids.add(item.SecondOperand.id())
|
||||
continue
|
||||
item_mesh = bpy.data.meshes.new(f"Item/{item.is_a()}/{item_id}")
|
||||
item_mesh.BIMMeshProperties.ifc_definition_id = item_id
|
||||
|
||||
@@ -2705,6 +2716,7 @@ class ImportRepresentationItems(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
new = props.item_objs.add()
|
||||
new.obj = item_obj
|
||||
new.is_boolean = item_id in boolean_ids
|
||||
|
||||
tool.Geometry.import_item(item_obj)
|
||||
tool.Geometry.import_item_attributes(item_obj)
|
||||
@@ -2712,11 +2724,9 @@ class ImportRepresentationItems(bpy.types.Operator, tool.Ifc.Operator):
|
||||
if not tool.Geometry.is_movable(item):
|
||||
tool.Geometry.lock_object(item_obj)
|
||||
|
||||
if "IfcOpeningElement" in obj.name:
|
||||
item_obj.display_type = "WIRE"
|
||||
|
||||
item_obj.select_set(True) # so you can quickly hit tab again, for edit mode
|
||||
context.view_layer.objects.active = item_obj
|
||||
processed_ids.add(item_id)
|
||||
|
||||
tool.Root.reload_item_decorator()
|
||||
|
||||
|
||||
@@ -131,10 +131,7 @@ class RepresentationItemObject(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
obj: PointerProperty(type=bpy.types.Object)
|
||||
verts: StringProperty(name="Verts")
|
||||
edges: StringProperty(name="Edges")
|
||||
special_verts: StringProperty(name="Special Verts")
|
||||
special_edges: StringProperty(name="Special Edges")
|
||||
is_boolean: BoolProperty(name="Is Boolean", default=False)
|
||||
|
||||
|
||||
class ShapeAspect(PropertyGroup):
|
||||
|
||||
@@ -952,7 +952,7 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
|
||||
@classmethod
|
||||
def is_movable(cls, item: ifcopenshell.entity_instance) -> bool:
|
||||
return item.is_a("IfcSweptAreaSolid")
|
||||
return item.is_a("IfcSweptAreaSolid") or item.is_a("IfcHalfSpaceSolid")
|
||||
|
||||
@classmethod
|
||||
def is_profile_based(cls, data: bpy.types.Mesh) -> bool:
|
||||
@@ -1571,12 +1571,10 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
has_changed = False
|
||||
|
||||
for item_obj in props.item_objs:
|
||||
if not (obj := item_obj.obj):
|
||||
if not (obj := item_obj.obj) or not tool.Ifc.is_moved(obj):
|
||||
continue
|
||||
item = tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id)
|
||||
if is_swept_area := item.is_a("IfcSweptAreaSolid"):
|
||||
if not tool.Ifc.is_moved(obj):
|
||||
continue
|
||||
has_changed = True
|
||||
old_position = item.Position
|
||||
|
||||
@@ -1591,6 +1589,25 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
item.Position = builder.create_axis2_placement_3d_from_matrix(position)
|
||||
if old_position:
|
||||
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), old_position)
|
||||
if item.is_a("IfcHalfSpaceSolid"):
|
||||
has_changed = True
|
||||
surface = item.BaseSurface
|
||||
if surface.is_a("IfcPlane"):
|
||||
position = surface.Position
|
||||
m = Matrix(ifcopenshell.util.placement.get_axis2placement(position).tolist())
|
||||
m.translation *= unit_scale
|
||||
|
||||
new_m = rep_obj.matrix_world.inverted() @ obj.matrix_world
|
||||
new_m.normalize()
|
||||
new_m.translation /= unit_scale
|
||||
new_m = np.array(new_m)
|
||||
surface.Position = builder.create_axis2_placement_3d_from_matrix(new_m)
|
||||
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), position)
|
||||
else:
|
||||
self.report(
|
||||
{"INFO"},
|
||||
f"Editing boolean using non-IfcPlane IfcSurface ({surface.is_a()}) is not supported.",
|
||||
)
|
||||
|
||||
if has_changed:
|
||||
cls.reload_representation(rep_obj)
|
||||
@@ -1631,21 +1648,36 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
item = tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id)
|
||||
obj.data.clear_geometry()
|
||||
|
||||
geometry = tool.Loader.create_generic_shape(item)
|
||||
if (cartesian_point_offset := cls.get_cartesian_point_offset(rep_obj)) is not None:
|
||||
verts_array = np.array(geometry.verts)
|
||||
offset = np.array([-cartesian_point_offset[0], -cartesian_point_offset[1], -cartesian_point_offset[2]])
|
||||
offset_verts = verts_array + np.tile(offset, len(verts_array) // 3)
|
||||
verts = offset_verts.tolist()
|
||||
if item.is_a("IfcHalfSpaceSolid"):
|
||||
bm = bmesh.new()
|
||||
bmesh.ops.create_grid(bm, size=0.5)
|
||||
bm.verts.ensure_lookup_table()
|
||||
bm.edges.ensure_lookup_table()
|
||||
bm.faces.ensure_lookup_table()
|
||||
bm.to_mesh(obj.data)
|
||||
bm.free()
|
||||
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
position = item.BaseSurface.Position
|
||||
position = Matrix(ifcopenshell.util.placement.get_axis2placement(position).tolist())
|
||||
position.translation *= unit_scale
|
||||
obj.matrix_world = rep_obj.matrix_world @ position
|
||||
else:
|
||||
verts = geometry.verts
|
||||
tool.Loader.convert_geometry_to_mesh(geometry, obj.data, verts=verts)
|
||||
geometry = tool.Loader.create_generic_shape(item)
|
||||
if (cartesian_point_offset := cls.get_cartesian_point_offset(rep_obj)) is not None:
|
||||
verts_array = np.array(geometry.verts)
|
||||
offset = np.array([-cartesian_point_offset[0], -cartesian_point_offset[1], -cartesian_point_offset[2]])
|
||||
offset_verts = verts_array + np.tile(offset, len(verts_array) // 3)
|
||||
verts = offset_verts.tolist()
|
||||
else:
|
||||
verts = geometry.verts
|
||||
tool.Loader.convert_geometry_to_mesh(geometry, obj.data, verts=verts)
|
||||
|
||||
if ios_materials := list(obj.data["ios_materials"]):
|
||||
material = tool.Ifc.get_object(tool.Ifc.get().by_id(ios_materials[0]))
|
||||
obj.data.materials.append(material)
|
||||
if ios_materials := list(obj.data["ios_materials"]):
|
||||
material = tool.Ifc.get_object(tool.Ifc.get().by_id(ios_materials[0]))
|
||||
obj.data.materials.append(material)
|
||||
|
||||
obj.matrix_world = rep_obj.matrix_world.copy()
|
||||
obj.matrix_world = rep_obj.matrix_world.copy()
|
||||
|
||||
if is_swept_area := item.is_a("IfcSweptAreaSolid"):
|
||||
position = item.Position
|
||||
|
||||
Reference in New Issue
Block a user