mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 01:41:57 +00:00
Generate functions for all API usecases for better static code features. See #2693.
This commit is contained in:
@@ -15,3 +15,30 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .add_axis_representation import add_axis_representation
|
||||
from .add_boolean import add_boolean
|
||||
from .add_door_representation import add_door_representation
|
||||
from .add_footprint_representation import add_footprint_representation
|
||||
from .add_mesh_representation import add_mesh_representation
|
||||
from .add_profile_representation import add_profile_representation
|
||||
from .add_railing_representation import add_railing_representation
|
||||
|
||||
try:
|
||||
from .add_representation import add_representation
|
||||
except ModuleNotFoundError as e:
|
||||
print(f"Note: API not available due to missing dependencies: geometry.add_representation - {e}")
|
||||
from .add_slab_representation import add_slab_representation
|
||||
from .add_wall_representation import add_wall_representation
|
||||
from .add_window_representation import add_window_representation
|
||||
from .assign_representation import assign_representation
|
||||
from .connect_element import connect_element
|
||||
from .connect_path import connect_path
|
||||
from .create_2pt_wall import create_2pt_wall
|
||||
from .disconnect_element import disconnect_element
|
||||
from .disconnect_path import disconnect_path
|
||||
from .edit_object_placement import edit_object_placement
|
||||
from .map_representation import map_representation
|
||||
from .remove_boolean import remove_boolean
|
||||
from .remove_representation import remove_representation
|
||||
from .unassign_representation import unassign_representation
|
||||
|
||||
@@ -19,61 +19,64 @@
|
||||
import ifcopenshell.util.unit
|
||||
|
||||
|
||||
def add_axis_representation(file, context=None, axis=None) -> None:
|
||||
"""Adds a new axis representation
|
||||
|
||||
Certain objects are typically "axis-based", such as walls, beams,
|
||||
and columns. This means you can represent them abstractly by simply
|
||||
drawing a single line either in 2D (such as for walls) or 3D (for beams
|
||||
and columns). Humans can understand this axis-based representation as
|
||||
being a simplification of a layered extrusion or a profile that is being
|
||||
extruded along that axis and joined to other elements.
|
||||
|
||||
Using an axis-based representation makes it easy for users and computers
|
||||
to analyse connectivity and spatial relationships, as well as makes it
|
||||
easy to parametrically edit these objects by simply stretching the start
|
||||
or end of the axis.
|
||||
|
||||
For now, only simple straight line axes are supported, represented by a
|
||||
start and end coordinate. The order is important. For walls, the start
|
||||
must be at the minimum local X ordinate, and the end at the maximum
|
||||
local X ordinate. For beams and columns, the start is at the minimum
|
||||
local Z ordinate, and the end of the maximum local Z ordinate. The first
|
||||
coordinate is the "start" and the second coordinate is the "end". This
|
||||
stat and end is then used to determine any parametric junctions with
|
||||
other elements.
|
||||
|
||||
Using an axis-representation is optional, but highly recommended for
|
||||
"standard" representations of walls, beams, columns, and other
|
||||
structural members. A rule of thumb is that if you can draw it as a line
|
||||
on paper, you can probably represent it using an axis.
|
||||
|
||||
:param context: The IfcGeometricRepresentationContext that the
|
||||
representation is part of. This must be either a
|
||||
Model/Axis/GRAPH_VIEW (3D) or Plan/Axis/GRAPH_VIEW (2D).
|
||||
:type context: ifcopenshell.entity_instance
|
||||
:param axis: The axis, as a list of two coordinates, the coordinates
|
||||
being either a list of 2 or 3 float coordinates depending on whether
|
||||
the axis is 2D or 3D.
|
||||
:type axis: list[list[float]]
|
||||
:return: The newly created IfcShapeRepresentation entity
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
context = ifcopenshell.util.representation.get_context(model, "Plan", "Axis", "GRAPH_VIEW")
|
||||
axis = ifcopenshell.api.run("geometry.add_axis_representation", model,
|
||||
context=context, axis=[(0.0, 0.0), (1.0, 0.0)])
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {
|
||||
"context": context,
|
||||
"axis": axis or [],
|
||||
}
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, context=None, axis=None):
|
||||
"""Adds a new axis representation
|
||||
|
||||
Certain objects are typically "axis-based", such as walls, beams,
|
||||
and columns. This means you can represent them abstractly by simply
|
||||
drawing a single line either in 2D (such as for walls) or 3D (for beams
|
||||
and columns). Humans can understand this axis-based representation as
|
||||
being a simplification of a layered extrusion or a profile that is being
|
||||
extruded along that axis and joined to other elements.
|
||||
|
||||
Using an axis-based representation makes it easy for users and computers
|
||||
to analyse connectivity and spatial relationships, as well as makes it
|
||||
easy to parametrically edit these objects by simply stretching the start
|
||||
or end of the axis.
|
||||
|
||||
For now, only simple straight line axes are supported, represented by a
|
||||
start and end coordinate. The order is important. For walls, the start
|
||||
must be at the minimum local X ordinate, and the end at the maximum
|
||||
local X ordinate. For beams and columns, the start is at the minimum
|
||||
local Z ordinate, and the end of the maximum local Z ordinate. The first
|
||||
coordinate is the "start" and the second coordinate is the "end". This
|
||||
stat and end is then used to determine any parametric junctions with
|
||||
other elements.
|
||||
|
||||
Using an axis-representation is optional, but highly recommended for
|
||||
"standard" representations of walls, beams, columns, and other
|
||||
structural members. A rule of thumb is that if you can draw it as a line
|
||||
on paper, you can probably represent it using an axis.
|
||||
|
||||
:param context: The IfcGeometricRepresentationContext that the
|
||||
representation is part of. This must be either a
|
||||
Model/Axis/GRAPH_VIEW (3D) or Plan/Axis/GRAPH_VIEW (2D).
|
||||
:type context: ifcopenshell.entity_instance
|
||||
:param axis: The axis, as a list of two coordinates, the coordinates
|
||||
being either a list of 2 or 3 float coordinates depending on whether
|
||||
the axis is 2D or 3D.
|
||||
:type axis: list[list[float]]
|
||||
:return: The newly created IfcShapeRepresentation entity
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
context = ifcopenshell.util.representation.get_context(model, "Plan", "Axis", "GRAPH_VIEW")
|
||||
axis = ifcopenshell.api.run("geometry.add_axis_representation", model,
|
||||
context=context, axis=[(0.0, 0.0), (1.0, 0.0)])
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"context": context,
|
||||
"axis": axis or [],
|
||||
}
|
||||
|
||||
def execute(self):
|
||||
self.settings["unit_scale"] = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
is_2d = len(self.settings["axis"][0]) == 2
|
||||
@@ -82,9 +85,13 @@ class Usecase:
|
||||
curve = self.file.createIfcPolyline([self.file.createIfcCartesianPoint(p) for p in points])
|
||||
else:
|
||||
if is_2d:
|
||||
curve = self.file.createIfcIndexedPolyCurve(self.file.createIfcCartesianPointList2D(points), None, False)
|
||||
curve = self.file.createIfcIndexedPolyCurve(
|
||||
self.file.createIfcCartesianPointList2D(points), None, False
|
||||
)
|
||||
else:
|
||||
curve = self.file.createIfcIndexedPolyCurve(self.file.createIfcCartesianPointList3D(points), None, False)
|
||||
curve = self.file.createIfcIndexedPolyCurve(
|
||||
self.file.createIfcCartesianPointList3D(points), None, False
|
||||
)
|
||||
return self.file.createIfcShapeRepresentation(
|
||||
self.settings["context"],
|
||||
self.settings["context"].ContextIdentifier,
|
||||
|
||||
@@ -20,24 +20,27 @@ import ifcopenshell.util.unit
|
||||
import numpy as np
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"representation": None,
|
||||
"operator": "DIFFERENCE",
|
||||
# IfcHalfSpaceSolid, Mesh
|
||||
"type": "IfcHalfSpaceSolid",
|
||||
# The XY plane is the clipping boundary and +Z is removed.
|
||||
"matrix": None, # A matrix to define a clipping Ifchalfspacesolid.
|
||||
"blender_obj": None, # A Blender OBJ to define the voided OBJ for a "Mesh" type
|
||||
"blender_void": None, # A Blender OBJ to define the void OBJ for a "Mesh" type
|
||||
"should_force_faceted_brep": False,
|
||||
"should_force_triangulation": False,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
def add_boolean(file, **usecase_settings) -> None:
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {
|
||||
"representation": None,
|
||||
"operator": "DIFFERENCE",
|
||||
# IfcHalfSpaceSolid, Mesh
|
||||
"type": "IfcHalfSpaceSolid",
|
||||
# The XY plane is the clipping boundary and +Z is removed.
|
||||
"matrix": None, # A matrix to define a clipping Ifchalfspacesolid.
|
||||
"blender_obj": None, # A Blender OBJ to define the voided OBJ for a "Mesh" type
|
||||
"blender_void": None, # A Blender OBJ to define the void OBJ for a "Mesh" type
|
||||
"should_force_faceted_brep": False,
|
||||
"should_force_triangulation": False,
|
||||
}
|
||||
for key, value in usecase_settings.items():
|
||||
usecase.settings[key] = value
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
self.settings["unit_scale"] = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
if self.settings["type"] == "IfcHalfSpaceSolid":
|
||||
|
||||
@@ -63,11 +63,7 @@ def create_ifc_door_lining(
|
||||
|
||||
points = [p.xz for p in points]
|
||||
door_lining = builder.polyline(points, closed=True)
|
||||
door_lining = builder.extrude(
|
||||
door_lining,
|
||||
size.y,
|
||||
**builder.extrude_kwargs("Y")
|
||||
)
|
||||
door_lining = builder.extrude(door_lining, size.y, **builder.extrude_kwargs("Y"))
|
||||
builder.translate(door_lining, position)
|
||||
|
||||
return door_lining
|
||||
@@ -79,75 +75,78 @@ def create_ifc_box(builder: ShapeBuilder, size: Vector, position: Vector = V(0,
|
||||
return box
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
"""units in settings expected to be in ifc project units"""
|
||||
self.file = file
|
||||
# http://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcDoor.htm
|
||||
# http://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcDoorTypeOperationEnum.htm
|
||||
# http://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcDoorLiningProperties.htm
|
||||
# http://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcDoorPanelProperties.htm
|
||||
self.settings = {"unit_scale": ifcopenshell.util.unit.calculate_unit_scale(self.file)}
|
||||
self.settings.update(
|
||||
{
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
"overall_height": self.convert_si_to_unit(2.0),
|
||||
"overall_width": self.convert_si_to_unit(0.9),
|
||||
# DOUBLE_DOOR_DOUBLE_SWING, DOUBLE_DOOR_FOLDING, DOUBLE_DOOR_LIFTING_VERTICAL,
|
||||
# DOUBLE_DOOR_SINGLE_SWING, DOUBLE_DOOR_SINGLE_SWING_OPPOSITE_LEFT,
|
||||
# DOUBLE_DOOR_SINGLE_SWING_OPPOSITE_RIGHT, DOUBLE_DOOR_SLIDING,
|
||||
# DOUBLE_SWING_LEFT, DOUBLE_SWING_RIGHT, FOLDING_TO_LEFT,
|
||||
# FOLDING_TO_RIGHT, LIFTING_HORIZONTAL, LIFTING_VERTICAL_LEFT,
|
||||
# LIFTING_VERTICAL_RIGHT, REVOLVING, REVOLVING_VERTICAL,
|
||||
# ROLLINGUP, SINGLE_SWING_LEFT, SINGLE_SWING_RIGHT, SLIDING_TO_LEFT,
|
||||
# SLIDING_TO_RIGHT, SWING_FIXED_LEFT, SWING_FIXED_RIGHT
|
||||
"operation_type": "SINGLE_SWING_LEFT", # door type
|
||||
"lining_properties": {
|
||||
"LiningDepth": self.convert_si_to_unit(0.050),
|
||||
"LiningThickness": self.convert_si_to_unit(0.050),
|
||||
# offset from the outer side of the wall (by Y-axis)
|
||||
"LiningOffset": self.convert_si_to_unit(0.0),
|
||||
# offset from the wall
|
||||
"LiningToPanelOffsetX": self.convert_si_to_unit(0.025),
|
||||
# offset from the X-axis (unlike windows)
|
||||
"LiningToPanelOffsetY": self.convert_si_to_unit(0.025),
|
||||
# transom - vertical distance between door and window panels
|
||||
"TransomThickness": self.convert_si_to_unit(0.000),
|
||||
# TransomOffset - distance from the bottom door opening
|
||||
# to the beginning of the transom
|
||||
# unlike windows TransomOffset which goes to the center of the transom
|
||||
"TransomOffset": self.convert_si_to_unit(1.525),
|
||||
"ShapeAspectStyle": None, # DEPRECATED
|
||||
# Casing cover wall faces around the opening
|
||||
# on the left, right and upper sides
|
||||
# Casing should be either on both sides of the wall or no casing
|
||||
# If `LiningOffset` is present then therefore casing is not possible on outer wall
|
||||
# therefore there will be no casing on inner wall either
|
||||
"CasingDepth": self.convert_si_to_unit(0.005),
|
||||
"CasingThickness": self.convert_si_to_unit(0.075), # by Z-axis
|
||||
# Threshold covers the bottom side of the opening
|
||||
"ThresholdDepth": self.convert_si_to_unit(0.1),
|
||||
"ThresholdThickness": self.convert_si_to_unit(0.025), # by Z-axis
|
||||
# offset by Y-axis
|
||||
"ThresholdOffset": self.convert_si_to_unit(0.000),
|
||||
},
|
||||
"panel_properties": {
|
||||
"PanelDepth": self.convert_si_to_unit(0.035), # by Y
|
||||
"PanelWidth": 1.0, # as ratio to the clear door opening
|
||||
"FrameDepth": self.convert_si_to_unit(0.035), # by Y
|
||||
"FrameThickness": self.convert_si_to_unit(0.035), # by X
|
||||
# LEFT, MIDDLE, RIGHT, NOTDEFINED
|
||||
"PanelPosition": ..., # NEVER USED
|
||||
# defines the basic ways to describe how door panels operate
|
||||
# basically how it opens
|
||||
"PanelOperation": None, # NEVER USED
|
||||
"ShapeAspectStyle": None, # DEPRECATED
|
||||
},
|
||||
}
|
||||
)
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
def add_door_representation(file, **usecase_settings) -> None:
|
||||
"""units in usecase_settings expected to be in ifc project units"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
# http://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcDoor.htm
|
||||
# http://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcDoorTypeOperationEnum.htm
|
||||
# http://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcDoorLiningProperties.htm
|
||||
# http://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcDoorPanelProperties.htm
|
||||
usecase.settings = {"unit_scale": ifcopenshell.util.unit.calculate_unit_scale(usecase.file)}
|
||||
usecase.settings.update(
|
||||
{
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
"overall_height": usecase.convert_si_to_unit(2.0),
|
||||
"overall_width": usecase.convert_si_to_unit(0.9),
|
||||
# DOUBLE_DOOR_DOUBLE_SWING, DOUBLE_DOOR_FOLDING, DOUBLE_DOOR_LIFTING_VERTICAL,
|
||||
# DOUBLE_DOOR_SINGLE_SWING, DOUBLE_DOOR_SINGLE_SWING_OPPOSITE_LEFT,
|
||||
# DOUBLE_DOOR_SINGLE_SWING_OPPOSITE_RIGHT, DOUBLE_DOOR_SLIDING,
|
||||
# DOUBLE_SWING_LEFT, DOUBLE_SWING_RIGHT, FOLDING_TO_LEFT,
|
||||
# FOLDING_TO_RIGHT, LIFTING_HORIZONTAL, LIFTING_VERTICAL_LEFT,
|
||||
# LIFTING_VERTICAL_RIGHT, REVOLVING, REVOLVING_VERTICAL,
|
||||
# ROLLINGUP, SINGLE_SWING_LEFT, SINGLE_SWING_RIGHT, SLIDING_TO_LEFT,
|
||||
# SLIDING_TO_RIGHT, SWING_FIXED_LEFT, SWING_FIXED_RIGHT
|
||||
"operation_type": "SINGLE_SWING_LEFT", # door type
|
||||
"lining_properties": {
|
||||
"LiningDepth": usecase.convert_si_to_unit(0.050),
|
||||
"LiningThickness": usecase.convert_si_to_unit(0.050),
|
||||
# offset from the outer side of the wall (by Y-axis)
|
||||
"LiningOffset": usecase.convert_si_to_unit(0.0),
|
||||
# offset from the wall
|
||||
"LiningToPanelOffsetX": usecase.convert_si_to_unit(0.025),
|
||||
# offset from the X-axis (unlike windows)
|
||||
"LiningToPanelOffsetY": usecase.convert_si_to_unit(0.025),
|
||||
# transom - vertical distance between door and window panels
|
||||
"TransomThickness": usecase.convert_si_to_unit(0.000),
|
||||
# TransomOffset - distance from the bottom door opening
|
||||
# to the beginning of the transom
|
||||
# unlike windows TransomOffset which goes to the center of the transom
|
||||
"TransomOffset": usecase.convert_si_to_unit(1.525),
|
||||
"ShapeAspectStyle": None, # DEPRECATED
|
||||
# Casing cover wall faces around the opening
|
||||
# on the left, right and upper sides
|
||||
# Casing should be either on both sides of the wall or no casing
|
||||
# If `LiningOffset` is present then therefore casing is not possible on outer wall
|
||||
# therefore there will be no casing on inner wall either
|
||||
"CasingDepth": usecase.convert_si_to_unit(0.005),
|
||||
"CasingThickness": usecase.convert_si_to_unit(0.075), # by Z-axis
|
||||
# Threshold covers the bottom side of the opening
|
||||
"ThresholdDepth": usecase.convert_si_to_unit(0.1),
|
||||
"ThresholdThickness": usecase.convert_si_to_unit(0.025), # by Z-axis
|
||||
# offset by Y-axis
|
||||
"ThresholdOffset": usecase.convert_si_to_unit(0.000),
|
||||
},
|
||||
"panel_properties": {
|
||||
"PanelDepth": usecase.convert_si_to_unit(0.035), # by Y
|
||||
"PanelWidth": 1.0, # as ratio to the clear door opening
|
||||
"FrameDepth": usecase.convert_si_to_unit(0.035), # by Y
|
||||
"FrameThickness": usecase.convert_si_to_unit(0.035), # by X
|
||||
# LEFT, MIDDLE, RIGHT, NOTDEFINED
|
||||
"PanelPosition": ..., # NEVER USED
|
||||
# defines the basic ways to describe how door panels operate
|
||||
# basically how it opens
|
||||
"PanelOperation": None, # NEVER USED
|
||||
"ShapeAspectStyle": None, # DEPRECATED
|
||||
},
|
||||
}
|
||||
)
|
||||
for key, value in usecase_settings.items():
|
||||
usecase.settings[key] = value
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
builder = ShapeBuilder(self.file)
|
||||
overall_height = self.settings["overall_height"]
|
||||
|
||||
@@ -19,20 +19,17 @@
|
||||
import ifcopenshell.util.unit
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
"curves": [], # A list of IFC curves to include in the curve set
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
def add_footprint_representation(file, **usecase_settings) -> None:
|
||||
settings = {
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
"curves": [], # A list of IFC curves to include in the curve set
|
||||
}
|
||||
for key, value in usecase_settings.items():
|
||||
settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
return self.file.createIfcShapeRepresentation(
|
||||
self.settings["context"],
|
||||
self.settings["context"].ContextIdentifier,
|
||||
"GeometricCurveSet",
|
||||
[self.file.createIfcGeometricCurveSet(self.settings["curves"])],
|
||||
)
|
||||
return file.createIfcShapeRepresentation(
|
||||
settings["context"],
|
||||
settings["context"].ContextIdentifier,
|
||||
"GeometricCurveSet",
|
||||
[file.createIfcGeometricCurveSet(settings["curves"])],
|
||||
)
|
||||
|
||||
@@ -19,25 +19,28 @@
|
||||
import ifcopenshell.util.unit
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file: ifcopenshell.file, **settings):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
# Vertices, edges, and faces are given in the form of: [item1, item2, item3, ...]
|
||||
# ... where itemN = [(0., 0., 0.), (1., 1., 1.), (x, y, z), ...]
|
||||
"vertices": None, # A list of coordinates
|
||||
# ... where itemN = [(0, 1), (1, 2), (v1, v2), ...]
|
||||
"edges": None, # A list of edges, represented by vertex index pairs
|
||||
# ... where itemN = [(0, 1, 2), (5, 4, 2, 3), (v1, v2, v3, ... vN), ...]
|
||||
"faces": None, # A list of polygons, represented by vertex indices
|
||||
"coordinate_offset": None, # Optionally apply a vector offset to all coordinates
|
||||
"unit_scale": None, # A scale factor to apply for all vectors in case the unit is different
|
||||
"force_faceted_brep": False, # Force using IfcFacetedBreps instead of IfcPolygonalFaceSets
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
def add_mesh_representation(file: ifcopenshell.file, **usecase_settings) -> None:
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
# Vertices, edges, and faces are given in the form of: [item1, item2, item3, ...]
|
||||
# ... where itemN = [(0., 0., 0.), (1., 1., 1.), (x, y, z), ...]
|
||||
"vertices": None, # A list of coordinates
|
||||
# ... where itemN = [(0, 1), (1, 2), (v1, v2), ...]
|
||||
"edges": None, # A list of edges, represented by vertex index pairs
|
||||
# ... where itemN = [(0, 1, 2), (5, 4, 2, 3), (v1, v2, v3, ... vN), ...]
|
||||
"faces": None, # A list of polygons, represented by vertex indices
|
||||
"coordinate_offset": None, # Optionally apply a vector offset to all coordinates
|
||||
"unit_scale": None, # A scale factor to apply for all vectors in case the unit is different
|
||||
"force_faceted_brep": False, # Force using IfcFacetedBreps instead of IfcPolygonalFaceSets
|
||||
}
|
||||
for key, value in usecase_settings.items():
|
||||
usecase.settings[key] = value
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
if self.settings["unit_scale"] is None:
|
||||
self.settings["unit_scale"] = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
|
||||
@@ -21,22 +21,25 @@ import ifcopenshell.util.unit
|
||||
from ifcopenshell.util.data import Clipping
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
"profile": None,
|
||||
"depth": 1.0,
|
||||
"cardinal_point": 5,
|
||||
# Planes are defined either by Clipping objects
|
||||
# or by dictionaries of arguments for `Clipping.parse`
|
||||
"clippings": [], # A list of planes that define clipping half space solids
|
||||
"placement_zx_axes": (None, None),
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
def add_profile_representation(file, **usecase_settings) -> None:
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
"profile": None,
|
||||
"depth": 1.0,
|
||||
"cardinal_point": 5,
|
||||
# Planes are defined either by Clipping objects
|
||||
# or by dictionaries of arguments for `Clipping.parse`
|
||||
"clippings": [], # A list of planes that define clipping half space solids
|
||||
"placement_zx_axes": (None, None),
|
||||
}
|
||||
for key, value in usecase_settings.items():
|
||||
usecase.settings[key] = value
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
self.settings["unit_scale"] = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
self.settings["clippings"] = [Clipping.parse(c) for c in self.settings["clippings"]]
|
||||
|
||||
@@ -31,39 +31,42 @@ def mm(x):
|
||||
return x / 1000
|
||||
|
||||
|
||||
def add_railing_representation(file, **usecase_settings) -> None:
|
||||
"""
|
||||
units in usecase_settings expected to be in ifc project units
|
||||
|
||||
`railing_path` is a list of point coordinates for the railing path,
|
||||
coordinates are expected to be at the top of the railing, not at the center
|
||||
|
||||
`railing_path` is expected to be a list of Vector objects
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"unit_scale": ifcopenshell.util.unit.calculate_unit_scale(usecase.file)}
|
||||
usecase.settings.update(
|
||||
{
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
"railing_type": "WALL_MOUNTED_HANDRAIL",
|
||||
"railing_path": usecase.path_si_to_units([V(0, 0, 1), V(1, 0, 1), V(2, 0, 1)]),
|
||||
"use_manual_supports": False,
|
||||
"support_spacing": usecase.convert_si_to_unit(mm(1000)),
|
||||
"railing_diameter": usecase.convert_si_to_unit(mm(50)),
|
||||
"clear_width": usecase.convert_si_to_unit(mm(40)),
|
||||
"terminal_type": "180",
|
||||
"height": usecase.convert_si_to_unit(mm(1000)),
|
||||
"looped_path": False,
|
||||
}
|
||||
)
|
||||
|
||||
for key, value in usecase_settings.items():
|
||||
usecase.settings[key] = value
|
||||
|
||||
if usecase.settings["railing_type"] != "WALL_MOUNTED_HANDRAIL":
|
||||
raise Exception('Only "WALL_MOUNTED_HANDRAIL" railing_type is supported at the moment.')
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
"""
|
||||
units in settings expected to be in ifc project units
|
||||
|
||||
`railing_path` is a list of point coordinates for the railing path,
|
||||
coordinates are expected to be at the top of the railing, not at the center
|
||||
|
||||
`railing_path` is expected to be a list of Vector objects
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {"unit_scale": ifcopenshell.util.unit.calculate_unit_scale(self.file)}
|
||||
self.settings.update(
|
||||
{
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
"railing_type": "WALL_MOUNTED_HANDRAIL",
|
||||
"railing_path": self.path_si_to_units([V(0, 0, 1), V(1, 0, 1), V(2, 0, 1)]),
|
||||
"use_manual_supports": False,
|
||||
"support_spacing": self.convert_si_to_unit(mm(1000)),
|
||||
"railing_diameter": self.convert_si_to_unit(mm(50)),
|
||||
"clear_width": self.convert_si_to_unit(mm(40)),
|
||||
"terminal_type": "180",
|
||||
"height": self.convert_si_to_unit(mm(1000)),
|
||||
"looped_path": False,
|
||||
}
|
||||
)
|
||||
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
if self.settings["railing_type"] != "WALL_MOUNTED_HANDRAIL":
|
||||
raise Exception('Only "WALL_MOUNTED_HANDRAIL" railing_type is supported at the moment.')
|
||||
|
||||
def execute(self):
|
||||
arc_points = []
|
||||
items_3d = []
|
||||
|
||||
@@ -28,37 +28,40 @@ X_AXIS = Vector((1, 0, 0))
|
||||
EPSILON = 1e-6
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file: ifcopenshell.file, **settings):
|
||||
# TODO: This usecase currently depends on Blender's data model
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
"blender_object": None, # This is (currently) a Blender object, hence this depends on Blender now
|
||||
"geometry": None, # This is (currently) a Blender data object, hence this depends on Blender now
|
||||
"coordinate_offset": None, # Optionally apply a vector offset to all coordinates
|
||||
"total_items": 1, # How many representation items to create
|
||||
"unit_scale": None, # A scale factor to apply for all vectors in case the unit is different
|
||||
"should_force_faceted_brep": False, # If we should force faceted breps for meshes
|
||||
"should_force_triangulation": False, # If we should force triangulation for meshes
|
||||
"should_generate_uvs": False, # If UV coordinates should also be generated
|
||||
# Possible IFC representation classes:
|
||||
# IfcExtrudedAreaSolid/IfcRectangleProfileDef
|
||||
# IfcExtrudedAreaSolid/IfcCircleProfileDef
|
||||
# IfcExtrudedAreaSolid/IfcArbitraryClosedProfileDef
|
||||
# IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids
|
||||
# IfcExtrudedAreaSolid/IfcMaterialProfileSetUsage
|
||||
# IfcGeometricCurveSet/IfcTextLiteral
|
||||
# IfcTextLiteral
|
||||
"ifc_representation_class": None, # Whether to cast a mesh into a particular class
|
||||
"profile_set_usage": None, # The material profile set if the extrusion requires it
|
||||
"text_literal": None, # The text literal if the representation requires it
|
||||
}
|
||||
self.ifc_vertices = []
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
def add_representation(file: ifcopenshell.file, **usecase_settings) -> ifcopenshell.entity_instance:
|
||||
usecase = Usecase()
|
||||
# TODO: This usecase currently depends on Blender's data model
|
||||
usecase.file = file
|
||||
usecase.settings = {
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
"blender_object": None, # This is (currently) a Blender object, hence this depends on Blender now
|
||||
"geometry": None, # This is (currently) a Blender data object, hence this depends on Blender now
|
||||
"coordinate_offset": None, # Optionally apply a vector offset to all coordinates
|
||||
"total_items": 1, # How many representation items to create
|
||||
"unit_scale": None, # A scale factor to apply for all vectors in case the unit is different
|
||||
"should_force_faceted_brep": False, # If we should force faceted breps for meshes
|
||||
"should_force_triangulation": False, # If we should force triangulation for meshes
|
||||
"should_generate_uvs": False, # If UV coordinates should also be generated
|
||||
# Possible IFC representation classes:
|
||||
# IfcExtrudedAreaSolid/IfcRectangleProfileDef
|
||||
# IfcExtrudedAreaSolid/IfcCircleProfileDef
|
||||
# IfcExtrudedAreaSolid/IfcArbitraryClosedProfileDef
|
||||
# IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids
|
||||
# IfcExtrudedAreaSolid/IfcMaterialProfileSetUsage
|
||||
# IfcGeometricCurveSet/IfcTextLiteral
|
||||
# IfcTextLiteral
|
||||
"ifc_representation_class": None, # Whether to cast a mesh into a particular class
|
||||
"profile_set_usage": None, # The material profile set if the extrusion requires it
|
||||
"text_literal": None, # The text literal if the representation requires it
|
||||
}
|
||||
usecase.ifc_vertices = []
|
||||
for key, value in usecase_settings.items():
|
||||
usecase.settings[key] = value
|
||||
return usecase.execute()
|
||||
|
||||
def execute(self) -> ifcopenshell.entity_instance:
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
self.is_manifold = None
|
||||
if (
|
||||
isinstance(self.settings["geometry"], bpy.types.Mesh)
|
||||
@@ -374,10 +377,12 @@ class Usecase:
|
||||
return items
|
||||
|
||||
def create_plane(self, polygon):
|
||||
return self.file.createIfcPlane(Position=self.file.createIfcAxis2Placement3D(
|
||||
Location=self.file.createIfcCartesianPoint(polygon.center),
|
||||
Axis=self.file.createIfcDirection(polygon.normal),
|
||||
))
|
||||
return self.file.createIfcPlane(
|
||||
Position=self.file.createIfcAxis2Placement3D(
|
||||
Location=self.file.createIfcCartesianPoint(polygon.center),
|
||||
Axis=self.file.createIfcDirection(polygon.normal),
|
||||
)
|
||||
)
|
||||
|
||||
def create_annotation_fill_areas(self, is_2d=False) -> list[ifcopenshell.entity_instance]:
|
||||
items = []
|
||||
|
||||
@@ -20,20 +20,23 @@ import ifcopenshell.util.unit
|
||||
from math import sin, cos
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
"depth": 0.2,
|
||||
"x_angle": 0, # Radians
|
||||
# Planes are defined either by Clipping objects
|
||||
# or by dictionaries of arguments for `Clipping.parse`
|
||||
"clippings": [], # A list of planes that define clipping half space solids
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
def add_slab_representation(file, **usecase_settings) -> None:
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
"depth": 0.2,
|
||||
"x_angle": 0, # Radians
|
||||
# Planes are defined either by Clipping objects
|
||||
# or by dictionaries of arguments for `Clipping.parse`
|
||||
"clippings": [], # A list of planes that define clipping half space solids
|
||||
}
|
||||
for key, value in usecase_settings.items():
|
||||
usecase.settings[key] = value
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
self.settings["unit_scale"] = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
return self.file.createIfcShapeRepresentation(
|
||||
|
||||
@@ -21,25 +21,28 @@ from math import sin, cos
|
||||
from ifcopenshell.util.data import Clipping
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
"length": 1.0,
|
||||
"height": 3.0,
|
||||
"offset": 0.0,
|
||||
"thickness": 0.2,
|
||||
# Sloped walls along the wall's X axis, provided in radians
|
||||
"x_angle": 0,
|
||||
# Planes are defined either by Clipping objects
|
||||
# or by dictionaries of arguments for `Clipping.parse`
|
||||
"clippings": [], # A list of planes that define clipping half space solids
|
||||
"booleans": [], # Any existing IfcBooleanResults
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
def add_wall_representation(file, **usecase_settings) -> None:
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
"length": 1.0,
|
||||
"height": 3.0,
|
||||
"offset": 0.0,
|
||||
"thickness": 0.2,
|
||||
# Sloped walls along the wall's X axis, provided in radians
|
||||
"x_angle": 0,
|
||||
# Planes are defined either by Clipping objects
|
||||
# or by dictionaries of arguments for `Clipping.parse`
|
||||
"clippings": [], # A list of planes that define clipping half space solids
|
||||
"booleans": [], # Any existing IfcBooleanResults
|
||||
}
|
||||
for key, value in usecase_settings.items():
|
||||
usecase.settings[key] = value
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
self.settings["unit_scale"] = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
self.settings["clippings"] = [Clipping.parse(c) for c in self.settings["clippings"]]
|
||||
|
||||
@@ -56,12 +56,7 @@ def create_ifc_window_frame_simple(
|
||||
th_left, th_up, th_right, th_bottom = thickness
|
||||
|
||||
def get_extruded_profile(profile):
|
||||
return builder.extrude(
|
||||
profile,
|
||||
size.y,
|
||||
position=position,
|
||||
**builder.extrude_kwargs("Y")
|
||||
)
|
||||
return builder.extrude(profile, size.y, position=position, **builder.extrude_kwargs("Y"))
|
||||
|
||||
# if all lining sides are present then we can just use two rectangles
|
||||
# as inner and outer curves of the profile
|
||||
@@ -207,12 +202,7 @@ def create_ifc_window(
|
||||
|
||||
glass_position = frame_position + V(0, frame_size.y / 2 - glass_thickness / 2, 0)
|
||||
glass_rect = builder.deep_copy(frame_extruded_items[0].SweptArea.InnerCurves[0])
|
||||
glass = builder.extrude(
|
||||
glass_rect,
|
||||
glass_thickness,
|
||||
position=glass_position,
|
||||
**builder.extrude_kwargs("Y")
|
||||
)
|
||||
glass = builder.extrude(glass_rect, glass_thickness, position=glass_position, **builder.extrude_kwargs("Y"))
|
||||
|
||||
output_items = [lining_items, frame_extruded_items, [glass]]
|
||||
builder.translate(chain(*output_items), position)
|
||||
@@ -220,73 +210,76 @@ def create_ifc_window(
|
||||
return output_items
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
"""units in settings expected to be in ifc project units"""
|
||||
self.file = file
|
||||
# http://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcWindow.htm
|
||||
# http://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcWindowTypePartitioningEnum.htm
|
||||
# http://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcWindowLiningProperties.htm
|
||||
# http://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcWindowPanelProperties.htm
|
||||
self.settings = {"unit_scale": ifcopenshell.util.unit.calculate_unit_scale(self.file)}
|
||||
self.settings.update(
|
||||
{
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
# SINGLE_PANEL, DOUBLE_PANEL_HORIZONTAL, DOUBLE_PANEL_VERTICAL,
|
||||
# TRIPLE_PANEL_BOTTOM, TRIPLE_PANEL_HORIZONTAL, TRIPLE_PANEL_LEFT,
|
||||
# TRIPLE_PANEL_RIGHT, TRIPLE_PANEL_TOP, TRIPLE_PANEL_VERTICAL
|
||||
"partition_type": "SINGLE_PANEL",
|
||||
"overall_height": self.convert_si_to_unit(0.9),
|
||||
"overall_width": self.convert_si_to_unit(0.6),
|
||||
"lining_properties": {
|
||||
"LiningDepth": self.convert_si_to_unit(0.050),
|
||||
"LiningThickness": self.convert_si_to_unit(0.050),
|
||||
"LiningOffset": self.convert_si_to_unit(0.050), # offset to the wall
|
||||
# offset from the wall
|
||||
"LiningToPanelOffsetX": self.convert_si_to_unit(0.025),
|
||||
# offset from the lining
|
||||
# that way it allows you to define overall_depth constant between all panels
|
||||
# and still have panels with different size:
|
||||
# overall_depth = lining_depth + offset_y
|
||||
# full offset from X axis = overall_depth - frame_depth
|
||||
"LiningToPanelOffsetY": self.convert_si_to_unit(0.025),
|
||||
# applies to DoublePanelVertical, TriplePanelBottom, TriplePanelTop,
|
||||
# TriplePanelLeft, TriplePanelRight
|
||||
# mullion - horizontal distance between panels
|
||||
"MullionThickness": self.convert_si_to_unit(0.050),
|
||||
# distance from the first lining to the mullion center
|
||||
"FirstMullionOffset": self.convert_si_to_unit(0.3),
|
||||
# applies to TriplePanelVertical
|
||||
# distance from the first lining to the second mullion center
|
||||
"SecondMullionOffset": self.convert_si_to_unit(0.45),
|
||||
# applies to DoublePanelHorizontal, TriplePanelBottom, TriplePanelTop,
|
||||
# TriplePanelLeft, TriplePanelRight
|
||||
# works similar way to mullion
|
||||
"TransomThickness": self.convert_si_to_unit(0.050),
|
||||
"FirstTransomOffset": self.convert_si_to_unit(0.3),
|
||||
# applies to TriplePanelHorizontal
|
||||
"SecondTransomOffset": self.convert_si_to_unit(0.6),
|
||||
def add_window_representation(file, **usecase_settings) -> None:
|
||||
"""units in usecase_settings expected to be in ifc project units"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
# http://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcWindow.htm
|
||||
# http://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcWindowTypePartitioningEnum.htm
|
||||
# http://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcWindowLiningProperties.htm
|
||||
# http://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcWindowPanelProperties.htm
|
||||
usecase.settings = {"unit_scale": ifcopenshell.util.unit.calculate_unit_scale(usecase.file)}
|
||||
usecase.settings.update(
|
||||
{
|
||||
"context": None, # IfcGeometricRepresentationContext
|
||||
# SINGLE_PANEL, DOUBLE_PANEL_HORIZONTAL, DOUBLE_PANEL_VERTICAL,
|
||||
# TRIPLE_PANEL_BOTTOM, TRIPLE_PANEL_HORIZONTAL, TRIPLE_PANEL_LEFT,
|
||||
# TRIPLE_PANEL_RIGHT, TRIPLE_PANEL_TOP, TRIPLE_PANEL_VERTICAL
|
||||
"partition_type": "SINGLE_PANEL",
|
||||
"overall_height": usecase.convert_si_to_unit(0.9),
|
||||
"overall_width": usecase.convert_si_to_unit(0.6),
|
||||
"lining_properties": {
|
||||
"LiningDepth": usecase.convert_si_to_unit(0.050),
|
||||
"LiningThickness": usecase.convert_si_to_unit(0.050),
|
||||
"LiningOffset": usecase.convert_si_to_unit(0.050), # offset to the wall
|
||||
# offset from the wall
|
||||
"LiningToPanelOffsetX": usecase.convert_si_to_unit(0.025),
|
||||
# offset from the lining
|
||||
# that way it allows you to define overall_depth constant between all panels
|
||||
# and still have panels with different size:
|
||||
# overall_depth = lining_depth + offset_y
|
||||
# full offset from X axis = overall_depth - frame_depth
|
||||
"LiningToPanelOffsetY": usecase.convert_si_to_unit(0.025),
|
||||
# applies to DoublePanelVertical, TriplePanelBottom, TriplePanelTop,
|
||||
# TriplePanelLeft, TriplePanelRight
|
||||
# mullion - horizontal distance between panels
|
||||
"MullionThickness": usecase.convert_si_to_unit(0.050),
|
||||
# distance from the first lining to the mullion center
|
||||
"FirstMullionOffset": usecase.convert_si_to_unit(0.3),
|
||||
# applies to TriplePanelVertical
|
||||
# distance from the first lining to the second mullion center
|
||||
"SecondMullionOffset": usecase.convert_si_to_unit(0.45),
|
||||
# applies to DoublePanelHorizontal, TriplePanelBottom, TriplePanelTop,
|
||||
# TriplePanelLeft, TriplePanelRight
|
||||
# works similar way to mullion
|
||||
"TransomThickness": usecase.convert_si_to_unit(0.050),
|
||||
"FirstTransomOffset": usecase.convert_si_to_unit(0.3),
|
||||
# applies to TriplePanelHorizontal
|
||||
"SecondTransomOffset": usecase.convert_si_to_unit(0.6),
|
||||
"ShapeAspectStyle": None, # DEPRECATED
|
||||
},
|
||||
"panel_properties": [
|
||||
{
|
||||
"FrameDepth": usecase.convert_si_to_unit(0.035), # by Y
|
||||
"FrameThickness": usecase.convert_si_to_unit(0.035), # by X
|
||||
# BOTTOM, LEFT, MIDDLE, RIGHT, TOP
|
||||
"PanelPosition": ..., # NEVER USED
|
||||
# defines the basic ways to describe how window panels operate
|
||||
# how it's hanged, how it opens
|
||||
"OperationType": None, # NEVER USED
|
||||
"ShapeAspectStyle": None, # DEPRECATED
|
||||
},
|
||||
"panel_properties": [
|
||||
{
|
||||
"FrameDepth": self.convert_si_to_unit(0.035), # by Y
|
||||
"FrameThickness": self.convert_si_to_unit(0.035), # by X
|
||||
# BOTTOM, LEFT, MIDDLE, RIGHT, TOP
|
||||
"PanelPosition": ..., # NEVER USED
|
||||
# defines the basic ways to describe how window panels operate
|
||||
# how it's hanged, how it opens
|
||||
"OperationType": None, # NEVER USED
|
||||
"ShapeAspectStyle": None, # DEPRECATED
|
||||
},
|
||||
],
|
||||
}
|
||||
)
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
self.settings["panel_schema"] = DEFAULT_PANEL_SCHEMAS[self.settings["partition_type"]]
|
||||
for key, value in usecase_settings.items():
|
||||
usecase.settings[key] = value
|
||||
usecase.settings["panel_schema"] = DEFAULT_PANEL_SCHEMAS[usecase.settings["partition_type"]]
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
builder = ShapeBuilder(self.file)
|
||||
overall_height = self.settings["overall_height"]
|
||||
|
||||
@@ -20,13 +20,16 @@ import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
self.file = file
|
||||
self.settings = {"product": None, "representation": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
def assign_representation(file, **usecase_settings) -> None:
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"product": None, "representation": None}
|
||||
for key, value in usecase_settings.items():
|
||||
usecase.settings[key] = value
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
if self.settings["product"].is_a("IfcProduct"):
|
||||
product_type = ifcopenshell.util.element.get_type(self.settings["product"])
|
||||
|
||||
@@ -21,44 +21,41 @@ import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"relating_element": None,
|
||||
"related_element": None,
|
||||
"description": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
def connect_element(file, **usecase_settings) -> None:
|
||||
settings = {
|
||||
"relating_element": None,
|
||||
"related_element": None,
|
||||
"description": None,
|
||||
}
|
||||
for key, value in usecase_settings.items():
|
||||
settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
incompatible_connections = []
|
||||
incompatible_connections = []
|
||||
|
||||
for rel in self.settings["relating_element"].ConnectedFrom:
|
||||
if rel.is_a() == "IfcRelConnectsElements" and rel.RelatingElement == self.settings["related_element"]:
|
||||
incompatible_connections.append(rel)
|
||||
for rel in settings["relating_element"].ConnectedFrom:
|
||||
if rel.is_a() == "IfcRelConnectsElements" and rel.RelatingElement == settings["related_element"]:
|
||||
incompatible_connections.append(rel)
|
||||
|
||||
for rel in self.settings["related_element"].ConnectedTo:
|
||||
if rel.is_a() == "IfcRelConnectsElements" and rel.RelatedElement == self.settings["relating_element"]:
|
||||
incompatible_connections.append(rel)
|
||||
for rel in settings["related_element"].ConnectedTo:
|
||||
if rel.is_a() == "IfcRelConnectsElements" and rel.RelatedElement == settings["relating_element"]:
|
||||
incompatible_connections.append(rel)
|
||||
|
||||
if incompatible_connections:
|
||||
for connection in set(incompatible_connections):
|
||||
history = connection.OwnerHistory
|
||||
self.file.remove(connection)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
if incompatible_connections:
|
||||
for connection in set(incompatible_connections):
|
||||
history = connection.OwnerHistory
|
||||
file.remove(connection)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
|
||||
for rel in self.settings["relating_element"].ConnectedTo:
|
||||
if rel.is_a() == "IfcRelConnectsElements" and rel.RelatedElement == self.settings["related_element"]:
|
||||
rel.Description = self.settings["description"]
|
||||
return rel
|
||||
for rel in settings["relating_element"].ConnectedTo:
|
||||
if rel.is_a() == "IfcRelConnectsElements" and rel.RelatedElement == settings["related_element"]:
|
||||
rel.Description = settings["description"]
|
||||
return rel
|
||||
|
||||
return self.file.createIfcRelConnectsElements(
|
||||
ifcopenshell.guid.new(),
|
||||
OwnerHistory=ifcopenshell.api.run("owner.create_owner_history", self.file),
|
||||
Description=self.settings["description"],
|
||||
RelatingElement=self.settings["relating_element"],
|
||||
RelatedElement=self.settings["related_element"],
|
||||
)
|
||||
return file.createIfcRelConnectsElements(
|
||||
ifcopenshell.guid.new(),
|
||||
OwnerHistory=ifcopenshell.api.run("owner.create_owner_history", file),
|
||||
Description=settings["description"],
|
||||
RelatingElement=settings["relating_element"],
|
||||
RelatedElement=settings["related_element"],
|
||||
)
|
||||
|
||||
@@ -21,76 +21,73 @@ import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"relating_element": None,
|
||||
"related_element": None,
|
||||
"relating_connection": "NOTDEFINED",
|
||||
"related_connection": "NOTDEFINED",
|
||||
"description": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
def connect_path(file, **usecase_settings) -> None:
|
||||
settings = {
|
||||
"relating_element": None,
|
||||
"related_element": None,
|
||||
"relating_connection": "NOTDEFINED",
|
||||
"related_connection": "NOTDEFINED",
|
||||
"description": None,
|
||||
}
|
||||
for key, value in usecase_settings.items():
|
||||
settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
incompatible_connections = []
|
||||
for rel in self.settings["relating_element"].ConnectedTo:
|
||||
if not rel.is_a("IfcRelConnectsPathElements"):
|
||||
continue
|
||||
if rel.RelatedElement == self.settings["related_element"]:
|
||||
incompatible_connections.append(rel)
|
||||
elif (
|
||||
rel.RelatingConnectionType in ["ATSTART", "ATEND"]
|
||||
and rel.RelatingConnectionType == self.settings["relating_connection"]
|
||||
):
|
||||
incompatible_connections.append(rel)
|
||||
incompatible_connections = []
|
||||
for rel in settings["relating_element"].ConnectedTo:
|
||||
if not rel.is_a("IfcRelConnectsPathElements"):
|
||||
continue
|
||||
if rel.RelatedElement == settings["related_element"]:
|
||||
incompatible_connections.append(rel)
|
||||
elif (
|
||||
rel.RelatingConnectionType in ["ATSTART", "ATEND"]
|
||||
and rel.RelatingConnectionType == settings["relating_connection"]
|
||||
):
|
||||
incompatible_connections.append(rel)
|
||||
|
||||
for rel in self.settings["relating_element"].ConnectedFrom:
|
||||
if not rel.is_a("IfcRelConnectsPathElements"):
|
||||
continue
|
||||
if (
|
||||
rel.RelatedConnectionType in ["ATSTART", "ATEND"]
|
||||
and rel.RelatedConnectionType == self.settings["relating_connection"]
|
||||
):
|
||||
incompatible_connections.append(rel)
|
||||
for rel in settings["relating_element"].ConnectedFrom:
|
||||
if not rel.is_a("IfcRelConnectsPathElements"):
|
||||
continue
|
||||
if (
|
||||
rel.RelatedConnectionType in ["ATSTART", "ATEND"]
|
||||
and rel.RelatedConnectionType == settings["relating_connection"]
|
||||
):
|
||||
incompatible_connections.append(rel)
|
||||
|
||||
for rel in self.settings["related_element"].ConnectedFrom:
|
||||
if not rel.is_a("IfcRelConnectsPathElements"):
|
||||
continue
|
||||
if (
|
||||
rel.RelatedConnectionType in ["ATSTART", "ATEND"]
|
||||
and rel.RelatedConnectionType == self.settings["related_connection"]
|
||||
):
|
||||
incompatible_connections.append(rel)
|
||||
for rel in settings["related_element"].ConnectedFrom:
|
||||
if not rel.is_a("IfcRelConnectsPathElements"):
|
||||
continue
|
||||
if (
|
||||
rel.RelatedConnectionType in ["ATSTART", "ATEND"]
|
||||
and rel.RelatedConnectionType == settings["related_connection"]
|
||||
):
|
||||
incompatible_connections.append(rel)
|
||||
|
||||
for rel in self.settings["related_element"].ConnectedTo:
|
||||
if not rel.is_a("IfcRelConnectsPathElements"):
|
||||
continue
|
||||
if rel.RelatedElement == self.settings["relating_element"]:
|
||||
incompatible_connections.append(rel)
|
||||
elif (
|
||||
rel.RelatingConnectionType in ["ATSTART", "ATEND"]
|
||||
and rel.RelatingConnectionType == self.settings["related_connection"]
|
||||
):
|
||||
incompatible_connections.append(rel)
|
||||
for rel in settings["related_element"].ConnectedTo:
|
||||
if not rel.is_a("IfcRelConnectsPathElements"):
|
||||
continue
|
||||
if rel.RelatedElement == settings["relating_element"]:
|
||||
incompatible_connections.append(rel)
|
||||
elif (
|
||||
rel.RelatingConnectionType in ["ATSTART", "ATEND"]
|
||||
and rel.RelatingConnectionType == settings["related_connection"]
|
||||
):
|
||||
incompatible_connections.append(rel)
|
||||
|
||||
if incompatible_connections:
|
||||
for connection in set(incompatible_connections):
|
||||
history = connection.OwnerHistory
|
||||
self.file.remove(connection)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
if incompatible_connections:
|
||||
for connection in set(incompatible_connections):
|
||||
history = connection.OwnerHistory
|
||||
file.remove(connection)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
|
||||
return self.file.createIfcRelConnectsPathElements(
|
||||
ifcopenshell.guid.new(),
|
||||
OwnerHistory=ifcopenshell.api.run("owner.create_owner_history", self.file),
|
||||
Description=self.settings["description"],
|
||||
RelatingElement=self.settings["relating_element"],
|
||||
RelatedElement=self.settings["related_element"],
|
||||
RelatingConnectionType=self.settings["relating_connection"],
|
||||
RelatedConnectionType=self.settings["related_connection"],
|
||||
RelatingPriorities=[],
|
||||
RelatedPriorities=[],
|
||||
)
|
||||
return file.createIfcRelConnectsPathElements(
|
||||
ifcopenshell.guid.new(),
|
||||
OwnerHistory=ifcopenshell.api.run("owner.create_owner_history", file),
|
||||
Description=settings["description"],
|
||||
RelatingElement=settings["relating_element"],
|
||||
RelatedElement=settings["related_element"],
|
||||
RelatingConnectionType=settings["relating_connection"],
|
||||
RelatedConnectionType=settings["related_connection"],
|
||||
RelatingPriorities=[],
|
||||
RelatedPriorities=[],
|
||||
)
|
||||
|
||||
@@ -21,20 +21,25 @@ import ifcopenshell.api
|
||||
import ifcopenshell.util.unit
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, element=None, context=None, p1=None, p2=None, elevation=None, height=None, thickness=None, is_si=True):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"element": element,
|
||||
"context": context,
|
||||
"p1": p1,
|
||||
"p2": p2,
|
||||
"elevation": elevation,
|
||||
"height": height,
|
||||
"thickness": thickness,
|
||||
"is_si": is_si
|
||||
}
|
||||
def create_2pt_wall(
|
||||
file, element=None, context=None, p1=None, p2=None, elevation=None, height=None, thickness=None, is_si=True
|
||||
) -> None:
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {
|
||||
"element": element,
|
||||
"context": context,
|
||||
"p1": p1,
|
||||
"p2": p2,
|
||||
"elevation": elevation,
|
||||
"height": height,
|
||||
"thickness": thickness,
|
||||
"is_si": is_si,
|
||||
}
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
self.settings["unit_scale"] = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
|
||||
@@ -44,9 +49,9 @@ class Usecase:
|
||||
length = float(np.linalg.norm(self.settings["p2"] - self.settings["p1"]))
|
||||
|
||||
if not self.settings["is_si"]:
|
||||
length=self.convert_unit_to_si(length)
|
||||
self.settings["height"]=self.convert_unit_to_si(self.settings["height"])
|
||||
self.settings["thickness"]=self.convert_unit_to_si(self.settings["thickness"])
|
||||
length = self.convert_unit_to_si(length)
|
||||
self.settings["height"] = self.convert_unit_to_si(self.settings["height"])
|
||||
self.settings["thickness"] = self.convert_unit_to_si(self.settings["thickness"])
|
||||
self.settings["p1"][0] = self.convert_unit_to_si(self.settings["p1"][0])
|
||||
self.settings["p1"][1] = self.convert_unit_to_si(self.settings["p1"][1])
|
||||
self.settings["elevation"] = self.convert_unit_to_si(self.settings["elevation"])
|
||||
|
||||
@@ -20,38 +20,35 @@ import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"relating_element": None,
|
||||
"related_element": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
def disconnect_element(file, **usecase_settings) -> None:
|
||||
settings = {
|
||||
"relating_element": None,
|
||||
"related_element": None,
|
||||
}
|
||||
for key, value in usecase_settings.items():
|
||||
settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
incompatible_connections = []
|
||||
incompatible_connections = []
|
||||
|
||||
for rel in self.settings["relating_element"].ConnectedTo:
|
||||
if rel.is_a() == "IfcRelConnectsElements" and rel.RelatedElement == self.settings["related_element"]:
|
||||
incompatible_connections.append(rel)
|
||||
for rel in settings["relating_element"].ConnectedTo:
|
||||
if rel.is_a() == "IfcRelConnectsElements" and rel.RelatedElement == settings["related_element"]:
|
||||
incompatible_connections.append(rel)
|
||||
|
||||
for rel in self.settings["relating_element"].ConnectedFrom:
|
||||
if rel.is_a() == "IfcRelConnectsElements" and rel.RelatingElement == self.settings["related_element"]:
|
||||
incompatible_connections.append(rel)
|
||||
for rel in settings["relating_element"].ConnectedFrom:
|
||||
if rel.is_a() == "IfcRelConnectsElements" and rel.RelatingElement == settings["related_element"]:
|
||||
incompatible_connections.append(rel)
|
||||
|
||||
for rel in self.settings["related_element"].ConnectedTo:
|
||||
if rel.is_a() == "IfcRelConnectsElements" and rel.RelatedElement == self.settings["relating_element"]:
|
||||
incompatible_connections.append(rel)
|
||||
for rel in settings["related_element"].ConnectedTo:
|
||||
if rel.is_a() == "IfcRelConnectsElements" and rel.RelatedElement == settings["relating_element"]:
|
||||
incompatible_connections.append(rel)
|
||||
|
||||
for rel in self.settings["related_element"].ConnectedFrom:
|
||||
if rel.is_a() == "IfcRelConnectsElements" and rel.RelatingElement == self.settings["relating_element"]:
|
||||
incompatible_connections.append(rel)
|
||||
for rel in settings["related_element"].ConnectedFrom:
|
||||
if rel.is_a() == "IfcRelConnectsElements" and rel.RelatingElement == settings["relating_element"]:
|
||||
incompatible_connections.append(rel)
|
||||
|
||||
if incompatible_connections:
|
||||
for connection in set(incompatible_connections):
|
||||
history = connection.OwnerHistory
|
||||
self.file.remove(connection)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
if incompatible_connections:
|
||||
for connection in set(incompatible_connections):
|
||||
history = connection.OwnerHistory
|
||||
file.remove(connection)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
|
||||
@@ -21,38 +21,35 @@ import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"relating_element": None,
|
||||
"related_element": None,
|
||||
"element": None,
|
||||
"connection_type": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
def disconnect_path(file, **usecase_settings) -> None:
|
||||
settings = {
|
||||
"relating_element": None,
|
||||
"related_element": None,
|
||||
"element": None,
|
||||
"connection_type": None,
|
||||
}
|
||||
for key, value in usecase_settings.items():
|
||||
settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
if self.settings["connection_type"] and self.settings["element"]:
|
||||
connections = [
|
||||
r
|
||||
for r in self.settings["element"].ConnectedTo
|
||||
if r.is_a("IfcRelConnectsPathElements") and r.RelatingConnectionType == self.settings["connection_type"]
|
||||
] + [
|
||||
r
|
||||
for r in self.settings["element"].ConnectedFrom
|
||||
if r.is_a("IfcRelConnectsPathElements") and r.RelatedConnectionType == self.settings["connection_type"]
|
||||
]
|
||||
else:
|
||||
connections = [
|
||||
r
|
||||
for r in self.settings["relating_element"].ConnectedTo
|
||||
if r.is_a("IfcRelConnectsPathElements") and r.RelatedElement == self.settings["related_element"]
|
||||
]
|
||||
if settings["connection_type"] and settings["element"]:
|
||||
connections = [
|
||||
r
|
||||
for r in settings["element"].ConnectedTo
|
||||
if r.is_a("IfcRelConnectsPathElements") and r.RelatingConnectionType == settings["connection_type"]
|
||||
] + [
|
||||
r
|
||||
for r in settings["element"].ConnectedFrom
|
||||
if r.is_a("IfcRelConnectsPathElements") and r.RelatedConnectionType == settings["connection_type"]
|
||||
]
|
||||
else:
|
||||
connections = [
|
||||
r
|
||||
for r in settings["relating_element"].ConnectedTo
|
||||
if r.is_a("IfcRelConnectsPathElements") and r.RelatedElement == settings["related_element"]
|
||||
]
|
||||
|
||||
for connection in set(connections):
|
||||
history = connection.OwnerHistory
|
||||
self.file.remove(connection)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
for connection in set(connections):
|
||||
history = connection.OwnerHistory
|
||||
file.remove(connection)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
|
||||
@@ -27,24 +27,26 @@ from typing import Optional, Union
|
||||
NPArrayOfFloats = npt.NDArray[np.float64]
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(
|
||||
self,
|
||||
file: ifcopenshell.file,
|
||||
product: ifcopenshell.entity_instance,
|
||||
matrix: Optional[NPArrayOfFloats] = None,
|
||||
is_si=True,
|
||||
should_transform_children=False,
|
||||
):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": product,
|
||||
"matrix": matrix if matrix is not None else np.eye(4),
|
||||
"is_si": is_si,
|
||||
"should_transform_children": should_transform_children,
|
||||
}
|
||||
def edit_object_placement(
|
||||
file: ifcopenshell.file,
|
||||
product: ifcopenshell.entity_instance,
|
||||
matrix: Optional[NPArrayOfFloats] = None,
|
||||
is_si=True,
|
||||
should_transform_children=False,
|
||||
) -> ifcopenshell.entity_instance:
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {
|
||||
"product": product,
|
||||
"matrix": matrix if matrix is not None else np.eye(4),
|
||||
"is_si": is_si,
|
||||
"should_transform_children": should_transform_children,
|
||||
}
|
||||
return usecase.execute()
|
||||
|
||||
def execute(self) -> ifcopenshell.entity_instance:
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
if not hasattr(self.settings["product"], "ObjectPlacement"):
|
||||
return
|
||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
|
||||
@@ -17,14 +17,17 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
self.file = file
|
||||
self.settings = {"representation": None}
|
||||
self.ifc_vertices = []
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
def map_representation(file, **usecase_settings) -> None:
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"representation": None}
|
||||
usecase.ifc_vertices = []
|
||||
for key, value in usecase_settings.items():
|
||||
usecase.settings[key] = value
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
mapping_source = self.get_mapping_source()
|
||||
|
||||
|
||||
@@ -19,13 +19,16 @@
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
self.file = file
|
||||
self.settings = {"item": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
def remove_boolean(file, **usecase_settings) -> None:
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"item": None}
|
||||
for key, value in usecase_settings.items():
|
||||
usecase.settings[key] = value
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
item = None
|
||||
for inverse in self.file.get_inverse(self.settings["item"]):
|
||||
|
||||
@@ -19,62 +19,57 @@
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file: ifcopenshell.file, representation: ifcopenshell.entity_instance):
|
||||
"""Remove a representation.
|
||||
def remove_representation(file: ifcopenshell.file, representation: ifcopenshell.entity_instance) -> None:
|
||||
"""Remove a representation.
|
||||
|
||||
Also purges representation items and their related elements
|
||||
like IfcStyledItem, tessellated facesets colours and UV map.
|
||||
Also purges representation items and their related elements
|
||||
like IfcStyledItem, tessellated facesets colours and UV map.
|
||||
|
||||
:param representation: IfcRepresentation to remove.
|
||||
Note that it's expected that IfcRepresentation won't be in use
|
||||
before calling this method (in such elements as IfcProductRepresentation, IfcShapeAspect)
|
||||
otherwise representation won't be removed.
|
||||
:type representation: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {"representation": representation}
|
||||
:param representation: IfcRepresentation to remove.
|
||||
Note that it's expected that IfcRepresentation won't be in use
|
||||
before calling this method (in such elements as IfcProductRepresentation, IfcShapeAspect)
|
||||
otherwise representation won't be removed.
|
||||
:type representation: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
settings = {"representation": representation}
|
||||
|
||||
def execute(self) -> None:
|
||||
styled_items = set()
|
||||
presentation_layer_assignments = set()
|
||||
textures = set()
|
||||
colours = set()
|
||||
for subelement in self.file.traverse(self.settings["representation"]):
|
||||
if subelement.is_a("IfcRepresentationItem"):
|
||||
[styled_items.add(s) for s in subelement.StyledByItem or []]
|
||||
# IFC2X3 is using LayerAssignments
|
||||
for s in (
|
||||
subelement.LayerAssignment
|
||||
if hasattr(subelement, "LayerAssignment")
|
||||
else subelement.LayerAssignments
|
||||
):
|
||||
presentation_layer_assignments.add(s)
|
||||
# IfcTessellatedFaceSet inverses
|
||||
[textures.add(t) for t in getattr(subelement, "HasTextures", []) or []]
|
||||
[colours.add(t) for t in getattr(subelement, "HasColours", []) or []]
|
||||
elif subelement.is_a("IfcRepresentation"):
|
||||
for layer in subelement.LayerAssignments:
|
||||
presentation_layer_assignments.add(layer)
|
||||
styled_items = set()
|
||||
presentation_layer_assignments = set()
|
||||
textures = set()
|
||||
colours = set()
|
||||
for subelement in file.traverse(settings["representation"]):
|
||||
if subelement.is_a("IfcRepresentationItem"):
|
||||
[styled_items.add(s) for s in subelement.StyledByItem or []]
|
||||
# IFC2X3 is using LayerAssignments
|
||||
for s in (
|
||||
subelement.LayerAssignment if hasattr(subelement, "LayerAssignment") else subelement.LayerAssignments
|
||||
):
|
||||
presentation_layer_assignments.add(s)
|
||||
# IfcTessellatedFaceSet inverses
|
||||
[textures.add(t) for t in getattr(subelement, "HasTextures", []) or []]
|
||||
[colours.add(t) for t in getattr(subelement, "HasColours", []) or []]
|
||||
elif subelement.is_a("IfcRepresentation"):
|
||||
for layer in subelement.LayerAssignments:
|
||||
presentation_layer_assignments.add(layer)
|
||||
|
||||
ifcopenshell.util.element.remove_deep2(
|
||||
self.file,
|
||||
self.settings["representation"],
|
||||
also_consider=list(styled_items | presentation_layer_assignments | colours),
|
||||
do_not_delete=self.file.by_type("IfcGeometricRepresentationContext"),
|
||||
)
|
||||
ifcopenshell.util.element.remove_deep2(
|
||||
file,
|
||||
settings["representation"],
|
||||
also_consider=list(styled_items | presentation_layer_assignments | colours),
|
||||
do_not_delete=file.by_type("IfcGeometricRepresentationContext"),
|
||||
)
|
||||
|
||||
for texture in textures:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, texture)
|
||||
for colour in colours:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, colour)
|
||||
for texture in textures:
|
||||
ifcopenshell.util.element.remove_deep2(file, texture)
|
||||
for colour in colours:
|
||||
ifcopenshell.util.element.remove_deep2(file, colour)
|
||||
|
||||
to_delete = getattr(self.file, "to_delete", ())
|
||||
for element in styled_items:
|
||||
if not element.Item or element.Item in to_delete:
|
||||
self.file.remove(element)
|
||||
for element in presentation_layer_assignments:
|
||||
if all(item in to_delete for item in element.AssignedItems):
|
||||
self.file.remove(element)
|
||||
to_delete = getattr(file, "to_delete", ())
|
||||
for element in styled_items:
|
||||
if not element.Item or element.Item in to_delete:
|
||||
file.remove(element)
|
||||
for element in presentation_layer_assignments:
|
||||
if all(item in to_delete for item in element.AssignedItems):
|
||||
file.remove(element)
|
||||
|
||||
@@ -20,13 +20,16 @@ import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
self.file = file
|
||||
self.settings = {"product": None, "representation": None}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
def unassign_representation(file, **usecase_settings) -> None:
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"product": None, "representation": None}
|
||||
for key, value in usecase_settings.items():
|
||||
usecase.settings[key] = value
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
if self.settings["product"].is_a("IfcProduct"):
|
||||
self.unassign_product_representation(self.settings["product"], self.settings["representation"])
|
||||
|
||||
Reference in New Issue
Block a user