Merge remote-tracking branch 'origin/v0.8.0' into light/radiance

This commit is contained in:
Chirag Singh
2024-09-01 12:42:50 +05:30
13 changed files with 218 additions and 103 deletions
@@ -30,6 +30,7 @@ class MATERIAL_UL_radiance_materials(bpy.types.UIList):
if self.layout_type in {"DEFAULT", "COMPACT"}: if self.layout_type in {"DEFAULT", "COMPACT"}:
row = layout.row(align=True) row = layout.row(align=True)
# Adding color preview or glass icon
if item.category == "Glass": if item.category == "Glass":
row.label(icon="SHADING_TEXTURE") row.label(icon="SHADING_TEXTURE")
else: else:
@@ -386,7 +386,6 @@ ground_glow source ground
self.report({"INFO"}, "Exported Scene file to: {}".format(scene_file)) self.report({"INFO"}, "Exported Scene file to: {}".format(scene_file))
print("Setting up Radiance scene...") print("Setting up Radiance scene...")
scene = pr.Scene("ascene") scene = pr.Scene("ascene")
material_path = os.path.join(output_dir, "materials.rad") material_path = os.path.join(output_dir, "materials.rad")
@@ -247,10 +247,17 @@ class ToggleContainerElement(bpy.types.Operator):
bl_idname = "bim.toggle_container_element" bl_idname = "bim.toggle_container_element"
bl_label = "Toggle Container Element" bl_label = "Toggle Container Element"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Toggle children\nALT+CLICK to recursively toggle children"
element_index: bpy.props.IntProperty() element_index: bpy.props.IntProperty()
is_recursive: bpy.props.BoolProperty(name="Is Recursive", default=False, options={"SKIP_SAVE"})
def invoke(self, context, event):
if event.type == "LEFTMOUSE" and event.alt:
self.is_recursive = True
return self.execute(context)
def execute(self, context): def execute(self, context):
core.toggle_container_element(tool.Spatial, element_index=self.element_index) core.toggle_container_element(tool.Spatial, element_index=self.element_index, is_recursive=self.is_recursive)
return {"FINISHED"} return {"FINISHED"}
+2 -2
View File
@@ -141,8 +141,8 @@ def delete_container(
spatial.import_spatial_decomposition() spatial.import_spatial_decomposition()
def toggle_container_element(spatial: tool.Spatial, element_index: int) -> None: def toggle_container_element(spatial: tool.Spatial, element_index: int, is_recursive: bool) -> None:
spatial.toggle_container_element(element_index) spatial.toggle_container_element(element_index, is_recursive=is_recursive)
spatial.load_contained_elements() spatial.load_contained_elements()
+49 -13
View File
@@ -199,14 +199,8 @@ class Spatial(bonsai.core.tool.Spatial):
src_obj.location.xy = destination_obj.location.xy src_obj.location.xy = destination_obj.location.xy
@classmethod @classmethod
def load_contained_elements(cls) -> None: def get_grouped_elements_in_container(cls, container: ifcopenshell.entity_instance) -> dict:
props = bpy.context.scene.BIMSpatialDecompositionProperties props = bpy.context.scene.BIMSpatialDecompositionProperties
props.elements.clear()
if not (container := props.active_container):
return
container = tool.Ifc.get().by_id(container.ifc_definition_id)
results: defaultdict[str, dict[int, Any]] = defaultdict(dict) results: defaultdict[str, dict[int, Any]] = defaultdict(dict)
if props.should_include_children: if props.should_include_children:
elements = ifcopenshell.util.element.get_decomposition(container, is_recursive=True) elements = ifcopenshell.util.element.get_decomposition(container, is_recursive=True)
@@ -222,25 +216,39 @@ class Spatial(bonsai.core.tool.Spatial):
class_data = results.setdefault(ifc_class, {}) class_data = results.setdefault(ifc_class, {})
type_data = class_data.setdefault(ifc_definition_id, {"type_name": type_name, "elements": []}) type_data = class_data.setdefault(ifc_definition_id, {"type_name": type_name, "elements": []})
type_data["elements"].append(element) type_data["elements"].append(element)
return results
@classmethod
def load_contained_elements(cls) -> None:
props = bpy.context.scene.BIMSpatialDecompositionProperties
props.elements.clear()
if not (container := props.active_container):
return
container = tool.Ifc.get().by_id(container.ifc_definition_id)
results = cls.get_grouped_elements_in_container(container)
expanded_elements = json.loads(props.expanded_elements) expanded_elements = json.loads(props.expanded_elements)
expanded_classes = expanded_elements.get("CLASS", []) expanded_classes = expanded_elements.get("CLASS", [])
expanded_ifc_ids = expanded_elements.get("IFC_ID", []) expanded_ifc_ids = expanded_elements.get("IFC_ID", [])
expanded_untyped = expanded_elements.get("UNTYPED_CLASSES", []) expanded_untyped = expanded_elements.get("UNTYPED_CLASSES", [])
expanded_classes_r = expanded_elements.get("CLASS_R", [])
total_elements = 0 total_elements = 0
for ifc_class in sorted(results.keys()): for ifc_class in sorted(results.keys()):
new = props.elements.add() new = props.elements.add()
new.name = ifc_class new.name = ifc_class
new.type = "CLASS" new.type = "CLASS"
class_is_expanded = ifc_class in expanded_classes class_is_expanded = ifc_class in expanded_classes
new.is_expanded = class_is_expanded class_is_expanded_r = ifc_class in expanded_classes_r
new.is_expanded = class_is_expanded or class_is_expanded_r
total = 0 total = 0
for ifc_definition_id in sorted( for ifc_definition_id in sorted(
results[ifc_class].keys(), key=lambda x: results[ifc_class][x]["type_name"] results[ifc_class].keys(), key=lambda x: results[ifc_class][x]["type_name"]
): ):
type_data = results[ifc_class][ifc_definition_id] type_data = results[ifc_class][ifc_definition_id]
total2 = len(type_data["elements"]) total2 = len(type_data["elements"])
if class_is_expanded: if new.is_expanded:
new2 = props.elements.add() new2 = props.elements.add()
new2.type = "TYPE" new2.type = "TYPE"
new2.name = type_data["type_name"] new2.name = type_data["type_name"]
@@ -251,9 +259,9 @@ class Spatial(bonsai.core.tool.Spatial):
type_is_expanded = ifc_class in expanded_untyped type_is_expanded = ifc_class in expanded_untyped
else: else:
type_is_expanded = ifc_definition_id in expanded_ifc_ids type_is_expanded = ifc_definition_id in expanded_ifc_ids
new2.is_expanded = type_is_expanded new2.is_expanded = type_is_expanded or class_is_expanded_r
if type_is_expanded: if new2.is_expanded:
for element in type_data["elements"]: for element in type_data["elements"]:
occurrence = props.elements.add() occurrence = props.elements.add()
occurrence.name = element.Name or "Unnamed" occurrence.name = element.Name or "Unnamed"
@@ -363,25 +371,53 @@ class Spatial(bonsai.core.tool.Spatial):
props.contracted_containers = json.dumps(contracted_containers) props.contracted_containers = json.dumps(contracted_containers)
@classmethod @classmethod
def toggle_container_element(cls, element_index: int) -> None: def toggle_container_element(cls, element_index: int, is_recursive: bool) -> None:
props = bpy.context.scene.BIMSpatialDecompositionProperties props = bpy.context.scene.BIMSpatialDecompositionProperties
expanded_elements: dict[str, list[Union[str, int]]] = json.loads(props.expanded_elements) expanded_elements: dict[str, list[Union[str, int]]] = json.loads(props.expanded_elements)
element = props.elements[element_index] element = props.elements[element_index]
if element.type == "CLASS": if element.type == "CLASS":
element_type = "CLASS" element_type = "CLASS"
filtered_item = element.name filtered_item = element.name
else: elif element.type == "TYPE":
if element.ifc_definition_id == 0: if element.ifc_definition_id == 0:
element_type = "UNTYPED_CLASSES" element_type = "UNTYPED_CLASSES"
filtered_item = element.ifc_class filtered_item = element.ifc_class
else: else:
element_type = "IFC_ID" element_type = "IFC_ID"
filtered_item = element.ifc_definition_id filtered_item = element.ifc_definition_id
else:
return
expanded_elements_list: list[Union[str, int]] = expanded_elements.setdefault(element_type, []) expanded_elements_list: list[Union[str, int]] = expanded_elements.setdefault(element_type, [])
if filtered_item in expanded_elements_list: if filtered_item in expanded_elements_list:
expanded_elements_list.remove(filtered_item) expanded_elements_list.remove(filtered_item)
should_expand = False
else: else:
expanded_elements_list.append(filtered_item) expanded_elements_list.append(filtered_item)
should_expand = True
if is_recursive and element.type == "CLASS":
container = tool.Ifc.get().by_id(props.active_container.ifc_definition_id)
results = cls.get_grouped_elements_in_container(container)
for ifc_class in results.keys():
if ifc_class != element.name:
continue
for ifc_definition_id in results[ifc_class].keys():
if ifc_definition_id == 0:
element_type = "UNTYPED_CLASSES"
filtered_item = ifc_class
else:
element_type = "IFC_ID"
filtered_item = ifc_definition_id
expanded_elements_list = expanded_elements.setdefault(element_type, [])
if should_expand is False and filtered_item in expanded_elements_list:
expanded_elements_list.remove(filtered_item)
elif should_expand is True and filtered_item not in expanded_elements_list:
expanded_elements_list.append(filtered_item)
props.expanded_elements = json.dumps(expanded_elements) props.expanded_elements = json.dumps(expanded_elements)
# HERE STARTS SPATIAL TOOL # HERE STARTS SPATIAL TOOL
+79 -86
View File
@@ -121,49 +121,34 @@ pressing the button on the top right of the **Viewport** panel. The hotkey is
Overview of all objects Overview of all objects
----------------------- -----------------------
The **Outliner** panel on the top right shows a hierarchy of all the currently All physical **Elements** are organised in a hierarchy of **Spatial
loaded physical **Objects** in your IFC project. These **Objects** correlate to Containers**. By default, this hierarchy represents a breakdown of spaces, from
what you can see in the **Viewport** panel. large spaces such as a site and a building, down to smaller spaces like
building storeys and room spaces. The hierarchy will always begin with an
**IfcProject**.
Every **Object** in the **Outliner** represents an IFC **Element**. These The :menuselection:`Properties --> Project Overview --> Spatial Decomposition`
**Objects** have a name with the pattern ``Class/Name``. The class prefix panel shows this hierarchy. Below, it shows a list of all **Elements**
represents the type of object, and the name is the name of the object. Examples contained inside the actively selected **Spatial Container**.
of classes you will see are ``IfcBuilding``, or ``IfcWall``. This naming
convention makes it easy to quickly spot types of objects.
.. image:: images/outliner.png .. image:: images/spatial-tree.png
Objects are organised in a hierarchy. By default, this hierarchy represents a With a **Spatial Container** selected, use the **Isolate** button or **Hide /
breakdown of spaces, from large spaces such as a site and a building, down to Show Icons** to quickly focus or control visibility. Use the search filters at
smaller spaces like building storeys and room spaces. The hierarchy will always the bottom of the **Container** or **Element** lists to quickly find objects,
begin with an **IfcProject** object. You can click on the triangle to toggle the and use the **Select Icon** to select them.
hierarchy.
.. image:: images/spatial-tree-features.png
**Elements** are grouped into IFC **Classes**, such as Wall, Slab, or Door.
Within that, **Elements** are grouped into **Construction Types**. You'll see a
count of how many objects of that type exist. In the example above, there is
only one stair contained in the building storey.
.. tip:: .. tip::
In large projects with deep hierarchies, you can ``Shift-LMB`` click the Hold :kbd:`Alt` when clicking on triangles in the hierarchy to show / hide
triangle to recursively toggle the hierarchy. You can also click and drag the children recursively.
``MMB`` to pan left and right.
When there are lots of objects, you can type a name in the filter box to quickly
identify objects by name or type.
.. image:: images/outliner-filter.png
Clicking on an object in the **Outliner** panel also selects the corresponding
object in the **Viewport** panel. A good strategy to find objects is to then use
``View > Frame Selected`` to zoom to it in the **Viewport**.
The **Outliner** panel is also great for isolating portions of your project. You
can include and exclude portions by clicking on the **Tick Icon** next to
collections of objects in the hierarchy.
Let's isolate a single building storey. Start by disabling the **Tick Icon**
next to the **IfcProject** collection. This will hide everything in the project.
Then navigate through the hierarchy and enable the **Tick Icon** next to an
**IfcBuildingStory**.
.. image:: images/outliner-isolate.png
Viewing element classes Viewing element classes
----------------------- -----------------------
@@ -185,16 +170,15 @@ properties and relationships it is allowed to have. For example, a Wall
worry about memorising all the available **Classes**, you'll get a feel for them worry about memorising all the available **Classes**, you'll get a feel for them
as you explore more. as you explore more.
To view an object's class, click on an object in the **Viewport** or **Outliner** To view an object's class, click on an object in the :menuselection:`3D
panel, then switch to the **Object Information** tab in the **Properties** panel. Viewport`, then go to :menuselection:`Properties --> Object Information -->
You can see the **Class** name in the **Object Metadata** subpanel. Object Metadata` to see the **Class** name.
.. image:: images/element-class.png .. image:: images/element-class.png
In this case, the **Class** of our roof is an **IfcSlab**. You'll notice this is In this case, the **Class** of our roof is an **IfcSlab**. You can also see the
the same **Class** name used as a prefix for the object name in the **Outliner** name of the actively selected object in the top left of the :menuselection:`3D
panel. You can also see the name of the actively selected object in the top left Viewport`.
of the **Viewport** panel.
.. warning:: .. warning::
@@ -219,24 +203,26 @@ not see it all the time.
classes and predefined types you should see. classes and predefined types you should see.
Press the **Select Icon** to select all objects that are of the same Press the **Select Icon** to select all objects that are of the same
**IfcSlab** **Class**. Then, you can isolate these elements by going to ``Object **IfcSlab** **Class**. Then, you can isolate these elements by going to
> Show/Hide > Hide Unselected`` (hotkey ``Shift-H``). To show all elements again, you can use :menuselection:`3D Viewport --> Object --> Show/Hide --> Hide Unselected`
``Object > Show/Hide > Show Hidden Objects`` (hotkey ``Alt-H``). If you want to (:kbd:`Shift-H`). To show all elements again, you can use :menuselection:`3D
hide elements instead, you can use ``Object > Show/Hidden > Hide Selected`` Viewport --> Object --> Show/Hide --> Show Hidden Objects` (:kbd:`Alt-H`). If
(hotkey ``H``). you want to hide elements instead, you can use :menuselection:`3D Viewport -->
Object --> Show/Hidden --> Hide Selected` (:kbd:`H`).
.. image:: images/element-class-select.png .. image:: images/element-class-select.png
.. note:: .. note::
Remember that Blender's hotkeys are context sensitive. Make sure your mouse Remember that Blender's hotkeys are context sensitive. Make sure your mouse
is hovering over the **Viewport** panel when you press a hotkey or no cake is hovering over the :menuselection:`Viewport` panel when you press a hotkey
for you. or no cake for you.
You can also see statistics about the number of selected objects. If you right You can also see statistics about the number of selected objects. If you right
click on the bottom right status bar and enable **Scene Statistics** you will click on the bottom right :menuselection:`Status Bar` and enable **Scene
see information like **Objects 4/4**, which means that 4 objects are selected Statistics** you will see information like **Objects 4/4**, which means that 4
out of 4 available objects. This is a great way of counting objects like toilets. objects are selected out of 4 available objects. This is a great way of
counting objects like toilets.
.. image:: images/scene-statistics.png .. image:: images/scene-statistics.png
@@ -244,7 +230,7 @@ Viewing attributes and properties
--------------------------------- ---------------------------------
You can view the **Attributes**, **Properties**, and **Quantities** of the You can view the **Attributes**, **Properties**, and **Quantities** of the
selected object in the **Object Properties** tab. selected object in the :menuselection:`Properties --> Object Information` tab.
Let's focus on **Attributes** first. Scroll down to the **Attributes** Let's focus on **Attributes** first. Scroll down to the **Attributes**
subpanel. **Attributes** are a limited set of fundamental data (usually less subpanel. **Attributes** are a limited set of fundamental data (usually less
@@ -279,7 +265,8 @@ have different **Properties** depending on what information they want to store.
Each **Property** has a name and a value, and are grouped into **Property Each **Property** has a name and a value, and are grouped into **Property
Sets**. Each **Property Set** also has a name. Sets**. Each **Property Set** also has a name.
You can find **Properties** in the **Object Property Sets** subpanel. You can find **Properties** in the :menuselection:`Properties --> Object
Information --> Property Sets` panel.
.. image:: images/psets.png .. image:: images/psets.png
@@ -303,7 +290,8 @@ value, and are grouped into **Quantity Sets**. Similarly, there are also common
quantities defined as part of the international standard, denoted by the prefix quantities defined as part of the international standard, denoted by the prefix
``Qto_``. This prefix is short for "Quantity Take-Off". ``Qto_``. This prefix is short for "Quantity Take-Off".
You can find **Quantities** in the **Object Quantity Sets** subpanel. You can find **Quantities** in the :menuselection:`Properties --> Object
Information --> Quantity Sets` panel.
.. image:: images/qtos.png .. image:: images/qtos.png
@@ -313,16 +301,17 @@ Finding the location of objects
Every object in the built environment has a location in the world. For example, Every object in the built environment has a location in the world. For example,
a chair will be located in a space, and a wall is typically located in a a chair will be located in a space, and a wall is typically located in a
building storey. You've already seen this hierarchy of spaces in the building storey. You've already seen this hierarchy of spaces in the
**Outliner** panel, where an IFC project is broken down into site, building, :menuselection:`Properties --> Project Overview --> Spatial Decomposition`
storeys, and spaces. panel, where an IFC project is broken down into site, building, storeys, and
spaces.
Sometimes, objects may have multiple relevant locations, such Sometimes, objects may have multiple relevant locations, such
as a multi-storey column which can be related to multiple building storeys. as a multi-storey column which can be related to multiple building storeys.
Even in these cases, IFC enforces one location to be its primary Even in these cases, IFC enforces one location to be its primary
location, known as its **Spatial Container**. location, known as its **Spatial Container**.
If you click on any object, you can see its location in the **Spatial If you click on any object, you can see its location in the
Container** subpanel in the **Object Information** tab. :menuselection:`Properties --> Object Information --> Spatial Container` panel.
Press the **Select Icon** to select all objects that are in the same location. Press the **Select Icon** to select all objects that are in the same location.
@@ -334,20 +323,22 @@ Checking construction types
Almost everything in the built environment will have a **Construction Type**. Almost everything in the built environment will have a **Construction Type**.
For example, an architect will specify a door type for every door in a project. For example, an architect will specify a door type for every door in a project.
You can see a list of **Construction Types** in the **Outliner** panel in the You can see a list of **Construction Types** in the :menuselection:`Outliner`
**Types** collection. For example, if the architect has a wall types schedule in the **Types** collection. For example, if the architect has a wall types
with the wall type names of ``WT01``, ``WT02``, and ``WT03``, you should see schedule with the wall type names of ``WT01``, ``WT02``, and ``WT03``, you
three **IfcWallType** objects with those same names in the **Outliner**. should see three **IfcWallType** objects with those same names in the
**Outliner**.
You can click on these types to see more details about them in the You can click on these types to see more details about them in the
**Properties** panel. :menuselection:`Properties` panel.
.. image:: images/outliner-types.png .. image:: images/outliner-types.png
When selecting an object, you can also see its construction type in **Object When selecting an object, you can also see its construction type in
Information** under the **Type** subpanel. You can press the **Select Icon** to :menuselection:`Properties --> Object Information --> Type`. You can press the
select all objects that are of the same **Construction Type**. You can use the **Select Icon** to select all objects that are of the same **Construction
hide and isolate hotkeys to quickly view them in the model. Type**. You can use the hide and isolate hotkeys to quickly view them in the
model.
.. image:: images/properties-types.png .. image:: images/properties-types.png
@@ -361,10 +352,10 @@ geometry of the pump, so all occurrences of that pump will have the same
geometry. geometry.
You can visually inspect types in isolation to the rest of the model. Types are You can visually inspect types in isolation to the rest of the model. Types are
hidden by default, so first enable the visibility of the **Types** collection in hidden by default, so first enable the visibility of the **Types** collection
the **Outliner** by pressing the **Visibility Icon**. Then, select a type, and in the **Outliner** by pressing the **Visibility Icon**. Then, select a type,
click on ``View > Local View > Toggle Local View`` (hotkey ``/``) in the and click on :menuselection:`3D Viewport --> View --> Local View --> Toggle
**Viewport**. Toggle the view to see the entire model again. Local View` (:kbd:`/`). Toggle the view to see the entire model again.
.. image:: images/type-local-view.png .. image:: images/type-local-view.png
@@ -383,8 +374,8 @@ resources. For example, a **Material** might be blockwork. Another
**Material** might be in-situ concrete. **Materials** are grouped into **Material** might be in-situ concrete. **Materials** are grouped into
categories like steel, concrete, brick, block, and so on. categories like steel, concrete, brick, block, and so on.
We can see a list of **Materials** used in the project in the **Materials** We can see a list of **Materials** used in the project in the
subpanel in the **Geometry and Materials** tab. :menuselection:`Properties --> Geometry and Materials --> Materials` panel.
Press the **Select Icon** to select all objects that are of the selected Press the **Select Icon** to select all objects that are of the selected
material. material.
@@ -395,18 +386,20 @@ Taking simple measurements
-------------------------- --------------------------
The simplest form of measurement is the one that's already taken for you. The The simplest form of measurement is the one that's already taken for you. The
**Viewing attributes and properties** section describes how to view :ref:`quickstart/explore_model:Viewing attributes and properties` section
pre-calculated **Quantities**. describes how to view pre-calculated **Quantities**.
Sometimes, you may wish to take manual measurements yourself. You can view the Sometimes, you may wish to take manual measurements yourself. You can view the
overall X, Y, and Z dimensions of the currently selected object in the overall X, Y, and Z dimensions of the currently selected object in the
**Derived Coordinates** subpanel in the **Geometry and Materials** tab. :menuselection:`Properties --> Geometry and Materials --> Placement --> Derived
Coordinates` panel.
.. image:: images/dimensions.png .. image:: images/dimensions.png
Another way to manually measure from two points is to use the **Measure** tool. Another way to manually measure from two points is to use the **Measure** tool.
First, press the **Snap Icon** to enable snapping. Then choose snap targets in First, press the **Snap Icon** to enable snapping. Then choose snap targets in
the **Snap Menu** in the top middle section of the **Viewport** panel. the **Snap Menu** in the top middle section of the :menuselection:`3D
Viewport`.
.. image:: images/snap-targets.png .. image:: images/snap-targets.png
@@ -418,12 +411,12 @@ the **Snap Menu** in the top middle section of the **Viewport** panel.
measurements will automatically snap to the nearest object's surface. measurements will automatically snap to the nearest object's surface.
Now that you have configured snapping, press the **Measure Tool Icon** on the Now that you have configured snapping, press the **Measure Tool Icon** on the
left of the **Viewport** panel. **Click** and **Drag** in the 3D viewport to left of the :menuselection:`3D Viewport`. **Click** and **Drag** in the 3D
take a measurement. A circle will appear guiding the first point of your viewport to take a measurement. A circle will appear guiding the first point of
measurement. While **Dragging**, press the ``X`` key to lock the measurement your measurement. While **Dragging**, press the ``X`` key to lock the
line along the X axis. Alternatively, press the ``Y`` or ``Z`` key to lock the measurement line along the X axis. Alternatively, press the ``Y`` or ``Z`` key
measurement line along the Y or Z axis. Let go of the mouse to finish your to lock the measurement line along the Y or Z axis. Let go of the mouse to
measurement. finish your measurement.
.. image:: images/measure-tool.png .. image:: images/measure-tool.png
Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

@@ -0,0 +1,60 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2021 Thomas Krijnen <thomas@aecgeeks.com>
#
# This file is part of IfcOpenShell.
#
# IfcOpenShell is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcOpenShell is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
import pytest
import test.bootstrap
import ifcopenshell
import ifcopenshell.api
import ifcopenshell.util.element
class TestGetInfo2(test.bootstrap.IFC4):
def test_instance_attribute(self):
brep = self.file.create_entity("IfcFacetedBrep")
shell = self.file.create_entity("IfcClosedShell")
brep.Outer = shell
assert brep.get_info_2(recursive=True) == {
"Outer": {"CfsFaces": None, "id": 2, "type": "IfcClosedShell"},
"id": 1,
"type": "IfcFacetedBrep",
}
def test_aggregate_of_instance_attribute(self):
shell = self.file.create_entity("IfcClosedShell")
faces = [self.file.create_entity("IfcFace") for i in range(3)]
shell.CfsFaces = faces
assert shell.get_info_2(recursive=True)["CfsFaces"] == (
{"Bounds": None, "id": 2, "type": "IfcFace"},
{"Bounds": None, "id": 3, "type": "IfcFace"},
{"Bounds": None, "id": 4, "type": "IfcFace"},
)
def test_aggregate_of_aggregate_of_instance_attribute(self):
surface = self.file.create_entity("IfcBSplineSurfaceWithKnots")
pp = [self.file.create_entity("IfcCartesianPoint", [float(i)]) for i in range(4)]
surface.ControlPointsList = [pp[:2], pp[2:]]
assert surface.get_info_2(recursive=True)["ControlPointsList"] == (
(
{"Coordinates": (0.0,), "id": 2, "type": "IfcCartesianPoint"},
{"Coordinates": (1.0,), "id": 3, "type": "IfcCartesianPoint"},
),
(
{"Coordinates": (2.0,), "id": 4, "type": "IfcCartesianPoint"},
{"Coordinates": (3.0,), "id": 5, "type": "IfcCartesianPoint"},
),
)
+19
View File
@@ -773,6 +773,25 @@ static IfcUtil::ArgumentType helper_fn_attribute_type(const IfcUtil::IfcBaseClas
Py_INCREF(Py_None); Py_INCREF(Py_None);
return static_cast<PyObject*>(Py_None); return static_cast<PyObject*>(Py_None);
} }
} else if constexpr (std::is_same_v<U, IfcUtil::IfcBaseClass*>) {
return get_info_cpp(v);
} else if constexpr (std::is_same_v<U, aggregate_of_instance::ptr>) {
auto r = PyTuple_New(v->size());
for (unsigned i = 0; i < v->size(); ++i) {
PyTuple_SetItem(r, i, get_info_cpp((*v)[i]));
}
return r;
} else if constexpr (std::is_same_v<U, aggregate_of_aggregate_of_instance::ptr>) {
auto rs = PyTuple_New(v->size());
for (auto it = v->begin(); it != v->end(); ++it) {
auto v_i = it;
auto r = PyTuple_New(v_i->size());
for (unsigned i = 0; i < v_i->size(); ++i) {
PyTuple_SetItem(r, i, get_info_cpp((*v_i)[i]));
}
PyTuple_SetItem(rs, std::distance(v->begin(), it), r);
}
return rs;
} else if constexpr (std::is_same_v<U, empty_aggregate_t> || std::is_same_v<U, empty_aggregate_of_aggregate_t> || std::is_same_v<U, Blank>) { } else if constexpr (std::is_same_v<U, empty_aggregate_t> || std::is_same_v<U, empty_aggregate_of_aggregate_t> || std::is_same_v<U, Blank>) {
Py_INCREF(Py_None); Py_INCREF(Py_None);
return static_cast<PyObject*>(Py_None); return static_cast<PyObject*>(Py_None);