This commit is contained in:
Andrej730
2024-03-20 12:22:23 +05:00
parent a511be18a8
commit acafc910f7
7 changed files with 51 additions and 26 deletions
+13 -7
View File
@@ -38,8 +38,9 @@ import blenderbim.tool as tool
import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper
from itertools import chain, accumulate from itertools import chain, accumulate
from blenderbim.bim.ifc import IfcStore, IFC_CONNECTED_TYPE from blenderbim.bim.ifc import IfcStore, IFC_CONNECTED_TYPE
from blenderbim.tool.loader import OBJECT_DATA_TYPE
from blenderbim.bim.module.drawing.prop import ANNOTATION_TYPES_DATA from blenderbim.bim.module.drawing.prop import ANNOTATION_TYPES_DATA
from typing import Dict, Union, Optional from typing import Dict, Union, Optional, Any
class MaterialCreator: class MaterialCreator:
@@ -855,10 +856,10 @@ class IfcImporter:
self.create_product(element, mesh=mesh) self.create_product(element, mesh=mesh)
print("Done creating geometry") print("Done creating geometry")
def create_spatial_elements(self): def create_spatial_elements(self) -> None:
self.create_generic_elements(self.spatial_elements) self.create_generic_elements(self.spatial_elements, unselectable=True)
def create_elements(self): def create_elements(self) -> None:
self.create_generic_elements(self.elements) self.create_generic_elements(self.elements)
tmp = self.context_settings tmp = self.context_settings
self.context_settings = self.gross_context_settings self.context_settings = self.gross_context_settings
@@ -876,7 +877,7 @@ class IfcImporter:
except: except:
pass pass
def create_generic_elements(self, elements: set[ifcopenshell.entity_instance]) -> None: def create_generic_elements(self, elements: set[ifcopenshell.entity_instance], unselectable=False) -> None:
if isinstance(self.file, ifcopenshell.sqlite): if isinstance(self.file, ifcopenshell.sqlite):
return self.create_generic_sqlite_elements(elements) return self.create_generic_sqlite_elements(elements)
@@ -1108,7 +1109,12 @@ class IfcImporter:
self.link_element(product, obj) self.link_element(product, obj)
return product return product
def create_product(self, element, shape=None, mesh=None): def create_product(
self,
element: ifcopenshell.entity_instance,
shape: Optional[Any] = None,
mesh: Optional[OBJECT_DATA_TYPE] = None,
) -> Union[bpy.types.Object, None]:
if element is None: if element is None:
return return
@@ -1833,7 +1839,7 @@ class IfcImporter:
): ):
return representation.Items[0].MappingTarget return representation.Items[0].MappingTarget
def create_curve(self, element, shape): def create_curve(self, element: ifcopenshell.entity_instance, shape) -> bpy.types.Curve:
if hasattr(shape, "geometry"): if hasattr(shape, "geometry"):
geometry = shape.geometry geometry = shape.geometry
else: else:
+7 -3
View File
@@ -26,6 +26,7 @@ import os
import numpy as np import numpy as np
from mathutils import Vector from mathutils import Vector
from pathlib import Path from pathlib import Path
from typing import Union
# Progressively we'll refactor loading elements into Blender objects into this # Progressively we'll refactor loading elements into Blender objects into this
@@ -34,6 +35,9 @@ from pathlib import Path
# supplementary objects (e.g. drawings, structural analysis models, etc). # supplementary objects (e.g. drawings, structural analysis models, etc).
OBJECT_DATA_TYPE = Union[bpy.types.Mesh, bpy.types.Curve]
class Loader(blenderbim.core.tool.Loader): class Loader(blenderbim.core.tool.Loader):
@classmethod @classmethod
def create_project_collection(cls, name: str) -> bpy.types.Collection: def create_project_collection(cls, name: str) -> bpy.types.Collection:
@@ -51,7 +55,7 @@ class Loader(blenderbim.core.tool.Loader):
return collection return collection
@classmethod @classmethod
def get_mesh_name(cls, geometry): def get_mesh_name(cls, geometry) -> str:
representation_id = geometry.id representation_id = geometry.id
if "-" in representation_id: if "-" in representation_id:
representation_id = int(re.sub(r"\D", "", representation_id.split("-")[0])) representation_id = int(re.sub(r"\D", "", representation_id.split("-")[0]))
@@ -62,11 +66,11 @@ class Loader(blenderbim.core.tool.Loader):
return "{}/{}".format(context_id, representation_id) return "{}/{}".format(context_id, representation_id)
@classmethod @classmethod
def get_name(cls, element): def get_name(cls, element: ifcopenshell.entity_instance) -> str:
return "{}/{}".format(element.is_a(), getattr(element, "Name", "None")) return "{}/{}".format(element.is_a(), getattr(element, "Name", "None"))
@classmethod @classmethod
def link_mesh(cls, shape, mesh): def link_mesh(cls, shape, mesh: OBJECT_DATA_TYPE) -> None:
geometry = shape.geometry if hasattr(shape, "geometry") else shape geometry = shape.geometry if hasattr(shape, "geometry") else shape
if "-" in geometry.id: if "-" in geometry.id:
mesh.BIMMeshProperties.ifc_definition_id = int(geometry.id.split("-")[0]) mesh.BIMMeshProperties.ifc_definition_id = int(geometry.id.split("-")[0])
@@ -18,7 +18,7 @@
from fractions import Fraction from fractions import Fraction
from math import pi from math import pi
from typing import Tuple, Iterable, Any from typing import Tuple, Iterable, Any, Union, Literal
import ifcopenshell import ifcopenshell
import ifcopenshell.api import ifcopenshell.api
@@ -599,14 +599,14 @@ def calculate_unit_scale(ifc_file, unit_type="LENGTHUNIT"):
def format_length( def format_length(
value, value: float,
precision, precision: float,
decimal_places=2, decimal_places: int = 2,
suppress_zero_inches=True, suppress_zero_inches=True,
unit_system="imperial", unit_system: Union[Literal["metric"], Literal["imperial"]] = "imperial",
input_unit="foot", input_unit="foot",
output_unit="foot", output_unit="foot",
): ) -> str:
"""Formats a length for readability and imperial formatting """Formats a length for readability and imperial formatting
:param value: The value in meters if metric, or either decimal feet or :param value: The value in meters if metric, or either decimal feet or
@@ -670,7 +670,7 @@ def format_length(
def is_attr_type( def is_attr_type(
content_type: ifcopenshell.ifcopenshell_wrapper.named_type | ifcopenshell.ifcopenshell_wrapper.type_declaration, content_type: ifcopenshell.ifcopenshell_wrapper.named_type | ifcopenshell.ifcopenshell_wrapper.type_declaration,
ifc_unit_type_name: str, ifc_unit_type_name: str,
) -> ifcopenshell.ifcopenshell_wrapper.type_declaration | None: ) -> Union[ifcopenshell.ifcopenshell_wrapper.type_declaration, None]:
cur_decl = content_type cur_decl = content_type
while hasattr(cur_decl, "declared_type") is True: while hasattr(cur_decl, "declared_type") is True:
cur_decl = cur_decl.declared_type() cur_decl = cur_decl.declared_type()
@@ -22,16 +22,17 @@ import ifcopenshell.api.owner.settings
import ifcopenshell.util.pset import ifcopenshell.util.pset
import ifcopenshell.util.element import ifcopenshell.util.element
import ifcopenshell.util.unit import ifcopenshell.util.unit
from logging import Logger
class Patcher: class Patcher:
def __init__(self, src, file, logger, unit="METERS"): def __init__(self, src: str, file: ifcopenshell.file, logger: Logger, unit: str = "METERS"):
"""Converts the length unit of a model to the specified unit """Converts the length unit of a model to the specified unit
Allowed metric units include METERS, MILLIMETERS, CENTIMETERS, etc. Allowed metric units include METERS, MILLIMETERS, CENTIMETERS, etc.
Allowed imperial units include INCHES, FEET, MILES. Allowed imperial units include INCHES, FEET, MILES.
:param unit: The name of the desired unit. :param unit: The name of the desired unit, defaults to "METERS"
:type unit: str :type unit: str
Example: Example:
@@ -48,7 +49,7 @@ class Patcher:
self.file = file self.file = file
self.logger = logger self.logger = logger
self.unit = unit self.unit = unit
self.file_patched: ifcopenshell.file = None self.file_patched: ifcopenshell.file
def patch(self): def patch(self):
self.file_patched = ifcopenshell.util.unit.convert_file_length_units(self.file, self.unit) self.file_patched = ifcopenshell.util.unit.convert_file_length_units(self.file, self.unit)
+15 -4
View File
@@ -18,10 +18,12 @@
import ifcopenshell import ifcopenshell
import ifcopenshell.util.element import ifcopenshell.util.element
from typing import Union
from logging import Logger
class Patcher: class Patcher:
def __init__(self, src, file, logger, filepath=None): def __init__(self, src: str, file: ifcopenshell.file, logger: Logger, filepath: str):
"""Merge two IFC models into one """Merge two IFC models into one
Note that other than combining the two IfcProject elements into one, no Note that other than combining the two IfcProject elements into one, no
@@ -46,18 +48,25 @@ class Patcher:
def patch(self): def patch(self):
source = ifcopenshell.open(self.filepath) source = ifcopenshell.open(self.filepath)
self.existing_contexts = self.file.by_type("IfcGeometricRepresentationContext") self.existing_contexts: list[ifcopenshell.entity_instance] = self.file.by_type(
self.added_contexts = set() "IfcGeometricRepresentationContext"
)
self.added_contexts: set[ifcopenshell.entity_instance] = set()
original_project = self.file.by_type("IfcProject")[0] original_project = self.file.by_type("IfcProject")[0]
merged_project = self.file.add(source.by_type("IfcProject")[0]) merged_project = self.file.add(source.by_type("IfcProject")[0])
for element in source.by_type("IfcGeometricRepresentationContext"): for element in source.by_type("IfcGeometricRepresentationContext"):
new = self.file.add(element) new = self.file.add(element)
self.added_contexts.add(new) self.added_contexts.add(new)
for element in source: for element in source:
self.file.add(element) self.file.add(element)
for inverse in self.file.get_inverse(merged_project): for inverse in self.file.get_inverse(merged_project):
ifcopenshell.util.element.replace_attribute(inverse, merged_project, original_project) ifcopenshell.util.element.replace_attribute(inverse, merged_project, original_project)
self.file.remove(merged_project) self.file.remove(merged_project)
self.reuse_existing_contexts() self.reuse_existing_contexts()
def reuse_existing_contexts(self): def reuse_existing_contexts(self):
@@ -73,7 +82,9 @@ class Patcher:
for added_context in to_delete: for added_context in to_delete:
ifcopenshell.util.element.remove_deep2(self.file, added_context) ifcopenshell.util.element.remove_deep2(self.file, added_context)
def get_equivalent_existing_context(self, added_context): def get_equivalent_existing_context(
self, added_context: ifcopenshell.entity_instance
) -> Union[ifcopenshell.entity_instance, None]:
for context in self.existing_contexts: for context in self.existing_contexts:
if context.is_a() != added_context.is_a(): if context.is_a() != added_context.is_a():
continue continue
+2 -1
View File
@@ -18,10 +18,11 @@
import ifcopenshell import ifcopenshell
import ifcopenshell.util.schema import ifcopenshell.util.schema
from logging import Logger
class Patcher: class Patcher:
def __init__(self, src, file, logger, schema="IFC4"): def __init__(self, src: str, file: ifcopenshell.file, logger: Logger, schema: str = "IFC4"):
"""Migrate from one IFC version to another """Migrate from one IFC version to another
Note that this is experimental and will try to preserve as much data as Note that this is experimental and will try to preserve as much data as
+3 -1
View File
@@ -17,10 +17,12 @@
# along with IfcPatch. If not, see <http://www.gnu.org/licenses/>. # along with IfcPatch. If not, see <http://www.gnu.org/licenses/>.
import datetime import datetime
import ifcopenshell
from logging import Logger
class Patcher: class Patcher:
def __init__(self, src, file, logger): def __init__(self, src: str, file: ifcopenshell.file, logger: Logger):
"""Purge IFC properties, relationships, and other data """Purge IFC properties, relationships, and other data
In some rare cases (i.e. "resetting" a model or for security purposes) In some rare cases (i.e. "resetting" a model or for security purposes)