This commit is contained in:
Andrej730
2025-04-29 15:05:25 +05:00
parent 1856eeddeb
commit ecf461e1e0
7 changed files with 47 additions and 31 deletions
+15 -5
View File
@@ -198,11 +198,16 @@ class MaterialCreator:
class IfcImporter:
file: ifcopenshell.file
"""Either provided by user as an attribute or will be loaded from ``input_file`` during ``execute()``."""
elements: set[ifcopenshell.entity_instance]
"""Set of IfcElements to import. Excluding ``gross_elements`` and ```native_elements``."""
def __init__(self, ifc_import_settings: IfcImportSettings):
self.ifc_import_settings = ifc_import_settings
tool.Loader.set_settings(ifc_import_settings)
self.diff = None
self.file: ifcopenshell.file = None
self.project = None
self.has_existing_project = False
# element guids to blender collections mapping
@@ -300,6 +305,7 @@ class IfcImporter:
bpy.context.window_manager.progress_end()
def process_context_filter(self) -> None:
"""Setup contexts. Necessary for importing elements representations."""
contexts = self.file.by_type("IfcGeometricRepresentationContext")
if len(contexts) > 100: # Probably something strange happening. Encountered from Revizto.
print("Warning! Excessive contexts were found and merged where applicable.")
@@ -384,6 +390,7 @@ class IfcImporter:
return results
def parse_native_elements(self) -> None:
# TODO: move to `process_element_filter` to incapsulate all `self.elements` logic.
if not self.ifc_import_settings.should_load_geometry:
return
if not self.file.by_type("IfcSweptDiskSolid"):
@@ -1129,7 +1136,7 @@ class IfcImporter:
bpy.ops.view3d.view_selected()
bpy.ops.object.select_all(action="DESELECT")
def setup_arrays(self):
def setup_arrays(self, elements: Optional[set[ifcopenshell.entity_instance]] = None):
for pset in self.file.by_type("IfcPropertySet"):
if pset.Name != "BBIM_Array":
continue
@@ -1144,9 +1151,10 @@ class IfcImporter:
class IfcImportSettings:
input_file: Union[str, None] = None
logger: Union[logging.Logger, None] = None
def __init__(self):
self.logger: logging.Logger = None
self.input_file = None
self.diff_file = None
self.geometry_library = "opencascade"
self.should_use_cpu_multiprocessing = True
@@ -1177,7 +1185,9 @@ class IfcImportSettings:
self.load_indexed_maps = False
@staticmethod
def factory(context=None, input_file=None, logger=None):
def factory(
context=None, input_file: Optional[str] = None, logger: Optional[logging.Logger] = None
) -> IfcImportSettings:
scene_diff = tool.Blender.get_diff_props()
props = tool.Project.get_project_props()
settings = IfcImportSettings()
@@ -58,6 +58,7 @@ from bpy_extras.image_utils import load_image
if TYPE_CHECKING:
from bonsai.bim.module.project.prop import Link
from bpy._typing import rna_enums
cwd = os.path.dirname(os.path.realpath(__file__))
@@ -223,6 +224,7 @@ class CreateDrawing(bpy.types.Operator):
)
drawing_name: str
is_manifold_cache: dict[str, bool]
@classmethod
def poll(cls, context):
@@ -1225,7 +1227,7 @@ class CreateDrawing(bpy.types.Operator):
)
return classes
def is_manifold(self, obj):
def is_manifold(self, obj) -> bool:
result = self.is_manifold_cache.get(obj.data.name, None)
if result is not None:
return result
@@ -2127,14 +2129,14 @@ class ActivateModel(bpy.types.Operator):
class ActivateDrawingBase:
def invoke(self, context, event):
def invoke(self, context, event) -> set["rna_enums.OperatorReturnItems"]:
if event.type == "LEFTMOUSE" and event.alt:
self.should_view_from_camera = False
if event.type == "LEFTMOUSE" and event.shift:
self.use_quick_preview = True
return self.execute(context)
def execute(self, context):
def execute(self, context) -> set["rna_enums.OperatorReturnItems"]:
props = tool.Drawing.get_document_props()
if props.is_editing_drawings == False:
bpy.ops.bim.load_drawings()
+8 -7
View File
@@ -20,6 +20,7 @@ import bpy
import json
import ifcopenshell
import ifcopenshell.api
import ifcopenshell.api.pset
import ifcopenshell.util.element
import ifcopenshell.util.unit
import bonsai.tool as tool
@@ -33,8 +34,9 @@ class AddArray(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
obj = context.active_object
element = tool.Ifc.get_entity(obj)
assert (obj := context.active_object)
assert (element := tool.Ifc.get_entity(obj))
ifc_file = tool.Ifc.get()
array = {
"children": [],
@@ -54,14 +56,13 @@ class AddArray(bpy.types.Operator, tool.Ifc.Operator):
data.append(array)
pset = tool.Ifc.get().by_id(pset["id"])
else:
pset = ifcopenshell.api.run("pset.add_pset", tool.Ifc.get(), product=element, name="BBIM_Array")
pset = ifcopenshell.api.pset.add_pset(ifc_file, product=element, name="BBIM_Array")
data = [array]
ifcopenshell.api.run(
"pset.edit_pset",
tool.Ifc.get(),
ifcopenshell.api.pset.edit_pset(
ifc_file,
pset=pset,
properties={"Parent": element.GlobalId, "Data": tool.Ifc.get().createIfcText(json.dumps(data))},
properties={"Parent": element.GlobalId, "Data": ifc_file.create_entity("IfcText", json.dumps(data))},
)
return {"FINISHED"}
+14 -7
View File
@@ -18,14 +18,17 @@
import bpy
import ifcopenshell.api
import ifcopenshell.api.grid
import bonsai.tool as tool
import bonsai.core.root
from bpy.types import Operator
from bpy.props import FloatProperty, IntProperty
from mathutils import Vector
from typing import TYPE_CHECKING
def add_object(self, context):
def add_object(self: "BIM_OT_add_object", context: bpy.types.Context) -> None:
ifc_file = tool.Ifc.get()
obj = bpy.data.objects.new("Grid", None)
obj.name = "Grid"
@@ -33,6 +36,7 @@ def add_object(self, context):
tool.Ifc, tool.Collector, tool.Root, obj=obj, ifc_class="IfcGrid", should_add_representation=False
)
grid = tool.Ifc.get_entity(obj)
assert grid
for i in range(0, self.total_u):
verts = [
@@ -46,9 +50,7 @@ def add_object(self, context):
tag = chr(ord("A") + i)
obj = bpy.data.objects.new(f"IfcGridAxis/{tag}", mesh)
result = ifcopenshell.api.run(
"grid.create_grid_axis", tool.Ifc.get(), axis_tag=tag, uvw_axes="UAxes", grid=grid
)
result = ifcopenshell.api.grid.create_grid_axis(ifc_file, axis_tag=tag, uvw_axes="UAxes", grid=grid)
tool.Ifc.link(result, obj)
tool.Model.create_axis_curve(obj, result)
tool.Collector.assign(obj)
@@ -65,9 +67,7 @@ def add_object(self, context):
tag = str(i + 1).zfill(2)
obj = bpy.data.objects.new(f"IfcGridAxis/{tag}", mesh)
result = ifcopenshell.api.run(
"grid.create_grid_axis", tool.Ifc.get(), axis_tag=tag, uvw_axes="VAxes", grid=grid
)
result = ifcopenshell.api.grid.create_grid_axis(ifc_file, axis_tag=tag, uvw_axes="VAxes", grid=grid)
tool.Ifc.link(result, obj)
tool.Model.create_axis_curve(obj, result)
tool.Collector.assign(obj)
@@ -78,6 +78,7 @@ def add_object(self, context):
class BIM_OT_add_object(Operator, tool.Ifc.Operator):
bl_idname = "mesh.add_grid"
bl_label = "Grid"
bl_description = "Add IfcGrid."
bl_options = {"REGISTER", "UNDO"}
u_spacing: FloatProperty(name="U Spacing", default=10)
@@ -85,6 +86,12 @@ class BIM_OT_add_object(Operator, tool.Ifc.Operator):
v_spacing: FloatProperty(name="V Spacing", default=10)
total_v: IntProperty(name="Number of V Grids", default=3)
if TYPE_CHECKING:
u_spacing: float
total_u: int
v_spacing: float
total_v: int
@classmethod
def poll(cls, context):
return tool.Ifc.get() and context.mode == "OBJECT"
+1
View File
@@ -2123,6 +2123,7 @@ class Model(bonsai.core.tool.Model):
@classmethod
def create_axis_curve(cls, obj: bpy.types.Object, grid_axis: ifcopenshell.entity_instance) -> None:
m = tool.Surveyor.get_absolute_matrix(obj)
assert isinstance(obj.data, bpy.types.Mesh)
points = [m @ np.array(v.co.to_4d()) for v in obj.data.vertices[0:2]]
ifcopenshell.api.grid.create_axis_curve(
tool.Ifc.get(), p1=points[0], p2=points[1], is_si=True, grid_axis=grid_axis
@@ -69,10 +69,10 @@ def create_axis_curve(
grid = [i for i in file.get_inverse(grid_axis) if i.is_a("IfcGrid")][0]
grid_matrix_i = np.linalg.inv(ifcopenshell.util.placement.get_local_placement(grid.ObjectPlacement))
grid_axis.AxisCurve = file.createIfcPolyline(
(
file.createIfcCartesianPoint(ifc_safe_vector_type(grid_matrix_i @ p1)),
file.createIfcCartesianPoint(ifc_safe_vector_type(grid_matrix_i @ p2)),
grid_axis.AxisCurve = file.create_entity(
"IfcPolyline"(
file.create_entity("IfcCartesianPoint", ifc_safe_vector_type(grid_matrix_i @ p1)),
file.create_entity("IfcCartesianPoint", ifc_safe_vector_type(grid_matrix_i @ p2)),
)
)
@@ -50,20 +50,15 @@ def create_grid_axis(
:param axis_tag: The name of the axis, that would typically be labeled
on drawings or described on site during coordination, such as A, B,
C, 1, 2, 3, etc. Defaults to "A".
:type axis_tag: str, optional
:param same_sense: Determines whether the direction of the axis's line
is reversed. True means the direction the geometry is defined in
represents the direction of the axis. False means the direction is
reversed. Leave as True if unsure. Defaults to "True".
:type same_sense: bool, optional
:param uvw_axes: Choose from "UAxes", "VAxes" or "WAxes" depending on
which set of axes the new axis you are adding should belong to.
Defaults to "UAxes".
:type uvw_axes: str, optional
:param grid: The IfcGrid you are adding the axis to.
:type grid: ifcopenshell.entity_instance
:return: The newly created IfcGridAxis
:rtype: ifcopenshell.entity_instance
Example: