mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
You can now query data about a linked object from a SQLite cache.
This commit is contained in:
@@ -39,6 +39,7 @@ classes = (
|
||||
operator.LoadProject,
|
||||
operator.LoadProjectElements,
|
||||
operator.NewProject,
|
||||
operator.QueryLinkedElement,
|
||||
operator.RefreshLibrary,
|
||||
operator.ReloadLink,
|
||||
operator.RevertProject,
|
||||
|
||||
@@ -65,5 +65,6 @@ class ProjectData:
|
||||
|
||||
|
||||
class LinksData:
|
||||
linked_data = {}
|
||||
enable_culling = False
|
||||
is_loaded = False
|
||||
|
||||
@@ -1469,6 +1469,133 @@ class LoadLinkedProject(bpy.types.Operator):
|
||||
self.collection.objects.link(obj)
|
||||
|
||||
|
||||
class QueryLinkedElement(bpy.types.Operator):
|
||||
bl_idname = "bim.query_linked_element"
|
||||
bl_label = "Query Linked Element"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.area.type == "VIEW_3D"
|
||||
|
||||
def execute(self, context):
|
||||
import sqlite3
|
||||
from bpy_extras.view3d_utils import region_2d_to_vector_3d, region_2d_to_origin_3d
|
||||
|
||||
LinksData.linked_data = {}
|
||||
bpy.context.scene.BIMProjectProperties.queried_obj = None
|
||||
|
||||
for area in bpy.context.screen.areas:
|
||||
if area.type == "PROPERTIES":
|
||||
for region in area.regions:
|
||||
if region.type == "WINDOW":
|
||||
region.tag_redraw()
|
||||
elif area.type == "VIEW_3D":
|
||||
area.tag_redraw()
|
||||
|
||||
region = context.region
|
||||
rv3d = context.region_data
|
||||
coord = (self.mouse_x, self.mouse_y)
|
||||
origin = region_2d_to_origin_3d(region, rv3d, coord)
|
||||
direction = region_2d_to_vector_3d(region, rv3d, coord)
|
||||
hit, location, normal, face_index, obj, matrix = self.ray_cast(context, origin, direction)
|
||||
if not hit:
|
||||
self.report({"INFO"}, "No object found.")
|
||||
return {"FINISHED"}
|
||||
|
||||
if "guids" not in obj:
|
||||
self.report({"INFO"}, "Object is not a linked IFC element.")
|
||||
return {"FINISHED"}
|
||||
|
||||
guid = None
|
||||
guid_start_index = 0
|
||||
for i, guid_end_index in enumerate(obj["guid_ids"]):
|
||||
if face_index < guid_end_index:
|
||||
guid = obj["guids"][i]
|
||||
bpy.context.scene.BIMProjectProperties.queried_obj = obj
|
||||
|
||||
selected_tris = []
|
||||
selected_edges = []
|
||||
vert_indices = set()
|
||||
for polygon in obj.data.polygons[guid_start_index:guid_end_index]:
|
||||
vert_indices.update(polygon.vertices)
|
||||
vert_indices = list(vert_indices)
|
||||
vert_map = {k: v for v, k in enumerate(vert_indices)}
|
||||
selected_vertices = [tuple(obj.matrix_world @ obj.data.vertices[vi].co) for vi in vert_indices]
|
||||
for polygon in obj.data.polygons[guid_start_index:guid_end_index]:
|
||||
selected_tris.append(tuple(vert_map[v] for v in polygon.vertices))
|
||||
selected_edges.extend(tuple([vert_map[vi] for vi in e] for e in polygon.edge_keys))
|
||||
|
||||
obj["selected_vertices"] = selected_vertices
|
||||
obj["selected_edges"] = selected_edges
|
||||
obj["selected_tris"] = selected_tris
|
||||
|
||||
break
|
||||
guid_start_index = guid_end_index
|
||||
|
||||
self.db = sqlite3.connect(obj["db"])
|
||||
self.c = self.db.cursor()
|
||||
|
||||
self.c.execute(f"SELECT * FROM elements WHERE global_id = '{guid}' LIMIT 1")
|
||||
element = self.c.fetchone()
|
||||
|
||||
attributes = {}
|
||||
for i, attr in enumerate(["GlobalId", "IFC Class", "Predefined Type", "Name", "Description"]):
|
||||
if element[i + 1] is not None:
|
||||
attributes[attr] = element[i + 1]
|
||||
|
||||
self.c.execute("SELECT * FROM properties WHERE element_id = ?", (element[0],))
|
||||
rows = self.c.fetchall()
|
||||
|
||||
properties = {}
|
||||
for row in rows:
|
||||
properties.setdefault(row[1], {})[row[2]] = row[3]
|
||||
|
||||
self.c.execute("SELECT * FROM relationships WHERE from_id = ?", (element[0],))
|
||||
relationships = self.c.fetchall()
|
||||
|
||||
relating_type_id = None
|
||||
|
||||
for relationship in relationships:
|
||||
if relationship[1] == "IfcRelDefinesByType":
|
||||
relating_type_id = relationship[2]
|
||||
|
||||
type_properties = {}
|
||||
if relating_type_id is not None:
|
||||
self.c.execute("SELECT * FROM properties WHERE element_id = ?", (relating_type_id,))
|
||||
rows = self.c.fetchall()
|
||||
for row in rows:
|
||||
type_properties.setdefault(row[1], {})[row[2]] = row[3]
|
||||
|
||||
LinksData.linked_data = {
|
||||
"attributes": attributes,
|
||||
"properties": [(k, properties[k]) for k in sorted(properties.keys())],
|
||||
"type_properties": [(k, type_properties[k]) for k in sorted(type_properties.keys())],
|
||||
}
|
||||
|
||||
for area in bpy.context.screen.areas:
|
||||
if area.type == "PROPERTIES":
|
||||
for region in area.regions:
|
||||
if region.type == "WINDOW":
|
||||
region.tag_redraw()
|
||||
elif area.type == "VIEW_3D":
|
||||
area.tag_redraw()
|
||||
|
||||
self.report({"INFO"}, f"Loaded data for {guid}")
|
||||
ProjectDecorator.install(bpy.context)
|
||||
return {"FINISHED"}
|
||||
|
||||
def ray_cast(self, context, origin, direction):
|
||||
depsgraph = context.evaluated_depsgraph_get()
|
||||
result = context.scene.ray_cast(depsgraph, origin, direction)
|
||||
return result
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.mouse_x = event.mouse_region_x
|
||||
self.mouse_y = event.mouse_region_y
|
||||
return self.execute(context)
|
||||
|
||||
|
||||
class EnableCulling(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_culling"
|
||||
bl_label = "Enable Culling"
|
||||
|
||||
@@ -170,6 +170,7 @@ class BIMProjectProperties(PropertyGroup):
|
||||
export_schema: EnumProperty(items=get_export_schema, name="IFC Schema")
|
||||
template_file: EnumProperty(items=get_template_file, name="Template File")
|
||||
use_relative_project_path: BoolProperty(name="Use Relative Project Path", default=False)
|
||||
queried_obj: bpy.props.PointerProperty(type=bpy.types.Object)
|
||||
|
||||
def get_library_element_index(self, lib_element):
|
||||
return next((i for i in range(len(self.library_elements)) if self.library_elements[i] == lib_element))
|
||||
|
||||
@@ -21,7 +21,7 @@ import blenderbim.bim
|
||||
from blenderbim.bim.helper import prop_with_search
|
||||
from bpy.types import Panel, Menu, UIList
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.project.data import ProjectData
|
||||
from blenderbim.bim.module.project.data import ProjectData, LinksData
|
||||
|
||||
|
||||
class BIM_MT_project(Menu):
|
||||
@@ -307,6 +307,41 @@ class BIM_PT_links(Panel):
|
||||
"active_link_index",
|
||||
)
|
||||
|
||||
if LinksData.enable_culling:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Object Culling Enabled", icon="MOD_TRIANGULATE")
|
||||
|
||||
if not LinksData.linked_data:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="No Object Selected", icon="QUESTION")
|
||||
return
|
||||
|
||||
for name, value in LinksData.linked_data["attributes"].items():
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=name)
|
||||
row.label(text=value)
|
||||
|
||||
for pset in LinksData.linked_data["properties"]:
|
||||
box = self.layout.box()
|
||||
row = box.row(align=True)
|
||||
row.label(text=pset[0], icon="COPY_ID")
|
||||
for name, value in pset[1].items():
|
||||
row = box.row(align=True)
|
||||
row.label(text=name)
|
||||
row.label(text=value)
|
||||
|
||||
if LinksData.linked_data["type_properties"]:
|
||||
row = self.layout.row()
|
||||
row.label(icon="LINKED", text="Type Properties")
|
||||
for pset in LinksData.linked_data["type_properties"]:
|
||||
box = self.layout.box()
|
||||
row = box.row(align=True)
|
||||
row.label(text=pset[0], icon="COPY_ID")
|
||||
for name, value in pset[1].items():
|
||||
row = box.row(align=True)
|
||||
row.label(text=name)
|
||||
row.label(text=value)
|
||||
|
||||
|
||||
class BIM_UL_library(UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
|
||||
Reference in New Issue
Block a user