This commit is contained in:
Andrej730
2024-11-08 11:04:18 +05:00
parent 1d3ca475d9
commit fe8c396e12
4 changed files with 17 additions and 99 deletions
@@ -25,6 +25,7 @@ import shutil
import mathutils
import xml.etree.ElementTree as ET
import svgwrite
import svgwrite.text
import ifcopenshell
import ifcopenshell.util.element
import ifcopenshell.util.representation
@@ -774,7 +775,7 @@ class SvgWriter:
"text-anchor": text_anchor,
}
def add_fill_bg(self, element, copy=True):
def add_fill_bg(self, element: svgwrite.text.Text, copy: bool = True) -> svgwrite.text.Text:
if copy:
element = element.copy()
if hasattr(element, "xml"):
+4 -2
View File
@@ -16,10 +16,12 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import bonsai.bim.helper
from bpy.types import Panel, UIList
from bonsai.bim.ifc import IfcStore
from bonsai.bim.module.resource.data import ResourceData
from typing import Any
class BIM_PT_resources(Panel):
@@ -287,7 +289,7 @@ class BIM_PT_resources(Panel):
if self.props.cost_value_editing_type == "ATTRIBUTES":
bonsai.bim.helper.draw_attributes(self.props.cost_value_attributes, self.layout.box())
def draw_readonly_cost_value_ui(self, layout, cost_value):
def draw_readonly_cost_value_ui(self, layout: bpy.types.UILayout, cost_value: dict[str, Any]) -> None:
if self.props.active_cost_value_id == cost_value["id"] and self.props.cost_value_editing_type == "FORMULA":
layout.prop(self.props, "cost_value_formula", text="")
else:
@@ -295,7 +297,7 @@ class BIM_PT_resources(Panel):
self.draw_cost_value_operator_ui(layout, cost_value["id"], self.props.active_resource_id)
def draw_cost_value_operator_ui(self, layout, cost_value_id, parent_id):
def draw_cost_value_operator_ui(self, layout: bpy.types.UILayout, cost_value_id: int, parent_id: int) -> None:
if self.props.active_cost_value_id and self.props.active_cost_value_id == cost_value_id:
if self.props.cost_value_editing_type == "ATTRIBUTES":
op = layout.operator("bim.edit_resource_cost_value", text="", icon="CHECKMARK")
@@ -53,20 +53,13 @@ def get_pset(
occurrence, not the type's pset.
:param element: The IFC Element entity
:type element: ifcopenshell.entity_instance
:param name: The name of the pset
:type name: str
:param prop: The name of the property
:type prop: str,optional
:param psets_only: Default as False. Set to true if only property sets are needed.
:type psets_only: bool,optional
:param qtos_only: Default as False. Set to true if only quantities are needed.
:type qtos_only: bool,optional
:param should_inherit: Default as True. Set to false if you don't want to inherit property sets from the Type.
:type should_inherit: bool,optional
:return: A dictionary of property names and values, or a single value if a
property is specified.
:rtype: Union[Any, dict[str, Any]]
Example:
@@ -157,17 +150,11 @@ def get_psets(
occurrence, not the type's pset.
:param element: The IFC Element entity
:type element: ifcopenshell.entity_instance
:param psets_only: Default as False. Set to true if only property sets are needed.
:type psets_only: bool,optional
:param qtos_only: Default as False. Set to true if only quantities are needed.
:type qtos_only: bool,optional
:param should_inherit: Default as True. Set to false if you don't want to inherit property sets from the Type.
:type should_inherit: bool,optional
:param verbose: More detailed prop values, defaults to False.
:type verbose: bool,optional
:return: Key, value pair of psets' names and their properties' names & values
:rtype: dict[str, dict[str, Any]]
Example:
@@ -471,9 +458,7 @@ def get_predefined_type(element: ifcopenshell.entity_instance) -> str:
considered first.
:param element: The IFC Element entity
:type element: ifcopenshell.entity_instance
:return: The predefined type of the element
:rtype: str
Example:
@@ -503,9 +488,7 @@ def get_type(element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity
Note: `get_type(type_element) == type_element`.
:param element: The element occurrence (IfcObject)
:type: ifcopenshell.entity_instance
:return: The related type element
:rtype: Union[ifcopenshell.entity_instance, None]
Example:
@@ -533,9 +516,7 @@ def get_types(type: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_in
"""Get all the occurrences of a type element
:param type: The type element
:type type: ifcopenshell.entity_instance
:return: A list of occurrences of that type
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -588,17 +569,13 @@ def get_material(
constituent), or a material set usage.
:param element: The element to get the material of.
:type element: ifcopenshell.entity_instance
: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 or `None`.
:rtype: Union[ifcopenshell.entity_instance, None]
Example:
@@ -632,11 +609,9 @@ def get_materials(
returned as a list.
:param element: The element to get the materials of.
:type element: ifcopenshell.entity_instance
:param should_inherit: If True, any inherited materials from associated
types will be considered.
:return: The associated materials of the element.
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -658,6 +633,8 @@ def get_materials(
return [c.Material for c in material.MaterialConstituents]
elif material.is_a("IfcMaterialList"):
return list(material.Materials)
else:
assert False, f"Unexpected material type: {material.is_a()}"
def get_styles(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
@@ -666,9 +643,7 @@ def get_styles(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entit
Styles may be retreived from the material or the body representation.
:param element: The element to get the styles of.
:type element: ifcopenshell.entity_instance
:return: A list of surface styles
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -749,15 +724,12 @@ def get_elements_by_material(
def get_elements_by_style(
ifc_file: ifcopenshell.file, style: ifcopenshell.entity_instance
) -> list[ifcopenshell.entity_instance]:
) -> set[ifcopenshell.entity_instance]:
"""Retrieves the elements whose geometric representation uses a style
:param ifc_file: The IFC file
:type ifc_file: ifcopenshell.file
:param style: The IfcPresentationStyle entity
:type style: ifcopenshell.entity_instance
:return: The elements related to the style
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -804,11 +776,8 @@ def get_elements_by_representation(
"""Gets all elements using a geometric representation
:param ifc_file: The IFC file
:type ifc_file: ifcopenshell.file
:param representation: The IfcShapeRepresentation representation
:type representation: ifcopenshell.entity_instance
:return: The elements using the geometric representation
:rtype: set[ifcopenshell.entity_instance]
Example:
@@ -834,15 +803,12 @@ def get_elements_by_representation(
def get_elements_by_layer(
ifc_file: ifcopenshell.file, layer: ifcopenshell.entity_instance
) -> list[ifcopenshell.entity_instance]:
) -> set[ifcopenshell.entity_instance]:
"""Get all the elements that are used by a presentation layer
:param ifc_file: The IFC file
:type ifc_file: ifcopenshell.file
:param layer: The IfcPresentationLayerAssignment layer
:type layer: ifcopenshell.entity_instance
:return: The elements using the geometric representation
:rtype: list[ifcopenshell.entity_instance]
"""
results = set()
for item in layer.AssignedItems or []:
@@ -864,11 +830,8 @@ def get_layers(
traditional CAD presentation layer.
:param ifc_file: The IFC file object
:type ifc_file: ifcopenshell.file
:param element: The IFC element to interrogate
:type element: ifcopenshell.entity_instance
:return: A list of IfcPresentationLayerAssignment
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -902,18 +865,14 @@ def get_container(
Retrieves the spatial structure container of an element.
:param element: The IFC element
:type element: ifcopenshell.entity_instance
:param should_get_direct: If True, a result is only returned if the element
is directly contained in a spatial structure element. If False, an
indirect spatial container may be returned, such as if an element is a
part of an aggregate, and then if that aggregate is contained in a
spatial structure element.
:type should_get_direct: bool
:param ifc_class: Optionally filter the type of container you're after. For
example, you may be after the storey, not a space.
:type ifc_class: str, optional
:return: The direct or indirect container of the element or None.
:rtype: Union[ifcopenshell.entity_instance, None]
Example:
@@ -958,9 +917,7 @@ def get_referenced_structures(element: ifcopenshell.entity_instance) -> list[ifc
as stairs, doors, etc.
:param element: The IFC element
:type element: ifcopenshell.entity_instance
:return: A list of IfcSpatialElement
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -976,9 +933,7 @@ def get_structure_referenced_elements(structure: ifcopenshell.entity_instance) -
"""Retreives a set of elements referenced by a structure
:param structure: IfcSpatialElement
:type element: ifcopenshell.entity_instance
:return: A set of referenced elements, IfcSpatialReferenceSelect
:rtype: set[ifcopenshell.entity_instance]
Example:
@@ -1000,9 +955,7 @@ def get_decomposition(element: ifcopenshell.entity_instance, is_recursive=True)
parts of an aggreate, all openings, and all fills of any openings.
:param element: The IFC element
:type element: ifcopenshell.entity_instance
:return: The decomposition of the element
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -1044,9 +997,7 @@ def get_grouped_by(element: ifcopenshell.entity_instance) -> list[ifcopenshell.e
"""Retrieves all subelements of an element based on the group.
:param element: IfcGroup entity
:type element: ifcopenshell.entity_instance
:return: All subelements of the group
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -1072,7 +1023,6 @@ def get_groups(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entit
:param element: The IFC element
:return: List of IfcGroups element is assigned to.
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -1105,9 +1055,7 @@ def get_parent(element: ifcopenshell.entity_instance) -> Union[ifcopenshell.enti
- Voiding: the opening voids another physical element, such as a hole in a wall
:param element: Any physical or spatial element in the tree
:type element: ifcopenshell.entity_instance
:return: Its parent. This must exist for any valid file, or None if we've reached the IfcProject.
:rtype: Union[ifcopenshell.entity_instance, None]
Example:
@@ -1131,9 +1079,7 @@ def get_filled_void(element: ifcopenshell.entity_instance) -> Union[ifcopenshell
Examples include windows and doors which fill a opening inside a wall.
:param element: The building element, typically a window or door
:type element: ifcopenshell.entity_instance
:return: The IfcOpeningElement that it is filling
:rtype: Union[ifcopenshell.entity_instance, None]
Example:
@@ -1152,9 +1098,7 @@ def get_voided_element(element: ifcopenshell.entity_instance) -> Union[ifcopensh
For all valid models, this should never return None.
:param element: The IfcOpeningElement
:type element: ifcopenshell.entity_instance
:return: The building element, such as a wall or slab
:rtype: Union[ifcopenshell.entity_instance, None]
Example:
@@ -1172,9 +1116,7 @@ def get_aggregate(element: ifcopenshell.entity_instance) -> Union[ifcopenshell.e
Retrieves the aggregate parent of an element.
:param element: The IFC element
:type element: ifcopenshell.entity_instance
:return: The aggregate of the element
:rtype: Union[ifcopenshell.entity_instance, None]
Example:
@@ -1193,9 +1135,7 @@ def get_nest(element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity
Retrieves the nest parent of an element.
:param element: The IFC element
:type element: ifcopenshell.entity_instance
:return: The nested whole of the element
:rtype: Union[ifcopenshell.entity_instance, None]
Example:
@@ -1217,9 +1157,7 @@ def get_parts(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entity
Retrieves the parts of an element that have an aggregation relationship.
:param element: The IFC element
:type element: ifcopenshell.entity_instance
:return: The parts of the element
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -1239,9 +1177,7 @@ def get_contained(element: ifcopenshell.entity_instance) -> list[ifcopenshell.en
Retrieves the contained elements of spatial element.
:param element: The IFC element
:type element: ifcopenshell.entity_instance
:return: The parts of the element
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -1263,9 +1199,7 @@ def get_components(element: ifcopenshell.entity_instance, include_ports=False) -
:param element: The IFC element
:param include_ports: Default as False. Set to true if you also want to get ports.
:type include_ports: bool,optional
:return: The components of the element
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -1314,9 +1248,7 @@ def get_referenced_elements(reference: ifcopenshell.entity_instance) -> set[ifco
"""Get all elements with assigned `reference`
:param reference: IfcExternalReference/IfcExternalInformation subtype reference
:type reference: ifcopenshell.entity_instance
:return: The elements with assigned `reference`
:rtype: set[ifcopenshell.entity_instance]
Example:
@@ -1401,8 +1333,6 @@ def batch_remove_deep2(ifc_file: ifcopenshell.file) -> None:
on existing variables in memory.
:param ifc_file: The IFC file object
:type ifc_file: ifcopenshell.file
:rtype: None
Example:
@@ -1428,9 +1358,7 @@ def unbatch_remove_deep2(ifc_file: ifcopenshell.file) -> ifcopenshell.file:
See documentation for batch_remove_deep2.
:param ifc_file: The IFC file object
:type ifc_file: ifcopenshell.file
:return: A newly loaded file with the elements removed.
:rtype: ifcopenshell.file
"""
ifc_string = ifc_file.to_string()
lines = iter(ifc_string.split("\n"))
@@ -1483,13 +1411,9 @@ def remove_deep2(
subgraph but are protected from deletion.
:param ifc_file: The IFC file object
:type ifc_file: ifcopenshell.file
:param also_consider: elements to also consider as a part of a subgraph
:type also_consider: list[ifcopenshell.entity_instance], optional
:param do_not_delete: elements to protect from deletion
:type do_not_delete: list[ifcopenshell.entity_instance], optional
:param element: The starting element that defines the subgraph
:type element: ifcopenshell.entity_instance
"""
# ifc_file.batch()
also_considered_inverses = 0
@@ -1554,11 +1478,8 @@ def copy(ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance) ->
GlobalIds are regenerated.
:param ifc_file: The IFC file object
:type ifc_file: ifcopenshell.file
:param element: The IFC element to copy
:type element: ifcopenshell.entity_instance
:return: The newly copied element
:rtype: ifcopenshell.entity_instance
"""
new = ifc_file.create_entity(element.is_a())
for i, attribute in enumerate(element):
@@ -1584,22 +1505,16 @@ def copy_deep(
GlobalIds are regenerated.
:param ifc_file: The IFC file object
:type ifc_file: ifcopenshell.file
:param element: The IFC element to copy
:type element: ifcopenshell.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.
:type exclude: list[str],optional
:param exclude_callback: A callback to determine whether or not to exclude
an entity or not. Returns True to exclude and False to exclude.
:type exclude_callback: function,optional
:param copied_entities: A dictionary of IDs as keys and entities as values
to reuse when coming across the same entity twice. This can typically
be left as None.
:type copied_entities: dict[int:ifcopenshell.entity_instance], optional
:return: The newly copied element
:rtype: ifcopenshell.entity_instance
"""
if copied_entities is None:
copied_entities = {}
@@ -1653,11 +1568,8 @@ def has_property(product: ifcopenshell.entity_instance, property_name: str) -> b
Check if a product has a property with a given name.
:param product: The IFC product
:type product: ifcopenshell.entity_instance
:param property_name: The property name
:type property_name: str
:return: True if the product has the property, False otherwise
:rtype: bool
Example:
@@ -27,7 +27,9 @@ from logging import Logger
class Patcher:
def __init__(self, src: str, file: ifcopenshell.file, logger: Logger, filepaths: Union[str, ifcopenshell.file]):
def __init__(
self, src: str, file: ifcopenshell.file, logger: Logger, filepaths: list[Union[str, ifcopenshell.file]]
):
"""Merge two or more IFC models into one
Note that other than combining the two (or more) IfcProject elements into
@@ -40,7 +42,7 @@ class Patcher:
:param filepaths: The filepath(s) of the second (, third, ...) IFC model
to merge into the first. The first model is already specified as the
input to IfcPatch.
:type filepaths: Union[str, ifcopenshell.file]
:type filepaths: list[Union[str, ifcopenshell.file]]
:filter_glob filepaths: *.ifc;*.ifczip;*.ifcxml
Example:
@@ -60,10 +62,11 @@ class Patcher:
other = filepath
else:
other = ifcopenshell.open(filepath)
assert isinstance(other, ifcopenshell.file)
self.merge(other)
def merge(self, other):
def merge(self, other: ifcopenshell.file) -> None:
if (main_unit := self.get_unit_name(self.file)) != self.get_unit_name(other):
other = ifcopenshell.util.unit.convert_file_length_units(other, main_unit)
@@ -128,7 +131,7 @@ class Patcher:
length_unit = ifcopenshell.util.unit.get_project_unit(ifc_file, "LENGTHUNIT")
return ifcopenshell.util.unit.get_full_unit_name(length_unit)
def reuse_existing_contexts(self):
def reuse_existing_contexts(self) -> None:
to_delete = set()
for added_context in self.added_contexts: