mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 14:31:39 +00:00
Update type manager thumbnails on editing profiles
Example - https://imgur.com/a/IcV8IIR
This commit is contained in:
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user