Add aggregate mode decorator.

This commit is contained in:
Bruno Perdigão
2024-11-25 17:46:48 -03:00
committed by Bruno Perdigão
parent 3c590f097a
commit 226ea10de8
2 changed files with 102 additions and 22 deletions
@@ -16,15 +16,22 @@
# 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 blf
import bpy import bpy
import gpu import gpu
import ifcopenshell import ifcopenshell
import bonsai.tool as tool import bonsai.tool as tool
from bpy.types import SpaceView3D from bpy.types import SpaceView3D
from bpy_extras import view3d_utils
from gpu_extras.batch import batch_for_shader from gpu_extras.batch import batch_for_shader
from mathutils import Vector from mathutils import Vector
def transparent_color(color, alpha=0.1):
color = [i for i in color]
color[3] = alpha
return color
class AggregateDecorator: class AggregateDecorator:
is_installed = False is_installed = False
handlers = [] handlers = []
@@ -47,23 +54,19 @@ class AggregateDecorator:
pass pass
cls.is_installed = False cls.is_installed = False
def transparent_color(self, color, alpha=0.1):
color = [i for i in color]
color[3] = alpha
return color
def dotted_line_shader(self): def dotted_line_shader(self):
vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") vert_out = gpu.types.GPUStageInterfaceInfo("my_interface")
vert_out.smooth('FLOAT', "v_ArcLength") vert_out.smooth("FLOAT", "v_ArcLength")
shader_info = gpu.types.GPUShaderCreateInfo() shader_info = gpu.types.GPUShaderCreateInfo()
shader_info.push_constant('MAT4', "u_ViewProjectionMatrix") shader_info.push_constant("MAT4", "u_ViewProjectionMatrix")
shader_info.push_constant('FLOAT', "u_Scale") shader_info.push_constant("FLOAT", "u_Scale")
shader_info.vertex_in(0, 'VEC3', "position") shader_info.vertex_in(0, "VEC3", "position")
shader_info.vertex_in(1, 'FLOAT', "arcLength") shader_info.vertex_in(1, "FLOAT", "arcLength")
shader_info.vertex_out(vert_out) shader_info.vertex_out(vert_out)
shader_info.fragment_out(0, 'VEC4', "FragColor") shader_info.fragment_out(0, "VEC4", "FragColor")
shader_info.push_constant('VEC4', "color") shader_info.push_constant("VEC4", "color")
shader_info.vertex_source( shader_info.vertex_source(
"void main()" "void main()"
@@ -74,11 +77,7 @@ class AggregateDecorator:
) )
shader_info.fragment_source( shader_info.fragment_source(
"void main()" "void main()" "{" " if (step(sin(v_ArcLength * u_Scale), 0.4) == 1) discard;" " FragColor = color;" "}"
"{"
" if (step(sin(v_ArcLength * u_Scale), 0.4) == 1) discard;"
" FragColor = color;"
"}"
) )
shader = gpu.shader.create_from_info(shader_info) shader = gpu.shader.create_from_info(shader_info)
@@ -86,7 +85,6 @@ class AggregateDecorator:
del shader_info del shader_info
return shader return shader
def draw_custom_batch(self, coords, color): def draw_custom_batch(self, coords, color):
shader = self.dotted_line_shader() shader = self.dotted_line_shader()
@@ -95,7 +93,8 @@ class AggregateDecorator:
arc_lengths.append(arc_lengths[-1] + (a - b).length) arc_lengths.append(arc_lengths[-1] + (a - b).length)
batch = batch_for_shader( batch = batch_for_shader(
shader, 'LINE_STRIP', shader,
"LINE_STRIP",
{"position": coords, "arcLength": arc_lengths}, {"position": coords, "arcLength": arc_lengths},
) )
@@ -105,7 +104,6 @@ class AggregateDecorator:
shader.uniform_float("u_Scale", 25) shader.uniform_float("u_Scale", 25)
batch.draw(shader) batch.draw(shader)
def draw_batch(self, shader_type, content_pos, color, indices=None): def draw_batch(self, shader_type, content_pos, color, indices=None):
shader = self.line_shader if shader_type == "LINES" else self.shader shader = self.line_shader if shader_type == "LINES" else self.shader
batch = batch_for_shader(shader, shader_type, {"pos": content_pos}, indices=indices) batch = batch_for_shader(shader, shader_type, {"pos": content_pos}, indices=indices)
@@ -156,10 +154,91 @@ class AggregateDecorator:
self.draw_batch("LINES", line_y, color, [(0, 1)]) 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))) 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)]) self.draw_batch("LINES", line_z, color, [(0, 1)])
if context.scene.BIMAggregateProperties.in_edit_mode: if context.scene.BIMAggregateProperties.in_aggregate_mode:
return return
parts = ifcopenshell.util.element.get_parts(tool.Ifc.get_entity(aggregate)) parts = ifcopenshell.util.element.get_parts(tool.Ifc.get_entity(aggregate))
for part in parts: for part in parts:
part_obj = tool.Ifc.get_object(part) part_obj = tool.Ifc.get_object(part)
line = (part_obj.matrix_world.translation, location) line = (part_obj.matrix_world.translation, location)
self.draw_custom_batch(line, decorator_color_unselected) self.draw_custom_batch(line, decorator_color_unselected)
class AggregateModeDecorator:
is_installed = False
handlers = []
@classmethod
def install(cls, context):
if cls.is_installed:
cls.uninstall()
handler = cls()
cls.handlers.append(
SpaceView3D.draw_handler_add(handler.draw_aggregate_name, (context,), "WINDOW", "POST_PIXEL")
)
cls.handlers.append(
SpaceView3D.draw_handler_add(handler.draw_aggregate_empty, (context,), "WINDOW", "POST_VIEW")
)
cls.is_installed = True
@classmethod
def uninstall(cls):
for handler in cls.handlers:
try:
SpaceView3D.draw_handler_remove(handler, "WINDOW")
except ValueError:
pass
cls.is_installed = False
def draw_batch(self, shader_type, content_pos, color, indices=None):
shader = self.line_shader if shader_type == "LINES" else self.shader
batch = batch_for_shader(shader, shader_type, {"pos": content_pos}, indices=indices)
shader.uniform_float("color", color)
batch.draw(shader)
def draw_aggregate_name(self, context):
region = context.region
rv3d = region.data
props = context.scene.BIMAggregateProperties
aggregate_obj = props.editing_aggregate
self.addon_prefs = tool.Blender.get_addon_preferences()
self.font_id = 0
font_size = tool.Blender.scale_font_size(12)
blf.size(self.font_id, font_size)
blf.enable(self.font_id, blf.SHADOW)
blf.shadow(self.font_id, 6, 0, 0, 0, 1)
color = self.addon_prefs.decorator_color_special
if aggregate_obj in context.selected_objects:
color = self.addon_prefs.decorator_color_selected
blf.color(self.font_id, *color)
text = aggregate_obj.name
text_coords = view3d_utils.location_3d_to_region_2d(region, rv3d, aggregate_obj.location)
text_length = blf.dimensions(self.font_id, text)
text_coords[0] -= (text_length[0] / 2)
text_coords[1] -= 20
blf.position(self.font_id, text_coords[0], text_coords[1], 0)
self.shader = gpu.shader.from_builtin("UNIFORM_COLOR")
blf.draw(self.font_id, text)
def draw_aggregate_empty(self, context):
props = context.scene.BIMAggregateProperties
aggregate_obj = props.editing_aggregate
self.addon_prefs = tool.Blender.get_addon_preferences()
self.line_shader = gpu.shader.from_builtin("POLYLINE_UNIFORM_COLOR")
self.line_shader.bind()
self.line_shader.uniform_float("viewportSize", (context.region.width, context.region.height))
self.line_shader.uniform_float("lineWidth", 1.0)
color = self.addon_prefs.decorator_color_special
if aggregate_obj in context.selected_objects:
self.line_shader.uniform_float("lineWidth", 2.0)
color = self.addon_prefs.decorator_color_selected
size = aggregate_obj.empty_display_size
location = aggregate_obj.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)])
@@ -24,6 +24,7 @@ import bonsai.tool as tool
import bonsai.core.aggregate as core import bonsai.core.aggregate as core
import bonsai.core.spatial import bonsai.core.spatial
from bonsai.bim.ifc import IfcStore from bonsai.bim.ifc import IfcStore
from bonsai.bim.module.aggregate.decorator import AggregateModeDecorator
class BIM_OT_aggregate_assign_object(bpy.types.Operator, tool.Ifc.Operator): class BIM_OT_aggregate_assign_object(bpy.types.Operator, tool.Ifc.Operator):
@@ -388,10 +389,10 @@ class BIM_OT_toggle_mode_set_aggregate(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMAggregateProperties props = context.scene.BIMAggregateProperties
if props.in_aggregate_mode: if props.in_aggregate_mode:
#AggregateModeDecorator.uninstall() AggregateModeDecorator.uninstall()
BIM_OT_disable_mode_set_aggregate._execute(self, context) BIM_OT_disable_mode_set_aggregate._execute(self, context)
else: else:
#AggregateModeDecorator.install(context) AggregateModeDecorator.install(context)
BIM_OT_mode_set_aggregate._execute(self, context) BIM_OT_mode_set_aggregate._execute(self, context)