mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-26 18:21:59 +00:00
Merge branch 'IfcOpenShell:v0.7.0' into v0.7.0
This commit is contained in:
+4
-1
@@ -94,4 +94,7 @@ src/ifcopenshell-python/ifcopenshell/_ifcopenshell_wrapper.so
|
|||||||
src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.py
|
src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.py
|
||||||
|
|
||||||
# apple
|
# apple
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
# Brickschema
|
||||||
|
src/blenderbim/blenderbim/bim/schema/Brick.ttl
|
||||||
@@ -275,6 +275,7 @@ class TopicHandler:
|
|||||||
"""
|
"""
|
||||||
new_viewpoint = VisualizationInfoHandler.create_new(element, self._xml_handler)
|
new_viewpoint = VisualizationInfoHandler.create_new(element, self._xml_handler)
|
||||||
self.add_visinfo_handler(new_viewpoint)
|
self.add_visinfo_handler(new_viewpoint)
|
||||||
|
return new_viewpoint
|
||||||
|
|
||||||
def add_viewpoint_from_point_and_guids(self, position: NDArray[np.float_], *guids: str) -> None:
|
def add_viewpoint_from_point_and_guids(self, position: NDArray[np.float_], *guids: str) -> None:
|
||||||
"""Add a viewpoint pointing at an XYZ point in space
|
"""Add a viewpoint pointing at an XYZ point in space
|
||||||
@@ -287,6 +288,7 @@ class TopicHandler:
|
|||||||
position, *guids, xml_handler=self._xml_handler
|
position, *guids, xml_handler=self._xml_handler
|
||||||
)
|
)
|
||||||
self.add_visinfo_handler(vi_handler)
|
self.add_visinfo_handler(vi_handler)
|
||||||
|
return vi_handler
|
||||||
|
|
||||||
def add_visinfo_handler(self, new_viewpoint: VisualizationInfoHandler) -> None:
|
def add_visinfo_handler(self, new_viewpoint: VisualizationInfoHandler) -> None:
|
||||||
self.viewpoints[new_viewpoint.guid + ".bcfv"] = new_viewpoint
|
self.viewpoints[new_viewpoint.guid + ".bcfv"] = new_viewpoint
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ classes = (
|
|||||||
operator.SelectBcfBimSnippetReference,
|
operator.SelectBcfBimSnippetReference,
|
||||||
operator.SelectBcfDocumentReference,
|
operator.SelectBcfDocumentReference,
|
||||||
operator.SelectBcfHeaderFile,
|
operator.SelectBcfHeaderFile,
|
||||||
|
operator.UnloadBcfProject,
|
||||||
operator.ViewBcfTopic,
|
operator.ViewBcfTopic,
|
||||||
prop.BcfReferenceLink,
|
prop.BcfReferenceLink,
|
||||||
prop.BcfLabel,
|
prop.BcfLabel,
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ class LoadBcfProject(bpy.types.Operator):
|
|||||||
filter_glob: bpy.props.StringProperty(default="*.bcf;*.bcfzip", options={"HIDDEN"})
|
filter_glob: bpy.props.StringProperty(default="*.bcf;*.bcfzip", options={"HIDDEN"})
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
context.scene.BCFProperties.is_loaded = False
|
|
||||||
if self.filepath:
|
if self.filepath:
|
||||||
bcfstore.BcfStore.bcfxml = bcf.bcfxml.load(self.filepath)
|
bcfstore.BcfStore.bcfxml = bcf.bcfxml.load(self.filepath)
|
||||||
bcfxml = bcfstore.BcfStore.get_bcfxml()
|
bcfxml = bcfstore.BcfStore.get_bcfxml()
|
||||||
@@ -72,6 +71,17 @@ class LoadBcfProject(bpy.types.Operator):
|
|||||||
return {"RUNNING_MODAL"}
|
return {"RUNNING_MODAL"}
|
||||||
|
|
||||||
|
|
||||||
|
class UnloadBcfProject(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.unload_bcf_project"
|
||||||
|
bl_label = "Unload BCF Project"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
bcfstore.BcfStore.set(None)
|
||||||
|
context.scene.BCFProperties.is_loaded = False
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class LoadBcfTopics(bpy.types.Operator):
|
class LoadBcfTopics(bpy.types.Operator):
|
||||||
bl_idname = "bim.load_bcf_topics"
|
bl_idname = "bim.load_bcf_topics"
|
||||||
bl_label = "Load BCF Topics"
|
bl_label = "Load BCF Topics"
|
||||||
|
|||||||
@@ -39,14 +39,16 @@ class BIM_PT_bcf(Panel):
|
|||||||
scene = context.scene
|
scene = context.scene
|
||||||
props = scene.BCFProperties
|
props = scene.BCFProperties
|
||||||
|
|
||||||
row = layout.row(align=True)
|
|
||||||
row.operator("bim.new_bcf_project", text="New Project")
|
|
||||||
row.operator("bim.load_bcf_project", text="Load Project")
|
|
||||||
|
|
||||||
if not props.is_loaded:
|
if not props.is_loaded:
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.operator("bim.new_bcf_project", text="New Project")
|
||||||
|
row.operator("bim.load_bcf_project", text="Load Project")
|
||||||
return
|
return
|
||||||
|
|
||||||
row.operator("bim.save_bcf_project", text="Save Project")
|
row = layout.row(align=True)
|
||||||
|
row.operator("bim.save_bcf_project", icon="EXPORT", text="Save Project")
|
||||||
|
row.operator("bim.unload_bcf_project", text="", icon="CANCEL")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(props, "name")
|
row.prop(props, "name")
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ classes = (
|
|||||||
operator.RewindBrickClass,
|
operator.RewindBrickClass,
|
||||||
operator.ViewBrickClass,
|
operator.ViewBrickClass,
|
||||||
operator.ViewBrickItem,
|
operator.ViewBrickItem,
|
||||||
|
operator.UndoBrick,
|
||||||
|
operator.RedoBrick,
|
||||||
|
operator.SerializeBrick,
|
||||||
prop.Brick,
|
prop.Brick,
|
||||||
prop.BIMBrickProperties,
|
prop.BIMBrickProperties,
|
||||||
ui.BIM_PT_brickschema,
|
ui.BIM_PT_brickschema,
|
||||||
|
|||||||
@@ -110,7 +110,8 @@ class BrickschemaData:
|
|||||||
return []
|
return []
|
||||||
results = []
|
results = []
|
||||||
for alias, uri in BrickStore.graph.namespaces():
|
for alias, uri in BrickStore.graph.namespaces():
|
||||||
results.append((uri, f"{alias}: {uri}", ""))
|
# results.append((uri, f"{alias}: {uri}", ""))
|
||||||
|
results.append((uri, f"{alias}", ""))
|
||||||
return results
|
return results
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -189,3 +189,24 @@ class RemoveBrick(bpy.types.Operator, Operator):
|
|||||||
library=tool.Ifc.get().by_id(int(props.libraries)) if props.libraries else None,
|
library=tool.Ifc.get().by_id(int(props.libraries)) if props.libraries else None,
|
||||||
brick_uri=props.bricks[props.active_brick_index].uri,
|
brick_uri=props.bricks[props.active_brick_index].uri,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class UndoBrick(bpy.types.Operator, Operator):
|
||||||
|
bl_idname = "bim.undo_brick"
|
||||||
|
bl_label = "Undo Brick"
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
core.undo_brick(tool.Brick)
|
||||||
|
|
||||||
|
class RedoBrick(bpy.types.Operator, Operator):
|
||||||
|
bl_idname = "bim.redo_brick"
|
||||||
|
bl_label = "Redo Brick"
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
core.redo_brick(tool.Brick)
|
||||||
|
|
||||||
|
class SerializeBrick(bpy.types.Operator, Operator):
|
||||||
|
bl_idname = "bim.serialize_brick"
|
||||||
|
bl_label = "Serialize Brick"
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
core.serialize_brick(tool.Brick)
|
||||||
@@ -58,6 +58,13 @@ class BIM_PT_brickschema(Panel):
|
|||||||
row.operator("bim.add_brick_feed", text="", icon="PLUGIN")
|
row.operator("bim.add_brick_feed", text="", icon="PLUGIN")
|
||||||
row.operator("bim.remove_brick", text="", icon="X")
|
row.operator("bim.remove_brick", text="", icon="X")
|
||||||
|
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.operator("bim.undo_brick", icon="LOOP_BACK")
|
||||||
|
row.operator("bim.redo_brick", icon="LOOP_FORWARDS")
|
||||||
|
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.operator("bim.serialize_brick")
|
||||||
|
|
||||||
self.layout.template_list("BIM_UL_bricks", "", self.props, "bricks", self.props, "active_brick_index")
|
self.layout.template_list("BIM_UL_bricks", "", self.props, "bricks", self.props, "active_brick_index")
|
||||||
|
|
||||||
for attribute in BrickschemaData.data["attributes"]:
|
for attribute in BrickschemaData.data["attributes"]:
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import bmesh
|
|||||||
import logging
|
import logging
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
from mathutils import Matrix
|
from mathutils import Matrix, Vector
|
||||||
from math import radians
|
from math import radians
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
|
|
||||||
@@ -222,6 +222,7 @@ class ExecuteIfcClash(bpy.types.Operator):
|
|||||||
_, extension = os.path.splitext(self.filepath)
|
_, extension = os.path.splitext(self.filepath)
|
||||||
if extension != ".json":
|
if extension != ".json":
|
||||||
self.filepath = bpy.path.ensure_ext(self.filepath, ".bcf")
|
self.filepath = bpy.path.ensure_ext(self.filepath, ".bcf")
|
||||||
|
|
||||||
settings = ifcclash.ClashSettings()
|
settings = ifcclash.ClashSettings()
|
||||||
settings.output = self.filepath
|
settings.output = self.filepath
|
||||||
settings.logger = logging.getLogger("Clash")
|
settings.logger = logging.getLogger("Clash")
|
||||||
@@ -230,12 +231,28 @@ class ExecuteIfcClash(bpy.types.Operator):
|
|||||||
|
|
||||||
if context.scene.BIMClashProperties.should_create_clash_snapshots:
|
if context.scene.BIMClashProperties.should_create_clash_snapshots:
|
||||||
|
|
||||||
def get_viewpoint_snapshot(viewpoint, mat):
|
def get_viewpoint_snapshot(viewpoint):
|
||||||
camera = bpy.data.objects.get("IFC Clash Camera")
|
camera = bpy.data.objects.get("IFC Clash Camera")
|
||||||
if not camera:
|
if not camera:
|
||||||
camera = bpy.data.objects.new("IFC Clash Camera", bpy.data.cameras.new("IFC Clash Camera"))
|
camera = bpy.data.objects.new("IFC Clash Camera", bpy.data.cameras.new("IFC Clash Camera"))
|
||||||
context.scene.collection.objects.link(camera)
|
context.scene.collection.objects.link(camera)
|
||||||
camera.matrix_world = Matrix(mat)
|
|
||||||
|
bcf_camera = viewpoint.visualization_info.perspective_camera
|
||||||
|
p = bcf_camera.camera_view_point
|
||||||
|
z = bcf_camera.camera_direction
|
||||||
|
z = Vector([z.x, z.y, z.z]) * -1
|
||||||
|
y = bcf_camera.camera_up_vector
|
||||||
|
y = Vector([y.x, y.y, y.z])
|
||||||
|
x = y.cross(z)
|
||||||
|
|
||||||
|
mat = Matrix([
|
||||||
|
[x[0], y[0], z[0], p.x],
|
||||||
|
[x[1], y[1], z[1], p.y],
|
||||||
|
[x[2], y[2], z[2], p.z],
|
||||||
|
[0, 0, 0, 0],
|
||||||
|
])
|
||||||
|
|
||||||
|
camera.matrix_world = mat
|
||||||
context.scene.camera = camera
|
context.scene.camera = camera
|
||||||
camera.data.angle = radians(60)
|
camera.data.angle = radians(60)
|
||||||
area = next(area for area in context.screen.areas if area.type == "VIEW_3D")
|
area = next(area for area in context.screen.areas if area.type == "VIEW_3D")
|
||||||
@@ -246,7 +263,8 @@ class ExecuteIfcClash(bpy.types.Operator):
|
|||||||
context.scene.render.image_settings.file_format = "PNG"
|
context.scene.render.image_settings.file_format = "PNG"
|
||||||
context.scene.render.filepath = os.path.join(context.scene.BIMProperties.data_dir, "snapshot.png")
|
context.scene.render.filepath = os.path.join(context.scene.BIMProperties.data_dir, "snapshot.png")
|
||||||
bpy.ops.render.opengl(write_still=True)
|
bpy.ops.render.opengl(write_still=True)
|
||||||
return context.scene.render.filepath
|
with open(context.scene.render.filepath, "rb") as f:
|
||||||
|
return ("snapshot.png", f.read())
|
||||||
|
|
||||||
clasher.get_viewpoint_snapshot = get_viewpoint_snapshot
|
clasher.get_viewpoint_snapshot = get_viewpoint_snapshot
|
||||||
|
|
||||||
|
|||||||
@@ -111,10 +111,13 @@ class ConnectionsData:
|
|||||||
for rel in connected_to:
|
for rel in connected_to:
|
||||||
if element.is_a("IfcDistributionPort"):
|
if element.is_a("IfcDistributionPort"):
|
||||||
related_element = rel.RelatedPort
|
related_element = rel.RelatedPort
|
||||||
related_element_connection_type = ""
|
|
||||||
else:
|
else:
|
||||||
related_element = rel.RelatedElement
|
related_element = rel.RelatedElement
|
||||||
|
|
||||||
|
if element.is_a("IfcRelConnectsPathElements"):
|
||||||
related_element_connection_type = rel.RelatedConnectionType
|
related_element_connection_type = rel.RelatedConnectionType
|
||||||
|
else:
|
||||||
|
related_element_connection_type = ""
|
||||||
|
|
||||||
results.append(
|
results.append(
|
||||||
{
|
{
|
||||||
@@ -128,10 +131,13 @@ class ConnectionsData:
|
|||||||
for rel in connected_from:
|
for rel in connected_from:
|
||||||
if element.is_a("IfcDistributionPort"):
|
if element.is_a("IfcDistributionPort"):
|
||||||
relating_element = rel.RelatingPort
|
relating_element = rel.RelatingPort
|
||||||
relating_element_connection_type = ""
|
|
||||||
else:
|
else:
|
||||||
relating_element = rel.RelatingElement
|
relating_element = rel.RelatingElement
|
||||||
|
|
||||||
|
if element.is_a("IfcRelConnectsPathElements"):
|
||||||
relating_element_connection_type = rel.RelatingConnectionType
|
relating_element_connection_type = rel.RelatingConnectionType
|
||||||
|
else:
|
||||||
|
relating_element_connection_type = ""
|
||||||
|
|
||||||
results.append(
|
results.append(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -292,8 +292,6 @@ class LoadTypeThumbnails(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
offset: bpy.props.IntProperty()
|
offset: bpy.props.IntProperty()
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
from PIL import Image, ImageDraw
|
|
||||||
|
|
||||||
if bpy.app.background:
|
if bpy.app.background:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -310,106 +308,11 @@ class LoadTypeThumbnails(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
offset = 0
|
offset = 0
|
||||||
queue = queue[offset : offset + 9]
|
queue = queue[offset : offset + 9]
|
||||||
|
|
||||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
|
||||||
|
|
||||||
while queue:
|
while queue:
|
||||||
# if bpy.app.is_job_running("RENDER_PREVIEW") does not seem to reflect asset preview generation
|
# if bpy.app.is_job_running("RENDER_PREVIEW") does not seem to reflect asset preview generation
|
||||||
element = queue.pop()
|
element = queue.pop()
|
||||||
obj = tool.Ifc.get_object(element)
|
if tool.Model.update_thumbnail_for_element(element):
|
||||||
|
queue.append(element)
|
||||||
if not obj:
|
|
||||||
continue # Nothing to process
|
|
||||||
elif AuthoringData.type_thumbnails.get(element.id(), None):
|
|
||||||
continue # Already processed
|
|
||||||
elif obj.preview and obj.preview.icon_id:
|
|
||||||
AuthoringData.type_thumbnails[element.id()] = obj.preview.icon_id
|
|
||||||
continue
|
|
||||||
|
|
||||||
if obj.data:
|
|
||||||
obj.asset_generate_preview()
|
|
||||||
while not obj.preview:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
size = 128
|
|
||||||
img = Image.new("RGBA", (size, size))
|
|
||||||
draw = ImageDraw.Draw(img)
|
|
||||||
|
|
||||||
material = ifcopenshell.util.element.get_material(element)
|
|
||||||
if material and material.is_a("IfcMaterialProfileSet"):
|
|
||||||
profile = material.MaterialProfiles[0].Profile
|
|
||||||
tool.Profile.draw_image_for_ifc_profile(draw, profile, size)
|
|
||||||
|
|
||||||
elif material and material.is_a("IfcMaterialLayerSet"):
|
|
||||||
thicknesses = [l.LayerThickness for l in material.MaterialLayers]
|
|
||||||
total_thickness = sum(thicknesses)
|
|
||||||
si_total_thickness = total_thickness * unit_scale
|
|
||||||
if si_total_thickness <= 0.051:
|
|
||||||
width = 10
|
|
||||||
elif si_total_thickness <= 0.11:
|
|
||||||
width = 20
|
|
||||||
elif si_total_thickness <= 0.21:
|
|
||||||
width = 30
|
|
||||||
elif si_total_thickness <= 0.31:
|
|
||||||
width = 40
|
|
||||||
else:
|
|
||||||
width = 50
|
|
||||||
|
|
||||||
height = 100
|
|
||||||
|
|
||||||
is_horizontal = False
|
|
||||||
if element.is_a("IfcSlabType"):
|
|
||||||
is_horizontal = True
|
|
||||||
|
|
||||||
parametric = ifcopenshell.util.element.get_psets(element).get("EPset_Parametric")
|
|
||||||
if parametric:
|
|
||||||
layer_set_direction = parametric.get("LayerSetDirection", None)
|
|
||||||
if layer_set_direction == "AXIS2":
|
|
||||||
is_horizontal = False
|
|
||||||
elif layer_set_direction == "AXIS3":
|
|
||||||
is_horizontal = True
|
|
||||||
|
|
||||||
if is_horizontal:
|
|
||||||
width, height = height, width
|
|
||||||
|
|
||||||
x_offset = (size / 2) - (width / 2)
|
|
||||||
y_offset = (size / 2) - (height / 2)
|
|
||||||
draw.rectangle([x_offset, y_offset, width + x_offset, height + y_offset], outline="white", width=5)
|
|
||||||
current_thickness = 0
|
|
||||||
del thicknesses[-1]
|
|
||||||
for thickness in thicknesses:
|
|
||||||
current_thickness += thickness
|
|
||||||
if element.is_a("IfcSlabType"):
|
|
||||||
y = (current_thickness / total_thickness) * height
|
|
||||||
line = [x_offset, y_offset + y, x_offset + width, y_offset + y]
|
|
||||||
else:
|
|
||||||
x = (current_thickness / total_thickness) * width
|
|
||||||
line = [x_offset + x, y_offset, x_offset + x, y_offset + height]
|
|
||||||
draw.line(line, fill="white", width=2)
|
|
||||||
elif False:
|
|
||||||
# TODO: things like parametric duct segments
|
|
||||||
pass
|
|
||||||
elif not element.RepresentationMaps:
|
|
||||||
# Empties are represented by a generic thumbnail
|
|
||||||
width = height = 100
|
|
||||||
x_offset = (size / 2) - (width / 2)
|
|
||||||
y_offset = (size / 2) - (height / 2)
|
|
||||||
draw.line([x_offset, y_offset, width + x_offset, height + y_offset], fill="white", width=2)
|
|
||||||
draw.line([x_offset, y_offset + height, width + x_offset, y_offset], fill="white", width=2)
|
|
||||||
draw.rectangle([x_offset, y_offset, width + x_offset, height + y_offset], outline="white", width=5)
|
|
||||||
else:
|
|
||||||
draw.line([0, 0, size, size], fill="red", width=2)
|
|
||||||
draw.line([0, size, size, 0], fill="red", width=2)
|
|
||||||
|
|
||||||
pixels = [item for sublist in img.getdata() for item in sublist]
|
|
||||||
|
|
||||||
obj.asset_generate_preview()
|
|
||||||
while not obj.preview:
|
|
||||||
pass
|
|
||||||
|
|
||||||
obj.preview.image_size = size, size
|
|
||||||
obj.preview.image_pixels_float = pixels
|
|
||||||
|
|
||||||
queue.append(element)
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -472,7 +375,6 @@ class MirrorElements(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
obj.matrix_world = newmat
|
obj.matrix_world = newmat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def generate_box(usecase_path, ifc_file, settings):
|
def generate_box(usecase_path, ifc_file, settings):
|
||||||
box_context = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Box", "MODEL_VIEW")
|
box_context = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Box", "MODEL_VIEW")
|
||||||
if not box_context:
|
if not box_context:
|
||||||
|
|||||||
@@ -145,12 +145,21 @@ class DumbProfileRegenerator:
|
|||||||
objs = []
|
objs = []
|
||||||
if not profile:
|
if not profile:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
element_types = set()
|
||||||
for element in self.get_elements_using_profile(profile):
|
for element in self.get_elements_using_profile(profile):
|
||||||
obj = tool.Ifc.get_object(element)
|
obj = tool.Ifc.get_object(element)
|
||||||
if obj:
|
if obj:
|
||||||
objs.append(obj)
|
objs.append(obj)
|
||||||
|
if element.is_a("IfcElementType"):
|
||||||
|
element_types.add(element)
|
||||||
|
|
||||||
DumbProfileRecalculator().recalculate(objs)
|
DumbProfileRecalculator().recalculate(objs)
|
||||||
|
|
||||||
|
# update related thumbnails
|
||||||
|
for element in self.get_element_types_using_profile(profile):
|
||||||
|
tool.Model.update_thumbnail_for_element(element, refresh=True)
|
||||||
|
|
||||||
def regenerate_from_profile(self, usecase_path, ifc_file, settings):
|
def regenerate_from_profile(self, usecase_path, ifc_file, settings):
|
||||||
self.file = ifc_file
|
self.file = ifc_file
|
||||||
objs = []
|
objs = []
|
||||||
@@ -165,9 +174,10 @@ class DumbProfileRegenerator:
|
|||||||
|
|
||||||
def get_elements_using_profile(self, profile):
|
def get_elements_using_profile(self, profile):
|
||||||
results = []
|
results = []
|
||||||
for profile_set in [
|
profile_sets = [
|
||||||
mp.ToMaterialProfileSet[0] for mp in self.file.get_inverse(profile) if mp.is_a("IfcMaterialProfile")
|
mp.ToMaterialProfileSet[0] for mp in self.file.get_inverse(profile) if mp.is_a("IfcMaterialProfile")
|
||||||
]:
|
]
|
||||||
|
for profile_set in profile_sets:
|
||||||
for inverse in self.file.get_inverse(profile_set):
|
for inverse in self.file.get_inverse(profile_set):
|
||||||
if not inverse.is_a("IfcMaterialProfileSetUsage"):
|
if not inverse.is_a("IfcMaterialProfileSetUsage"):
|
||||||
continue
|
continue
|
||||||
@@ -181,6 +191,18 @@ class DumbProfileRegenerator:
|
|||||||
results.extend(rel.RelatedObjects)
|
results.extend(rel.RelatedObjects)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
def get_element_types_using_profile(self, profile):
|
||||||
|
results = []
|
||||||
|
profile_sets = [
|
||||||
|
mp.ToMaterialProfileSet[0] for mp in self.file.get_inverse(profile) if mp.is_a("IfcMaterialProfile")
|
||||||
|
]
|
||||||
|
for profile_set in profile_sets:
|
||||||
|
for inverse in self.file.get_inverse(profile_set):
|
||||||
|
if not inverse.is_a("IfcRelAssociatesMaterial"):
|
||||||
|
continue
|
||||||
|
results.extend(inverse.RelatedObjects)
|
||||||
|
return results
|
||||||
|
|
||||||
def regenerate_from_type(self, usecase_path, ifc_file, settings):
|
def regenerate_from_type(self, usecase_path, ifc_file, settings):
|
||||||
obj = tool.Ifc.get_object(settings["related_object"])
|
obj = tool.Ifc.get_object(settings["related_object"])
|
||||||
if not obj or not obj.data or not obj.data.BIMMeshProperties.ifc_definition_id:
|
if not obj or not obj.data or not obj.data.BIMMeshProperties.ifc_definition_id:
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ class BIM_PT_project(Panel):
|
|||||||
op.should_save_as = False
|
op.should_save_as = False
|
||||||
op = row.operator("export_ifc.bim", icon="FILE_TICK", text="Save As")
|
op = row.operator("export_ifc.bim", icon="FILE_TICK", text="Save As")
|
||||||
op.should_save_as = True
|
op.should_save_as = True
|
||||||
row.operator("bim.unload_project", text="", icon="X")
|
row.operator("bim.unload_project", text="", icon="CANCEL")
|
||||||
|
|
||||||
def draw_create_project_ui(self, context):
|
def draw_create_project_ui(self, context):
|
||||||
props = context.scene.BIMProperties
|
props = context.scene.BIMProperties
|
||||||
|
|||||||
@@ -109,3 +109,14 @@ def remove_brick(ifc, brick, library=None, brick_uri=None):
|
|||||||
ifc.run("library.remove_reference", reference=reference)
|
ifc.run("library.remove_reference", reference=reference)
|
||||||
brick.remove_brick(brick_uri)
|
brick.remove_brick(brick_uri)
|
||||||
brick.run_refresh_brick_viewer()
|
brick.run_refresh_brick_viewer()
|
||||||
|
|
||||||
|
def undo_brick(brick):
|
||||||
|
brick.undo_brick()
|
||||||
|
brick.run_refresh_brick_viewer()
|
||||||
|
|
||||||
|
def redo_brick(brick):
|
||||||
|
brick.redo_brick()
|
||||||
|
brick.run_refresh_brick_viewer()
|
||||||
|
|
||||||
|
def serialize_brick(brick, file_name="BlenderBIMSerializeTest.ttl"):
|
||||||
|
brick.serialize_brick(file_name)
|
||||||
@@ -25,6 +25,7 @@ import blenderbim.tool as tool
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
import brickschema
|
import brickschema
|
||||||
|
import brickschema.persistent
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
from rdflib import Literal, URIRef, Namespace
|
from rdflib import Literal, URIRef, Namespace
|
||||||
from rdflib.namespace import RDF
|
from rdflib.namespace import RDF
|
||||||
@@ -32,14 +33,20 @@ except:
|
|||||||
# See #1860
|
# See #1860
|
||||||
print("Warning: brickschema not available.")
|
print("Warning: brickschema not available.")
|
||||||
|
|
||||||
|
# silence known rdflib_sqlalchemy TypeError warning
|
||||||
|
# see https://github.com/BrickSchema/Brick/issues/513#issuecomment-1558493675
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger("rdflib")
|
||||||
|
logger.setLevel(logging.ERROR)
|
||||||
|
|
||||||
class Brick(blenderbim.core.tool.Brick):
|
class Brick(blenderbim.core.tool.Brick):
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_brick(cls, namespace, brick_class):
|
def add_brick(cls, namespace, brick_class):
|
||||||
ns = Namespace(namespace)
|
ns = Namespace(namespace)
|
||||||
brick = ns[ifcopenshell.guid.expand(ifcopenshell.guid.new())]
|
brick = ns[ifcopenshell.guid.expand(ifcopenshell.guid.new())]
|
||||||
BrickStore.graph.add((brick, RDF.type, URIRef(brick_class)))
|
with BrickStore.graph.new_changeset("PROJECT") as cs:
|
||||||
BrickStore.graph.add((brick, URIRef("http://www.w3.org/2000/01/rdf-schema#label"), Literal("Unnamed")))
|
cs.add((brick, RDF.type, URIRef(brick_class)))
|
||||||
|
cs.add((brick, URIRef("http://www.w3.org/2000/01/rdf-schema#label"), Literal("Unnamed")))
|
||||||
return str(brick)
|
return str(brick)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -100,7 +107,7 @@ class Brick(blenderbim.core.tool.Brick):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def clear_project(cls):
|
def clear_project(cls):
|
||||||
BrickStore.graph = None
|
BrickStore.purge()
|
||||||
bpy.context.scene.BIMBrickProperties.active_brick_class == ""
|
bpy.context.scene.BIMBrickProperties.active_brick_class == ""
|
||||||
bpy.context.scene.BIMBrickProperties.brick_breadcrumbs.clear()
|
bpy.context.scene.BIMBrickProperties.brick_breadcrumbs.clear()
|
||||||
|
|
||||||
@@ -249,24 +256,24 @@ class Brick(blenderbim.core.tool.Brick):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load_brick_file(cls, filepath):
|
def load_brick_file(cls, filepath):
|
||||||
if not BrickStore.schema:
|
if not BrickStore.schema: # important check for running under test cases
|
||||||
BrickStore.schema = brickschema.Graph()
|
|
||||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||||
schema_path = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl")
|
BrickStore.schema = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl")
|
||||||
BrickStore.schema.load_file(schema_path)
|
BrickStore.graph = brickschema.persistent.VersionedGraphCollection("sqlite://")
|
||||||
BrickStore.graph = brickschema.Graph().load_file(filepath) + BrickStore.schema
|
with BrickStore.graph.new_changeset("SCHEMA") as cs:
|
||||||
|
cs.load_file(BrickStore.schema)
|
||||||
|
with BrickStore.graph.new_changeset("PROJECT") as cs:
|
||||||
|
cs.load_file(filepath)
|
||||||
BrickStore.path = filepath
|
BrickStore.path = filepath
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def new_brick_file(cls):
|
def new_brick_file(cls):
|
||||||
if not BrickStore.schema:
|
if not BrickStore.schema: # important check for running under test cases
|
||||||
BrickStore.schema = brickschema.Graph()
|
|
||||||
#BrickStore.schema = brickschema.persistent.VersionedGraphCollection("sqlite://")
|
|
||||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||||
schema_path = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl")
|
BrickStore.schema = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl")
|
||||||
BrickStore.schema.load_file(schema_path)
|
BrickStore.graph = brickschema.persistent.VersionedGraphCollection("sqlite://")
|
||||||
#BrickStore.schema.load_graph(schema_path)
|
with BrickStore.graph.new_changeset("SCHEMA") as cs:
|
||||||
BrickStore.graph = brickschema.Graph() + BrickStore.schema
|
cs.load_file(BrickStore.schema)
|
||||||
BrickStore.graph.bind("digitaltwin", Namespace("https://example.org/digitaltwin#"))
|
BrickStore.graph.bind("digitaltwin", Namespace("https://example.org/digitaltwin#"))
|
||||||
BrickStore.graph.bind("brick", Namespace("https://brickschema.org/schema/Brick#"))
|
BrickStore.graph.bind("brick", Namespace("https://brickschema.org/schema/Brick#"))
|
||||||
BrickStore.graph.bind("rdfs", Namespace("http://www.w3.org/2000/01/rdf-schema#"))
|
BrickStore.graph.bind("rdfs", Namespace("http://www.w3.org/2000/01/rdf-schema#"))
|
||||||
@@ -281,8 +288,10 @@ class Brick(blenderbim.core.tool.Brick):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def remove_brick(cls, brick_uri):
|
def remove_brick(cls, brick_uri):
|
||||||
for triple in BrickStore.graph.triples((URIRef(brick_uri), None, None)):
|
if(BrickStore.graph.triples((URIRef(brick_uri), None, None))):
|
||||||
BrickStore.graph.remove(triple)
|
with BrickStore.graph.new_changeset("PROJECT") as cs:
|
||||||
|
for triple in BrickStore.graph.triples((URIRef(brick_uri), None, None)):
|
||||||
|
cs.remove(triple)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run_assign_brick_reference(cls, element=None, library=None, brick_uri=None):
|
def run_assign_brick_reference(cls, element=None, library=None, brick_uri=None):
|
||||||
@@ -308,14 +317,39 @@ class Brick(blenderbim.core.tool.Brick):
|
|||||||
def set_active_brick_class(cls, brick_class):
|
def set_active_brick_class(cls, brick_class):
|
||||||
bpy.context.scene.BIMBrickProperties.active_brick_class = brick_class
|
bpy.context.scene.BIMBrickProperties.active_brick_class = brick_class
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def undo_brick(cls):
|
||||||
|
if(len(BrickStore.graph.versions()) > 1):
|
||||||
|
BrickStore.graph.undo()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def redo_brick(cls):
|
||||||
|
with BrickStore.graph.conn() as conn:
|
||||||
|
redo_record = conn.execute(
|
||||||
|
"SELECT * from redos " "ORDER BY timestamp ASC LIMIT 1"
|
||||||
|
).fetchone()
|
||||||
|
if redo_record is not None:
|
||||||
|
BrickStore.graph.redo()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def serialize_brick(cls, file_name):
|
||||||
|
#temporary file path, could either be user selected for "save as" or use the BrickStore.path for simply "save"
|
||||||
|
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
dest = os.path.join(cwd, "..", "bim", "schema", file_name)
|
||||||
|
BrickStore.get_project().serialize(destination=dest, format="turtle")
|
||||||
|
|
||||||
class BrickStore:
|
class BrickStore:
|
||||||
schema = None
|
schema = None # this is now a os path
|
||||||
graph = None
|
path = None # file path if the project was loaded in
|
||||||
path = None
|
graph = None # this is the VersionedGraphCollection with 2 arbitrarily named graphs: "schema" and "project"
|
||||||
|
# "SCHEMA" holds the Brick.ttl metadata; "PROJECT" holds all the authored entities
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def purge():
|
def purge():
|
||||||
BrickStore.schema = None
|
BrickStore.schema = None
|
||||||
BrickStore.graph = None
|
BrickStore.graph = None
|
||||||
BrickStore.path = None
|
BrickStore.path = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_project(cls):
|
||||||
|
return BrickStore.graph.graph_at(graph="PROJECT")
|
||||||
@@ -202,7 +202,6 @@ class Loader(blenderbim.core.tool.Loader):
|
|||||||
ifc_path = Path(tool.Ifc.get_path())
|
ifc_path = Path(tool.Ifc.get_path())
|
||||||
image_url = ifc_path.parent / image_url
|
image_url = ifc_path.parent / image_url
|
||||||
|
|
||||||
# import pdb; pdb.set_trace()
|
|
||||||
if not image_url.exists():
|
if not image_url.exists():
|
||||||
print(f"WARNING. Couldn't find texture by path {image_url}, it will be skipped.")
|
print(f"WARNING. Couldn't find texture by path {image_url}, it will be skipped.")
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ from mathutils import Matrix, Vector
|
|||||||
from blenderbim.bim import import_ifc
|
from blenderbim.bim import import_ifc
|
||||||
from blenderbim.bim.module.geometry.helper import Helper
|
from blenderbim.bim.module.geometry.helper import Helper
|
||||||
import collections
|
import collections
|
||||||
|
from blenderbim.bim.module.model.data import AuthoringData
|
||||||
|
|
||||||
|
|
||||||
class Model(blenderbim.core.tool.Model):
|
class Model(blenderbim.core.tool.Model):
|
||||||
@@ -630,3 +631,101 @@ class Model(blenderbim.core.tool.Model):
|
|||||||
is_global=True,
|
is_global=True,
|
||||||
should_sync_changes_first=False,
|
should_sync_changes_first=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def update_thumbnail_for_element(cls, element, refresh=False):
|
||||||
|
if bpy.app.background:
|
||||||
|
return
|
||||||
|
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
obj = tool.Ifc.get_object(element)
|
||||||
|
if not obj:
|
||||||
|
return # Nothing to process
|
||||||
|
|
||||||
|
if not refresh and element.id() in AuthoringData.type_thumbnails:
|
||||||
|
return # Already processed
|
||||||
|
|
||||||
|
obj.asset_generate_preview()
|
||||||
|
while not obj.preview:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# if object has .data we can use default blender .asset_generate_preview()
|
||||||
|
if not obj.data:
|
||||||
|
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||||
|
size = 128
|
||||||
|
img = Image.new("RGBA", (size, size))
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
|
||||||
|
material = ifcopenshell.util.element.get_material(element)
|
||||||
|
if material and material.is_a("IfcMaterialProfileSet"):
|
||||||
|
profile = material.MaterialProfiles[0].Profile
|
||||||
|
tool.Profile.draw_image_for_ifc_profile(draw, profile, size)
|
||||||
|
|
||||||
|
elif material and material.is_a("IfcMaterialLayerSet"):
|
||||||
|
thicknesses = [l.LayerThickness for l in material.MaterialLayers]
|
||||||
|
total_thickness = sum(thicknesses)
|
||||||
|
si_total_thickness = total_thickness * unit_scale
|
||||||
|
if si_total_thickness <= 0.051:
|
||||||
|
width = 10
|
||||||
|
elif si_total_thickness <= 0.11:
|
||||||
|
width = 20
|
||||||
|
elif si_total_thickness <= 0.21:
|
||||||
|
width = 30
|
||||||
|
elif si_total_thickness <= 0.31:
|
||||||
|
width = 40
|
||||||
|
else:
|
||||||
|
width = 50
|
||||||
|
|
||||||
|
height = 100
|
||||||
|
|
||||||
|
is_horizontal = False
|
||||||
|
if element.is_a("IfcSlabType"):
|
||||||
|
is_horizontal = True
|
||||||
|
|
||||||
|
parametric = ifcopenshell.util.element.get_psets(element).get("EPset_Parametric")
|
||||||
|
if parametric:
|
||||||
|
layer_set_direction = parametric.get("LayerSetDirection", None)
|
||||||
|
if layer_set_direction == "AXIS2":
|
||||||
|
is_horizontal = False
|
||||||
|
elif layer_set_direction == "AXIS3":
|
||||||
|
is_horizontal = True
|
||||||
|
|
||||||
|
if is_horizontal:
|
||||||
|
width, height = height, width
|
||||||
|
|
||||||
|
x_offset = (size / 2) - (width / 2)
|
||||||
|
y_offset = (size / 2) - (height / 2)
|
||||||
|
draw.rectangle([x_offset, y_offset, width + x_offset, height + y_offset], outline="white", width=5)
|
||||||
|
current_thickness = 0
|
||||||
|
del thicknesses[-1]
|
||||||
|
for thickness in thicknesses:
|
||||||
|
current_thickness += thickness
|
||||||
|
if element.is_a("IfcSlabType"):
|
||||||
|
y = (current_thickness / total_thickness) * height
|
||||||
|
line = [x_offset, y_offset + y, x_offset + width, y_offset + y]
|
||||||
|
else:
|
||||||
|
x = (current_thickness / total_thickness) * width
|
||||||
|
line = [x_offset + x, y_offset, x_offset + x, y_offset + height]
|
||||||
|
draw.line(line, fill="white", width=2)
|
||||||
|
elif False:
|
||||||
|
# TODO: things like parametric duct segments
|
||||||
|
pass
|
||||||
|
elif not element.RepresentationMaps:
|
||||||
|
# Empties are represented by a generic thumbnail
|
||||||
|
width = height = 100
|
||||||
|
x_offset = (size / 2) - (width / 2)
|
||||||
|
y_offset = (size / 2) - (height / 2)
|
||||||
|
draw.line([x_offset, y_offset, width + x_offset, height + y_offset], fill="white", width=2)
|
||||||
|
draw.line([x_offset, y_offset + height, width + x_offset, y_offset], fill="white", width=2)
|
||||||
|
draw.rectangle([x_offset, y_offset, width + x_offset, height + y_offset], outline="white", width=5)
|
||||||
|
else:
|
||||||
|
draw.line([0, 0, size, size], fill="red", width=2)
|
||||||
|
draw.line([0, size, size, 0], fill="red", width=2)
|
||||||
|
|
||||||
|
pixels = [item for sublist in img.getdata() for item in sublist]
|
||||||
|
|
||||||
|
obj.preview.image_size = size, size
|
||||||
|
obj.preview.image_pixels_float = pixels
|
||||||
|
|
||||||
|
AuthoringData.type_thumbnails[element.id()] = obj.preview.icon_id
|
||||||
|
|||||||
@@ -75,7 +75,8 @@ def an_empty_blender_session():
|
|||||||
# default project settings
|
# default project settings
|
||||||
bpy.context.scene.unit_settings.system = "METRIC"
|
bpy.context.scene.unit_settings.system = "METRIC"
|
||||||
bpy.context.scene.unit_settings.length_unit = "MILLIMETERS"
|
bpy.context.scene.unit_settings.length_unit = "MILLIMETERS"
|
||||||
bpy.context.scene.BIMProjectProperties.template_file = '0'
|
bpy.context.scene.BIMProjectProperties.template_file = "0"
|
||||||
|
bpy.context.preferences.addons["blenderbim"].preferences.should_play_chaching_sound = False
|
||||||
|
|
||||||
|
|
||||||
@given("an empty IFC project")
|
@given("an empty IFC project")
|
||||||
|
|||||||
@@ -307,10 +307,8 @@ class TestImportBrickItems(NewFile):
|
|||||||
class TestLoadBrickFile(NewFile):
|
class TestLoadBrickFile(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
# We stub the schema to make tests run faster
|
# We stub the schema to make tests run faster
|
||||||
BrickStore.schema = brickschema.Graph()
|
|
||||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||||
schema_path = os.path.join(cwd, "..", "files", "BrickStub.ttl")
|
BrickStore.schema = os.path.join(cwd, "..", "files", "BrickStub.ttl")
|
||||||
BrickStore.schema.load_file(schema_path)
|
|
||||||
|
|
||||||
# This is the actual test
|
# This is the actual test
|
||||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||||
@@ -322,10 +320,8 @@ class TestLoadBrickFile(NewFile):
|
|||||||
class TestNewBrickFile(NewFile):
|
class TestNewBrickFile(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
# We stub the schema to make tests run faster
|
# We stub the schema to make tests run faster
|
||||||
BrickStore.schema = brickschema.Graph()
|
|
||||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||||
schema_path = os.path.join(cwd, "..", "files", "BrickStub.ttl")
|
BrickStore.schema = os.path.join(cwd, "..", "files", "BrickStub.ttl")
|
||||||
BrickStore.schema.load_file(schema_path)
|
|
||||||
|
|
||||||
# This is the actual test
|
# This is the actual test
|
||||||
subject.new_brick_file()
|
subject.new_brick_file()
|
||||||
|
|||||||
@@ -122,14 +122,20 @@ class Clasher:
|
|||||||
for clash in clash_set["clashes"].values():
|
for clash in clash_set["clashes"].values():
|
||||||
title = f'{clash["a_ifc_class"]}/{clash["a_name"]} and {clash["b_ifc_class"]}/{clash["b_name"]}'
|
title = f'{clash["a_ifc_class"]}/{clash["a_name"]} and {clash["b_ifc_class"]}/{clash["b_name"]}'
|
||||||
topic = bcfxml.add_topic(title, title, "IfcClash")
|
topic = bcfxml.add_topic(title, title, "IfcClash")
|
||||||
topic.add_viewpoint_from_point_and_guids(
|
viewpoint = topic.add_viewpoint_from_point_and_guids(
|
||||||
np.array(clash["position"]), clash["a_global_id"], clash["b_global_id"],
|
np.array(clash["position"]), clash["a_global_id"], clash["b_global_id"],
|
||||||
)
|
)
|
||||||
|
snapshot = self.get_viewpoint_snapshot(viewpoint)
|
||||||
|
if snapshot:
|
||||||
|
topic.markup.viewpoints[0].snapshot = snapshot[0]
|
||||||
|
viewpoint.snapshot = snapshot[1]
|
||||||
suffix = f".{i}" if i else ""
|
suffix = f".{i}" if i else ""
|
||||||
bcfxml.save_project(f"{self.settings.output}{suffix}")
|
bcfxml.save_project(f"{self.settings.output}{suffix}")
|
||||||
|
|
||||||
def get_viewpoint_snapshot(self, viewpoint, mat):
|
def get_viewpoint_snapshot(self, viewpoint):
|
||||||
return None # Possible to overload this function in a GUI application if used as a library
|
# Possible to overload this function in a GUI application if used as a library.
|
||||||
|
# Should return a tuple of (filename, bytes).
|
||||||
|
return None
|
||||||
|
|
||||||
def export_json(self):
|
def export_json(self):
|
||||||
clash_sets = self.clash_sets.copy()
|
clash_sets = self.clash_sets.copy()
|
||||||
|
|||||||
@@ -29,9 +29,10 @@ import multiprocessing
|
|||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.geom
|
import ifcopenshell.geom
|
||||||
import ifcopenshell.util.element
|
import ifcopenshell.util.element
|
||||||
|
import ifcopenshell.util.selector
|
||||||
import ifcopenshell.util.placement
|
import ifcopenshell.util.placement
|
||||||
import ifcopenshell.util.classification
|
import ifcopenshell.util.classification
|
||||||
import ifcopenshell.util.selector
|
import ifcopenshell.util.representation
|
||||||
from deepdiff import DeepDiff
|
from deepdiff import DeepDiff
|
||||||
|
|
||||||
|
|
||||||
@@ -141,8 +142,9 @@ class IfcDiff:
|
|||||||
continue
|
continue
|
||||||
if should_check_geometry:
|
if should_check_geometry:
|
||||||
# Option 1: check everything heuristically using the iterator (seems faster)
|
# Option 1: check everything heuristically using the iterator (seems faster)
|
||||||
potential_old_changes.append(old)
|
if ifcopenshell.util.representation.get_representation(new, "Model", "Body", "MODEL_VIEW"):
|
||||||
potential_new_changes.append(new)
|
potential_old_changes.append(old)
|
||||||
|
potential_new_changes.append(new)
|
||||||
# Option 2: check first using Python, then fallback to iterator (twice as slow)
|
# Option 2: check first using Python, then fallback to iterator (twice as slow)
|
||||||
# diff = self.diff_element_basic_geometry(old, new)
|
# diff = self.diff_element_basic_geometry(old, new)
|
||||||
# if diff:
|
# if diff:
|
||||||
|
|||||||
Reference in New Issue
Block a user