mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-25 09:32:37 +00:00
Fix #4854. Make IFC edit mode toggle dynamic to prevent editing uneditable things.
This commit is contained in:
@@ -24,6 +24,7 @@ from mathutils import Vector
|
|||||||
|
|
||||||
|
|
||||||
def refresh():
|
def refresh():
|
||||||
|
ViewportData.is_loaded = False
|
||||||
PlacementData.is_loaded = False
|
PlacementData.is_loaded = False
|
||||||
DerivedCoordinatesData.is_loaded = False
|
DerivedCoordinatesData.is_loaded = False
|
||||||
RepresentationsData.is_loaded = False
|
RepresentationsData.is_loaded = False
|
||||||
@@ -31,6 +32,28 @@ def refresh():
|
|||||||
ConnectionsData.is_loaded = False
|
ConnectionsData.is_loaded = False
|
||||||
|
|
||||||
|
|
||||||
|
class ViewportData:
|
||||||
|
data = {}
|
||||||
|
is_loaded = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls):
|
||||||
|
cls.is_loaded = True
|
||||||
|
cls.data = {"mode": cls.mode()}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def mode(cls):
|
||||||
|
obj = bpy.context.active_object
|
||||||
|
obj_mode = [("OBJECT", "IFC Object Mode", "", "OBJECT_DATAMODE", 0)]
|
||||||
|
mesh_modes = [
|
||||||
|
("OBJECT", "IFC Object Mode", "", "OBJECT_DATAMODE", 0),
|
||||||
|
("EDIT", "IFC Edit Mode", "", "EDITMODE_HLT", 1),
|
||||||
|
]
|
||||||
|
if not obj or not tool.Blender.is_editable(obj):
|
||||||
|
return obj_mode
|
||||||
|
return mesh_modes
|
||||||
|
|
||||||
|
|
||||||
class RepresentationsData:
|
class RepresentationsData:
|
||||||
data = {}
|
data = {}
|
||||||
is_loaded = False
|
is_loaded = False
|
||||||
@@ -334,11 +357,13 @@ class PlacementData:
|
|||||||
obj = bpy.context.active_object
|
obj = bpy.context.active_object
|
||||||
if obj and props.has_blender_offset:
|
if obj and props.has_blender_offset:
|
||||||
xyz = cls.original_xyz(obj)
|
xyz = cls.original_xyz(obj)
|
||||||
cls.data.update({
|
cls.data.update(
|
||||||
"original_x": str(xyz[0]),
|
{
|
||||||
"original_y": str(xyz[1]),
|
"original_x": str(xyz[0]),
|
||||||
"original_z": str(xyz[2]),
|
"original_y": str(xyz[1]),
|
||||||
})
|
"original_z": str(xyz[2]),
|
||||||
|
}
|
||||||
|
)
|
||||||
cls.is_loaded = True
|
cls.is_loaded = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -1531,7 +1531,7 @@ class OverrideModeSetEdit(bpy.types.Operator):
|
|||||||
return IfcStore.execute_ifc_operator(self, context)
|
return IfcStore.execute_ifc_operator(self, context)
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
selected_objs = context.selected_objects or ([context.active_object] if context.active_object else [])
|
selected_objs = tool.Blender.get_selected_objects()
|
||||||
active_obj = context.active_object
|
active_obj = context.active_object
|
||||||
|
|
||||||
if context.active_object:
|
if context.active_object:
|
||||||
@@ -1542,23 +1542,13 @@ class OverrideModeSetEdit(bpy.types.Operator):
|
|||||||
return bpy.ops.bim.enable_editing_boundary_geometry()
|
return bpy.ops.bim.enable_editing_boundary_geometry()
|
||||||
|
|
||||||
for obj in selected_objs:
|
for obj in selected_objs:
|
||||||
if not obj:
|
if not tool.Blender.is_editable(obj):
|
||||||
continue
|
self.report({"INFO"}, f"Object cannot be edited: {obj.name}")
|
||||||
obj_supports_edit_mode, message = tool.Blender.object_supports_edit_mode(obj)
|
|
||||||
if not obj_supports_edit_mode:
|
|
||||||
self.report({"INFO"}, message)
|
|
||||||
obj.select_set(False)
|
obj.select_set(False)
|
||||||
continue
|
continue
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
if not element:
|
if not element:
|
||||||
continue
|
continue
|
||||||
usage_type = tool.Model.get_usage_type(element)
|
|
||||||
if usage_type is not None and usage_type not in ("PROFILE", "LAYER3"):
|
|
||||||
# Parametric objects shall not be edited as meshes as they
|
|
||||||
# can be modified to be incompatible with the parametric
|
|
||||||
# constraints.
|
|
||||||
obj.select_set(False)
|
|
||||||
continue
|
|
||||||
representation = tool.Geometry.get_active_representation(obj)
|
representation = tool.Geometry.get_active_representation(obj)
|
||||||
if not representation:
|
if not representation:
|
||||||
continue
|
continue
|
||||||
@@ -1566,6 +1556,7 @@ class OverrideModeSetEdit(bpy.types.Operator):
|
|||||||
obj.select_set(False)
|
obj.select_set(False)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
usage_type = tool.Model.get_usage_type(element)
|
||||||
is_profile = True
|
is_profile = True
|
||||||
representation_class = tool.Geometry.get_ifc_representation_class(element, representation)
|
representation_class = tool.Geometry.get_ifc_representation_class(element, representation)
|
||||||
if usage_type == "PROFILE":
|
if usage_type == "PROFILE":
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
import bpy
|
import bpy
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
from blenderbim.bim.prop import StrProperty, Attribute
|
from blenderbim.bim.prop import StrProperty, Attribute
|
||||||
from blenderbim.bim.module.geometry.data import RepresentationsData
|
from blenderbim.bim.module.geometry.data import RepresentationsData, ViewportData
|
||||||
from bpy.types import PropertyGroup
|
from bpy.types import PropertyGroup
|
||||||
from bpy.props import (
|
from bpy.props import (
|
||||||
PointerProperty,
|
PointerProperty,
|
||||||
@@ -48,6 +48,12 @@ def update_mode(self, context):
|
|||||||
bpy.ops.bim.override_mode_set_edit("INVOKE_DEFAULT")
|
bpy.ops.bim.override_mode_set_edit("INVOKE_DEFAULT")
|
||||||
|
|
||||||
|
|
||||||
|
def get_mode(self, context):
|
||||||
|
if not ViewportData.is_loaded:
|
||||||
|
ViewportData.load()
|
||||||
|
return ViewportData.data["mode"]
|
||||||
|
|
||||||
|
|
||||||
def get_styles(self, context):
|
def get_styles(self, context):
|
||||||
# postponed import to avoid circular import
|
# postponed import to avoid circular import
|
||||||
from blenderbim.bim.module.material.data import MaterialsData
|
from blenderbim.bim.module.material.data import MaterialsData
|
||||||
@@ -129,13 +135,5 @@ class BIMGeometryProperties(PropertyGroup):
|
|||||||
# Navisworks workaround
|
# Navisworks workaround
|
||||||
should_force_triangulation: BoolProperty(name="Force Triangulation", default=False)
|
should_force_triangulation: BoolProperty(name="Force Triangulation", default=False)
|
||||||
is_changing_mode: BoolProperty(name="Is Changing Mode", default=False)
|
is_changing_mode: BoolProperty(name="Is Changing Mode", default=False)
|
||||||
mode: EnumProperty(
|
mode: EnumProperty(items=get_mode, name="IFC Interaction Mode", update=update_mode)
|
||||||
default="OBJECT",
|
|
||||||
items=[
|
|
||||||
("OBJECT", "IFC Object Mode", "", "OBJECT_DATAMODE", 0),
|
|
||||||
("EDIT", "IFC Edit Mode", "", "EDITMODE_HLT", 1),
|
|
||||||
],
|
|
||||||
name="IFC Interaction Mode",
|
|
||||||
update=update_mode,
|
|
||||||
)
|
|
||||||
representation_from_object: PointerProperty(type=bpy.types.Object)
|
representation_from_object: PointerProperty(type=bpy.types.Object)
|
||||||
|
|||||||
@@ -131,8 +131,12 @@ class Blender(blenderbim.core.tool.Blender):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def get_selected_objects(cls) -> set[bpy.types.Object]:
|
def get_selected_objects(cls) -> set[bpy.types.Object]:
|
||||||
if bpy.context.selected_objects:
|
if bpy.context.selected_objects:
|
||||||
return set(bpy.context.selected_objects + [bpy.context.active_object])
|
if active_obj := bpy.context.active_object:
|
||||||
return set([bpy.context.active_object])
|
return set(bpy.context.selected_objects + [active_obj])
|
||||||
|
return set(bpy.context.selected_objects)
|
||||||
|
if active_obj := bpy.context.active_object:
|
||||||
|
return {active_obj}
|
||||||
|
return set()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_ifc_object(
|
def create_ifc_object(
|
||||||
@@ -666,8 +670,7 @@ class Blender(blenderbim.core.tool.Blender):
|
|||||||
return bpy.ops.object.mode_set(mode="EDIT", toggle=True)
|
return bpy.ops.object.mode_set(mode="EDIT", toggle=True)
|
||||||
elif ao.type in cls.OBJECT_TYPES_THAT_SUPPORT_EDIT_GPENCIL_MODE:
|
elif ao.type in cls.OBJECT_TYPES_THAT_SUPPORT_EDIT_GPENCIL_MODE:
|
||||||
return bpy.ops.object.mode_set(mode="EDIT_GPENCIL", toggle=True)
|
return bpy.ops.object.mode_set(mode="EDIT_GPENCIL", toggle=True)
|
||||||
else:
|
return {"CANCELLED"}
|
||||||
return {"CANCELLED"}
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_object_an_ifc_class(cls, obj: bpy.types.Object, classes: Iterable[str]) -> bool:
|
def is_object_an_ifc_class(cls, obj: bpy.types.Object, classes: Iterable[str]) -> bool:
|
||||||
@@ -766,12 +769,19 @@ class Blender(blenderbim.core.tool.Blender):
|
|||||||
return collections_mapping
|
return collections_mapping
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def object_supports_edit_mode(cls, obj):
|
def is_editable(cls, obj):
|
||||||
if not obj.data:
|
if obj.type not in cls.OBJECT_TYPES_THAT_SUPPORT_EDIT_MODE:
|
||||||
return False, "Can't Edit Empty Object"
|
return False
|
||||||
|
if not (element := tool.Ifc.get_entity(obj)):
|
||||||
|
return True
|
||||||
if obj in bpy.context.scene.BIMProjectProperties.clipping_planes_objs:
|
if obj in bpy.context.scene.BIMProjectProperties.clipping_planes_objs:
|
||||||
return False, "Can't Edit Clipping Plane Geometry"
|
return False
|
||||||
return True, ""
|
usage_type = tool.Model.get_usage_type(element)
|
||||||
|
if usage_type in ("LAYER1", "LAYER2"):
|
||||||
|
# At the moment, these type types of parametric elements (walls,
|
||||||
|
# and "blocks") cannot be edited as a mesh-like object.
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
class Modifier:
|
class Modifier:
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
Reference in New Issue
Block a user