mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Fix #2285. You can now get all the elements in a presentation layer.
This commit is contained in:
@@ -20,14 +20,15 @@ import bpy
|
||||
from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.LoadLayers,
|
||||
operator.DisableLayerEditingUI,
|
||||
operator.EnableEditingLayer,
|
||||
operator.DisableEditingLayer,
|
||||
operator.AddPresentationLayer,
|
||||
operator.EditPresentationLayer,
|
||||
operator.RemovePresentationLayer,
|
||||
operator.AssignPresentationLayer,
|
||||
operator.DisableEditingLayer,
|
||||
operator.DisableLayerEditingUI,
|
||||
operator.EditPresentationLayer,
|
||||
operator.EnableEditingLayer,
|
||||
operator.LoadLayers,
|
||||
operator.RemovePresentationLayer,
|
||||
operator.SelectLayerProducts,
|
||||
operator.UnassignPresentationLayer,
|
||||
prop.Layer,
|
||||
prop.BIMLayerProperties,
|
||||
|
||||
@@ -18,9 +18,11 @@
|
||||
|
||||
import bpy
|
||||
import json
|
||||
import ifcopenshell.util.attribute
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.attribute
|
||||
import blenderbim.bim.helper
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.layer.data import Data
|
||||
|
||||
@@ -182,3 +184,19 @@ class UnassignPresentationLayer(bpy.types.Operator):
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SelectLayerProducts(bpy.types.Operator):
|
||||
bl_idname = "bim.select_layer_products"
|
||||
bl_label = "Select Layer Products"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
layer: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
elements = ifcopenshell.util.element.get_elements_by_layer(tool.Ifc.get(), tool.Ifc.get().by_id(self.layer))
|
||||
for obj in context.visible_objects:
|
||||
obj.select_set(False)
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if element and element in elements:
|
||||
obj.select_set(True)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -91,11 +91,17 @@ class BIM_UL_layers(UIList):
|
||||
row.operator("bim.disable_editing_layer", text="", icon="FREEZE", emboss=False)
|
||||
|
||||
if context.scene.BIMLayerProperties.active_layer_id == item.ifc_definition_id:
|
||||
op = row.operator("bim.select_layer_products", text="", icon="RESTRICT_SELECT_OFF")
|
||||
op.layer = item.ifc_definition_id
|
||||
row.operator("bim.edit_presentation_layer", text="", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_layer", text="", icon="CANCEL")
|
||||
elif context.scene.BIMLayerProperties.active_layer_id:
|
||||
op = row.operator("bim.select_layer_products", text="", icon="RESTRICT_SELECT_OFF")
|
||||
op.layer = item.ifc_definition_id
|
||||
row.operator("bim.remove_presentation_layer", text="", icon="X").layer = item.ifc_definition_id
|
||||
else:
|
||||
op = row.operator("bim.select_layer_products", text="", icon="RESTRICT_SELECT_OFF")
|
||||
op.layer = item.ifc_definition_id
|
||||
op = row.operator("bim.enable_editing_layer", text="", icon="GREASEPENCIL")
|
||||
op.layer = item.ifc_definition_id
|
||||
row.operator("bim.remove_presentation_layer", text="", icon="X").layer = item.ifc_definition_id
|
||||
|
||||
@@ -31,6 +31,7 @@ def get_psets(element, psets_only=False, qtos_only=False, should_inherit=True):
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
element = ifcopenshell.by_type("IfcBuildingElement")[0]
|
||||
psets = ifcopenshell.util.element.get_psets(element, psets_only=True)
|
||||
qsets = ifcopenshell.util.element.get_psets(element, qtos_only=True)
|
||||
@@ -120,17 +121,24 @@ def get_properties(properties):
|
||||
|
||||
|
||||
def get_predefined_type(element):
|
||||
"""
|
||||
Retrieves the PrefefinedType attribute of an element.
|
||||
"""Retrieves the PrefefinedType attribute of an element.
|
||||
|
||||
If the predefined type is user defined, the custom type (such as object
|
||||
type, element type, or process type depending on the class) is returned
|
||||
instead. Predefined types from the associated type element are also
|
||||
considered first.
|
||||
|
||||
:param element: The IFC Element entity
|
||||
:type element: ifcopenshell.entity_instance.entity_instance
|
||||
:return: The predefined type of the element
|
||||
:rtype: str
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
element = ifcopenshell.by_type("IfcWall")[0]
|
||||
predefined_type = ifcopenshell.util.element.get_predefined_type(element)
|
||||
|
||||
element = ifcopenshell.by_type("IfcWall")[0]
|
||||
predefined_type = ifcopenshell.util.element.get_predefined_type(element)
|
||||
"""
|
||||
element_type = get_type(element)
|
||||
if element_type:
|
||||
@@ -146,17 +154,19 @@ def get_predefined_type(element):
|
||||
|
||||
|
||||
def get_type(element):
|
||||
"""
|
||||
Retrieves the Element Type entity related to an element entity.
|
||||
"""Retrieves the construction type element of an element occurrence
|
||||
|
||||
:param element: The IFC Element entity
|
||||
:return: The Element Type entity defining the element
|
||||
:param element: The element occurrence
|
||||
:type: ifcopenshell.entity_instance.entity_instance
|
||||
:return: The related type element
|
||||
:rtype ifcopenshell.entity_instance.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
element = ifcopenshell.by_type("IfcWall")[0]
|
||||
element_type = ifcopenshell.util.element.get_type(element)
|
||||
|
||||
element = ifcopenshell.by_type("IfcWall")[0]
|
||||
element_type = ifcopenshell.util.element.get_type(element)
|
||||
"""
|
||||
if element.is_a("IfcTypeObject"):
|
||||
return element
|
||||
@@ -169,6 +179,20 @@ def get_type(element):
|
||||
|
||||
|
||||
def get_types(type):
|
||||
"""Get all the occurrences of a type element
|
||||
|
||||
:param type: The type element
|
||||
:type type: ifcopenshell.entity_instance.entity_instance
|
||||
:return: A list of occurrences of that type
|
||||
:rtype: list[ifcopenshell.entity_instance.entity_instance]
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
element_type = ifcopenshell.by_type("IfcWallType")[0]
|
||||
walls = ifcopenshell.util.element.get_types(element_type)
|
||||
"""
|
||||
for rel in getattr(type, "Types", []):
|
||||
return rel.RelatedObjects
|
||||
for rel in getattr(type, "ObjectTypeOf", []):
|
||||
@@ -177,6 +201,29 @@ def get_types(type):
|
||||
|
||||
|
||||
def get_material(element, should_skip_usage=False, should_inherit=True):
|
||||
"""Gets the material of the element
|
||||
|
||||
The material may be a single material, material set (layered, profiled, or
|
||||
constituent), or a material set usage.
|
||||
|
||||
:param should_skip_usage: If set to True, if the material is a material set
|
||||
usage, the material set itself will be returned. Useful if you don't
|
||||
care about occurrence usage parameters. If False, the usage will be
|
||||
returned.
|
||||
:type should_skip_usage: bool
|
||||
:param should_inherit: If True, any inherited materials from associated
|
||||
types will be considered.
|
||||
:type should_inherit: bool
|
||||
:return: The associated material of the element.
|
||||
:rtype: ifcopenshell.entity_instance.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
element = ifcopenshell.by_type("IfcWall")[0]
|
||||
material = ifcopenshell.util.element.material(element)
|
||||
"""
|
||||
if hasattr(element, "HasAssociations") and element.HasAssociations:
|
||||
for relationship in element.HasAssociations:
|
||||
if relationship.is_a("IfcRelAssociatesMaterial"):
|
||||
@@ -193,15 +240,17 @@ def get_material(element, should_skip_usage=False, should_inherit=True):
|
||||
|
||||
|
||||
def get_elements_by_material(ifc_file, material):
|
||||
"""
|
||||
Retrieves the elements related to a material.
|
||||
"""Retrieves the elements related to a material.
|
||||
|
||||
This includes elements using the material as part of a material set or set
|
||||
usage.
|
||||
|
||||
:param ifc_file: The IFC file
|
||||
:type ifc_file: ifcopenshell.file.file
|
||||
:param material: The IFC Material entity
|
||||
:type material: ifcopenshell.entity_instance.entity_instance
|
||||
:return: A list of elements using the to the material
|
||||
:rtype: list[ifcopenshell.entity_instance.entity_instance]
|
||||
|
||||
Example:
|
||||
|
||||
@@ -233,12 +282,14 @@ def get_elements_by_material(ifc_file, material):
|
||||
|
||||
|
||||
def get_elements_by_style(ifc_file, style):
|
||||
"""
|
||||
Retrieves the elements related to a style.
|
||||
"""Retrieves the elements whose geometric representation uses a style
|
||||
|
||||
:param ifc_file: The IFC file
|
||||
:param style: The IFC Style entity
|
||||
:type ifc_file: ifcopenshell.file.file
|
||||
:param style: The IfcPresentationStyle entity
|
||||
:type style: ifcopenshell.entity_instance.entity_instance
|
||||
:return: The elements related to the style
|
||||
:rtype: list[ifcopenshell.entity_instance.entity_instance]
|
||||
|
||||
Example:
|
||||
|
||||
@@ -271,6 +322,22 @@ def get_elements_by_style(ifc_file, style):
|
||||
|
||||
|
||||
def get_elements_by_representation(ifc_file, representation):
|
||||
"""Gets all elements using a geometric representation
|
||||
|
||||
:param ifc_file: The IFC file
|
||||
:type ifc_file: ifcopenshell.file.file
|
||||
:param representation: The IfcShapeRepresentation representation
|
||||
:type representation: ifcopenshell.entity_instance.entity_instance
|
||||
:return: The elements using the geometric representation
|
||||
:rtype: list[ifcopenshell.entity_instance.entity_instance]
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
representation = file.by_type("IfcShapeRepresentation")[0]
|
||||
elements = ifcopenshell.util.element.get_elements_by_representation(file, representation)
|
||||
"""
|
||||
results = set()
|
||||
[results.update(pr.ShapeOfProduct) for pr in representation.OfProductRepresentation]
|
||||
for rep_map in representation.RepresentationMap:
|
||||
@@ -286,7 +353,47 @@ def get_elements_by_representation(ifc_file, representation):
|
||||
return results
|
||||
|
||||
|
||||
def get_elements_by_layer(ifc_file, layer):
|
||||
"""Get all the elements that are used by a presentation layer
|
||||
|
||||
:param ifc_file: The IFC file
|
||||
:type ifc_file: ifcopenshell.file.file
|
||||
:param layer: The IfcPresentationLayerAssignment layer
|
||||
:type layer: ifcopenshell.entity_instance.entity_instance
|
||||
:return: The elements using the geometric representation
|
||||
:rtype: list[ifcopenshell.entity_instance.entity_instance]
|
||||
"""
|
||||
results = set()
|
||||
for item in layer.AssignedItems:
|
||||
if item.is_a("IfcShapeRepresentation"):
|
||||
results.update(get_elements_by_representation(ifc_file, item))
|
||||
elif item.is_a("IfcRepresentationItem"):
|
||||
for inverse in ifc_file.get_inverse(item):
|
||||
if inverse.is_a("IfcShapeRepresentation"):
|
||||
results.update(get_elements_by_representation(ifc_file, inverse))
|
||||
return results
|
||||
|
||||
|
||||
def get_layers(ifc_file, element):
|
||||
"""Get the CAD layers that an element is part of
|
||||
|
||||
An element may have portions or all of its geometry assigned to a
|
||||
traditional CAD presentation layer.
|
||||
|
||||
:param ifc_file: The IFC file object
|
||||
:type ifc_file: ifcopenshell.file.file
|
||||
:param element: The IFC element to interrogate
|
||||
:type element: ifcopenshell.entity_instance.entity_instance
|
||||
:return: A list of IfcPresentationLayerAssignment
|
||||
:rtype: list[ifcopenshell.entity_instance.entity_instance]
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
element = ifcopenshell.by_type("IfcWall")[0]
|
||||
layers = ifcopenshell.util.element.get_layers(element)
|
||||
"""
|
||||
layers = []
|
||||
representations = []
|
||||
if getattr(element, "Representation", None):
|
||||
@@ -338,10 +445,11 @@ def get_container(element, should_get_direct=False):
|
||||
|
||||
|
||||
def get_referenced_structures(element):
|
||||
"""
|
||||
Retreives a list of referenced spatial elements, typically useful for
|
||||
multistorey elements or elements that span multiple spaces or in-between
|
||||
spaces.
|
||||
"""Retreives a list of referenced spatial elements
|
||||
|
||||
Typically useful for multistorey elements, such as columns or facade
|
||||
elements, or elements that span multiple spaces or in-between spaces, such
|
||||
as stairs, doors, etc.
|
||||
|
||||
:param element: The IFC element
|
||||
:type element: ifcopenshell.entity_instance.entity_instance
|
||||
@@ -469,6 +577,10 @@ def has_element_reference(value, element):
|
||||
|
||||
|
||||
def remove_deep(ifc_file, element):
|
||||
"""Recursively purges a subgraph safely.
|
||||
|
||||
Do not use, use remove_deep2() instead.
|
||||
"""
|
||||
# @todo maybe some sort of try-finally mechanism.
|
||||
ifc_file.batch()
|
||||
subgraph = list(ifc_file.traverse(element, breadth_first=True))
|
||||
@@ -480,8 +592,7 @@ def remove_deep(ifc_file, element):
|
||||
|
||||
|
||||
def remove_deep2(ifc_file, element, also_consider=[], do_not_delete=[]):
|
||||
"""
|
||||
Recursively purges a subgraph safely, starting at an element
|
||||
"""Recursively purges a subgraph safely, starting at an element
|
||||
|
||||
This should always be used instead of remove_deep. See #1812. The start
|
||||
element must have no inverses. The subgraph to be purged is calculated using
|
||||
@@ -505,6 +616,8 @@ def remove_deep2(ifc_file, element, also_consider=[], do_not_delete=[]):
|
||||
The do_not_delete argument contains all elements that may be part of the
|
||||
subgraph but are protected from deletion.
|
||||
|
||||
:param ifc_file: The IFC file object
|
||||
:type ifc_file: ifcopenshell.file.file
|
||||
:param element: The starting element that defines the subgraph
|
||||
:type element: ifcopenshell.entity_instance.entity_instance
|
||||
"""
|
||||
@@ -536,8 +649,11 @@ def copy(ifc_file, element):
|
||||
GlobalIds are regenerated.
|
||||
|
||||
:param ifc_file: The IFC file object
|
||||
:type ifc_file: ifcopenshell.file.file
|
||||
:param element: The IFC element to copy
|
||||
:type element: ifcopenshell.entity_instance.entity_instance
|
||||
:return: The newly copied element
|
||||
:rtype: ifcopenshell.entity_instance.entity_instance
|
||||
"""
|
||||
new = ifc_file.create_entity(element.is_a())
|
||||
for i, attribute in enumerate(element):
|
||||
@@ -557,11 +673,14 @@ def copy_deep(ifc_file, element, exclude=None):
|
||||
GlobalIds are regenerated.
|
||||
|
||||
:param ifc_file: The IFC file object
|
||||
:type ifc_file: ifcopenshell.file.file
|
||||
:param element: The IFC element to copy
|
||||
:type element: ifcopenshell.entity_instance.entity_instance
|
||||
:param exclude: An optional list of strings of IFC class names to not copy.
|
||||
If any of the subelement is this class, it will not be copied and the
|
||||
original instance will be referenced.
|
||||
:return: The newly copied element
|
||||
:rtype: ifcopenshell.entity_instance.entity_instance
|
||||
"""
|
||||
new = ifc_file.create_entity(element.is_a())
|
||||
for i, attribute in enumerate(element):
|
||||
|
||||
@@ -441,9 +441,7 @@ class TestGetElementsByRepresentation(test.bootstrap.IFC4):
|
||||
self.file.createIfcShapeRepresentation(
|
||||
Items=[
|
||||
self.file.createIfcMappedItem(
|
||||
MappingSource=self.file.createIfcRepresentationMap(
|
||||
MappedRepresentation=representation
|
||||
)
|
||||
MappingSource=self.file.createIfcRepresentationMap(MappedRepresentation=representation)
|
||||
)
|
||||
]
|
||||
)
|
||||
@@ -458,6 +456,16 @@ class TestGetElementsByRepresentation(test.bootstrap.IFC4):
|
||||
assert subject.get_elements_by_representation(self.file, representation) == {element}
|
||||
|
||||
|
||||
class TestGetElementsByLayer(test.bootstrap.IFC4):
|
||||
def test_getting_the_elements_of_a_layer(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
layer = ifcopenshell.api.run("layer.add_layer", self.file)
|
||||
representation = self.file.createIfcShapeRepresentation()
|
||||
element.Representation = self.file.createIfcProductDefinitionShape(Representations=[representation])
|
||||
ifcopenshell.api.run("layer.assign_layer", self.file, item=representation, layer=layer)
|
||||
assert list(subject.get_elements_by_layer(self.file, layer)) == [element]
|
||||
|
||||
|
||||
class TestGetlayers(test.bootstrap.IFC4):
|
||||
def test_getting_the_layer_of_a_product_representation(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
|
||||
Reference in New Issue
Block a user