mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-12 10:33:20 +00:00
Merge branch 'v0.7.0' of https://github.com/bdamay/IfcOpenShell into v0.7.0
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1504,7 +1504,7 @@ class Drawing(blenderbim.core.tool.Drawing):
|
||||
def get_drawing_metadata(cls, drawing):
|
||||
return [
|
||||
v.strip()
|
||||
for v in ifcopenshell.util.element.get_psets(drawing)["EPset_Drawing"].get("Metadata", "").split(",")
|
||||
for v in (ifcopenshell.util.element.get_psets(drawing)["EPset_Drawing"].get("Metadata", "") or "").split(",")
|
||||
if v
|
||||
]
|
||||
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
# 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/>.
|
||||
|
||||
import os
|
||||
import bpy
|
||||
import csv
|
||||
import random
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
@@ -30,6 +32,10 @@ from mathutils import Vector, Matrix
|
||||
from random import uniform
|
||||
|
||||
|
||||
# When run from Blender
|
||||
BLEND_DIR = os.path.dirname(bpy.data.filepath)
|
||||
OUT_PATH = os.path.join(BLEND_DIR, "..", "blenderbim", "bim", "data", "libraries", "IFC4 Landscape Library.ifc")
|
||||
|
||||
SimpleTreeParams = namedtuple("SimpleTreeParams", "plant_height crown_diameter trunk_diameter")
|
||||
LowPolyTreeParams = namedtuple(
|
||||
"LowPolyTreeParams", "plant_height crown_diameter crown_max_loc crown_taper trunk_height trunk_diameter random_seed"
|
||||
@@ -301,7 +307,7 @@ tree_presets = {
|
||||
|
||||
|
||||
class LibraryGenerator:
|
||||
def generate(self, library_name, output_filename="IFC4 EU Steel.ifc"):
|
||||
def generate(self, library_name, output_filename):
|
||||
ifcopenshell.api.pre_listeners = {}
|
||||
ifcopenshell.api.post_listeners = {}
|
||||
|
||||
@@ -368,7 +374,7 @@ class LibraryGenerator:
|
||||
representations[rep_key] = rep_obj.name
|
||||
self.create_type("IfcGeographicElementType", obj.name, representations)
|
||||
|
||||
# Auto generated trees
|
||||
# Auto generated generic trees
|
||||
|
||||
self.builder = ShapeBuilder(self.file)
|
||||
builder = self.builder
|
||||
@@ -401,6 +407,21 @@ class LibraryGenerator:
|
||||
"IfcGeographicElementType", tree_data.tree_name, **self.get_representations(tree_geometry)
|
||||
)
|
||||
|
||||
# From tree species table
|
||||
|
||||
with open(os.path.join(BLEND_DIR, "tree_species.csv"), 'r') as csvfile:
|
||||
reader = csv.reader(csvfile)
|
||||
for i, row in enumerate(reader):
|
||||
if i == 0:
|
||||
continue
|
||||
preset = tree_presets.get(row[0])
|
||||
data = [float(x) for x in row[2:]]
|
||||
preset_data = preset.preset_class(*data)._asdict()
|
||||
tree_geometry = preset.generator(builder, **preset_data)
|
||||
self.create_explicit_type(
|
||||
"IfcGeographicElementType", row[1], **self.get_representations(tree_geometry)
|
||||
)
|
||||
|
||||
self.file.write(output_filename)
|
||||
|
||||
def get_representations(self, generated_geometry: GeneratedGeometry):
|
||||
@@ -464,4 +485,4 @@ class LibraryGenerator:
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
LibraryGenerator().generate("Landscape Assets Library", output_filename="IFC4 Landscape Library.ifc")
|
||||
LibraryGenerator().generate("Landscape Assets Library", output_filename=OUT_PATH)
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
"f","name","PlantHeight","CrownDiameter","CrownMaxLoc","CrownTaper","TrunkHeight","TrunkDiameter","RandomSeed"
|
||||
"low_poly","Apple",8,9,0.5,0.2,1.5,0.2,1
|
||||
"low_poly","Beech",30,20,0,0.4,3,0.75,2
|
||||
"low_poly","Cedar",25,17,0,1,1,0.625,3
|
||||
"low_poly","Dogwood",8,6,1,0.9,0.3,0.2,4
|
||||
"low_poly","Elm",17,12,0.6,0.7,2,0.425,5
|
||||
"low_poly","Fir",27,15,0.1,1,0.1,0.675,6
|
||||
"low_poly","Ginkgo",25,9,0.5,0.6,7,0.625,7
|
||||
"low_poly","Horsechesnut",30,23,0.5,0.2,3,0.75,8
|
||||
"low_poly","Ilex",26,13,0.4,0.3,12,0.65,9
|
||||
"low_poly","Juniper",30,15,0.7,1,1,0.75,10
|
||||
"low_poly","Kentucky Coffeetree",20,10,0.5,0,6,0.5,11
|
||||
"low_poly","Linden",28,18,0.3,0.2,3,0.7,12
|
||||
"low_poly","Mulberry",15,12,0.5,0.5,2,0.375,13
|
||||
"low_poly","Nannybery",5,4,0.7,0.8,1,0.125,14
|
||||
"low_poly","Oak",25,13,0.5,0.5,6,0.625,15
|
||||
"low_poly","Pine",27,9,0.5,0.2,14,0.675,16
|
||||
"low_poly","Quaking Aspen",13,4,0.5,0.3,4,0.325,17
|
||||
"low_poly","Redwood",90,24,0.1,0.8,8,2.25,18
|
||||
"low_poly","Sycamore",35,22,0.2,0.6,5,0.875,19
|
||||
"low_poly","Tree of Heaven",20,15,0.2,0.8,3,0.5,20
|
||||
"low_poly","Umbrella Tree",8,5,0.4,0.5,2,0.2,21
|
||||
"low_poly","Viburnum",4,3,0.8,0.7,0.2,0.1,22
|
||||
"low_poly","Weeping Willow",13,12,0.9,0.3,1,0.325,23
|
||||
"low_poly","Zanthoxylum",10,8,0.4,0.6,2,0.25,24
|
||||
"low_poly","Yellowwood",25,20,0.2,0.3,5,0.625,25
|
||||
"low_poly","Zelkova",12,8,0.4,0.4,2,0.3,26
|
||||
|
@@ -84,12 +84,12 @@ class Usecase:
|
||||
# Now we can easily append our wall type from our libary
|
||||
wall_type = ifcopenshell.api.run("project.append_asset", model, library=library, element=wall_type)
|
||||
"""
|
||||
self.file = file
|
||||
self.file: ifcopenshell.file = file
|
||||
self.settings = {"library": library, "element": element}
|
||||
|
||||
def execute(self):
|
||||
# mapping of old element ids to new elements
|
||||
self.added_elements:dict[int, ifcopenshell.entity_instance] = {}
|
||||
self.added_elements: dict[int, ifcopenshell.entity_instance] = {}
|
||||
self.whitelisted_inverse_attributes = {}
|
||||
if self.settings["element"].is_a("IfcTypeProduct"):
|
||||
self.target_class = "IfcTypeProduct"
|
||||
@@ -268,6 +268,7 @@ class Usecase:
|
||||
|
||||
def reuse_existing_contexts(self):
|
||||
added_contexts = set([e for e in self.added_elements.values() if e.is_a("IfcGeometricRepresentationContext")])
|
||||
added_contexts -= set(self.existing_contexts)
|
||||
for added_context in added_contexts:
|
||||
equivalent_existing_context = self.get_equivalent_existing_context(added_context)
|
||||
if not equivalent_existing_context:
|
||||
|
||||
@@ -30,6 +30,7 @@ import functools
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from typing import Union
|
||||
|
||||
from . import ifcopenshell_wrapper
|
||||
from . import settings
|
||||
@@ -117,6 +118,8 @@ class entity_instance(object):
|
||||
>>> #423=IfcProductDefinitionShape($,$,(#409,#421))
|
||||
"""
|
||||
|
||||
wrapped_data: ifcopenshell_wrapper.entity_instance
|
||||
|
||||
def __init__(self, e, file=None):
|
||||
if isinstance(e, tuple):
|
||||
e = ifcopenshell_wrapper.new_IfcBaseClass(*e)
|
||||
@@ -221,7 +224,7 @@ class entity_instance(object):
|
||||
|
||||
return entity_instance.walk(is_instance, unwrap, v)
|
||||
|
||||
def attribute_type(self, attr):
|
||||
def attribute_type(self, attr: int) -> str:
|
||||
"""Return the data type of a positional attribute of the element
|
||||
|
||||
:param attr: The index of the attribute
|
||||
@@ -231,7 +234,7 @@ class entity_instance(object):
|
||||
attr_idx = attr if isinstance(attr, numbers.Integral) else self.wrapped_data.get_argument_index(attr)
|
||||
return self.wrapped_data.get_argument_type(attr_idx)
|
||||
|
||||
def attribute_name(self, attr_idx):
|
||||
def attribute_name(self, attr_idx: int) -> str:
|
||||
"""Return the name of a positional attribute of the element
|
||||
|
||||
:param attr_idx: The index of the attribute
|
||||
@@ -272,7 +275,7 @@ class entity_instance(object):
|
||||
def __repr__(self):
|
||||
return repr(self.wrapped_data)
|
||||
|
||||
def to_string(self, valid_spf=True):
|
||||
def to_string(self, valid_spf=True) -> str:
|
||||
"""Returns a string representation of the current entity instance.
|
||||
Equal to str(self) when valid_spf=False. When valid_spf is True
|
||||
returns a representation of the string that conforms to valid Step
|
||||
@@ -283,7 +286,7 @@ class entity_instance(object):
|
||||
|
||||
return self.wrapped_data.to_string(valid_spf)
|
||||
|
||||
def is_a(self, *args):
|
||||
def is_a(self, *args) -> Union[str, bool]:
|
||||
"""Return the IFC class name of an instance, or checks if an instance belongs to a class.
|
||||
|
||||
The check will also return true if a parent class name is provided.
|
||||
@@ -306,7 +309,7 @@ class entity_instance(object):
|
||||
"""
|
||||
return self.wrapped_data.is_a(*args)
|
||||
|
||||
def id(self):
|
||||
def id(self) -> int:
|
||||
"""Return the STEP numerical identifier
|
||||
|
||||
:rtype: int
|
||||
@@ -335,7 +338,7 @@ class entity_instance(object):
|
||||
other.wrapped_data.file_pointer(),
|
||||
)
|
||||
|
||||
def is_entity(self):
|
||||
def is_entity(self) -> bool:
|
||||
"""Tests whether the instance is an entity type as opposed to a simple data type.
|
||||
|
||||
Returns:
|
||||
@@ -430,7 +433,9 @@ class entity_instance(object):
|
||||
)
|
||||
)
|
||||
|
||||
def get_info(self, include_identifier=True, recursive=False, return_type=dict, ignore=(), scalar_only=False):
|
||||
def get_info(
|
||||
self, include_identifier=True, recursive=False, return_type=dict, ignore=(), scalar_only=False
|
||||
) -> dict:
|
||||
"""Return a dictionary of the entity_instance's properties (Python and IFC) and their values.
|
||||
|
||||
:param include_identifier: Whether or not to include the STEP numerical identifier
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
@@ -27,6 +28,7 @@ import numbers
|
||||
import zipfile
|
||||
import functools
|
||||
from pathlib import Path
|
||||
from typing import Tuple, List
|
||||
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.file
|
||||
@@ -195,7 +197,9 @@ class file(object):
|
||||
print(products[0] == ifc_file[122] == ifc_file["2XQ$n5SLP5MBLyL442paFx"]) # True
|
||||
"""
|
||||
|
||||
def __init__(self, f=None, schema=None, schema_version=None):
|
||||
wrapped_data: ifcopenshell_wrapper.file
|
||||
|
||||
def __init__(self, f: ifcopenshell_wrapper.file = None, schema: str = None, schema_version: Tuple[int] = None):
|
||||
"""Create a new blank IFC model
|
||||
|
||||
This IFC model does not have any entities in it yet. See the
|
||||
@@ -253,8 +257,9 @@ class file(object):
|
||||
self.transaction = None
|
||||
|
||||
import weakref
|
||||
|
||||
file_dict[self.file_pointer()] = weakref.ref(self)
|
||||
|
||||
|
||||
def __del__(self):
|
||||
del file_dict[self.file_pointer()]
|
||||
|
||||
@@ -294,7 +299,7 @@ class file(object):
|
||||
transaction.commit()
|
||||
self.history.append(transaction)
|
||||
|
||||
def create_entity(self, type, *args, **kwargs):
|
||||
def create_entity(self, type: str, *args, **kwargs) -> ifcopenshell.entity_instance:
|
||||
"""Create a new IFC entity in the file.
|
||||
|
||||
:param type: Case insensitive name of the IFC class
|
||||
@@ -392,30 +397,43 @@ class file(object):
|
||||
elif isinstance(key, basestring):
|
||||
return entity_instance(self.wrapped_data.by_guid(str(key)), self)
|
||||
|
||||
def by_id(self, id):
|
||||
def by_id(self, id: int) -> ifcopenshell.entity_instance:
|
||||
"""Return an IFC entity instance filtered by IFC ID.
|
||||
|
||||
:param id: STEP numerical identifier
|
||||
:type id: int
|
||||
|
||||
:raises RuntimeError: If `id` is not found.
|
||||
|
||||
:returns: An ifcopenshell.entity_instance.entity_instance
|
||||
:rtype: ifcopenshell.entity_instance.entity_instance
|
||||
"""
|
||||
return self[id]
|
||||
|
||||
def by_guid(self, guid):
|
||||
def by_guid(self, guid: str) -> ifcopenshell.entity_instance:
|
||||
"""Return an IFC entity instance filtered by IFC GUID.
|
||||
|
||||
:param guid: GlobalId value in 22-character encoded form
|
||||
:type guid: string
|
||||
|
||||
:raises RuntimeError: If `guid` is not found.
|
||||
|
||||
:returns: An ifcopenshell.entity_instance.entity_instance
|
||||
:rtype: ifcopenshell.entity_instance.entity_instance
|
||||
|
||||
"""
|
||||
return self[guid]
|
||||
|
||||
def add(self, inst, _id=None):
|
||||
def add(self, inst: ifcopenshell.entity_instance, _id: int = None) -> ifcopenshell.entity_instance:
|
||||
"""Adds an entity including any dependent entities to an IFC file.
|
||||
If the entity already exists, it is not re-added. Existence of entity is checked by it's `.identity()`.
|
||||
|
||||
:param inst: The entity instance to add
|
||||
:type inst: ifcopenshell.entity_instance.entity_instance
|
||||
:returns: An ifcopenshell.entity_instance.entity_instance
|
||||
:rtype: ifcopenshell.entity_instance.entity_instance
|
||||
"""
|
||||
|
||||
If the entity already exists, it is not re-added."""
|
||||
if self.transaction:
|
||||
max_id = self.wrapped_data.getMaxId()
|
||||
inst.wrapped_data.this.disown()
|
||||
@@ -425,7 +443,7 @@ class file(object):
|
||||
[self.transaction.store_create(e) for e in reversed(added_elements)]
|
||||
return result
|
||||
|
||||
def by_type(self, type, include_subtypes=True):
|
||||
def by_type(self, type: str, include_subtypes=True) -> List[ifcopenshell.entity_instance]:
|
||||
"""Return IFC objects filtered by IFC Type and wrapped with the entity_instance class.
|
||||
|
||||
If an IFC type class has subclasses, all entities of those subclasses are also returned.
|
||||
@@ -441,7 +459,9 @@ class file(object):
|
||||
return [entity_instance(e, self) for e in self.wrapped_data.by_type(type)]
|
||||
return [entity_instance(e, self) for e in self.wrapped_data.by_type_excl_subtypes(type)]
|
||||
|
||||
def traverse(self, inst, max_levels=None, breadth_first=False):
|
||||
def traverse(
|
||||
self, inst: ifcopenshell.entity_instance, max_levels=None, breadth_first=False
|
||||
) -> List[ifcopenshell.entity_instance]:
|
||||
"""Get a list of all referenced instances for a particular instance including itself
|
||||
|
||||
:param inst: The entity instance to get all sub instances
|
||||
@@ -463,7 +483,9 @@ class file(object):
|
||||
|
||||
return [entity_instance(e, self) for e in fn(inst.wrapped_data, max_levels)]
|
||||
|
||||
def get_inverse(self, inst, allow_duplicate=False, with_attribute_indices=False):
|
||||
def get_inverse(
|
||||
self, inst: ifcopenshell.entity_instance, allow_duplicate=False, with_attribute_indices=False
|
||||
) -> List[ifcopenshell.entity_instance]:
|
||||
"""Return a list of entities that reference this entity
|
||||
|
||||
:param inst: The entity instance to get inverse relationships
|
||||
@@ -488,7 +510,7 @@ class file(object):
|
||||
|
||||
return set(inverses)
|
||||
|
||||
def get_total_inverses(self, inst):
|
||||
def get_total_inverses(self, inst: ifcopenshell.entity_instance) -> int:
|
||||
"""Returns the number of entities that reference this entity
|
||||
|
||||
:param inst: The entity instance to get inverse relationships
|
||||
@@ -498,7 +520,7 @@ class file(object):
|
||||
"""
|
||||
return self.wrapped_data.get_total_inverses(inst.wrapped_data)
|
||||
|
||||
def remove(self, inst):
|
||||
def remove(self, inst: ifcopenshell.entity_instance) -> None:
|
||||
"""Deletes an IFC object in the file.
|
||||
|
||||
Attribute values in other entity instances that reference the deleted
|
||||
@@ -573,7 +595,7 @@ class file(object):
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
def from_string(s):
|
||||
def from_string(s: str) -> ifcopenshell.entity_instance:
|
||||
return file(ifcopenshell_wrapper.read(s))
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -44,6 +44,26 @@ class TestAppendAsset(test.bootstrap.IFC4):
|
||||
ifcopenshell.api.run("project.append_asset", self.file, library=library, element=element)
|
||||
assert len(self.file.by_type("IfcWallType")) == 1
|
||||
|
||||
def test_reuse_an_existing_context_if_it_was_added_from_library_previously(self):
|
||||
library = ifcopenshell.api.run("project.create_file")
|
||||
project = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcProject")
|
||||
lib_context = ifcopenshell.api.run("context.add_context", library, context_type="Model")
|
||||
|
||||
self.file.add(project) # will add project and it's contexts
|
||||
|
||||
material = ifcopenshell.api.run("material.add_material", library, name="Material")
|
||||
style = ifcopenshell.api.run("style.add_style", library)
|
||||
ifcopenshell.api.run(
|
||||
"style.assign_material_style", library, material=material, style=style, context=lib_context
|
||||
)
|
||||
|
||||
ifcopenshell.api.run("project.append_asset", self.file, library=library, element=material)
|
||||
assert len(self.file.by_type("IfcMaterial")) == 1
|
||||
assert len(self.file.by_type("IfcGeometricRepresentationContext")) == 1
|
||||
context = self.file.by_type("IfcMaterial")[0].HasRepresentation[0].Representations[0].ContextOfItems
|
||||
# make sure it's still valid
|
||||
assert context.WorldCoordinateSystem
|
||||
|
||||
def test_append_a_single_type_product_even_though_an_inverse_material_relationship_is_shared(self):
|
||||
library = ifcopenshell.api.run("project.create_file")
|
||||
element = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWallType")
|
||||
@@ -202,24 +222,40 @@ class TestAppendAsset(test.bootstrap.IFC4):
|
||||
style = ifcopenshell.api.run("style.add_style", library)
|
||||
context = ifcopenshell.api.run("context.add_context", library, context_type="Model")
|
||||
ifcopenshell.api.run("style.assign_material_style", library, material=material, style=style, context=context)
|
||||
|
||||
ifcopenshell.api.run("project.append_asset", self.file, library=library, element=material)
|
||||
assert len(self.file.by_type("IfcMaterial")) == 1
|
||||
assert len(self.file.by_type("IfcGeometricRepresentationContext")) == 1
|
||||
context = self.file.by_type("IfcMaterial")[0].HasRepresentation[0].Representations[0].ContextOfItems
|
||||
assert context == file_context
|
||||
# make sure it's still valid
|
||||
assert context.WorldCoordinateSystem
|
||||
|
||||
def test_append_a_material_with_a_representation_and_reuse_an_existing_subcontext(self):
|
||||
ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject")
|
||||
file_context = ifcopenshell.api.run("context.add_context", self.file, context_type="Model")
|
||||
file_subcontext = ifcopenshell.api.run("context.add_context", self.file, parent=file_context, context_type="Model", context_identifier="Body", target_view="MODEL_VIEW")
|
||||
file_subcontext = ifcopenshell.api.run(
|
||||
"context.add_context",
|
||||
self.file,
|
||||
parent=file_context,
|
||||
context_type="Model",
|
||||
context_identifier="Body",
|
||||
target_view="MODEL_VIEW",
|
||||
)
|
||||
|
||||
library = ifcopenshell.api.run("project.create_file")
|
||||
ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcProject")
|
||||
material = ifcopenshell.api.run("material.add_material", library, name="Material")
|
||||
style = ifcopenshell.api.run("style.add_style", library)
|
||||
context = ifcopenshell.api.run("context.add_context", library, context_type="Model")
|
||||
subcontext = ifcopenshell.api.run("context.add_context", library, parent=context, context_type="Model", context_identifier="Body", target_view="MODEL_VIEW")
|
||||
subcontext = ifcopenshell.api.run(
|
||||
"context.add_context",
|
||||
library,
|
||||
parent=context,
|
||||
context_type="Model",
|
||||
context_identifier="Body",
|
||||
target_view="MODEL_VIEW",
|
||||
)
|
||||
ifcopenshell.api.run("style.assign_material_style", library, material=material, style=style, context=subcontext)
|
||||
ifcopenshell.api.run("project.append_asset", self.file, library=library, element=material)
|
||||
assert len(self.file.by_type("IfcMaterial")) == 1
|
||||
@@ -227,6 +263,7 @@ class TestAppendAsset(test.bootstrap.IFC4):
|
||||
assert len(self.file.by_type("IfcGeometricRepresentationSubContext", include_subtypes=False)) == 1
|
||||
subcontext = self.file.by_type("IfcMaterial")[0].HasRepresentation[0].Representations[0].ContextOfItems
|
||||
assert subcontext == file_subcontext
|
||||
# make sure it's still valid
|
||||
assert subcontext.ParentContext.WorldCoordinateSystem
|
||||
|
||||
def test_append_a_material_with_a_representation_and_reuse_an_existing_context_by_a_new_subcontext(self):
|
||||
@@ -238,8 +275,14 @@ class TestAppendAsset(test.bootstrap.IFC4):
|
||||
material = ifcopenshell.api.run("material.add_material", library, name="Material")
|
||||
style = ifcopenshell.api.run("style.add_style", library)
|
||||
context = ifcopenshell.api.run("context.add_context", library, context_type="Model")
|
||||
subcontext = ifcopenshell.api.run("context.add_context", library, context_type="Model",
|
||||
context_identifier="Body", target_view="MODEL_VIEW", parent=context)
|
||||
subcontext = ifcopenshell.api.run(
|
||||
"context.add_context",
|
||||
library,
|
||||
context_type="Model",
|
||||
context_identifier="Body",
|
||||
target_view="MODEL_VIEW",
|
||||
parent=context,
|
||||
)
|
||||
ifcopenshell.api.run("style.assign_material_style", library, material=material, style=style, context=subcontext)
|
||||
ifcopenshell.api.run("project.append_asset", self.file, library=library, element=material)
|
||||
assert len(self.file.by_type("IfcMaterial")) == 1
|
||||
|
||||
@@ -25,9 +25,10 @@ import typing
|
||||
import inspect
|
||||
import collections
|
||||
import importlib
|
||||
from typing import Union
|
||||
|
||||
|
||||
def execute(args):
|
||||
def execute(args: dict) -> Union[ifcopenshell.file, str]:
|
||||
"""Execute a patch recipe
|
||||
|
||||
The details of how the patch recipe is executed depends on the definition of
|
||||
@@ -80,7 +81,7 @@ def execute(args):
|
||||
return output
|
||||
|
||||
|
||||
def write(output, filepath):
|
||||
def write(output: Union[ifcopenshell.file, str], filepath: str) -> None:
|
||||
"""Write the output of an IFC patch to a file
|
||||
|
||||
Typically a patch output would be a patched IFC model file object, or as a
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
from toposort import toposort_flatten as toposort
|
||||
|
||||
|
||||
class Patcher:
|
||||
@@ -53,6 +52,8 @@ class Patcher:
|
||||
self.optimized_file = ifcopenshell.file(schema=self.file.schema)
|
||||
|
||||
def patch(self):
|
||||
from toposort import toposort_flatten as toposort
|
||||
|
||||
def generate_instances_and_references():
|
||||
"""
|
||||
Generator which yields an entity id and
|
||||
|
||||
@@ -493,6 +493,9 @@ namespace {
|
||||
for (auto& prop : *props) {
|
||||
if (prop->declaration().is("IfcPropertySingleValue")) {
|
||||
std::string name = *((IfcUtil::IfcBaseEntity*) prop)->get("Name");
|
||||
if (((IfcUtil::IfcBaseEntity*) prop)->get("NominalValue")->isNull()) {
|
||||
continue;
|
||||
}
|
||||
IfcUtil::IfcBaseClass* v = *((IfcUtil::IfcBaseEntity*) prop)->get("NominalValue");
|
||||
auto value = v->data().getArgument(0);
|
||||
if (value->type() == IfcUtil::Argument_STRING) {
|
||||
|
||||
Reference in New Issue
Block a user