mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-13 10:57:49 +00:00
Plan view fixes (#7022)
This commit is contained in:
@@ -241,6 +241,7 @@ class DecoratorData:
|
||||
cls.is_loaded = True
|
||||
cls.cut_cache = {}
|
||||
cls.layerset_cache = {}
|
||||
cls.fill_cache = {}
|
||||
|
||||
text = {}
|
||||
dimension = {}
|
||||
|
||||
@@ -465,6 +465,12 @@ class DocProperties(PropertyGroup):
|
||||
return None
|
||||
return tool.Ifc.get().by_id(drawing_id)
|
||||
|
||||
def get_active_target_view(self) -> Union[str, None]:
|
||||
active_drawing = self.get_active_drawing()
|
||||
if not active_drawing:
|
||||
return None
|
||||
return tool.Drawing.get_drawing_target_view(active_drawing)
|
||||
|
||||
|
||||
def update_width_height(self: "BIMCameraProperties", context: bpy.types.Context) -> None:
|
||||
self.update_camera_resolution()
|
||||
|
||||
@@ -557,7 +557,36 @@ def get_generic_product_preview_data(context, relating_type):
|
||||
|
||||
mouse_point.z = snap_obj.matrix_world.translation.z
|
||||
|
||||
if snap_element and (container := ifcopenshell.util.element.get_container(snap_element)):
|
||||
container_obj = tool.Ifc.get_object(container)
|
||||
mouse_point.z = container_obj.location.z
|
||||
|
||||
obj_type = tool.Ifc.get_object(relating_type)
|
||||
|
||||
subcontexts = tool.Drawing.get_active_drawing_subcontexts()
|
||||
if not subcontexts:
|
||||
subcontexts = [("Model", "Body", "MODEL_VIEW")]
|
||||
|
||||
active_context = tool.Geometry.get_active_representation_context(obj_type)
|
||||
active_context_params = tool.Geometry.get_subcontext_parameters(active_context)
|
||||
for subcontext in subcontexts:
|
||||
if subcontext == active_context_params:
|
||||
break
|
||||
|
||||
representation = ifcopenshell.util.representation.get_representation(relating_type, *subcontext)
|
||||
if representation:
|
||||
bonsai.core.geometry.switch_representation(
|
||||
tool.Ifc,
|
||||
tool.Geometry,
|
||||
obj_type,
|
||||
representation,
|
||||
should_reload=True,
|
||||
is_global=False,
|
||||
should_sync_changes_first=False,
|
||||
)
|
||||
context.view_layer.update()
|
||||
break
|
||||
|
||||
if obj_type.data:
|
||||
data = ItemDecorator.get_obj_data(obj_type)
|
||||
data["verts"] = [tuple(obj_type.matrix_world.inverted() @ Vector(v)) for v in data["verts"]]
|
||||
|
||||
@@ -327,9 +327,21 @@ class AddOccurrence(bpy.types.Operator, tool.Ifc.Operator):
|
||||
if self.from_invoke and str(self.relating_type_id) in AuthoringData.data["relating_type_id"]:
|
||||
props.relating_type_id = str(self.relating_type_id)
|
||||
|
||||
building_obj = None
|
||||
if len(context.selected_objects) == 1 and context.active_object:
|
||||
building_obj = context.active_object
|
||||
building_element = tool.Ifc.get_entity(building_obj)
|
||||
|
||||
self.container = None
|
||||
self.container_obj = None
|
||||
if container := tool.Root.get_default_container():
|
||||
if (
|
||||
building_obj
|
||||
and building_element
|
||||
and (container := ifcopenshell.util.element.get_container(building_element))
|
||||
):
|
||||
self.container = container
|
||||
self.container_obj = tool.Ifc.get_object(container)
|
||||
elif container := tool.Root.get_default_container():
|
||||
self.container = container
|
||||
self.container_obj = tool.Ifc.get_object(container)
|
||||
|
||||
@@ -416,11 +428,6 @@ class AddOccurrence(bpy.types.Operator, tool.Ifc.Operator):
|
||||
)
|
||||
return
|
||||
|
||||
building_obj = None
|
||||
if len(context.selected_objects) == 1 and context.active_object:
|
||||
building_obj = context.active_object
|
||||
building_element = tool.Ifc.get_entity(building_obj)
|
||||
|
||||
mesh = bpy.data.meshes.new(name="Instance")
|
||||
obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(relating_type, instance_class), mesh)
|
||||
|
||||
@@ -487,12 +494,15 @@ class AddOccurrence(bpy.types.Operator, tool.Ifc.Operator):
|
||||
building_obj
|
||||
and building_element
|
||||
and building_element.is_a() in ["IfcWall", "IfcWallStandardCase", "IfcCovering", "IfcElementAssembly"]
|
||||
and instance_class in ["IfcWindow", "IfcDoor"]
|
||||
):
|
||||
if instance_class in ["IfcWindow", "IfcDoor"]:
|
||||
# TODO For now we are hardcoding windows and doors as a prototype
|
||||
tool.Model.add_filled_opening(building_obj, obj)
|
||||
# TODO For now we are hardcoding windows and doors as a prototype
|
||||
tool.Model.add_filled_opening(building_obj, obj)
|
||||
else:
|
||||
if self.container_obj:
|
||||
bonsai.core.spatial.assign_container(
|
||||
tool.Ifc, tool.Collector, tool.Spatial, container=self.container, element_obj=obj
|
||||
)
|
||||
if props.rl_mode == "BOTTOM":
|
||||
obj.location.z = self.container_obj.location.z - tool.Blender.get_object_bounding_box(obj)["min_z"]
|
||||
elif props.rl_mode == "CONTAINER":
|
||||
|
||||
@@ -2123,22 +2123,9 @@ class Drawing(bonsai.core.tool.Drawing):
|
||||
layer_collection2.hide_viewport = False
|
||||
|
||||
@classmethod
|
||||
def activate_drawing(cls, camera: bpy.types.Object) -> None:
|
||||
selected_objects_before = bpy.context.selected_objects
|
||||
non_ifc_objects_hide = {o: o.hide_get() for o in bpy.context.view_layer.objects if not tool.Ifc.get_entity(o)}
|
||||
|
||||
# Sync viewport objects visibility with selectors from EPset_Drawing/Include and /Exclude
|
||||
drawing = tool.Ifc.get_entity(camera)
|
||||
assert drawing and isinstance(camera.data, bpy.types.Camera)
|
||||
|
||||
filtered_elements = cls.get_drawing_elements(drawing) | cls.get_drawing_spaces(drawing)
|
||||
filtered_elements.add(drawing)
|
||||
|
||||
subcontexts: list[ifcopenshell.entity_instance] = []
|
||||
target_view = cls.get_drawing_target_view(drawing)
|
||||
|
||||
def get_drawing_context_filters(cls, target_view: str) -> list[tuple[str, str, str]]:
|
||||
if target_view in ("PLAN_VIEW", "REFLECTED_PLAN_VIEW"):
|
||||
context_filters = [
|
||||
return [
|
||||
("Plan", "Body", target_view),
|
||||
("Plan", "Body", "MODEL_VIEW"),
|
||||
("Plan", "Facetation", target_view),
|
||||
@@ -2153,7 +2140,7 @@ class Drawing(bonsai.core.tool.Drawing):
|
||||
("Model", "Annotation", "MODEL_VIEW"),
|
||||
]
|
||||
else:
|
||||
context_filters = [
|
||||
return [
|
||||
("Model", "Body", target_view),
|
||||
("Model", "Body", "MODEL_VIEW"),
|
||||
("Model", "Facetation", target_view),
|
||||
@@ -2162,11 +2149,42 @@ class Drawing(bonsai.core.tool.Drawing):
|
||||
("Model", "Annotation", "MODEL_VIEW"),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def get_drawing_subcontexts(cls, target_view: str) -> list[tuple[str, str, str]]:
|
||||
context_filters = cls.get_drawing_context_filters(target_view)
|
||||
subcontexts = []
|
||||
|
||||
for context_filter in context_filters:
|
||||
subcontext = ifcopenshell.util.representation.get_context(tool.Ifc.get(), *context_filter)
|
||||
if subcontext:
|
||||
subcontexts.append(context_filter)
|
||||
|
||||
return subcontexts
|
||||
|
||||
@classmethod
|
||||
def get_active_drawing_subcontexts(cls) -> list[tuple[str, str, str]] | None:
|
||||
props = cls.get_document_props()
|
||||
target_view = props.get_active_target_view()
|
||||
if not target_view:
|
||||
return None
|
||||
|
||||
return cls.get_drawing_subcontexts(target_view)
|
||||
|
||||
@classmethod
|
||||
def activate_drawing(cls, camera: bpy.types.Object) -> None:
|
||||
selected_objects_before = bpy.context.selected_objects
|
||||
non_ifc_objects_hide = {o: o.hide_get() for o in bpy.context.view_layer.objects if not tool.Ifc.get_entity(o)}
|
||||
|
||||
# Sync viewport objects visibility with selectors from EPset_Drawing/Include and /Exclude
|
||||
drawing = tool.Ifc.get_entity(camera)
|
||||
assert drawing and isinstance(camera.data, bpy.types.Camera)
|
||||
|
||||
filtered_elements = cls.get_drawing_elements(drawing) | cls.get_drawing_spaces(drawing)
|
||||
filtered_elements.add(drawing)
|
||||
|
||||
target_view = cls.get_drawing_target_view(drawing)
|
||||
subcontexts = cls.get_drawing_subcontexts(target_view)
|
||||
|
||||
# Hide everything first, then selectively show. This is significantly faster.
|
||||
with bpy.context.temp_override(**tool.Blender.get_viewport_context()):
|
||||
bpy.ops.object.hide_view_set(unselected=False)
|
||||
|
||||
@@ -18,10 +18,13 @@
|
||||
|
||||
from __future__ import annotations
|
||||
import bpy
|
||||
import bmesh
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.unit
|
||||
import bonsai.core.tool
|
||||
import bonsai.tool as tool
|
||||
from bonsai.bim.module.drawing.data import DecoratorData
|
||||
from bonsai.bim.module.drawing.decoration import CutDecorator
|
||||
from bonsai.bim.module.model.decorator import PolylineDecorator
|
||||
import math
|
||||
import mathutils
|
||||
@@ -428,6 +431,53 @@ class Snap(bonsai.core.tool.Snap):
|
||||
point["group"] = "Object"
|
||||
detected_snaps.append(point)
|
||||
|
||||
# snap to cut geometry (e.g. in plan view)
|
||||
if CutDecorator.installed:
|
||||
cut_snaps = []
|
||||
|
||||
model_props = tool.Model.get_model_props()
|
||||
|
||||
for obj in [o for o in context.visible_objects if o.type == "MESH"]:
|
||||
if not (element := tool.Ifc.get_entity(obj)):
|
||||
continue
|
||||
|
||||
if model_props.show_cut_decorator and element.id() in DecoratorData.cut_cache:
|
||||
verts, edges = DecoratorData.cut_cache[element.id()]
|
||||
if not verts or not edges:
|
||||
continue
|
||||
|
||||
bm = bmesh.new()
|
||||
bverts = [bm.verts.new(pos) for pos in verts]
|
||||
for edge in edges:
|
||||
bm.edges.new([bverts[vi] for vi in edge])
|
||||
|
||||
snap_points = tool.Raycast.ray_cast_by_proximity(context, event, None, None, bm)
|
||||
if snap_points:
|
||||
for p in snap_points:
|
||||
p["group"] = "Object"
|
||||
p["object"] = obj
|
||||
cut_snaps.append(p)
|
||||
|
||||
if model_props.show_cut_decorator_fill and element.id() in DecoratorData.fill_cache:
|
||||
bm = bmesh.new()
|
||||
for color, verts_and_tris in DecoratorData.fill_cache[element.id()].items():
|
||||
for verts, tris in verts_and_tris:
|
||||
bverts = [bm.verts.new(pos) for pos in verts]
|
||||
for tri in tris:
|
||||
verts = [bverts[vi] for vi in tri]
|
||||
if not bm.faces.get(verts):
|
||||
bm.faces.new(verts)
|
||||
|
||||
snap_points = tool.Raycast.ray_cast_by_proximity(context, event, None, None, bm)
|
||||
if snap_points:
|
||||
for p in snap_points:
|
||||
p["group"] = "Object"
|
||||
p["object"] = obj
|
||||
cut_snaps.append(p)
|
||||
|
||||
if len(cut_snaps) > 0:
|
||||
detected_snaps = cut_snaps
|
||||
|
||||
# Axis and Plane
|
||||
if tool.Ifc.get():
|
||||
elevation = tool.Root.get_default_container_elevation()
|
||||
|
||||
Reference in New Issue
Block a user