mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-28 11:18:18 +00:00
Fix #5416. Optimise item decorator and make decoration more subtle to make it easier to see the mesh.
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import bpy
|
||||||
import blf
|
import blf
|
||||||
import gpu
|
import gpu
|
||||||
import bmesh
|
import bmesh
|
||||||
@@ -34,11 +35,51 @@ class ItemDecorator:
|
|||||||
def install(cls, context):
|
def install(cls, context):
|
||||||
if cls.is_installed:
|
if cls.is_installed:
|
||||||
cls.uninstall()
|
cls.uninstall()
|
||||||
|
obj_is_selected = {}
|
||||||
|
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()
|
||||||
|
|
||||||
handler = cls()
|
handler = cls()
|
||||||
|
handler.objs = objs
|
||||||
|
handler.obj_is_selected = obj_is_selected
|
||||||
cls.handlers.append(SpaceView3D.draw_handler_add(handler.draw_text, (context,), "WINDOW", "POST_PIXEL"))
|
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.handlers.append(SpaceView3D.draw_handler_add(handler.draw, (context,), "WINDOW", "POST_VIEW"))
|
||||||
cls.is_installed = True
|
cls.is_installed = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_obj_data(cls, obj):
|
||||||
|
verts = []
|
||||||
|
edges = []
|
||||||
|
tris = []
|
||||||
|
|
||||||
|
if len(obj.data.loop_triangles) > 0:
|
||||||
|
verts = [tuple(obj.matrix_world @ v.co) for v in obj.data.vertices]
|
||||||
|
tris = [tuple(t.vertices) for t in obj.data.loop_triangles]
|
||||||
|
|
||||||
|
i = len(verts)
|
||||||
|
matrix_world = obj.matrix_world
|
||||||
|
bbox_verts = [matrix_world @ Vector(co) for co in obj.bound_box]
|
||||||
|
bbox_edges = [
|
||||||
|
(0 + i, 3 + i),
|
||||||
|
(3 + i, 7 + i),
|
||||||
|
(7 + i, 4 + i),
|
||||||
|
(4 + i, 0 + i),
|
||||||
|
(0 + i, 1 + i),
|
||||||
|
(3 + i, 2 + i),
|
||||||
|
(7 + i, 6 + i),
|
||||||
|
(4 + i, 5 + i),
|
||||||
|
(1 + i, 2 + i),
|
||||||
|
(2 + i, 6 + i),
|
||||||
|
(6 + i, 5 + i),
|
||||||
|
(5 + i, 1 + i),
|
||||||
|
]
|
||||||
|
edges = bbox_edges
|
||||||
|
verts.extend(bbox_verts)
|
||||||
|
return {"verts": verts, "edges": edges, "tris": tris}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def uninstall(cls):
|
def uninstall(cls):
|
||||||
for handler in cls.handlers:
|
for handler in cls.handlers:
|
||||||
@@ -80,7 +121,7 @@ class ItemDecorator:
|
|||||||
blf.disable(font_id, blf.SHADOW)
|
blf.disable(font_id, blf.SHADOW)
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
def transparent_color(color, alpha=0.3):
|
def transparent_color(color, alpha=0.05):
|
||||||
color = [i for i in color]
|
color = [i for i in color]
|
||||||
color[3] = alpha
|
color[3] = alpha
|
||||||
return color
|
return color
|
||||||
@@ -89,72 +130,30 @@ class ItemDecorator:
|
|||||||
selected_elements_color = self.addon_prefs.decorator_color_selected
|
selected_elements_color = self.addon_prefs.decorator_color_selected
|
||||||
unselected_elements_color = self.addon_prefs.decorator_color_unselected
|
unselected_elements_color = self.addon_prefs.decorator_color_unselected
|
||||||
special_elements_color = self.addon_prefs.decorator_color_special
|
special_elements_color = self.addon_prefs.decorator_color_special
|
||||||
|
decorator_color_background = self.addon_prefs.decorator_color_background
|
||||||
|
|
||||||
gpu.state.point_size_set(6)
|
|
||||||
gpu.state.blend_set("ALPHA")
|
gpu.state.blend_set("ALPHA")
|
||||||
|
|
||||||
self.line_shader = gpu.shader.from_builtin("POLYLINE_UNIFORM_COLOR")
|
self.line_shader = gpu.shader.from_builtin("POLYLINE_UNIFORM_COLOR")
|
||||||
self.line_shader.bind() # required to be able to change uniforms of the shader
|
self.line_shader.bind() # required to be able to change uniforms of the shader
|
||||||
# POLYLINE_UNIFORM_COLOR specific uniforms
|
# POLYLINE_UNIFORM_COLOR specific uniforms
|
||||||
self.line_shader.uniform_float("viewportSize", (context.region.width, context.region.height))
|
self.line_shader.uniform_float("viewportSize", (context.region.width, context.region.height))
|
||||||
self.line_shader.uniform_float("lineWidth", 2.0)
|
self.line_shader.uniform_float("lineWidth", 1.0)
|
||||||
|
|
||||||
# general shader
|
# general shader
|
||||||
self.shader = gpu.shader.from_builtin("UNIFORM_COLOR")
|
self.shader = gpu.shader.from_builtin("UNIFORM_COLOR")
|
||||||
|
|
||||||
selected_verts = []
|
for obj_name, data in self.objs.items():
|
||||||
selected_edges = []
|
if (obj := bpy.data.objects.get(obj_name)) and obj.hide_get() == False:
|
||||||
selected_tris = []
|
if self.obj_is_selected[obj_name] != obj.select_get():
|
||||||
unselected_verts = []
|
self.obj_is_selected[obj_name] = obj.select_get()
|
||||||
unselected_edges = []
|
data = ItemDecorator.get_obj_data(obj)
|
||||||
unselected_tris = []
|
self.objs[obj_name] = data
|
||||||
for item in context.scene.BIMGeometryProperties.item_objs:
|
|
||||||
if (obj := item.obj) and obj.hide_get() == False:
|
|
||||||
if obj.select_get():
|
if obj.select_get():
|
||||||
if context.mode != "OBJECT":
|
if context.mode != "OBJECT":
|
||||||
continue
|
continue
|
||||||
edges = selected_edges
|
self.draw_batch("LINES", data["verts"], selected_elements_color, data["edges"])
|
||||||
verts = selected_verts
|
self.draw_batch("TRIS", data["verts"], transparent_color(selected_elements_color), data["tris"])
|
||||||
tris = selected_tris
|
|
||||||
else:
|
else:
|
||||||
edges = unselected_edges
|
self.draw_batch("LINES", data["verts"], decorator_color_background, data["edges"])
|
||||||
verts = unselected_verts
|
self.draw_batch("TRIS", data["verts"], transparent_color(special_elements_color), data["tris"])
|
||||||
tris = unselected_tris
|
|
||||||
|
|
||||||
i = len(verts)
|
|
||||||
matrix_world = obj.matrix_world
|
|
||||||
bbox_verts = [matrix_world @ Vector(co) for co in obj.bound_box]
|
|
||||||
bbox_edges = [
|
|
||||||
(0 + i, 3 + i),
|
|
||||||
(3 + i, 7 + i),
|
|
||||||
(7 + i, 4 + i),
|
|
||||||
(4 + i, 0 + i),
|
|
||||||
(0 + i, 1 + i),
|
|
||||||
(3 + i, 2 + i),
|
|
||||||
(7 + i, 6 + i),
|
|
||||||
(4 + i, 5 + i),
|
|
||||||
(1 + i, 2 + i),
|
|
||||||
(2 + i, 6 + i),
|
|
||||||
(6 + i, 5 + i),
|
|
||||||
(5 + i, 1 + i),
|
|
||||||
]
|
|
||||||
edges.extend(bbox_edges)
|
|
||||||
verts.extend(bbox_verts)
|
|
||||||
|
|
||||||
if (total_tris := len(obj.data.loop_triangles)) == 0:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if total_tris > 1000: # For performance
|
|
||||||
continue
|
|
||||||
|
|
||||||
offset = len(verts)
|
|
||||||
verts.extend([tuple(obj.matrix_world @ v.co) for v in obj.data.vertices])
|
|
||||||
tris.extend([tuple([i + offset for i in t.vertices]) for t in obj.data.loop_triangles])
|
|
||||||
|
|
||||||
if unselected_verts:
|
|
||||||
self.draw_batch("LINES", unselected_verts, transparent_color(unselected_elements_color), unselected_edges)
|
|
||||||
self.draw_batch("TRIS", unselected_verts, transparent_color(special_elements_color), unselected_tris)
|
|
||||||
|
|
||||||
if selected_verts:
|
|
||||||
self.draw_batch("LINES", selected_verts, selected_elements_color, selected_edges)
|
|
||||||
self.draw_batch("TRIS", selected_verts, transparent_color(selected_elements_color), selected_tris)
|
|
||||||
|
|||||||
@@ -1745,6 +1745,7 @@ class OverrideModeSetObject(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
return bpy.ops.bim.edit_boundary_geometry()
|
return bpy.ops.bim.edit_boundary_geometry()
|
||||||
elif tool.Geometry.is_representation_item(context.active_object):
|
elif tool.Geometry.is_representation_item(context.active_object):
|
||||||
self.edit_representation_item(context.active_object)
|
self.edit_representation_item(context.active_object)
|
||||||
|
tool.Root.reload_item_decorator()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
objs = context.selected_objects or [context.active_object]
|
objs = context.selected_objects or [context.active_object]
|
||||||
@@ -2358,6 +2359,8 @@ class ImportRepresentationItems(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
if tool.Geometry.is_meshlike_item(item):
|
if tool.Geometry.is_meshlike_item(item):
|
||||||
tool.Geometry.lock_object(item_obj)
|
tool.Geometry.lock_object(item_obj)
|
||||||
|
|
||||||
|
tool.Root.reload_item_decorator()
|
||||||
|
|
||||||
|
|
||||||
class UpdateItemAttributes(bpy.types.Operator, tool.Ifc.Operator):
|
class UpdateItemAttributes(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.update_item_attributes"
|
bl_idname = "bim.update_item_attributes"
|
||||||
|
|||||||
@@ -131,7 +131,6 @@ class CreateProject(bpy.types.Operator):
|
|||||||
)
|
)
|
||||||
bonsai.bim.schema.reload(tool.Ifc.get().schema_identifier)
|
bonsai.bim.schema.reload(tool.Ifc.get().schema_identifier)
|
||||||
tool.Blender.register_toolbar()
|
tool.Blender.register_toolbar()
|
||||||
tool.Root.reload_item_decorator()
|
|
||||||
|
|
||||||
def rollback(self, data):
|
def rollback(self, data):
|
||||||
IfcStore.file = None
|
IfcStore.file = None
|
||||||
@@ -843,7 +842,6 @@ class LoadProjectElements(bpy.types.Operator):
|
|||||||
tool.Project.set_default_context()
|
tool.Project.set_default_context()
|
||||||
tool.Project.set_default_modeling_dimensions()
|
tool.Project.set_default_modeling_dimensions()
|
||||||
tool.Root.reload_grid_decorator()
|
tool.Root.reload_grid_decorator()
|
||||||
tool.Root.reload_item_decorator()
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def get_decomposition_elements(self):
|
def get_decomposition_elements(self):
|
||||||
|
|||||||
@@ -1434,7 +1434,8 @@ class Geometry(bonsai.core.tool.Geometry):
|
|||||||
has_changed = False
|
has_changed = False
|
||||||
|
|
||||||
for item_obj in props.item_objs:
|
for item_obj in props.item_objs:
|
||||||
obj = item_obj.obj
|
if not (obj := item_obj.obj):
|
||||||
|
continue
|
||||||
item = tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id)
|
item = tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id)
|
||||||
if item.is_a("IfcSweptAreaSolid"):
|
if item.is_a("IfcSweptAreaSolid"):
|
||||||
if not tool.Ifc.is_moved(obj):
|
if not tool.Ifc.is_moved(obj):
|
||||||
@@ -1455,6 +1456,7 @@ class Geometry(bonsai.core.tool.Geometry):
|
|||||||
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), old_position)
|
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), old_position)
|
||||||
if has_changed:
|
if has_changed:
|
||||||
cls.reload_representation(rep_obj)
|
cls.reload_representation(rep_obj)
|
||||||
|
tool.Root.reload_item_decorator()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def import_item_attributes(cls, obj: bpy.types.Object) -> None:
|
def import_item_attributes(cls, obj: bpy.types.Object) -> None:
|
||||||
|
|||||||
@@ -217,8 +217,7 @@ class Root(bonsai.core.tool.Root):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def reload_item_decorator(cls) -> None:
|
def reload_item_decorator(cls) -> None:
|
||||||
item_objs = bpy.context.scene.BIMGeometryProperties.item_objs
|
bpy.context.view_layer.update()
|
||||||
item_objs.clear()
|
|
||||||
ItemDecorator.install(bpy.context)
|
ItemDecorator.install(bpy.context)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
Reference in New Issue
Block a user