Openings are now specially shaded, and you can now add half space clipping booleans

# Conflicts:
#	src/blenderbim/blenderbim/bim/module/model/ui.py
This commit is contained in:
Dion Moult
2022-10-01 14:33:33 +10:00
parent e2a5b09d77
commit 527d26c1c6
4 changed files with 255 additions and 14 deletions
@@ -35,7 +35,10 @@ classes = (
wall.MergeWall, wall.MergeWall,
wall.RecalculateWall, wall.RecalculateWall,
wall.SplitWall, wall.SplitWall,
opening.AddBoolean,
opening.AddElementOpening, opening.AddElementOpening,
opening.AddPotentialHalfSpaceSolid,
opening.AddPotentialOpening,
profile.ChangeCardinalPoint, profile.ChangeCardinalPoint,
profile.ChangeProfileDepth, profile.ChangeProfileDepth,
profile.ExtendProfile, profile.ExtendProfile,
@@ -55,9 +58,9 @@ classes = (
ui.BIM_PT_authoring, ui.BIM_PT_authoring,
ui.DisplayConstrTypesUI, ui.DisplayConstrTypesUI,
ui.HelpConstrTypes, ui.HelpConstrTypes,
ui.BIM_MT_model,
grid.BIM_OT_add_object, grid.BIM_OT_add_object,
stair.BIM_OT_add_object, stair.BIM_OT_add_object,
opening.BIM_OT_add_object,
pie.OpenPieClass, pie.OpenPieClass,
pie.PieUpdateContainer, pie.PieUpdateContainer,
pie.PieAddOpening, pie.PieAddOpening,
@@ -74,8 +77,7 @@ def register():
bpy.types.Scene.BIMModelProperties = bpy.props.PointerProperty(type=prop.BIMModelProperties) bpy.types.Scene.BIMModelProperties = bpy.props.PointerProperty(type=prop.BIMModelProperties)
bpy.types.VIEW3D_MT_mesh_add.append(grid.add_object_button) bpy.types.VIEW3D_MT_mesh_add.append(grid.add_object_button)
bpy.types.VIEW3D_MT_mesh_add.append(stair.add_object_button) bpy.types.VIEW3D_MT_mesh_add.append(stair.add_object_button)
bpy.types.VIEW3D_MT_mesh_add.append(opening.add_object_button) bpy.types.VIEW3D_MT_add.append(ui.add_menu)
bpy.types.VIEW3D_MT_add.append(product.add_empty_type_button)
bpy.app.handlers.load_post.append(handler.load_post) bpy.app.handlers.load_post.append(handler.load_post)
wm = bpy.context.window_manager wm = bpy.context.window_manager
if wm.keyconfigs.addon: if wm.keyconfigs.addon:
@@ -92,8 +94,7 @@ def unregister():
bpy.app.handlers.load_post.remove(handler.load_post) bpy.app.handlers.load_post.remove(handler.load_post)
bpy.types.VIEW3D_MT_mesh_add.remove(grid.add_object_button) bpy.types.VIEW3D_MT_mesh_add.remove(grid.add_object_button)
bpy.types.VIEW3D_MT_mesh_add.remove(stair.add_object_button) bpy.types.VIEW3D_MT_mesh_add.remove(stair.add_object_button)
bpy.types.VIEW3D_MT_mesh_add.remove(opening.add_object_button) bpy.types.VIEW3D_MT_add.remove(ui.add_menu)
bpy.types.VIEW3D_MT_add.remove(product.add_empty_type_button)
wm = bpy.context.window_manager wm = bpy.context.window_manager
kc = wm.keyconfigs.addon kc = wm.keyconfigs.addon
if kc: if kc:
@@ -17,6 +17,8 @@
# 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 gpu
import bgl
import bmesh import bmesh
import blenderbim.bim.handler import blenderbim.bim.handler
import ifcopenshell import ifcopenshell
@@ -27,8 +29,11 @@ from blenderbim.bim.ifc import IfcStore
from math import pi from math import pi
from mathutils import Vector from mathutils import Vector
from bpy.types import Operator from bpy.types import Operator
from bpy.types import SpaceView3D
from bpy.props import FloatProperty from bpy.props import FloatProperty
from bpy_extras.object_utils import AddObjectHelper, object_data_add from bpy_extras.object_utils import AddObjectHelper, object_data_add
from gpu.types import GPUShader, GPUBatch, GPUIndexBuf, GPUVertBuf, GPUVertFormat
from gpu_extras.batch import batch_for_shader
def element_listener(element, obj): def element_listener(element, obj):
@@ -202,6 +207,7 @@ class AddElementOpening(bpy.types.Operator):
def add_object(self, context): def add_object(self, context):
props = context.scene.BIMModelProperties
bm = bmesh.new() bm = bmesh.new()
bmesh.ops.create_cube(bm, size=self.size) bmesh.ops.create_cube(bm, size=self.size)
bm.verts.ensure_lookup_table() bm.verts.ensure_lookup_table()
@@ -212,20 +218,237 @@ def add_object(self, context):
bm.free() bm.free()
obj = object_data_add(context, mesh, operator=self) obj = object_data_add(context, mesh, operator=self)
obj.name = "Opening" obj.name = "Opening"
obj.display_type = "WIRE"
has_deleted_opening = True
while has_deleted_opening:
has_deleted_opening = False
for i, opening in enumerate(props.openings):
if not opening.obj:
props.openings.remove(i)
has_deleted_opening = True
new = props.openings.add()
new.obj = obj
DecorationsHandler.install(context)
class BIM_OT_add_object(Operator, AddObjectHelper): class AddPotentialOpening(Operator, AddObjectHelper):
bl_idname = "mesh.add_opening" bl_idname = "bim.add_potential_opening"
bl_label = "Dumb Opening" bl_label = "Add Potential Opening"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
size: FloatProperty(name="Size", default=0.5)
size: FloatProperty(name="Size", default=2)
def execute(self, context): def execute(self, context):
add_object(self, context) add_object(self, context)
return {"FINISHED"} return {"FINISHED"}
def add_object_button(self, context): class AddPotentialHalfSpaceSolid(Operator, AddObjectHelper):
self.layout.operator(BIM_OT_add_object.bl_idname, icon="PLUGIN") bl_idname = "bim.add_potential_half_space_solid"
bl_label = "Add Potential Half Space Solid"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
props = context.scene.BIMModelProperties
bm = bmesh.new()
bmesh.ops.create_grid(bm, size=0.5)
bm.verts.ensure_lookup_table()
bm.edges.ensure_lookup_table()
bm.faces.ensure_lookup_table()
mesh = bpy.data.meshes.new(name="Dumb Opening")
bm.to_mesh(mesh)
bm.free()
obj = object_data_add(context, mesh, operator=self)
obj.name = "HalfSpaceSolid"
has_deleted_opening = True
while has_deleted_opening:
has_deleted_opening = False
for i, opening in enumerate(props.openings):
if not opening.obj:
props.openings.remove(i)
has_deleted_opening = True
new = props.openings.add()
new.obj = obj
DecorationsHandler.install(context)
return {"FINISHED"}
class AddBoolean(Operator, tool.Ifc.Operator):
bl_idname = "bim.add_boolean"
bl_label = "Add Boolean"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
props = context.scene.BIMModelProperties
objs = context.selected_objects
if len(objs) != 2:
return {"FINISHED"}
obj1, obj2 = objs
element1 = tool.Ifc.get_entity(obj1)
element2 = tool.Ifc.get_entity(obj2)
if element1 and element2:
return {"FINISHED"}
if not element1 and not element2:
return {"FINISHED"}
if element2 and not element1:
obj1, obj2 = obj2, obj1
if not obj1.data or not hasattr(obj1.data, "BIMMeshProperties"):
return {"FINISHED"}
representation = tool.Ifc.get().by_id(obj1.data.BIMMeshProperties.ifc_definition_id)
ifcopenshell.api.run(
"geometry.add_boolean",
tool.Ifc.get(),
representation=representation,
operator="DIFFERENCE",
matrix=obj1.matrix_world.inverted() @ obj2.matrix_world,
)
has_deleted_opening = True
while has_deleted_opening:
has_deleted_opening = False
for i, opening in enumerate(props.openings):
if not opening.obj:
props.openings.remove(i)
has_deleted_opening = True
blenderbim.core.geometry.switch_representation(
tool.Geometry,
obj=obj1,
representation=representation,
should_reload=True,
enable_dynamic_voids=False,
is_global=True,
should_sync_changes_first=False,
)
return {"FINISHED"}
class DecorationsHandler:
installed = None
@classmethod
def install(cls, context):
if cls.installed:
cls.uninstall()
handler = cls()
cls.installed = SpaceView3D.draw_handler_add(handler, (context,), "WINDOW", "POST_VIEW")
@classmethod
def uninstall(cls):
try:
SpaceView3D.draw_handler_remove(cls.installed, "WINDOW")
except ValueError:
pass
cls.installed = None
def __call__(self, context):
bgl.glLineWidth(2)
bgl.glPointSize(6)
bgl.glEnable(bgl.GL_BLEND)
bgl.glEnable(bgl.GL_LINE_SMOOTH)
for opening in context.scene.BIMModelProperties.openings:
obj = opening.obj
if not obj:
continue
white = (1, 1, 1, 1)
white_t = (1, 1, 1, 0.1)
green = (0.545, 0.863, 0, 1)
red = (1, 0.2, 0.322, 1)
red_t = (1, 0.2, 0.322, 0.1)
blue = (0.157, 0.565, 1, 1)
blue_t = (0.157, 0.565, 1, 0.1)
grey = (0.2, 0.2, 0.2, 1)
self.shader = gpu.shader.from_builtin("3D_UNIFORM_COLOR")
verts = []
selected_edges = []
unselected_edges = []
selected_vertices = []
unselected_vertices = []
if obj.mode == "EDIT":
bm = bmesh.from_edit_mesh(obj.data)
for vertex in bm.verts:
co = tuple(obj.matrix_world @ vertex.co)
verts.append(co)
if vertex.hide:
continue
if vertex.select:
selected_vertices.append(co)
else:
unselected_vertices.append(co)
for edge in bm.edges:
edge_indices = [v.index for v in edge.verts]
if edge.hide:
continue
if edge.select:
selected_edges.append(edge_indices)
else:
unselected_edges.append(edge_indices)
batch = batch_for_shader(self.shader, "LINES", {"pos": all_vertices}, indices=unselected_edges)
self.shader.bind()
self.shader.uniform_float("color", white)
batch.draw(self.shader)
batch = batch_for_shader(self.shader, "LINES", {"pos": all_vertices}, indices=selected_edges)
self.shader.uniform_float("color", green)
batch.draw(self.shader)
batch = batch_for_shader(self.shader, "POINTS", {"pos": unselected_vertices})
self.shader.uniform_float("color", white)
batch.draw(self.shader)
batch = batch_for_shader(self.shader, "POINTS", {"pos": selected_vertices})
self.shader.uniform_float("color", green)
batch.draw(self.shader)
else:
bm = bmesh.new()
bm.from_mesh(obj.data)
verts = [tuple(obj.matrix_world @ v.co) for v in bm.verts]
edges = [tuple([v.index for v in e.verts]) for e in bm.edges]
batch = batch_for_shader(self.shader, "LINES", {"pos": verts}, indices=edges)
self.shader.bind()
self.shader.uniform_float("color", green if obj in context.selected_objects else blue)
batch.draw(self.shader)
obj.data.calc_loop_triangles()
tris = [tuple(t.vertices) for t in obj.data.loop_triangles]
batch = batch_for_shader(self.shader, "TRIS", {"pos": verts}, indices=tris)
self.shader.bind()
self.shader.uniform_float("color", blue_t)
batch.draw(self.shader)
if "HalfSpaceSolid" in obj.name:
# Arrow shape
verts = [
tuple(obj.matrix_world @ Vector((0, 0, 0))),
tuple(obj.matrix_world @ Vector((0, 0, 0.5))),
tuple(obj.matrix_world @ Vector((0.05, 0, 0.45))),
tuple(obj.matrix_world @ Vector((-0.05, 0, 0.45))),
tuple(obj.matrix_world @ Vector((0, 0.05, 0.45))),
tuple(obj.matrix_world @ Vector((0, -0.05, 0.45))),
]
edges = [(0, 1), (1, 2), (1, 3), (1, 4), (1, 5)]
batch = batch_for_shader(self.shader, "LINES", {"pos": verts}, indices=edges)
self.shader.bind()
self.shader.uniform_float("color", green if obj in context.selected_objects else blue)
batch.draw(self.shader)
if obj.mode != "EDIT":
bm.free()
@@ -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
from blenderbim.bim.prop import ObjProperty
from blenderbim.bim.module.model.data import AuthoringData from blenderbim.bim.module.model.data import AuthoringData
from blenderbim.bim.module.model.root import ConstrTypeEntityNotFound from blenderbim.bim.module.model.root import ConstrTypeEntityNotFound
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
@@ -178,3 +179,4 @@ class BIMModelProperties(PropertyGroup):
default="5", default="5",
) )
length: bpy.props.FloatProperty(default=42.0) length: bpy.props.FloatProperty(default=42.0)
openings: bpy.props.CollectionProperty(type=ObjProperty)
@@ -17,7 +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
from bpy.types import Panel, Operator from bpy.types import Panel, Operator, Menu
from blenderbim.bim.module.model.data import AuthoringData from blenderbim.bim.module.model.data import AuthoringData
from blenderbim.bim.helper import prop_with_search, close_operator_panel from blenderbim.bim.helper import prop_with_search, close_operator_panel
@@ -153,3 +153,18 @@ class HelpConstrTypes(Operator):
"The Construction Type Browser allows to preview and add new instances to the model.", "The Construction Type Browser allows to preview and add new instances to the model.",
"For further support, please click on the Documentation link below.", "For further support, please click on the Documentation link below.",
] ]
class BIM_MT_model(Menu):
bl_idname = "BIM_MT_model"
bl_label = "IFC Objects"
def draw(self, context):
layout = self.layout
layout.operator("bim.add_empty_type", text="Empty Type", icon="EMPTY_AXIS")
layout.operator("bim.add_potential_half_space_solid", text="Half Space Proxy", icon="ORIENTATION_NORMAL")
layout.operator("bim.add_potential_opening", text="Opening Proxy", icon="CUBE")
def add_menu(self, context):
self.layout.menu("BIM_MT_model", icon="FILE_3D")