mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 14:41:25 +00:00
Clicking on the "Select all array objects" button now sets the parent object as active #3492
Moved the array objects fetching code to tool.Blender Also a bit of housekeeping and fixing minor typos here and there
This commit is contained in:
@@ -422,7 +422,7 @@ class IfcImporter:
|
|||||||
for representation in representations:
|
for representation in representations:
|
||||||
items = representation["raw"].Items or [] # Be forgiving of invalid IFCs because Revit :(
|
items = representation["raw"].Items or [] # Be forgiving of invalid IFCs because Revit :(
|
||||||
if len(items) == 1 and items[0].is_a("IfcSweptDiskSolid"):
|
if len(items) == 1 and items[0].is_a("IfcSweptDiskSolid"):
|
||||||
if tool.Pset.get_element_pset(element, "BBIM_Railing"):
|
if tool.Blender.Modifier.is_railing(element):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
elif len(items) and ( # See #2508 why we accommodate for invalid IFCs here
|
elif len(items) and ( # See #2508 why we accommodate for invalid IFCs here
|
||||||
@@ -430,7 +430,7 @@ class IfcImporter:
|
|||||||
and len({i.is_a() for i in items}) == 1
|
and len({i.is_a() for i in items}) == 1
|
||||||
and len({i.Radius for i in items}) == 1
|
and len({i.Radius for i in items}) == 1
|
||||||
):
|
):
|
||||||
if tool.Pset.get_element_pset(element, "BBIM_Railing"):
|
if tool.Blender.Modifier.is_railing(element):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -1433,9 +1433,9 @@ class OverrideModeSetObject(bpy.types.Operator):
|
|||||||
profile = tool.Ifc.get().by_id(profile_id)
|
profile = tool.Ifc.get().by_id(profile_id)
|
||||||
if tool.Ifc.get_object(profile): # We are editing an arbitrary profile
|
if tool.Ifc.get_object(profile): # We are editing an arbitrary profile
|
||||||
bpy.ops.bim.edit_arbitrary_profile()
|
bpy.ops.bim.edit_arbitrary_profile()
|
||||||
elif tool.Pset.get_element_pset(element, "BBIM_Railing"):
|
elif tool.Blender.Modifier.is_railing(element):
|
||||||
bpy.ops.bim.finish_editing_railing_path()
|
bpy.ops.bim.finish_editing_railing_path()
|
||||||
elif tool.Pset.get_element_pset(element, "BBIM_Roof"):
|
elif tool.Blender.Modifier.is_roof(element):
|
||||||
bpy.ops.bim.finish_editing_roof_path()
|
bpy.ops.bim.finish_editing_roof_path()
|
||||||
elif tool.Model.get_usage_type(element) == "PROFILE":
|
elif tool.Model.get_usage_type(element) == "PROFILE":
|
||||||
bpy.ops.bim.edit_extrusion_axis()
|
bpy.ops.bim.edit_extrusion_axis()
|
||||||
|
|||||||
@@ -217,10 +217,10 @@ class RemoveConstituent(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
constituent = tool.Ifc.get().by_id(self.constituent)
|
constituent = tool.Ifc.get().by_id(self.constituent)
|
||||||
for material_set in layer.ToMaterialConstituentSet:
|
for material_set in constituent.ToMaterialConstituentSet:
|
||||||
if len(material_set.MaterialConstituents) == 1:
|
if len(material_set.MaterialConstituents) == 1:
|
||||||
self.report({"ERROR"}, "At least one constituent must exist")
|
self.report({"ERROR"}, "At least one constituent must exist")
|
||||||
return {"ERROR"}
|
return {"CANCELLED"}
|
||||||
ifcopenshell.api.run("material.remove_constituent", tool.Ifc.get(), constituent=constituent)
|
ifcopenshell.api.run("material.remove_constituent", tool.Ifc.get(), constituent=constituent)
|
||||||
|
|
||||||
|
|
||||||
@@ -255,7 +255,7 @@ class RemoveProfile(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
for material_set in profile.ToMaterialProfileSet:
|
for material_set in profile.ToMaterialProfileSet:
|
||||||
if len(material_set.MaterialProfiles) == 1:
|
if len(material_set.MaterialProfiles) == 1:
|
||||||
self.report({"ERROR"}, "At least one profile must exist")
|
self.report({"ERROR"}, "At least one profile must exist")
|
||||||
return {"ERROR"}
|
return {"CANCELLED"}
|
||||||
ifcopenshell.api.run("material.remove_profile", tool.Ifc.get(), profile=profile)
|
ifcopenshell.api.run("material.remove_profile", tool.Ifc.get(), profile=profile)
|
||||||
|
|
||||||
|
|
||||||
@@ -319,7 +319,7 @@ class RemoveLayer(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
for material_set in layer.ToMaterialLayerSet:
|
for material_set in layer.ToMaterialLayerSet:
|
||||||
if len(material_set.MaterialLayers) == 1:
|
if len(material_set.MaterialLayers) == 1:
|
||||||
self.report({"ERROR"}, "At least one layer must exist")
|
self.report({"ERROR"}, "At least one layer must exist")
|
||||||
return {"ERROR"}
|
return {"CANCELLED"}
|
||||||
ifcopenshell.api.run("material.remove_layer", tool.Ifc.get(), layer=layer)
|
ifcopenshell.api.run("material.remove_layer", tool.Ifc.get(), layer=layer)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -154,7 +154,9 @@ class RemoveArray(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
data[self.item]["count"] = 1
|
data[self.item]["count"] = 1
|
||||||
|
|
||||||
if (self.keep_objs) & (self.item < (len(data) - 1)):
|
if (self.keep_objs) & (self.item < (len(data) - 1)):
|
||||||
self.report({"INFO"}, "Keeping the objects is only allowed when you are removing the last Array of the object")
|
self.report(
|
||||||
|
{"INFO"}, "Keeping the objects is only allowed when you are removing the last Array of the object"
|
||||||
|
)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
props.is_editing = -1
|
props.is_editing = -1
|
||||||
@@ -188,17 +190,17 @@ class SelectArrayParent(bpy.types.Operator):
|
|||||||
bl_idname = "bim.select_array_parent"
|
bl_idname = "bim.select_array_parent"
|
||||||
bl_label = "Select Array Parent"
|
bl_label = "Select Array Parent"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
parent: bpy.props.StringProperty()
|
parent: bpy.props.StringProperty(description="Parent Element GUID")
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
try:
|
try:
|
||||||
element = tool.Ifc.get().by_guid(self.parent)
|
element = tool.Ifc.get().by_guid(self.parent)
|
||||||
except:
|
except:
|
||||||
return {"FINISHED"}
|
self.report({"ERROR"}, f"Couldn't find array parent by guid '{self.parent}'")
|
||||||
|
return {"CANCELLED"}
|
||||||
obj = tool.Ifc.get_object(element)
|
obj = tool.Ifc.get_object(element)
|
||||||
if obj:
|
if obj:
|
||||||
context.view_layer.objects.active = obj
|
tool.Blender.select_and_activate_single_object(context, active_object=obj)
|
||||||
obj.select_set(True)
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -206,28 +208,20 @@ class SelectAllArrayObjects(bpy.types.Operator):
|
|||||||
bl_idname = "bim.select_all_array_objects"
|
bl_idname = "bim.select_all_array_objects"
|
||||||
bl_label = "Select All Array Objects"
|
bl_label = "Select All Array Objects"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
parent: bpy.props.StringProperty()
|
parent: bpy.props.StringProperty(description="Parent Element GUID")
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
try:
|
try:
|
||||||
element = tool.Ifc.get().by_guid(self.parent)
|
parent_element = tool.Ifc.get().by_guid(self.parent)
|
||||||
except:
|
except RuntimeError:
|
||||||
return {"FINISHED"}
|
self.report({"ERROR"}, f"Couldn't find array parent by guid '{self.parent}'")
|
||||||
|
return {"CANCELLED"}
|
||||||
|
|
||||||
obj = tool.Ifc.get_object(element)
|
array_objects = tool.Blender.Modifier.Array.get_all_objects(parent_element)
|
||||||
obj.select_set(True)
|
tool.Blender.set_objects_selection(context, active_object=array_objects[0], selected_objects=array_objects)
|
||||||
|
|
||||||
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Array")
|
|
||||||
data = json.loads(pset["Data"])
|
|
||||||
for i in range(len(data)):
|
|
||||||
for child in data[i]["children"]:
|
|
||||||
element = tool.Ifc.get().by_guid(child)
|
|
||||||
obj = tool.Ifc.get_object(element)
|
|
||||||
if obj:
|
|
||||||
context.view_layer.objects.active = obj
|
|
||||||
obj.select_set(True)
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class Input3DCursorXArray(bpy.types.Operator):
|
class Input3DCursorXArray(bpy.types.Operator):
|
||||||
bl_idname = "bim.input_cursor_x_array"
|
bl_idname = "bim.input_cursor_x_array"
|
||||||
bl_label = "Get 3d Cursor X Input for Array"
|
bl_label = "Get 3d Cursor X Input for Array"
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ class ReloadSelectedIfcFile(bpy.types.Operator):
|
|||||||
valid_file = os.path.exists(filepath) and "ifc" in os.path.splitext(filepath)[1].lower()
|
valid_file = os.path.exists(filepath) and "ifc" in os.path.splitext(filepath)[1].lower()
|
||||||
if not valid_file:
|
if not valid_file:
|
||||||
self.report({"ERROR"}, f"Couldn't find .ifc file by the path '{filepath}'")
|
self.report({"ERROR"}, f"Couldn't find .ifc file by the path '{filepath}'")
|
||||||
return {"ERROR"}
|
return {"CANCELLED"}
|
||||||
context.scene.BIMProperties.ifc_file = context.scene.BIMProperties.ifc_file
|
context.scene.BIMProperties.ifc_file = context.scene.BIMProperties.ifc_file
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
import json
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
from mathutils import Vector
|
from mathutils import Vector
|
||||||
@@ -457,33 +458,40 @@ class Blender:
|
|||||||
else:
|
else:
|
||||||
return {"CANCELLED"}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_object_an_ifc_class(cls, obj, classes):
|
||||||
|
if not tool.Ifc.get():
|
||||||
|
return False
|
||||||
|
element = tool.Ifc.get_entity(obj)
|
||||||
|
return element and element.is_a() in classes
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_object_from_guid(cls, guid):
|
||||||
|
element = tool.Ifc.get().by_guid(guid)
|
||||||
|
obj = tool.Ifc.get_object(element)
|
||||||
|
if obj:
|
||||||
|
return obj
|
||||||
|
|
||||||
class Modifier:
|
class Modifier:
|
||||||
@classmethod
|
|
||||||
def is_object_an_ifc_class(cls, obj, classes):
|
|
||||||
if not tool.Ifc.get():
|
|
||||||
return False
|
|
||||||
element = tool.Ifc.get_entity(obj)
|
|
||||||
return element and element.is_a() in classes
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_eligible_for_railing_modifier(cls, obj):
|
def is_eligible_for_railing_modifier(cls, obj):
|
||||||
return cls.is_object_an_ifc_class(obj, ("IfcRailing", "IfcRailingType"))
|
return tool.Blender.is_object_an_ifc_class(obj, ("IfcRailing", "IfcRailingType"))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_eligible_for_stair_modifier(cls, obj):
|
def is_eligible_for_stair_modifier(cls, obj):
|
||||||
return cls.is_object_an_ifc_class(obj, ("IfcStairFlight", "IfcStairFlightType"))
|
return tool.Blender.is_object_an_ifc_class(obj, ("IfcStairFlight", "IfcStairFlightType"))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_eligible_for_window_modifier(cls, obj):
|
def is_eligible_for_window_modifier(cls, obj):
|
||||||
return cls.is_object_an_ifc_class(obj, ("IfcWindow", "IfcWindowType", "IfcWindowStyle"))
|
return tool.Blender.is_object_an_ifc_class(obj, ("IfcWindow", "IfcWindowType", "IfcWindowStyle"))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_eligible_for_door_modifier(cls, obj):
|
def is_eligible_for_door_modifier(cls, obj):
|
||||||
return cls.is_object_an_ifc_class(obj, ("IfcDoor", "IfcDoorType", "IfcDoorStyle"))
|
return tool.Blender.is_object_an_ifc_class(obj, ("IfcDoor", "IfcDoorType", "IfcDoorStyle"))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_eligible_for_roof_modifier(cls, obj):
|
def is_eligible_for_roof_modifier(cls, obj):
|
||||||
return cls.is_object_an_ifc_class(obj, ("IfcRoof", "IfcRoofType"))
|
return tool.Blender.is_object_an_ifc_class(obj, ("IfcRoof", "IfcRoofType"))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_railing(cls, element):
|
def is_railing(cls, element):
|
||||||
@@ -512,3 +520,29 @@ class Blender:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def is_modifier_with_non_editable_path(cls, element):
|
def is_modifier_with_non_editable_path(cls, element):
|
||||||
return cls.is_stair(element) or cls.is_door(element) or cls.is_window(element)
|
return cls.is_stair(element) or cls.is_door(element) or cls.is_window(element)
|
||||||
|
|
||||||
|
class Array:
|
||||||
|
@classmethod
|
||||||
|
def get_all_objects(cls, parent_element):
|
||||||
|
parent_obj = tool.Ifc.get_object(parent_element)
|
||||||
|
children_objects = list(cls.get_all_children_objects(parent_element))
|
||||||
|
array_objects = [parent_obj] + children_objects # We ensure the parent is at index 0
|
||||||
|
return array_objects
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_all_children_objects(cls, parent_element):
|
||||||
|
for array_modifier in cls.get_modifiers_data(parent_element):
|
||||||
|
yield from cls.get_children_objects(array_modifier)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_modifiers_data(cls, parent_element):
|
||||||
|
array_pset = ifcopenshell.util.element.get_pset(parent_element, "BBIM_Array")
|
||||||
|
for modifier_data in json.loads(array_pset["Data"]):
|
||||||
|
yield modifier_data
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_children_objects(cls, modifier_data):
|
||||||
|
for child_guid in modifier_data["children"]:
|
||||||
|
child_obj = tool.Blender.get_object_from_guid(child_guid)
|
||||||
|
if child_obj:
|
||||||
|
yield child_obj
|
||||||
|
|||||||
Reference in New Issue
Block a user