mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-17 22:11:36 +00:00
Merge branch 'v0.8.0' of github.com:IfcOpenShell/IfcOpenShell into v0.8.0
This commit is contained in:
@@ -33,6 +33,7 @@ from bonsai.bim.module.model.workspace import LIST_OF_TOOLS, TOOLS_TO_CLASSES_MA
|
||||
from bonsai.bim.module.aggregate.decorator import AggregateDecorator
|
||||
from bonsai.bim.module.georeference.decorator import GeoreferenceDecorator
|
||||
from bonsai.bim.module.model.decorator import WallAxisDecorator, SlabDirectionDecorator
|
||||
from bonsai.bim.module.nest.decorator import NestDecorator
|
||||
from mathutils import Vector
|
||||
from math import cos, degrees
|
||||
from typing import Union, Callable
|
||||
@@ -323,11 +324,14 @@ def load_post(scene):
|
||||
# Bonsai overlays
|
||||
georeference_props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
aggregate_props = bpy.context.scene.BIMAggregateProperties
|
||||
nest_props = bpy.context.scene.BIMNestProperties
|
||||
model_props = bpy.context.scene.BIMModelProperties
|
||||
if aggregate_props.aggregate_decorator:
|
||||
AggregateDecorator.install(bpy.context)
|
||||
if georeference_props.should_visualise:
|
||||
GeoreferenceDecorator.install(bpy.context)
|
||||
if aggregate_props.aggregate_decorator:
|
||||
AggregateDecorator.install(bpy.context)
|
||||
if nest_props.nest_decorator:
|
||||
NestDecorator.install(bpy.context)
|
||||
if model_props.show_wall_axis:
|
||||
WallAxisDecorator.install(bpy.context)
|
||||
if model_props.show_slab_direction:
|
||||
|
||||
@@ -167,6 +167,8 @@ class AggregateDecorator:
|
||||
theme = context.preferences.themes.items()[0][1]
|
||||
selected_object_color = (*theme.view_3d.object_active, 1)
|
||||
|
||||
self.shader = gpu.shader.from_builtin("UNIFORM_COLOR")
|
||||
self.shader.bind()
|
||||
self.line_shader = gpu.shader.from_builtin("POLYLINE_UNIFORM_COLOR")
|
||||
self.line_shader.bind()
|
||||
# POLYLINE_UNIFORM_COLOR specific uniforms
|
||||
|
||||
@@ -3037,6 +3037,23 @@ class OverrideMove(bpy.types.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
def _execute(self, context):
|
||||
# Get filling objects
|
||||
selection = []
|
||||
for obj in context.selected_objects:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
continue
|
||||
selection.append(obj)
|
||||
for rel in getattr(element, "HasOpenings", []) or []:
|
||||
opening = rel.RelatedOpeningElement
|
||||
for rel2 in getattr(opening, "HasFillings", []) or []:
|
||||
filling = rel2.RelatedBuildingElement
|
||||
selection.append(tool.Ifc.get_object(filling))
|
||||
for obj in selection:
|
||||
obj.select_set(True)
|
||||
self.new_active_obj = obj
|
||||
|
||||
|
||||
# Get aggregates
|
||||
props = context.scene.BIMAggregateProperties
|
||||
not_editing_objs = [o.obj for o in props.not_editing_objects]
|
||||
@@ -3046,6 +3063,8 @@ class OverrideMove(bpy.types.Operator):
|
||||
if obj in not_editing_objs:
|
||||
obj.select_set(False)
|
||||
continue
|
||||
if obj == props.editing_aggregate:
|
||||
continue
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element or not element.is_a("IfcElement"):
|
||||
continue
|
||||
@@ -3079,6 +3098,8 @@ class OverrideMove(bpy.types.Operator):
|
||||
if obj in not_editing_objs:
|
||||
obj.select_set(False)
|
||||
continue
|
||||
if obj == props.editing_nest:
|
||||
continue
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element or not element.is_a("IfcElement"):
|
||||
continue
|
||||
|
||||
@@ -88,6 +88,7 @@ classes = (
|
||||
opening.HideOpenings,
|
||||
opening.PurgeUnusedOpenings,
|
||||
opening.RecalculateFill,
|
||||
opening.RemoveBoolean,
|
||||
opening.RemoveBooleans,
|
||||
opening.ShowBooleans,
|
||||
opening.ShowOpenings,
|
||||
|
||||
@@ -1144,6 +1144,27 @@ class PurgeUnusedOpenings(Operator, tool.Ifc.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RemoveBoolean(Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.remove_boolean"
|
||||
bl_label = "Remove Boolean"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Removes the actively selected boolean"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
props = context.scene.BIMBooleanProperties
|
||||
return props.active_boolean
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMBooleanProperties
|
||||
ifcopenshell.api.geometry.remove_boolean(
|
||||
tool.Ifc.get(), tool.Ifc.get().by_id(props.active_boolean.ifc_definition_id)
|
||||
)
|
||||
bpy.ops.bim.enable_editing_booleans()
|
||||
rep_obj = bpy.context.scene.BIMGeometryProperties.representation_obj
|
||||
tool.Geometry.reload_representation(rep_obj)
|
||||
|
||||
|
||||
# TODO: merge with ProfileDecorator?
|
||||
class DecorationsHandler:
|
||||
installed = None
|
||||
|
||||
@@ -590,6 +590,11 @@ class EditObjectUI:
|
||||
row = cls.layout.row(align=True)
|
||||
op = row.operator("bim.disable_aggregate_mode", text="", icon="X")
|
||||
op = row.operator("bim.toggle_aggregate_mode_local_view", text="", icon="ZOOM_SELECTED")
|
||||
if context.scene.BIMNestProperties.in_nest_mode:
|
||||
layout.label(text=f"Nest Mode", icon="EMPTY_AXIS")
|
||||
row = cls.layout.row(align=True)
|
||||
op = row.operator("bim.disable_nest_mode", text="", icon="X")
|
||||
op = row.operator("bim.toggle_nest_mode_local_view", text="", icon="ZOOM_SELECTED")
|
||||
|
||||
text = format_ifc_camel_case(AuthoringData.data["active_class"])
|
||||
layout.label(text=f"{text} Edit Tools:", icon="RESTRICT_SELECT_OFF")
|
||||
|
||||
@@ -26,6 +26,8 @@ classes = (
|
||||
operator.BIM_OT_select_components,
|
||||
operator.BIM_OT_select_nest,
|
||||
operator.BIM_OT_nest_unassign_object,
|
||||
operator.BIM_OT_disable_nest_mode,
|
||||
operator.BIM_OT_toggle_nest_mode_local_view,
|
||||
prop.BIMObjectNestProperties,
|
||||
prop.Objects,
|
||||
prop.BIMNestProperties,
|
||||
|
||||
@@ -86,7 +86,7 @@ class NestDecorator:
|
||||
if cls.is_installed:
|
||||
cls.uninstall()
|
||||
handler = cls()
|
||||
cls.handlers.append(SpaceView3D.draw_handler_add(handler.draw_aggregate, (context,), "WINDOW", "POST_VIEW"))
|
||||
cls.handlers.append(SpaceView3D.draw_handler_add(handler.draw_nest, (context,), "WINDOW", "POST_VIEW"))
|
||||
cls.is_installed = True
|
||||
|
||||
@classmethod
|
||||
@@ -153,8 +153,8 @@ class NestDecorator:
|
||||
shader.uniform_float("color", color)
|
||||
batch.draw(shader)
|
||||
|
||||
def draw_aggregate(self, context):
|
||||
if context.scene.BIMAggregateProperties.in_aggregate_mode:
|
||||
def draw_nest(self, context):
|
||||
if context.scene.BIMNestProperties.in_nest_mode:
|
||||
return
|
||||
self.addon_prefs = tool.Blender.get_addon_preferences()
|
||||
decorator_color_special = self.addon_prefs.decorator_color_special
|
||||
@@ -165,11 +165,13 @@ class NestDecorator:
|
||||
theme = context.preferences.themes.items()[0][1]
|
||||
selected_object_color = (*theme.view_3d.object_active, 1)
|
||||
|
||||
self.shader = gpu.shader.from_builtin("UNIFORM_COLOR")
|
||||
self.shader.bind()
|
||||
self.line_shader = gpu.shader.from_builtin("POLYLINE_UNIFORM_COLOR")
|
||||
self.line_shader.bind()
|
||||
# POLYLINE_UNIFORM_COLOR specific uniforms
|
||||
self.line_shader.uniform_float("viewportSize", (context.region.width, context.region.height))
|
||||
aggregates = []
|
||||
nests = []
|
||||
if not (selected_objects := context.selected_objects):
|
||||
return
|
||||
for obj in selected_objects:
|
||||
@@ -177,35 +179,39 @@ class NestDecorator:
|
||||
if not element or not element.is_a("IfcElement"):
|
||||
return
|
||||
|
||||
parts = ifcopenshell.util.element.get_parts(element)
|
||||
if parts:
|
||||
aggregates.append(obj)
|
||||
components = ifcopenshell.util.element.get_components(element)
|
||||
if components:
|
||||
nests.append(obj)
|
||||
continue
|
||||
|
||||
aggregate = ifcopenshell.util.element.get_aggregate(element)
|
||||
if aggregate:
|
||||
aggregates.append(tool.Ifc.get_object(aggregate))
|
||||
nest = ifcopenshell.util.element.get_nest(element)
|
||||
if nest:
|
||||
nests.append(tool.Ifc.get_object(nest))
|
||||
|
||||
aggregates = set(aggregates)
|
||||
for aggregate in aggregates:
|
||||
nests = set(nests)
|
||||
for nest in nests:
|
||||
self.line_shader.uniform_float("lineWidth", 1.0)
|
||||
color = decorator_color_unselected
|
||||
if aggregate in selected_objects:
|
||||
if nest in selected_objects:
|
||||
color = selected_object_color
|
||||
size = aggregate.empty_display_size
|
||||
location = aggregate.location
|
||||
line_x = (location - Vector((size, 0.0, 0.0)), location + Vector((size, 0.0, 0.0)))
|
||||
self.draw_batch("LINES", line_x, color, [(0, 1)])
|
||||
line_y = (location - Vector((0.0, size, 0.0)), location + Vector((0.0, size, 0.0)))
|
||||
self.draw_batch("LINES", line_y, color, [(0, 1)])
|
||||
line_z = (location - Vector((0.0, 0.0, size)), location + Vector((0.0, 0.0, size)))
|
||||
self.draw_batch("LINES", line_z, color, [(0, 1)])
|
||||
if context.scene.BIMAggregateProperties.in_aggregate_mode:
|
||||
return
|
||||
parts = ifcopenshell.util.element.get_parts(tool.Ifc.get_entity(aggregate))
|
||||
parts_objs = [tool.Ifc.get_object(p) for p in parts]
|
||||
size = nest.empty_display_size
|
||||
location = nest.location
|
||||
if nest.type == "EMPTY":
|
||||
line_x = (location - Vector((size, 0.0, 0.0)), location + Vector((size, 0.0, 0.0)))
|
||||
self.draw_batch("LINES", line_x, color, [(0, 1)])
|
||||
line_y = (location - Vector((0.0, size, 0.0)), location + Vector((0.0, size, 0.0)))
|
||||
self.draw_batch("LINES", line_y, color, [(0, 1)])
|
||||
line_z = (location - Vector((0.0, 0.0, size)), location + Vector((0.0, 0.0, size)))
|
||||
self.draw_batch("LINES", line_z, color, [(0, 1)])
|
||||
else:
|
||||
self.draw_batch("POINTS", [location], color)
|
||||
# if context.scene.BIMNestProperties.in_aggregate_mode:
|
||||
# return
|
||||
components = ifcopenshell.util.element.get_components(tool.Ifc.get_entity(nest))
|
||||
components_objs = [tool.Ifc.get_object(p) for p in components]
|
||||
components_objs.append(nest)
|
||||
|
||||
indices, edges = create_bounding_box(parts_objs)
|
||||
indices, edges = create_bounding_box(components_objs)
|
||||
self.line_shader.uniform_float("lineWidth", 0.5)
|
||||
self.draw_batch("LINES", indices, color, edges)
|
||||
line = (Vector(indices[0]), location)
|
||||
|
||||
@@ -140,3 +140,33 @@ class BIM_OT_select_nest(bpy.types.Operator):
|
||||
nest_obj.select_set(True)
|
||||
bpy.context.view_layer.objects.active = nest_obj
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class BIM_OT_disable_nest_mode(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_nest_mode"
|
||||
bl_label = "Disable Nest Mode"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
bpy.ops.object.select_all(action="DESELECT")
|
||||
core.disable_nest_mode(tool.Nest)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class BIM_OT_toggle_nest_mode_local_view(bpy.types.Operator):
|
||||
bl_idname = "bim.toggle_nest_mode_local_view"
|
||||
bl_label = "Toggle Nest Mode Local View"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMNestProperties
|
||||
objs = [o.obj for o in props.editing_objects]
|
||||
if props.in_nest_mode:
|
||||
if context.space_data.local_view:
|
||||
bpy.ops.view3d.localview()
|
||||
else:
|
||||
for obj in objs:
|
||||
obj.select_set(True)
|
||||
bpy.ops.view3d.localview()
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -45,3 +45,8 @@ class BIMBooleanProperties(PropertyGroup):
|
||||
name="Operator",
|
||||
default="DIFFERENCE",
|
||||
)
|
||||
|
||||
@property
|
||||
def active_boolean(self):
|
||||
if self.booleans and self.active_boolean_index < len(self.booleans):
|
||||
return self.booleans[self.active_boolean_index]
|
||||
|
||||
@@ -176,6 +176,10 @@ class BIM_PT_booleans(Panel):
|
||||
row.prop(props, "operator", text="")
|
||||
row.operator("bim.add_boolean", text="", icon="ADD")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.alignment = "RIGHT"
|
||||
row.operator("bim.remove_boolean", text="", icon="X")
|
||||
|
||||
self.layout.template_list("BIM_UL_booleans", "", props, "booleans", props, "active_boolean_index")
|
||||
|
||||
|
||||
|
||||
@@ -1209,8 +1209,9 @@ class BIM_PT_decorators_overlay(Panel):
|
||||
view = context.space_data
|
||||
overlay = view.overlay
|
||||
|
||||
geo_props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
agg_props = bpy.context.scene.BIMAggregateProperties
|
||||
georeference_props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
aggregate_props = bpy.context.scene.BIMAggregateProperties
|
||||
nest_props = bpy.context.scene.BIMNestProperties
|
||||
model_props = bpy.context.scene.BIMModelProperties
|
||||
display_all = overlay.show_overlays
|
||||
|
||||
@@ -1218,10 +1219,12 @@ class BIM_PT_decorators_overlay(Panel):
|
||||
col.active = display_all
|
||||
|
||||
row = col.row(align=True)
|
||||
row.prop(geo_props, "should_visualise", text="Georeference")
|
||||
row.prop(geo_props, "visualization_scale", text="Size", slider=True)
|
||||
row.prop(georeference_props, "should_visualise", text="Georeference")
|
||||
row.prop(georeference_props, "visualization_scale", text="Size", slider=True)
|
||||
row = col.row(align=True)
|
||||
row.prop(agg_props, "aggregate_decorator", text="Aggregate")
|
||||
row.prop(aggregate_props, "aggregate_decorator", text="Aggregate")
|
||||
row = col.row(align=True)
|
||||
row.prop(nest_props, "nest_decorator", text="Nest")
|
||||
row = col.row(align=True)
|
||||
row.prop(model_props, "show_wall_axis", text="Wall Axis")
|
||||
row = col.row(align=True)
|
||||
|
||||
@@ -145,3 +145,4 @@ class Aggregate(bonsai.core.tool.Aggregate):
|
||||
props.in_aggregate_mode = False
|
||||
props.not_editing_objects.clear()
|
||||
props.editing_objects.clear()
|
||||
props.editing_aggregate = None
|
||||
|
||||
@@ -1742,6 +1742,8 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
cls.unlock_object(props.representation_obj)
|
||||
tool.Blender.set_active_object(props.representation_obj)
|
||||
cls.sync_item_positions()
|
||||
representation = cls.get_active_representation(props.representation_obj)
|
||||
ifcopenshell.api.geometry.validate_type(tool.Ifc.get(), representation)
|
||||
props.is_changing_mode = True
|
||||
if props.mode != "OBJECT":
|
||||
props.mode = "OBJECT"
|
||||
|
||||
@@ -120,3 +120,4 @@ class Nest(bonsai.core.tool.Nest):
|
||||
props.in_nest_mode = False
|
||||
props.not_editing_objects.clear()
|
||||
props.editing_objects.clear()
|
||||
props.editing_nest = None
|
||||
|
||||
Reference in New Issue
Block a user