mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-21 11:33:38 +00:00
Profile manager thumnails (#2568)
This commit is contained in:
@@ -267,6 +267,35 @@ def convert_property_group_from_si(property_group, skip_props=()):
|
|||||||
setattr(property_group, prop_name, prop_value)
|
setattr(property_group, prop_name, prop_value)
|
||||||
|
|
||||||
|
|
||||||
|
def draw_image_for_ifc_profile(draw, profile, size):
|
||||||
|
"""generates image based on `profile` using `PIL.ImageDraw`"""
|
||||||
|
settings = ifcopenshell.geom.settings()
|
||||||
|
settings.set(settings.INCLUDE_CURVES, True)
|
||||||
|
shape = ifcopenshell.geom.create_shape(settings, profile)
|
||||||
|
verts = shape.verts
|
||||||
|
edges = shape.edges
|
||||||
|
|
||||||
|
grouped_verts = [[verts[i], verts[i + 1]] for i in range(0, len(verts), 3)]
|
||||||
|
grouped_edges = [[edges[i], edges[i + 1]] for i in range(0, len(edges), 2)]
|
||||||
|
|
||||||
|
max_x = max([v[0] for v in grouped_verts])
|
||||||
|
min_x = min([v[0] for v in grouped_verts])
|
||||||
|
max_y = max([v[1] for v in grouped_verts])
|
||||||
|
min_y = min([v[1] for v in grouped_verts])
|
||||||
|
|
||||||
|
dim_x = max_x - min_x
|
||||||
|
dim_y = max_y - min_y
|
||||||
|
max_dim = max([dim_x, dim_y])
|
||||||
|
scale = 100 / max_dim
|
||||||
|
|
||||||
|
for vert in grouped_verts:
|
||||||
|
vert[0] = round(scale * (vert[0] - min_x)) + ((size / 2) - scale * (dim_x / 2))
|
||||||
|
vert[1] = round(scale * (vert[1] - min_y)) + ((size / 2) - scale * (dim_y / 2))
|
||||||
|
|
||||||
|
for e in grouped_edges:
|
||||||
|
draw.line((tuple(grouped_verts[e[0]]), tuple(grouped_verts[e[1]])), fill="white", width=2)
|
||||||
|
|
||||||
|
|
||||||
class IfcHeaderExtractor:
|
class IfcHeaderExtractor:
|
||||||
def __init__(self, filepath: str):
|
def __init__(self, filepath: str):
|
||||||
self.filepath = filepath
|
self.filepath = filepath
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ from . import wall, slab, profile, mep
|
|||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from blenderbim.bim.module.model.data import AuthoringData
|
from blenderbim.bim.module.model.data import AuthoringData
|
||||||
from blenderbim.bim.module.model.prop import store_cursor_position
|
from blenderbim.bim.module.model.prop import store_cursor_position
|
||||||
|
from blenderbim.bim.helper import draw_image_for_ifc_profile
|
||||||
from ifcopenshell.api.pset.data import Data as PsetData
|
from ifcopenshell.api.pset.data import Data as PsetData
|
||||||
from mathutils import Vector, Matrix
|
from mathutils import Vector, Matrix
|
||||||
from bpy_extras.object_utils import AddObjectHelper
|
from bpy_extras.object_utils import AddObjectHelper
|
||||||
@@ -370,30 +371,8 @@ class LoadTypeThumbnails(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
material = ifcopenshell.util.element.get_material(element)
|
material = ifcopenshell.util.element.get_material(element)
|
||||||
if material and material.is_a("IfcMaterialProfileSet"):
|
if material and material.is_a("IfcMaterialProfileSet"):
|
||||||
profile = material.MaterialProfiles[0].Profile
|
profile = material.MaterialProfiles[0].Profile
|
||||||
settings = ifcopenshell.geom.settings()
|
draw_image_for_ifc_profile(draw, profile, size)
|
||||||
settings.set(settings.INCLUDE_CURVES, True)
|
|
||||||
shape = ifcopenshell.geom.create_shape(settings, profile)
|
|
||||||
verts = shape.verts
|
|
||||||
edges = shape.edges
|
|
||||||
grouped_verts = [[verts[i], verts[i + 1]] for i in range(0, len(verts), 3)]
|
|
||||||
grouped_edges = [[edges[i], edges[i + 1]] for i in range(0, len(edges), 2)]
|
|
||||||
|
|
||||||
max_x = max([v[0] for v in grouped_verts])
|
|
||||||
min_x = min([v[0] for v in grouped_verts])
|
|
||||||
max_y = max([v[1] for v in grouped_verts])
|
|
||||||
min_y = min([v[1] for v in grouped_verts])
|
|
||||||
|
|
||||||
dim_x = max_x - min_x
|
|
||||||
dim_y = max_y - min_y
|
|
||||||
max_dim = max([dim_x, dim_y])
|
|
||||||
scale = 100 / max_dim
|
|
||||||
|
|
||||||
for vert in grouped_verts:
|
|
||||||
vert[0] = round(scale * (vert[0] - min_x)) + ((size / 2) - scale * (dim_x / 2))
|
|
||||||
vert[1] = round(scale * (vert[1] - min_y)) + ((size / 2) - scale * (dim_y / 2))
|
|
||||||
|
|
||||||
for e in grouped_edges:
|
|
||||||
draw.line((tuple(grouped_verts[e[0]]), tuple(grouped_verts[e[1]])), fill="white", width=2)
|
|
||||||
elif material and material.is_a("IfcMaterialLayerSet"):
|
elif material and material.is_a("IfcMaterialLayerSet"):
|
||||||
thicknesses = [l.LayerThickness for l in material.MaterialLayers]
|
thicknesses = [l.LayerThickness for l in material.MaterialLayers]
|
||||||
total_thickness = sum(thicknesses)
|
total_thickness = sum(thicknesses)
|
||||||
|
|||||||
@@ -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 . import ui, prop, operator
|
from . import ui, prop, operator, data
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
operator.AddProfileDef,
|
operator.AddProfileDef,
|
||||||
@@ -43,3 +43,5 @@ def register():
|
|||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
del bpy.types.Scene.BIMProfileProperties
|
del bpy.types.Scene.BIMProfileProperties
|
||||||
|
if data.ProfileData.preview_collection:
|
||||||
|
bpy.utils.previews.remove(data.ProfileData.preview_collection)
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ def refresh():
|
|||||||
|
|
||||||
class ProfileData:
|
class ProfileData:
|
||||||
data = {}
|
data = {}
|
||||||
|
preview_collection = bpy.utils.previews.new()
|
||||||
is_loaded = False
|
is_loaded = False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import blenderbim.bim.helper
|
|||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
import blenderbim.bim.module.model.profile as model_profile
|
import blenderbim.bim.module.model.profile as model_profile
|
||||||
from blenderbim.bim.module.model.slab import DecorationsHandler
|
from blenderbim.bim.module.model.slab import DecorationsHandler
|
||||||
|
from blenderbim.bim.module.profile.prop import generate_thumbnail_for_active_profile
|
||||||
|
|
||||||
|
|
||||||
class LoadProfiles(bpy.types.Operator):
|
class LoadProfiles(bpy.types.Operator):
|
||||||
@@ -103,6 +104,7 @@ class EditProfile(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
ifcopenshell.api.run("profile.edit_profile", tool.Ifc.get(), profile=profile, attributes=attributes)
|
ifcopenshell.api.run("profile.edit_profile", tool.Ifc.get(), profile=profile, attributes=attributes)
|
||||||
model_profile.DumbProfileRegenerator().regenerate_from_profile_def(profile)
|
model_profile.DumbProfileRegenerator().regenerate_from_profile_def(profile)
|
||||||
bpy.ops.bim.load_profiles()
|
bpy.ops.bim.load_profiles()
|
||||||
|
generate_thumbnail_for_active_profile()
|
||||||
|
|
||||||
|
|
||||||
class AddProfileDef(bpy.types.Operator, tool.Ifc.Operator):
|
class AddProfileDef(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
@@ -169,6 +171,7 @@ class EditArbitraryProfile(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
profile = tool.Model.export_profile(obj)
|
profile = tool.Model.export_profile(obj)
|
||||||
if not profile:
|
if not profile:
|
||||||
|
|
||||||
def msg(self, context):
|
def msg(self, context):
|
||||||
self.layout.label(text="INVALID PROFILE: " + indices[1])
|
self.layout.label(text="INVALID PROFILE: " + indices[1])
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,11 @@ import bpy
|
|||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.util.schema
|
import ifcopenshell.util.schema
|
||||||
import ifcopenshell.util.attribute
|
import ifcopenshell.util.attribute
|
||||||
|
import blenderbim.tool as tool
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from blenderbim.bim.prop import StrProperty, Attribute
|
from blenderbim.bim.prop import StrProperty, Attribute
|
||||||
from blenderbim.bim.module.profile.data import ProfileData
|
from blenderbim.bim.module.profile.data import ProfileData
|
||||||
|
from blenderbim.bim.helper import draw_image_for_ifc_profile
|
||||||
from bpy.types import PropertyGroup
|
from bpy.types import PropertyGroup
|
||||||
from bpy.props import (
|
from bpy.props import (
|
||||||
PointerProperty,
|
PointerProperty,
|
||||||
@@ -55,3 +57,35 @@ class BIMProfileProperties(PropertyGroup):
|
|||||||
active_profile_id: IntProperty(name="Active Profile Id")
|
active_profile_id: IntProperty(name="Active Profile Id")
|
||||||
profile_attributes: CollectionProperty(name="Profile Attributes", type=Attribute)
|
profile_attributes: CollectionProperty(name="Profile Attributes", type=Attribute)
|
||||||
profile_classes: EnumProperty(items=get_profile_classes, name="Profile Classes")
|
profile_classes: EnumProperty(items=get_profile_classes, name="Profile Classes")
|
||||||
|
|
||||||
|
|
||||||
|
def generate_thumbnail_for_active_profile():
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
if bpy.app.background:
|
||||||
|
return
|
||||||
|
|
||||||
|
props = bpy.context.scene.BIMProfileProperties
|
||||||
|
ifc_file = tool.Ifc.get()
|
||||||
|
preview_collection = ProfileData.preview_collection
|
||||||
|
|
||||||
|
if not props.profiles:
|
||||||
|
bpy.ops.bim.load_profiles()
|
||||||
|
|
||||||
|
profile_id = props.profiles[props.active_profile_index].ifc_definition_id
|
||||||
|
profile = ifc_file.by_id(profile_id)
|
||||||
|
|
||||||
|
# generate image
|
||||||
|
size = 128
|
||||||
|
img = Image.new("RGBA", (size, size))
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
draw_image_for_ifc_profile(draw, profile, size)
|
||||||
|
pixels = [item for sublist in img.getdata() for item in sublist]
|
||||||
|
|
||||||
|
# save generated image to preview collection
|
||||||
|
profile_id_str = str(profile_id)
|
||||||
|
if profile_id_str in preview_collection:
|
||||||
|
del preview_collection[profile_id_str]
|
||||||
|
preview_image = preview_collection.new(profile_id_str)
|
||||||
|
preview_image.image_size = size, size
|
||||||
|
preview_image.image_pixels_float = pixels
|
||||||
|
|||||||
@@ -16,12 +16,15 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# 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/>.
|
||||||
|
|
||||||
|
from bpy.types import Panel, UIList
|
||||||
|
import bpy
|
||||||
|
|
||||||
import blenderbim.bim.helper
|
import blenderbim.bim.helper
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
from bpy.types import Panel, UIList
|
|
||||||
from blenderbim.bim.module.profile.data import ProfileData
|
from blenderbim.bim.module.profile.data import ProfileData
|
||||||
|
from blenderbim.bim.module.profile.prop import generate_thumbnail_for_active_profile
|
||||||
|
|
||||||
|
# Profile Manager Class
|
||||||
class BIM_PT_profiles(Panel):
|
class BIM_PT_profiles(Panel):
|
||||||
bl_label = "IFC Profiles"
|
bl_label = "IFC Profiles"
|
||||||
bl_idname = "BIM_PT_profiles"
|
bl_idname = "BIM_PT_profiles"
|
||||||
@@ -40,6 +43,18 @@ class BIM_PT_profiles(Panel):
|
|||||||
ProfileData.load()
|
ProfileData.load()
|
||||||
self.props = context.scene.BIMProfileProperties
|
self.props = context.scene.BIMProfileProperties
|
||||||
|
|
||||||
|
if self.props.is_editing:
|
||||||
|
preview_collection = ProfileData.preview_collection
|
||||||
|
box = self.layout.box()
|
||||||
|
profile_id = self.props.profiles[self.props.active_profile_index].ifc_definition_id
|
||||||
|
preview_image = preview_collection.get(str(profile_id), None)
|
||||||
|
|
||||||
|
if preview_image:
|
||||||
|
box.template_icon(icon_value=preview_image.icon_id, scale=5)
|
||||||
|
else:
|
||||||
|
# TODO: test if called multiple times before one is loaded
|
||||||
|
generate_thumbnail_for_active_profile()
|
||||||
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.label(text=f"{ProfileData.data['total_profiles']} Named Profiles Found", icon="SNAP_GRID")
|
row.label(text=f"{ProfileData.data['total_profiles']} Named Profiles Found", icon="SNAP_GRID")
|
||||||
if self.props.is_editing:
|
if self.props.is_editing:
|
||||||
|
|||||||
Reference in New Issue
Block a user