Compare commits

..

16 Commits

Author SHA1 Message Date
Dion Moult 10d30b0de7 Document api modules and require explicit imports of API submodules 2024-05-08 17:00:35 +10:00
Dion Moult 984b1212a6 Whoops 2024-05-08 09:45:12 +10:00
Andrej730 bc72c927c1 replace deprecated api call
noticed fixing #4632
2024-05-07 21:41:01 +05:00
Andrej730 b8275f2802 fix errors using deprecated api after ab696b9 #4632 2024-05-07 21:39:09 +05:00
Andrej730 267527f3fc fix issue after removing ifcopenshell.main in d76462ca4 2024-05-07 21:26:48 +05:00
Ryan Schultz c5b4513f65 fix #4622 - can now reassign IfcWindowStyle and IfcDoorStyle 2024-05-07 09:46:55 -05:00
Dion Moult 5da4fbb39c Fix #4631. Fix packaging problem on PyPI for IfcPatch. 2024-05-07 23:36:56 +10:00
Dion Moult 93639e9e50 Even more cleaning of documentation references 2024-05-07 19:08:13 +10:00
Dion Moult d76462ca42 Write more documentation
Sphinx autoapi also now only shows subpackages 1 level deep. This prevents us having a huge long list. Also don't show private or special members. Also show imported members so ifcopenshell.file and ifcopenshell.entity_instance works in docs too.
2024-05-07 17:32:47 +10:00
Dion Moult 722201a1af Add py.typed for static analysis with mypy 2024-05-07 17:15:58 +10:00
Dion Moult 0a3dddef2f More Python 2 to Python 3 upgrades 2024-05-07 16:03:07 +10:00
Dion Moult 26434f0331 Fix #4589. Symlink entire ifcopenshell dir for dev setups. 2024-05-07 15:51:48 +10:00
Dion Moult f6c2e2c20d Fix #4530. Fix various styling issues on docs. 2024-05-07 15:44:06 +10:00
Dion Moult 424a06f6c8 More cleaning up of forward type hints to fix import errors 2024-05-07 14:58:12 +10:00
Dion Moult 89c4cbeb05 Drop support for Python 2. 2024-05-07 12:17:46 +10:00
Dion Moult 7e13ed746e Don't rely on util for basic ifcopenshell module capabilities. Keep util as an optional module for users to load. 2024-05-07 10:32:02 +10:00
77 changed files with 917 additions and 443 deletions
@@ -282,7 +282,6 @@ class ImportIfcCsv(bpy.types.Operator):
empty=props.empty_value,
bool_true=props.true_value,
bool_false=props.false_value,
concat=props.concat_value
)
if not props.should_load_from_memory:
ifc_file.write(props.csv_ifc_file)
@@ -926,7 +926,7 @@ class OverrideDuplicateMove(bpy.types.Operator):
if r.is_a("IfcRelAssignsToGroup")
if "BBIM_Linked_Aggregate" in r.RelatingGroup.Name
]
tool.Ifc.run("group.unassign_group", group=linked_aggregate_group[0], product=new[0])
tool.Ifc.run("group.unassign_group", group=linked_aggregate_group[0], products=[new[0]])
class OverrideDuplicateMoveLinkedMacro(bpy.types.Macro):
@@ -185,6 +185,8 @@ class IfcClassData:
if element:
if element.is_a("IfcOpeningElement") or element.is_a("IfcOpeningStandardCase"):
return False
if element.is_a() in ("IfcWindowStyle", "IfcDoorStyle"): #see https://github.com/IfcOpenShell/IfcOpenShell/issues/4622#issuecomment-2095676368
return True
for product in cls.ifc_products():
if element.is_a(product[0]):
return True
+1
View File
@@ -16,6 +16,7 @@ a {
}
.sidebar-brand-text {
font-size: 1rem;
text-align: center;
}
.blockbutton {
max-width: 500px;
+6
View File
@@ -95,7 +95,10 @@ html_theme_options = {
"color-background-border": "#cfd0cb",
"color-foreground-primary": "#2e3436",
"color-sidebar-item-background--hover": "#f7f7f6",
"color-link": "#39b54a",
"color-link--visited": "#39b54a",
"color-link--hover": "#d98014",
"color-link--visited--hover": "#d98014",
"font-stack": "Nunito, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji"
},
"dark_css_variables": {
@@ -106,7 +109,10 @@ html_theme_options = {
"color-background-border": "#2e3436",
"color-foreground-primary": "#eeeeec",
"color-sidebar-item-background--hover": "#2e3436",
"color-link": "#39b54a",
"color-link--visited": "#39b54a",
"color-link--hover": "#d98014",
"color-link--visited--hover": "#d98014",
"font-stack": "Nunito, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji"
},
+12 -13
View File
@@ -92,13 +92,14 @@ For Linux or Mac:
$ ln -s $PWD/src/blenderbim/blenderbim/tool $BLENDER_ADDON_PATH/tool
$ ln -s $PWD/src/blenderbim/blenderbim/bim $BLENDER_ADDON_PATH/bim
# Remove the IfcOpenShell dependency Python code
$ rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifcopenshell/api
$ rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifcopenshell/util
# Copy over compiled IfcOpenShell files
$ cp $BLENDER_ADDON_PATH/libs/site/packages/ifcopenshell/*_wrapper* $PWD/src/ifcopenshell-python/ifcopenshell/
# Remove the IfcOpenShell dependency
$ rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifcopenshell
# Replace them with links to the Git repository
$ ln -s $PWD/src/ifcopenshell-python/ifcopenshell/api $BLENDER_ADDON_PATH/libs/site/packages/ifcopenshell/api
$ ln -s $PWD/src/ifcopenshell-python/ifcopenshell/util $BLENDER_ADDON_PATH/libs/site/packages/ifcopenshell/util
$ ln -s $PWD/src/ifcopenshell-python/ifcopenshell $BLENDER_ADDON_PATH/libs/site/packages/ifcopenshell
# Remove and link other IfcOpenShell utilities
$ rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifccsv.py
@@ -153,21 +154,19 @@ Before running it follow the instructions descibed after `rem` tags.
rd /S /Q "%blenderbim%\tool\"
rd /S /Q "%blenderbim%\bim\"
echo Replacing them with links to the Git repository...
mklink /D "%blenderbim%\core" "%cd%\src\blenderbim\blenderbim\core"
mklink /D "%blenderbim%\tool" "%cd%\src\blenderbim\blenderbim\tool"
mklink /D "%blenderbim%\bim" "%cd%\src\blenderbim\blenderbim\bim"
echo Copy over compiled IfcOpenShell files...
copy "%blenderbim%\libs\site\packages\ifcopenshell\*_wrapper*" "%cd%\src\ifcopenshell-python\ifcopenshell\"
echo Remove the IfcOpenShell dependency Python code...
rd /S /Q "%blenderbim%\libs\site\packages\ifcopenshell\api"
rd /S /Q "%blenderbim%\libs\site\packages\ifcopenshell\util"
echo Remove the IfcOpenShell dependency...
rd /S /Q "%blenderbim%\libs\site\packages\ifcopenshell"
echo Replacing them with links to the Git repository...
mklink /D "%blenderbim%\libs\site\packages\ifcopenshell\api" "%cd%\src\ifcopenshell-python\ifcopenshell\api"
mklink /D "%blenderbim%\libs\site\packages\ifcopenshell\util" "%cd%\src\ifcopenshell-python\ifcopenshell\util"
echo Replace them with links to the Git repository...
mklink /D "%blenderbim%\libs\site\packages\ifcopenshell" "%cd%\src\ifcopenshell-python\ifcopenshell"
echo Remove and link other IfcOpenShell utilities...
del "%blenderbim%\libs\site\packages\ifccsv.py"
+11 -22
View File
@@ -391,16 +391,15 @@ class IfcCsv:
empty: str = "",
bool_true: str = "YES",
bool_false: str = "NO",
concat: str = ", ",
) -> None:
ext = table.split(".")[-1].lower()
if ext == "csv":
self.import_csv(ifc_file, table, attributes, delimiter, null, empty, bool_true, bool_false, concat)
self.import_csv(ifc_file, table, attributes, delimiter, null, empty, bool_true, bool_false)
elif ext == "ods":
self.import_ods(ifc_file, table, attributes, null, empty, bool_true, bool_false, concat)
self.import_ods(ifc_file, table, attributes, null, empty, bool_true, bool_false)
elif ext == "xlsx":
self.import_xlsx(ifc_file, table, attributes, null, empty, bool_true, bool_false, concat)
self.import_xlsx(ifc_file, table, attributes, null, empty, bool_true, bool_false)
def import_csv(
self,
@@ -412,7 +411,6 @@ class IfcCsv:
empty: str = "",
bool_true: str = "YES",
bool_false: str = "NO",
concat: str = ", ",
) -> None:
with open(table, newline="", encoding="utf-8") as f:
reader = csv.reader(f, delimiter=delimiter)
@@ -425,17 +423,17 @@ class IfcCsv:
elif len(attributes) == len(headers) - 1:
attributes.insert(0, "") # The GlobalId column
continue
self.process_row(ifc_file, row, headers, attributes, null, empty, bool_true, bool_false, concat)
self.process_row(ifc_file, row, headers, attributes, null, empty, bool_true, bool_false)
def import_xlsx(self, ifc_file, table, attributes, null, empty, bool_true, bool_false, concat):
def import_xlsx(self, ifc_file, table, attributes, null, empty, bool_true, bool_false):
df = pd.read_excel(table)
self.import_pd(ifc_file, df, attributes, null, empty, bool_true, bool_false, concat)
self.import_pd(ifc_file, df, attributes, null, empty, bool_true, bool_false)
def import_ods(self, ifc_file, table, attributes, null, empty, bool_true, bool_false, concat):
def import_ods(self, ifc_file, table, attributes, null, empty, bool_true, bool_false):
df = pd.read_excel(table, engine="odf")
self.import_pd(ifc_file, df, attributes, null, empty, bool_true, bool_false, concat)
self.import_pd(ifc_file, df, attributes, null, empty, bool_true, bool_false)
def import_pd(self, ifc_file, df, attributes=None, null="-", empty="", bool_true="YES", bool_false="NO", concat=", "):
def import_pd(self, ifc_file, df, attributes=None, null="-", empty="", bool_true="YES", bool_false="NO"):
headers = df.columns.tolist()
if not attributes:
@@ -444,7 +442,7 @@ class IfcCsv:
attributes.insert(0, "") # The GlobalId column
for _, row in df.iterrows():
self.process_row(ifc_file, row.tolist(), headers, attributes, null, empty, bool_true, bool_false, concat)
self.process_row(ifc_file, row.tolist(), headers, attributes, null, empty, bool_true, bool_false)
def process_row(
self,
@@ -456,7 +454,6 @@ class IfcCsv:
empty: str,
bool_true: str,
bool_false: str,
concat: str
) -> None:
try:
element = ifc_file.by_guid(row[0])
@@ -475,14 +472,7 @@ class IfcCsv:
elif value == bool_false:
value = False
key = attributes[i] or headers[i]
try:
ifcopenshell.util.selector.set_element_value(ifc_file, element, key, value)
except ValueError as e:
if "enum property" in e.args[0]:
value = value.split(concat)
ifcopenshell.util.selector.set_element_value(ifc_file, element, key, value)
else:
raise e
ifcopenshell.util.selector.set_element_value(ifc_file, element, key, value)
if __name__ == "__main__":
@@ -544,6 +534,5 @@ if __name__ == "__main__":
delimiter=args.delimiter,
null=args.null,
empty=args.empty,
concat=args.concat
)
ifc_file.write(args.ifc)
@@ -0,0 +1,16 @@
Python API Reference
====================
This page contains auto-generated API reference documentation [#f1]_.
.. toctree::
:titlesonly:
:maxdepth: 1
{% for page in pages %}
{% if page.top_level_object and page.display %}
{{ page.include_path }}
{% endif %}
{% endfor %}
.. [#f1] Created with `sphinx-autoapi <https://github.com/readthedocs/sphinx-autoapi>`_
@@ -0,0 +1,114 @@
{% if not obj.display %}
:orphan:
{% endif %}
:py:mod:`{{ obj.name }}`
=========={{ "=" * obj.name|length }}
.. py:module:: {{ obj.name }}
{% if obj.docstring %}
.. autoapi-nested-parse::
{{ obj.docstring|indent(3) }}
{% endif %}
{% block subpackages %}
{% set visible_subpackages = obj.subpackages|selectattr("display")|list %}
{% if visible_subpackages %}
Subpackages
-----------
.. toctree::
:titlesonly:
:maxdepth: 1
{% for subpackage in visible_subpackages %}
{{ subpackage.short_name }}/index.rst
{% endfor %}
{% endif %}
{% endblock %}
{% block submodules %}
{% set visible_submodules = obj.submodules|selectattr("display")|list %}
{% if visible_submodules %}
Submodules
----------
.. toctree::
:titlesonly:
:maxdepth: 1
{% for submodule in visible_submodules %}
{{ submodule.short_name }}/index.rst
{% endfor %}
{% endif %}
{% endblock %}
{% block content %}
{% if obj.all is not none %}
{% set visible_children = obj.children|selectattr("short_name", "in", obj.all)|list %}
{% elif obj.type is equalto("package") %}
{% set visible_children = obj.children|selectattr("display")|list %}
{% else %}
{% set visible_children = obj.children|selectattr("display")|rejectattr("imported")|list %}
{% endif %}
{% if visible_children %}
{{ obj.type|title }} Contents
{{ "-" * obj.type|length }}---------
{% set visible_classes = visible_children|selectattr("type", "equalto", "class")|list %}
{% set visible_functions = visible_children|selectattr("type", "equalto", "function")|list %}
{% set visible_attributes = visible_children|selectattr("type", "equalto", "data")|list %}
{% if "show-module-summary" in autoapi_options and (visible_classes or visible_functions) %}
{% block classes scoped %}
{% if visible_classes %}
Classes
~~~~~~~
.. autoapisummary::
{% for klass in visible_classes %}
{{ klass.id }}
{% endfor %}
{% endif %}
{% endblock %}
{% block functions scoped %}
{% if visible_functions %}
Functions
~~~~~~~~~
.. autoapisummary::
{% for function in visible_functions %}
{{ function.id }}
{% endfor %}
{% endif %}
{% endblock %}
{% block attributes scoped %}
{% if visible_attributes %}
Attributes
~~~~~~~~~~
.. autoapisummary::
{% for attribute in visible_attributes %}
{{ attribute.id }}
{% endfor %}
{% endif %}
{% endblock %}
{% endif %}
{% for obj_item in visible_children %}
{{ obj_item.render()|indent(0) }}
{% endfor %}
{% endif %}
{% endblock %}
+26 -4
View File
@@ -8,6 +8,9 @@ h1, h2, h3, h4 {
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
h1 code.literal {
background: none;
}
a {
text-decoration: none;
}
@@ -16,6 +19,7 @@ a {
}
.sidebar-brand-text {
font-size: 1rem;
text-align: center;
}
.blockbutton {
max-width: 500px;
@@ -47,14 +51,32 @@ section img {
box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
border-radius: 5px;
}
/* Make it clearer which signatures are part of a class */
.py.class {
/* Make it clearer which signatures are part of a class */
border-left: 3px solid var(--color-brand-primary);
}
.py.function, .py.method {
/* Make it clearer which signatures are part of a method or function */
border-left: 3px solid var(--color-background-item);
.py.class > .sig {
background: var(--color-brand-primary) !important;
margin: 0;
border-radius: 0;
}
.py.class > .sig * {
color: #2e3436 !important;
}
.py.class > .sig a {
color: #fff;
}
/* Make it easier to spot functions and methods */
.py.function, .py.method {
border-top: 1px solid var(--color-background-item);
}
dl.py.property, dl.py.attribute, dl.py.method, dl.py.function {
padding-top: 10px;
padding-bottom: 10px;
}
.field-list > dt {
/* Clearly distinguish parameters otherwise it looks like a wall of text */
color: var(--color-brand-content);
+10 -1
View File
@@ -74,6 +74,9 @@ autoapi_dirs = ['../ifcopenshell', '../../bcf/src', '../../bsdd', '../../ifccsv'
# These are auto-generated based on the IFC schema, so exclude them
autoapi_ignore = ['*ifcopenshell/express/rules*']
# Custom autoapi templates to make it easier to read our docs
autoapi_template_dir = "_autoapi_templates"
# autoapi_options doesn't have show-module-summary, as it tends to create one
# page per function which contradicts the presentation of showing all functions
# as a list. This creates two possible locations where a function is documented
@@ -81,7 +84,7 @@ autoapi_ignore = ['*ifcopenshell/express/rules*']
# ifcopenshell.file is imported from ifcopenshell.file.file, but it gets pretty
# confusing to see the docs again in multiple places (seriously,
# ifcopenshell.file.file is everywhere).
autoapi_options = ['members', 'undoc-members', 'private-members', 'special-members', 'show-inheritance']
autoapi_options = ['members', 'undoc-members', 'show-inheritance', 'imported-members']
# This option is set to both to allow both class docstrings and __init__ docstrings.
autoapi_python_class_content = 'both'
@@ -130,7 +133,10 @@ html_theme_options = {
"color-background-border": "#cfd0cb",
"color-foreground-primary": "#2e3436",
"color-sidebar-item-background--hover": "#f7f7f6",
"color-link": "#39b54a",
"color-link--visited": "#39b54a",
"color-link--hover": "#d98014",
"color-link--visited--hover": "#d98014",
"font-stack": "Nunito, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji"
},
"dark_css_variables": {
@@ -141,7 +147,10 @@ html_theme_options = {
"color-background-border": "#2e3436",
"color-foreground-primary": "#eeeeec",
"color-sidebar-item-background--hover": "#2e3436",
"color-link": "#39b54a",
"color-link--visited": "#39b54a",
"color-link--hover": "#d98014",
"color-link--visited--hover": "#d98014",
"font-stack": "Nunito, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji"
},
@@ -21,14 +21,15 @@ Python API documentation is autogenerated from docstrings present in the source
code of the respective Python module.
If you want to build the documentation locally, the documentation system uses
`Sphinx <https://www.sphinx-doc.org/en/master/>`_. First, install the theme and
theme dependencies:
`Sphinx <https://www.sphinx-doc.org/en/master/>`_. First, install Sphinx and
dependencies:
.. code-block:: console
$ pip install furo
$ pip install sphinx
$ pip install sphinx-autoapi
$ pip install sphinx-copybutton
$ pip install furo
Now you can generate the documentation:
@@ -16,32 +16,51 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""The entry module for IfcOpenShell
"""Welcome to IfcOpenShell! IfcOpenShell provides a way to read and write IFCs.
Typically used for opening an IFC via a filepath, or accessing one of the
submodules.
IfcOpenShell can open IFC files, read entities (such as walls, buildings,
properties, systems, etc), edit attributes, write out ``.ifc`` files and more.
This module provides primitive functions to interact with IFC, including:
- For most users, you can open and read IFC models, see docs for :func:`open`.
This returns an :class:`file` object representing the IFC model. You can then
query the model to filter elements.
- For developers, you can query the schema itself, see docs for
:func:`schema_by_name`. This returns a schema object which you can use to
analyse the definitions of IFC classes and data types.
You may also be interested in:
- For model authoring and editing operations, see :mod:`ifcopenshell.api`.
- For extracting information from models, see :mod:`ifcopenshell.util`.
- For processing geometry, see :mod:`ifcopenshell.geom`.
For more details, consult https://docs.ifcopenshell.org/
Example:
.. code:: python
import ifcopenshell
print(ifcopenshell.version) # v0.7.0-1b1fd1e6
model = ifcopenshell.open("/path/to/model.ifc")
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
print(ifcopenshell.version) # v0.7.0-1b1fd1e6
model = ifcopenshell.open("/path/to/model.ifc")
walls = model.by_type("IfcWall")
for wall in walls:
print(wall.Name)
"""
import os
import sys
import tempfile
import zipfile
import tempfile
from pathlib import Path
from typing import Optional
from typing import Optional, Union
import ifcopenshell.util.file
if hasattr(os, "uname"):
platform_system = os.uname()[0].lower()
@@ -60,22 +79,17 @@ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "lib", p
try:
from . import ifcopenshell_wrapper
except Exception as e:
if int(python_version_tuple[0]) == 2:
# Only for py2, as py3 has exception chaining
import traceback
traceback.print_exc()
print("-" * 64)
except Exception:
raise ImportError("IfcOpenShell not built for '%s'" % python_distribution)
from . import guid
from .file import file
from .entity_instance import entity_instance, register_schema_attributes
from .sql import sqlite, sqlite_entity
try:
from .stream import stream, stream_entity
except: pass
except:
pass
READ_ERROR = ifcopenshell_wrapper.file_open_status.READ_ERROR
NO_HEADER = ifcopenshell_wrapper.file_open_status.NO_HEADER
@@ -84,19 +98,22 @@ UNSUPPORTED_SCHEMA = ifcopenshell_wrapper.file_open_status.UNSUPPORTED_SCHEMA
class Error(Exception):
"""Error used when a generic problem occurs"""
pass
class SchemaError(Error):
"""Error used when an IFC schema related problem occurs"""
pass
def open(path: "os.PathLike | str", format: str = None, should_stream: bool = False) -> file:
def open(path: Union[os.PathLike, str], format: Optional[str] = None, should_stream: bool = False) -> file:
"""Loads an IFC dataset from a filepath
You can specify a file format. If no format is given, it is guessed from its extension.
Currently supported specified format : .ifc | .ifcZIP | .ifcXML
You can specify a file format. If no format is given, it is guessed from
its extension. Currently supported specified format: .ifc | .ifcZIP |
.ifcXML.
You can then filter by element ID, class, etc, and subscript by id or guid.
@@ -114,7 +131,7 @@ def open(path: "os.PathLike | str", format: str = None, should_stream: bool = Fa
"""
path = Path(path)
if format is None:
format = ifcopenshell.util.file.guess_format(path)
format = guess_format(path)
if format == ".ifcXML":
f = ifcopenshell_wrapper.parse_ifcxml(str(path.absolute()))
if f:
@@ -141,8 +158,7 @@ def open(path: "os.PathLike | str", format: str = None, should_stream: bool = Fa
NO_HEADER: (Error, "Unable to parse IFC SPF header"),
UNSUPPORTED_SCHEMA: (
SchemaError,
"Unsupported schema: %s"
% ",".join(f.header.file_schema.schema_identifiers),
"Unsupported schema: %s" % ",".join(f.header.file_schema.schema_identifiers),
),
}[f.good().value()]
raise exc(msg)
@@ -152,7 +168,7 @@ def create_entity(type, schema="IFC4", *args, **kwargs):
"""Creates a new IFC entity that does not belong to an IFC file object
Note that it is more common to create entities within a existing file
object. See :meth:`ifcopenshell.file.file.create_entity`.
object. See :meth:`ifcopenshell.file.create_entity`.
:param type: Case insensitive name of the IFC class
:type type: string
@@ -161,7 +177,7 @@ def create_entity(type, schema="IFC4", *args, **kwargs):
:param args: The positional arguments of the IFC class
:param kwargs: The keyword arguments of the IFC class
:returns: An entity instance
:rtype: ifcopenshell.entity_instance.entity_instance
:rtype: ifcopenshell.entity_instance
Example:
@@ -226,4 +242,35 @@ def schema_by_name(
return ifcopenshell_wrapper.schema_by_name(schema)
from .main import *
def guess_format(path: Path) -> Union[str | None]:
"""Guesses the IFC format using file extension
IFCs may be serialised as different formats. The most common is a ``.ifc``
file, which is plaintext and stores data using the STEP Physical File
format. IFC can also be stored as a Zipfile, XML, JSON, or SQL.
This will return the canonical form of the format. For example, if a path
has the extension of .xml or .ifcxml (case insensitive), it will return
.ifcXML.
Users generally won't call this function. The :func:`open` function uses
this internally to guess the file format.
:return: Either .ifc, .ifcZIP, .ifcXML, .ifcJSON, .ifcSQLite, or None.
"""
suffix = path.suffix.lower()
if suffix == ".ifc":
return ".ifc"
elif suffix in (".ifczip", ".zip"):
return ".ifcZIP"
elif suffix in (".ifcxml", ".xml"):
return ".ifcXML"
elif suffix in (".ifcjson", ".json"):
return ".ifcJSON"
elif suffix in (".ifcsqlite", ".sqlite", ".db"):
return ".ifcSQLite"
return None
version = ifcopenshell_wrapper.version()
get_log = ifcopenshell_wrapper.get_log
@@ -16,21 +16,26 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""High level user-oriented IFC authoring capabilities"""
"""High level IFC authoring and editing functions
Authoring, editing, and deleting IFC data requires a detailed understanding of
the rules of the IFC schema. This API module provides simple to use authoring
functions that hide this complexity from you. Things like managing differences
between IFC versions, tracking owernship changes, or cleaning up after orphaned
relationships are all handled automatically.
"""
import json
import numpy
import pkgutil
import inspect
import importlib
import ifcopenshell
import ifcopenshell.api
from typing import Callable, Any, Optional
from functools import partial
pre_listeners = {}
post_listeners = {}
pre_listeners: dict[str, dict] = {}
post_listeners: dict[str, dict] = {}
def batching_argument_deprecation(
@@ -128,8 +133,8 @@ ARGUMENTS_DEPRECATION = {
}
CACHED_USECASE_CLASSES = {}
CACHED_USECASES = {}
CACHED_USECASE_CLASSES: dict[str, Callable] = {}
CACHED_USECASES: dict[str, Callable] = {}
def run(
@@ -152,9 +157,6 @@ def run(
for listener in pre_listeners.get(usecase_path, {}).values():
listener(usecase_path, ifc_file, settings)
# see #4531
if usecase_path in ARGUMENTS_DEPRECATION:
usecase_path, settings = ARGUMENTS_DEPRECATION[usecase_path](usecase_path, settings)
# TODO: settings serialization for client-server systems
# def serialise_entity_instance(entity):
@@ -250,8 +252,6 @@ def extract_docs(module, usecase):
import typing
import collections
results = []
inputs = collections.OrderedDict()
function_init = getattr(getattr(ifcopenshell.api, module), usecase).Usecase.__init__
@@ -300,14 +300,19 @@ def wrap_usecase(usecase_path, usecase):
def wrapper(*args, should_run_listeners: bool = True, **settings):
ifc_file = args[0] if args else None
nonlocal usecase_path
if should_run_listeners:
for listener in pre_listeners.get(usecase_path, {}).values():
listener(usecase_path, ifc_file, settings)
# see #4531
if usecase_path in ARGUMENTS_DEPRECATION:
usecase_path, settings = ARGUMENTS_DEPRECATION[usecase_path](usecase_path, settings)
try:
result = usecase(*args, **settings)
except TypeError as e:
msg = f"Incorrect function arguments provided for {usecase_path}\n{str(e)}. You specified args {args} and settings {settings}\n\nCorrect signature is {inspect.signature(Usecase.__init__)}\nSee help(ifcopenshell.api.{usecase_path}) for documentation."
msg = f"Incorrect function arguments provided for {usecase_path}\n{str(e)}. You specified args {args} and settings {settings}\n\nCorrect signature is {inspect.signature(usecase)}\nSee help(ifcopenshell.api.{usecase_path}) for documentation."
raise TypeError(msg) from e
if should_run_listeners:
@@ -322,50 +327,15 @@ def wrap_usecase(usecase_path, usecase):
return wrapper
# Expose all submodules. This means that the user can just type `import ifcopenshell.api`.
import ifcopenshell.api.aggregate as aggregate
import ifcopenshell.api.attribute as attribute
import ifcopenshell.api.boundary as boundary
import ifcopenshell.api.classification as classification
import ifcopenshell.api.constraint as constraint
import ifcopenshell.api.context as context
import ifcopenshell.api.control as control
import ifcopenshell.api.cost as cost
import ifcopenshell.api.document as document
import ifcopenshell.api.drawing as drawing
import ifcopenshell.api.geometry as geometry
import ifcopenshell.api.georeference as georeference
import ifcopenshell.api.grid as grid
import ifcopenshell.api.group as group
import ifcopenshell.api.layer as layer
import ifcopenshell.api.library as library
import ifcopenshell.api.material as material
import ifcopenshell.api.nest as nest
import ifcopenshell.api.owner as owner
import ifcopenshell.api.profile as profile
import ifcopenshell.api.project as project
import ifcopenshell.api.pset as pset
import ifcopenshell.api.pset_template as pset_template
import ifcopenshell.api.resource as resource
import ifcopenshell.api.root as root
import ifcopenshell.api.sequence as sequence
import ifcopenshell.api.spatial as spatial
import ifcopenshell.api.structural as structural
import ifcopenshell.api.style as style
import ifcopenshell.api.system as system
import ifcopenshell.api.type as type # Whoohoo!
import ifcopenshell.api.unit as unit
import ifcopenshell.api.void as void
def wrap_usecases(path, name):
"""This developer feature wraps an API module's usecases with listeners."""
import sys
import pkgutil
# Wrap all submodule usecases with listeners.
# This for loop also conveniently ensures that the above imports are comprehensive.
for loader, module_name, is_pkg in pkgutil.iter_modules(__path__, __name__ + "."):
# Check if it's a direct child (only one level deep)
if module_name.count(".") == __name__.count(".") + 1:
module_name = module_name.split(".")[-1]
module = globals()[module_name]
for usecase_name in vars(module):
usecase = getattr(module, usecase_name)
if callable(usecase):
usecase_path = f"{module_name}.{usecase_name}"
setattr(module, usecase_name, wrap_usecase(usecase_path, usecase))
module_name = name.split(".")[-1]
module = sys.modules[name]
for loader, usecase_name, is_pkg in pkgutil.iter_modules(path):
usecase = getattr(module, usecase_name)
if callable(usecase):
usecase_path = f"{module_name}.{usecase_name}"
setattr(module, usecase_name, wrap_usecase(usecase_path, usecase))
@@ -16,12 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Aggregates are the concept of breaking down larger wholes into smaller parts.
"""Aggregates is the concept of breaking down larger wholes into smaller parts.
One common use is spatial elements, such as how a site has multiple buildings,
and a building has multiple storeys. Another is for regular elements, such as
how a wall is made out of members and coverings.
For example, spatial elements such as sites are broken down into one or more
buildings, and a building is broken down into storeys. Another example is for
physical elements, such as how a wall is made out of members and coverings.
"""
from .. import wrap_usecases
from .assign_object import assign_object
from .unassign_object import unassign_object
wrap_usecases(__path__, __name__)
@@ -16,4 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Basic modification of the attributes of an element.
All IFC entities have attributes. Some of these attributes contain rules about
inheritance and what they are allowed to contain. These usecases make sure that
any editing complies with these rules.
"""
from .. import wrap_usecases
from .edit_attributes import edit_attributes
wrap_usecases(__path__, __name__)
@@ -18,9 +18,15 @@
"""Boundaries are primarily used for representing virtual interfaces between
spaces for energy analysis.
Boundaries may be associated with spaces or physical elements that enclose
spaces such as walls, doors, and windows.
"""
from .. import wrap_usecases
from .assign_connection_geometry import assign_connection_geometry
from .copy_boundary import copy_boundary
from .edit_attributes import edit_attributes
from .remove_boundary import remove_boundary
wrap_usecases(__path__, __name__)
@@ -16,9 +16,23 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Classification systems are a way of categorising objects
Although IFC itself comes with a built-in classification hierarchy (e.g.
IfcWall and its predefined types of PARTITIONING, etc), there are many external
or custom classification systems such as Uniclass, Omniclass and more. IFC is
able to integrate with any external classification system.
This API allows you to manage and assign external classification systems and
references.
"""
from .. import wrap_usecases
from .add_classification import add_classification
from .add_reference import add_reference
from .edit_classification import edit_classification
from .edit_reference import edit_reference
from .remove_classification import remove_classification
from .remove_reference import remove_reference
wrap_usecases(__path__, __name__)
@@ -16,6 +16,13 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Constraints are an advanced feature allowing you to specify parametric
limits on properties
Warning: usage of constraints are mostly untested in real life applications.
"""
from .. import wrap_usecases
from .add_metric import add_metric
from .add_metric_reference import add_metric_reference
from .add_objective import add_objective
@@ -25,3 +32,5 @@ from .edit_objective import edit_objective
from .remove_constraint import remove_constraint
from .remove_metric import remove_metric
from .unassign_constraint import unassign_constraint
wrap_usecases(__path__, __name__)
@@ -16,6 +16,18 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Contexts allow you to classify when geometry should be used in different
purposes
For example, a door may have many geometries assigned to it: a 3D body
geometry, a clearance zone for disabled access and egress, and a 2D top down
plan view representation annotating swing extents. Each geometry is assigned to
a context to distinguish its purpose and level of detail.
"""
from .. import wrap_usecases
from .add_context import add_context
from .edit_context import edit_context
from .remove_context import remove_context
wrap_usecases(__path__, __name__)
@@ -16,5 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Processes and costs may be controlled by other entities which indicate
constraints that determine how they can change
This is an advanced feature mostly used in 4D/5D
"""
from .. import wrap_usecases
from .assign_control import assign_control
from .unassign_control import unassign_control
wrap_usecases(__path__, __name__)
@@ -16,6 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Manage cost schedules, cost items, cost estimation and parametric quantity
take-off
IFC supports storing cost schedules and detailed cost breakdown structures,
including formulas, subtotals, and parametric links to model element
quantities.
"""
from .. import wrap_usecases
from .add_cost_item import add_cost_item
from .add_cost_item_quantity import add_cost_item_quantity
from .add_cost_schedule import add_cost_schedule
@@ -35,3 +44,5 @@ from .remove_cost_item_quantity import remove_cost_item_quantity
from .remove_cost_schedule import remove_cost_schedule
from .remove_cost_value import remove_cost_value
from .unassign_cost_item_quantity import unassign_cost_item_quantity
wrap_usecases(__path__, __name__)
@@ -16,6 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Reference external project documents and associate them to model elements
Some project information (drawings, specifications, certificates, reports, etc)
may be stored in external documents (locally or in a CDE). IFC lets you store a
register of documents with metadata and associate them with elements (both
physical and non-physical).
"""
from .. import wrap_usecases
from .add_information import add_information
from .add_reference import add_reference
from .assign_document import assign_document
@@ -24,3 +33,5 @@ from .edit_reference import edit_reference
from .remove_information import remove_information
from .remove_reference import remove_reference
from .unassign_document import unassign_document
wrap_usecases(__path__, __name__)
@@ -16,6 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Create relationships necessary for smart annotations for drawings
Drawings may be generated from modeled elements and annotations. These
annotations may have relationships which indicate smart data being populated.
"""
from .. import wrap_usecases
from .assign_product import assign_product
from .edit_text_literal import edit_text_literal
from .unassign_product import unassign_product
wrap_usecases(__path__, __name__)
@@ -16,6 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Create geometric representations and assign them to elements
These functions support both the creation of arbitrary geometry as well as
geometry that follows parametric rules (e.g. layered geometry or profiled
geometry extrusions).
"""
from .. import wrap_usecases
from .add_axis_representation import add_axis_representation
from .add_boolean import add_boolean
try:
@@ -51,3 +59,5 @@ from .map_representation import map_representation
from .remove_boolean import remove_boolean
from .remove_representation import remove_representation
from .unassign_representation import unassign_representation
wrap_usecases(__path__, __name__)
@@ -16,6 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Manage georeferencing metadata
IFC model geometry may have a coordinate reference system (CRS) assigned to it.
It may also optionally have a map conversion defined to transform to and from
map coordinates and project local engineering coordinates.
"""
from .. import wrap_usecases
from .add_georeferencing import add_georeferencing
from .edit_georeferencing import edit_georeferencing
from .remove_georeferencing import remove_georeferencing
wrap_usecases(__path__, __name__)
@@ -16,9 +16,17 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Manages grid and grid axes
A grid in IFC may contain two or more axes running in two or more directions.
"""
from .. import wrap_usecases
try:
from .create_axis_curve import create_axis_curve
except ModuleNotFoundError as e:
print(f"Note: API not available due to missing dependencies: grid.create_axis_curve - {e}")
from .create_grid_axis import create_grid_axis
from .remove_grid_axis import remove_grid_axis
wrap_usecases(__path__, __name__)
@@ -16,9 +16,19 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Elements may be arbitrarily assigned to groups for organisation
Groups are useful for filtering elements or non-hierarchical organisation of a
model. Note that this only targets arbitrary groups. If you want to group
elements into a distribution system, see :mod:`ifcopenshell.api.system`.
"""
from .. import wrap_usecases
from .add_group import add_group
from .assign_group import assign_group
from .edit_group import edit_group
from .remove_group import remove_group
from .unassign_group import unassign_group
from .update_group_products import update_group_products
wrap_usecases(__path__, __name__)
@@ -16,8 +16,20 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Manage CAD layers
Note that in IFC, elements cannot be assigned to CAD layers. Instead, the
geometric representation of the element is associated to a layer.
If you want to associated a whole element to a "layer", consider using
:mod:`ifcopenshell.api.classification`.
"""
from .. import wrap_usecases
from .add_layer import add_layer
from .assign_layer import assign_layer
from .edit_layer import edit_layer
from .remove_layer import remove_layer
from .unassign_layer import unassign_layer
wrap_usecases(__path__, __name__)
@@ -16,6 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Manage references to external libraries
An external library is any system which uses a key to store information. This
allows you to associate IFC entities with any arbitrary external database, API,
system, and so on. This is typically useful in smart building systems.
"""
from .. import wrap_usecases
from .add_library import add_library
from .add_reference import add_reference
from .assign_reference import assign_reference
@@ -24,3 +32,5 @@ from .edit_reference import edit_reference
from .remove_library import remove_library
from .remove_reference import remove_reference
from .unassign_reference import unassign_reference
wrap_usecases(__path__, __name__)
@@ -16,6 +16,22 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Manage physical materials (concrete, steel, etc) and their association to
elements
IFC supports both simple materials and parametric materials (materials that
have layered thicknesses or cross sectional profiles).
Parametric materials will include parametric constraints on the geometry of
the element. These API functions do not cover that responsibility. See
:mod:`ifcopenshell.api.geometry`.
Note that this API only covers physical materials, not visual styles. If you
want to look at visual styles such as colours, transparency, shading, or
rendering options, see :mod:`ifcopenshell.api.style`.
"""
from .. import wrap_usecases
from .add_constituent import add_constituent
from .add_layer import add_layer
from .add_list_item import add_list_item
@@ -40,3 +56,5 @@ from .remove_material_set import remove_material_set
from .remove_profile import remove_profile
from .reorder_set_item import reorder_set_item
from .unassign_material import unassign_material
wrap_usecases(__path__, __name__)
@@ -16,7 +16,21 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Nesting is when a component is attached to a host element
Examples include when a faucet is attached using a predrilled hole in a basin,
or when a modular connection occurs through a connection point. This implies
that when a host element moves, the child nested components must move as well.
Note that this API is not meant to be used for connection points on
distribution systems. For that purpose, such as for pipe fittings and
equipment, please see :mod:`ifcopenshell.api.system`.
"""
from .. import wrap_usecases
from .assign_object import assign_object
from .change_nest import change_nest
from .reorder_nesting import reorder_nesting
from .unassign_object import unassign_object
wrap_usecases(__path__, __name__)
@@ -16,6 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""An element may have an owner, indicating who is responsible, liable, or
contactable regarding that element
Note that in IFC2X3, element ownership is mandatory and must be addressed prior
to the creation of any element at all. See :func:`create_owner_history` for
examples.
"""
from .. import wrap_usecases
from .add_actor import add_actor
from .add_address import add_address
from .add_application import add_application
@@ -39,3 +48,5 @@ from .remove_person_and_organisation import remove_person_and_organisation
from .remove_role import remove_role
from .unassign_actor import unassign_actor
from .update_owner_history import update_owner_history
wrap_usecases(__path__, __name__)
@@ -16,8 +16,17 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Handles the definition of cross sectional profiles
Maintaining a clean profile library is important for structural simulations and
identification of standardised profiles for fabrication and carbon counting.
"""
from .. import wrap_usecases
from .add_arbitrary_profile import add_arbitrary_profile
from .add_arbitrary_profile_with_voids import add_arbitrary_profile_with_voids
from .add_parameterized_profile import add_parameterized_profile
from .edit_profile import edit_profile
from .remove_profile import remove_profile
wrap_usecases(__path__, __name__)
@@ -16,7 +16,20 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Create an IFC project
All IFCs must have one, and only one IFC project before any data may be
associated. If you are starting from scratch, see :func:create_file.
Once a project exists, you may optionally create project libraries and
associate type assets with it. You may also append assets from other projects
into your project.
"""
from .. import wrap_usecases
from .append_asset import append_asset
from .assign_declaration import assign_declaration
from .create_file import create_file
from .unassign_declaration import unassign_declaration
wrap_usecases(__path__, __name__)
@@ -16,8 +16,18 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Property sets and quantity sets let you store simple key value metadata
associated with elements
This is the simplest and most common way to store information about an element.
For example, if a door has a fire rating, it is stored as a property.
"""
from .. import wrap_usecases
from .add_pset import add_pset
from .add_qto import add_qto
from .edit_pset import edit_pset
from .edit_qto import edit_qto
from .remove_pset import remove_pset
wrap_usecases(__path__, __name__)
@@ -16,9 +16,20 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Manage property templates to standard project property names and data types
To help standardise the naming, data types, and association of properties to
elements, IFC supports property set templates. buildingSMART provides their own
built-in ISO-standardised property templates, but governments, companies, and
individuals may also create their own.
"""
from .. import wrap_usecases
from .add_prop_template import add_prop_template
from .add_pset_template import add_pset_template
from .edit_prop_template import edit_prop_template
from .edit_pset_template import edit_pset_template
from .remove_prop_template import remove_prop_template
from .remove_pset_template import remove_pset_template
wrap_usecases(__path__, __name__)
@@ -16,6 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Manage construction and maintenance resources
Resources include equipment (cranes, etc), labour, material, and products. They
are typically referenced in construction planning, maintenance schedules, or
cost items.
"""
from .. import wrap_usecases
from .add_resource import add_resource
from .add_resource_quantity import add_resource_quantity
from .add_resource_time import add_resource_time
@@ -28,3 +36,5 @@ from .edit_resource_time import edit_resource_time
from .remove_resource import remove_resource
from .remove_resource_quantity import remove_resource_quantity
from .unassign_resource import unassign_resource
wrap_usecases(__path__, __name__)
@@ -16,7 +16,20 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Create, copy, or remove physical elements such as walls, doors, slabs, etc
This is one of the most used API modules and should be used any time you want
to create, remove, copy, or change a physical or spatial element. See
:func:`create_entity` to get started.
This module should also be used to create types. To then associate types with
elements, see :mod:`ifcopenshell.api.type`.
"""
from .. import wrap_usecases
from .copy_class import copy_class
from .create_entity import create_entity
from .reassign_class import reassign_class
from .remove_product import remove_product
wrap_usecases(__path__, __name__)
@@ -18,6 +18,7 @@
import ifcopenshell
import ifcopenshell.api
import ifcopenshell.guid
from typing import Optional
@@ -16,6 +16,13 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Manage work schedules, tasks, calendars, and more for 4D
These are typically used for construction planning, but may also be used in
managing recurring facility maintenance schedules.
"""
from .. import wrap_usecases
from .add_task import add_task
from .add_task_time import add_task_time
from .add_time_period import add_time_period
@@ -59,3 +66,5 @@ from .unassign_process import unassign_process
from .unassign_product import unassign_product
from .unassign_recurrence_pattern import unassign_recurrence_pattern
from .unassign_sequence import unassign_sequence
wrap_usecases(__path__, __name__)
@@ -16,7 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Assign spatial relationships such as when an element is in a space
Physical elements (walls, doors, etc) may be contained in or reference spatial
elements (spaces, storeys, buildings, etc).
"""
from .. import wrap_usecases
from .assign_container import assign_container
from .dereference_structure import dereference_structure
from .reference_structure import reference_structure
from .unassign_container import unassign_container
wrap_usecases(__path__, __name__)
@@ -16,6 +16,13 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Manage analytical properties for structural simulation
This only handles authoring the analytical model, and does not actually perform
any structural simulation. To perform the simulation, see IFC2CA.
"""
from .. import wrap_usecases
from .add_structural_activity import add_structural_activity
from .add_structural_analysis_model import add_structural_analysis_model
from .add_structural_boundary_condition import add_structural_boundary_condition
@@ -37,3 +44,5 @@ from .remove_structural_load import remove_structural_load
from .remove_structural_load_case import remove_structural_load_case
from .remove_structural_load_group import remove_structural_load_group
from .unassign_structural_analysis_model import unassign_structural_analysis_model
wrap_usecases(__path__, __name__)
@@ -16,6 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Manage visual styles of geometry (colours, transparency, rendering, etc)
Geometry may have visual styles associated with it, including surface styles,
2D curve styles, text styles, and more. Surface styles are most commonly used
for simple colouring.
"""
from .. import wrap_usecases
from .add_style import add_style
from .add_surface_style import add_surface_style
from .add_surface_textures import add_surface_textures
@@ -28,3 +36,5 @@ from .remove_styled_representation import remove_styled_representation
from .remove_surface_style import remove_surface_style
from .unassign_material_style import unassign_material_style
from .unassign_representation_styles import unassign_representation_styles
wrap_usecases(__path__, __name__)
@@ -16,6 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Manage distribution systems and port connectivity
Service distribution systems (mechanical, electrical, hydraulic, fire,
logistical, etc) consist of connected distribution segments, fittings,
terminals, control equipment, and more. This module handles port connectivity
and relationships describing distribution flow.
"""
from .. import wrap_usecases
from .add_port import add_port
from .add_system import add_system
from .assign_flow_control import assign_flow_control
@@ -28,3 +37,5 @@ from .remove_system import remove_system
from .unassign_flow_control import unassign_flow_control
from .unassign_port import unassign_port
from .unassign_system import unassign_system
wrap_usecases(__path__, __name__)
@@ -16,7 +16,18 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Manage common construction types of physical elements
Almost all constructed elements may be grouped into "types". Types include wall
types, window types, column types, equipment types, and more.
Using types is critical to the success of any project.
"""
from .. import wrap_usecases
from .assign_type import assign_type
from .get_related_objects import get_related_objects
from .map_type_representations import map_type_representations
from .unassign_type import unassign_type
wrap_usecases(__path__, __name__)
@@ -16,6 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Define units (length, area, monetary, pressure, etc)
Units can be defined as a default project unit or used specifically for certain
properties. Units may be especially complex when dealing with services and
equipment.
"""
from .. import wrap_usecases
from .add_context_dependent_unit import add_context_dependent_unit
from .add_conversion_based_unit import add_conversion_based_unit
from .add_monetary_unit import add_monetary_unit
@@ -26,3 +34,5 @@ from .edit_monetary_unit import edit_monetary_unit
from .edit_named_unit import edit_named_unit
from .remove_unit import remove_unit
from .unassign_unit import unassign_unit
wrap_usecases(__path__, __name__)
@@ -16,7 +16,18 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Create void relationships between openings and physical elements
An opening is a special element (created using
:func:`ifcopenshell.api.root.create_entity`) that may then be used to create
voids in other elements (such as walls and slabs). These voids may then be
filled with doors, trapdoors, skylights, and so on.
"""
from .. import wrap_usecases
from .add_filling import add_filling
from .add_opening import add_opening
from .remove_filling import remove_filling
from .remove_opening import remove_opening
wrap_usecases(__path__, __name__)
@@ -17,16 +17,11 @@
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import functools
import importlib
import numbers
import itertools
import operator
import functools
import subprocess
import sys
import time
@@ -37,7 +32,7 @@ from . import settings
try:
import logging
except ImportError as e:
except ImportError:
logging = type("logger", (object,), {"exception": staticmethod(lambda s: print(s))})
T = TypeVar("T")
@@ -104,21 +99,48 @@ for nm in ifcopenshell_wrapper.schema_names():
register_schema_attributes(schema)
class entity_instance(object):
"""Base class for all IFC objects.
class entity_instance:
"""Represents an entity (wall, slab, property, etc) of an IFC model
An instantiated entity_instance will have methods of Python and the IFC class itself.
An IFC model consists of entities. Examples of entities include walls,
slabs, doors and so on. Entities can also be non-physical things, like
properties, systems, construction tasks, colours, geometry, and more.
Entities are defined through an **IFC Class**. There are hundreds of **IFC
Classes** defined as part of the ISO standard by the buildingSMART
International organisation. The **IFC Class** defines the attributes of an
entity, as well as the data types and whether or not an attribute is
mandatory or optional.
IfcOpenShell's API dynamically implements the IFC schema. You will not find
documentation about available **IFC Classes**, or what attributes they
have. Please consult the buildingSMART official documentation or start
reading :doc:`/introduction/introduction_to_ifc`.
In addition to the Python methods you see documented here, an instantiated
entity_instance will have attributes defined by its IFC class. For example,
an entity instance which is an IfcWall class will have a ``Name``
attribute, and an IfcColourRgb will have a ``Red`` attribute. Please
consult the buildingSMART official documentation.
Example:
.. code:: python
ifc_file = ifcopenshell.open(file_path)
products = ifc_file.by_type("IfcProduct")
print(products[0].__class__)
>>> <class 'ifcopenshell.entity_instance.entity_instance'>
print(products[0].Representation)
>>> #423=IfcProductDefinitionShape($,$,(#409,#421))
model = ifcopenshell.open(file_path)
walls = model.by_type("IfcWall")
wall = walls[0]
print(wall) # #38=IFCWALL('2MEinnTPbCMwLOgceaQZFu',$,$,'My Wall',$,#52,#47,$,$);
print(wall.is_a()) # IfcWall
# Note: the `Name` attribute is dynamic, based on the IFC class.
print(wall.Name) # My Wall
# Attributes are ordered and may also be accessed via index.
print(wall[3]) # My Wall
print(wall.__class__) # <class 'ifcopenshell.entity_instance'>
"""
wrapped_data: ifcopenshell_wrapper.entity_instance
@@ -200,33 +222,36 @@ class entity_instance(object):
@staticmethod
def walk(f: Callable[[Any], bool], g: Callable[[Any], Any], value: Any) -> Any:
"""
Applies transformation to `value` based on a given condition.
If value is a nested structure (e.g., a list or a tuple) will apply transformation to it's elements.
.
"""Applies a transformation to `value` based on a given condition.
:param f: A callable that takes a single argument and returns a boolean value. It represents the condition
:type f: Callable
:param g: A callable that takes a single argument and returns a transformed value. It represents the transformation
:type g: Callable
:param value: Any object, the input value to be processed
:type value: Any
:return: Transformed value
:rtype: Any
If value is a nested structure (e.g., a list or a tuple) will apply
transformation to it's elements.
Example:
:param f: A callable that takes a single argument and returns a boolean
value. It represents the condition.
:type f: Callable
:param g: A callable that takes a single argument and returns a
transformed value. It represents the transformation.
:type g: Callable
:param value: Any object, the input value to be processed
:type value: Any
:return: Transformed value
:rtype: Any
.. code:: python
Example:
# Define condition and transformation functions
condition = lambda v: v == old
transform = lambda v: new
.. code:: python
# Usage example
attribute_value = element.RelatedElements
print(old in attribute_value, new in attribute_value) # True, False
result = element.walk(condition, transform, element.RelatedElements)
print(old in attribute_value, new in attribute_value) # False, True
# Define condition and transformation functions
condition = lambda v: v == old
transform = lambda v: new
# Usage example
attribute_value = element.RelatedElements
print(old in attribute_value, new in attribute_value) # True, False
result = element.walk(condition, transform, element.RelatedElements)
print(old in attribute_value, new in attribute_value) # False, True
"""
if isinstance(value, (tuple, list)):
@@ -29,7 +29,7 @@ def indent(n, s):
return "\n".join(" "*n + l for l in splitted)
class Base(object):
class Base:
"""
A base class for all code generation classes. Currently only working around
some python 2/3 incompatibilities in terms of unicode file handling.
@@ -17,8 +17,6 @@
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import sys
import nodes
import templates
@@ -17,13 +17,10 @@
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import io
import string
import operator
import collections
import bootstrap
class Node:
+50 -52
View File
@@ -17,31 +17,18 @@
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import annotations
import os
import re
import numbers
import zipfile
import functools
import ifcopenshell
from pathlib import Path
from typing import Optional, Any
import ifcopenshell.util.element
import ifcopenshell.util.file
from . import ifcopenshell_wrapper
from .entity_instance import entity_instance
try:
# Python 2
basestring
except NameError:
# Python 3 or newer
basestring = (str, bytes)
class Transaction:
def __init__(self, ifc_file):
@@ -120,11 +107,19 @@ class Transaction:
for inverse in self.file.get_inverse(element):
inverse_references = []
for i, attribute in enumerate(inverse):
if ifcopenshell.util.element.has_element_reference(attribute, element):
if self.has_element_reference(attribute, element):
inverse_references.append((i, self.serialise_value(inverse, attribute)))
inverses[inverse.id()] = inverse_references
return inverses
def has_element_reference(self, value: Any, element: ifcopenshell.entity_instance) -> bool:
if isinstance(value, (tuple, list)):
for v in value:
if self.has_element_reference(v, element):
return True
return False
return value == element
def rollback(self):
for operation in self.operations[::-1]:
if operation["action"] == "create":
@@ -181,7 +176,7 @@ class Transaction:
file_dict = {}
class file(object):
class file:
"""Base class for containing IFC files.
Class has instance methods for filtering by element Id, Type, etc.
@@ -312,7 +307,7 @@ class file(object):
:param args: The positional arguments of the IFC class
:param kwargs: The keyword arguments of the IFC class
:returns: An entity instance
:rtype: ifcopenshell.entity_instance.entity_instance
:rtype: ifcopenshell.entity_instance
Example:
@@ -376,14 +371,11 @@ class file(object):
match = re.match(reg, self.wrapped_data.schema)
version_tuple = tuple(
map(
lambda pp: int(pp[1][len(pp[0]):]) if pp[1] else None,
lambda pp: int(pp[1][len(pp[0]) :]) if pp[1] else None,
((p, match.group(p)) for p in prefixes),
)
)
return "".join(
"".join(map(str, t)) if t[1] else ""
for t in zip(prefixes, version_tuple[0:2])
)
return "".join("".join(map(str, t)) if t[1] else "" for t in zip(prefixes, version_tuple[0:2]))
elif attr == "schema_identifier":
return self.wrapped_data.schema
elif attr == "schema_version":
@@ -399,7 +391,7 @@ class file(object):
def __getitem__(self, key):
if isinstance(key, numbers.Integral):
return entity_instance(self.wrapped_data.by_id(key), self)
elif isinstance(key, basestring):
elif isinstance(key, (str, bytes)):
return entity_instance(self.wrapped_data.by_guid(str(key)), self)
def by_id(self, id: int) -> ifcopenshell.entity_instance:
@@ -410,8 +402,8 @@ class file(object):
:raises RuntimeError: If `id` is not found.
:returns: An ifcopenshell.entity_instance.entity_instance
:rtype: ifcopenshell.entity_instance.entity_instance
:returns: An ifcopenshell.entity_instance
:rtype: ifcopenshell.entity_instance
"""
return self[id]
@@ -423,8 +415,8 @@ class file(object):
:raises RuntimeError: If `guid` is not found.
:returns: An ifcopenshell.entity_instance.entity_instance
:rtype: ifcopenshell.entity_instance.entity_instance
:returns: An ifcopenshell.entity_instance
:rtype: ifcopenshell.entity_instance
"""
return self[guid]
@@ -434,9 +426,9 @@ class file(object):
If the entity already exists, it is not re-added. Existence of entity is checked by it's `.identity()`.
:param inst: The entity instance to add
:type inst: ifcopenshell.entity_instance.entity_instance
:returns: An ifcopenshell.entity_instance.entity_instance
:rtype: ifcopenshell.entity_instance.entity_instance
:type inst: ifcopenshell.entity_instance
:returns: An ifcopenshell.entity_instance
:rtype: ifcopenshell.entity_instance
"""
if self.transaction:
@@ -460,8 +452,8 @@ class file(object):
:raises RuntimeError: If `type` is not found in IFC schema.
:returns: A list of ifcopenshell.entity_instance.entity_instance objects
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:returns: A list of ifcopenshell.entity_instance objects
:rtype: list[ifcopenshell.entity_instance]
"""
if include_subtypes:
return [entity_instance(e, self) for e in self.wrapped_data.by_type(type)]
@@ -473,13 +465,13 @@ class file(object):
"""Get a list of all referenced instances for a particular instance including itself
:param inst: The entity instance to get all sub instances
:type inst: ifcopenshell.entity_instance.entity_instance
:type inst: ifcopenshell.entity_instance
:param max_levels: How far deep to recursively fetch sub instances. None or -1 means infinite.
:type max_levels: None|int
:param breadth_first: Whether to use breadth-first search, the default is depth-first.
:type max_levels: bool
:returns: A list of ifcopenshell.entity_instance.entity_instance objects
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:returns: A list of ifcopenshell.entity_instance objects
:rtype: list[ifcopenshell.entity_instance]
"""
if max_levels is None:
max_levels = -1
@@ -497,12 +489,12 @@ class file(object):
"""Return a list of entities that reference this entity
:param inst: The entity instance to get inverse relationships
:type inst: ifcopenshell.entity_instance.entity_instance
:type inst: ifcopenshell.entity_instance
:param allow_duplicate: Returns a `list` when True, `set` when False
:param with_attribute_indices: Returns pairs of <i, idx>
where i[idx] is inst or contains inst. Requires allow_duplicate=True
:returns: A list of ifcopenshell.entity_instance.entity_instance objects
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:returns: A list of ifcopenshell.entity_instance objects
:rtype: list[ifcopenshell.entity_instance]
"""
if with_attribute_indices and not allow_duplicate:
raise ValueError("with_attribute_indices requires allow_duplicate to be True")
@@ -522,7 +514,7 @@ class file(object):
"""Returns the number of entities that reference this entity
:param inst: The entity instance to get inverse relationships
:type inst: ifcopenshell.entity_instance.entity_instance
:type inst: ifcopenshell.entity_instance
:returns: The total number of references
:rtype: int
"""
@@ -536,7 +528,7 @@ class file(object):
the reference to the deleted will be removed from the aggregate.
:param inst: The entity instance to delete
:type inst: ifcopenshell.entity_instance.entity_instance
:type inst: ifcopenshell.entity_instance
:rtype: None
"""
if self.transaction:
@@ -558,25 +550,31 @@ class file(object):
def __iter__(self):
return iter(self[id] for id in self.wrapped_data.entity_names())
def write(self, path: "os.PathLike | str", format=None, zipped=False) -> None:
def write(self, path: "os.PathLike | str", format: Optional[str] = None, zipped: bool = False) -> None:
"""Write ifc model to file.
:param format: Force use of a specific format. Guessed from file name if None.
Supported formats : .ifc, .ifcXML, .ifcZIP (equivalent to format=".ifc" with zipped=True)
For zipped .ifcXML use format=".ifcXML" with zipped=True
:param format: Force use of a specific format. Guessed from file name
if None. Supported formats : .ifc, .ifcXML, .ifcZIP (equivalent to
format=".ifc" with zipped=True) For zipped .ifcXML use
format=".ifcXML" with zipped=True
:type format: str
:param zipped: zip the file after it is written
:type zipped: bool
Examples:
>>> model.write("path/to/model.ifc")
>>> model.write("path/to/model.ifcXML")
>>> model.write("path/to/model.ifcZIP")
>>> model.write("path/to/model.ifcZIP", format=".ifcXML", zipped=True)
>>> model.write("path/to/model.anyextension", format=".ifcXML")
Example:
.. code:: python
model.write("path/to/model.ifc")
model.write("path/to/model.ifcXML")
model.write("path/to/model.ifcZIP")
model.write("path/to/model.ifcZIP", format=".ifcXML", zipped=True)
model.write("path/to/model.anyextension", format=".ifcXML")
"""
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)
if format == None:
format = ifcopenshell.util.file.guess_format(path)
format = ifcopenshell.guess_format(path)
if format == ".ifcXML":
serializer = ifcopenshell_wrapper.XmlSerializer(self, str(path))
serializer.finalize()
@@ -603,7 +601,7 @@ class file(object):
return
@staticmethod
def from_string(s: str) -> file:
def from_string(s: str) -> "file":
return file(ifcopenshell_wrapper.read(s))
@staticmethod
@@ -16,11 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Geometry processing and analysis"""
"""Geometry processing and analysis
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
IFC may define geometry explicitly (such as meshes) or implicitly (such as
parametric extrusions). This module provides methods to extract geometric
definitions in IFC into explicitly tessellated triangles or OpenCASCADE Breps
for further processing.
This is typically needed when writing software to visualise or analyse
geometry. See also :mod:`ifcopenshell.util.shape` for deriving quantities.
"""
def _has_occ():
@@ -16,10 +16,6 @@
# 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 __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import sys
import time
@@ -126,7 +122,7 @@ class geometry_creation_thread(QtCore.QThread):
self.signals.completed.emit((it, self.f, list(_())))
class configuration(object):
class configuration:
def __init__(self):
try:
import ConfigParser
@@ -16,10 +16,6 @@
# 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 __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import sys
import logging
@@ -49,7 +45,7 @@ except BaseException:
CodeEdit = QtWidgets.QPlainTextEdit
class StdoutRedirector(object):
class StdoutRedirector:
"""A class for redirecting stdout to this Text widget."""
def __init__(self, widget):
@@ -17,11 +17,6 @@
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import annotations
import os
import sys
import operator
@@ -153,7 +148,7 @@ class tree(ifcopenshell_wrapper.tree):
def select(
self,
value: Union[
entity_instance, ifcopenshell_wrapper.BRepElement, tuple[float, float, float], TopoDS.TopoDS_Shape
entity_instance, ifcopenshell_wrapper.BRepElement, tuple[float, float, float], "TopoDS.TopoDS_Shape"
],
**kwargs,
) -> list[entity_instance]:
@@ -17,20 +17,12 @@
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import random
import operator
import warnings
from collections import namedtuple
try: # python 3.3+
from collections.abc import Iterable
except ImportError: # python 2
from collections import Iterable
from collections.abc import Iterable
import OCC
+7 -4
View File
@@ -16,11 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Reads and writes encoded GlobalIds"""
"""Reads and writes encoded GlobalIds
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
IFC entities may be identified using a unique ID (called a UUID or GUID). This
128-bit label is often represented in the form
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. However, in IFC, it is also usually
stored as a 22 character base 64 encoded string. This module lets you convert
between these representations and generate new UUIDs.
"""
import uuid
import string
@@ -1,27 +0,0 @@
# 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/>.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from . import ifcopenshell_wrapper
version = ifcopenshell_wrapper.version()
get_log = ifcopenshell_wrapper.get_log
+12 -6
View File
@@ -2,7 +2,6 @@ try:
import re
import json
import ifcopenshell.util.schema
from .file import file
from . import ifcopenshell_wrapper
from .entity_instance import entity_instance
@@ -56,6 +55,8 @@ class sqlite(file):
self.preprocess_schema()
def preprocess_schema(self):
import ifcopenshell.util.schema
self.ifc_class_subtypes = {}
self.ifc_class_attributes = {}
self.ifc_class_inverse_attributes = {}
@@ -122,6 +123,9 @@ class sqlite(file):
return entity
def by_type(self, type, include_subtypes=True):
# TODO use cached subtypes
import ifcopenshell.util.schema
if self.class_map:
results = []
subtypes = self.ifc_class_subtypes[type] if include_subtypes else self.ifc_class_subtypes[type][0:1]
@@ -167,7 +171,9 @@ class sqlite(file):
return results
def get_inverse(self, inst, allow_duplicate=False, with_attribute_indices=False):
query = f"SELECT inverses FROM {inst.sqlite_wrapper.ifc_class} WHERE `ifc_id` = {inst.sqlite_wrapper.id} LIMIT 1"
query = (
f"SELECT inverses FROM {inst.sqlite_wrapper.ifc_class} WHERE `ifc_id` = {inst.sqlite_wrapper.id} LIMIT 1"
)
self.cursor.execute(query)
row = self.cursor.fetchone()
if not row or not row[0]:
@@ -198,9 +204,9 @@ class sqlite(file):
"verts": np.frombuffer(row["verts"]).tolist() if row["verts"] else [],
"edges": np.frombuffer(row["edges"], dtype=np.int64).tolist() if row["edges"] else [],
"faces": np.frombuffer(row["faces"], dtype=np.int64).tolist() if row["faces"] else [],
"material_ids": np.frombuffer(row["material_ids"], dtype=np.int64).tolist()
if row["material_ids"]
else [],
"material_ids": (
np.frombuffer(row["material_ids"], dtype=np.int64).tolist() if row["material_ids"] else []
),
"materials": json.loads(row["materials"]) if row["materials"] else [],
}
shapes[row["ifc_id"]] = {
@@ -353,7 +359,7 @@ class sqlite_entity(entity_instance):
def get_info(self, include_identifier=True, recursive=False, return_type=dict, ignore=(), scalar_only=False):
info = {"id": self.sqlite_wrapper.id, "type": self.sqlite_wrapper.ifc_class}
if not self.sqlite_wrapper.attribute_cache:
self.__getitem__(0) # This will get all attributes
self.__getitem__(0) # This will get all attributes
info.update(self.sqlite_wrapper.attribute_cache)
return info
@@ -17,16 +17,12 @@
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import time
import uuid
from .file import file
from .guid import compress
from . import main
from .ifcopenshell_wrapper import version
# A quick way to setup an 'empty' IFC file, taken from:
# http://academy.ifcopenshell.org/creating-a-simple-wall-with-property-set-and-quantity-information/
@@ -62,8 +58,8 @@ END-ISO-10303-21;
"""
DEFAULTS = {
"application": lambda d: "IfcOpenShell-%s" % main.version,
"application_version": lambda d: main.version,
"application": lambda d: "IfcOpenShell-%s" % version(),
"application_version": lambda d: version(),
"project_globalid": lambda d: compress(uuid.uuid4().hex),
"schema_identifier": lambda d: "IFC4",
"timestamp": lambda d: int(time.time()),
@@ -16,4 +16,13 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Utility functions for common IFC queries"""
"""Utility functions for extracting IFC data
Data in IFC files is represented using relationships between IFC entities. To
extract data like "what properties does this wall have" involves looping
through these relationships which can be tedious.
This module makes it easy to get commonly requested data from IFC
relationships, such as properties of a wall, what elements are connected to
pipes, dates from work schedules, filtering maintainable elements, and more.
"""
@@ -27,9 +27,9 @@ def get_constraints(product: ifcopenshell.entity_instance) -> list[ifcopenshell.
Retrieves the constraints assigned to the `product`.
:param product: The IFC element.
:type product: ifcopenshell.entity_instance.entity_instance
:type product: ifcopenshell.entity_instance
:return: List of assigned constraints.
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
"""
constraints = []
for rel in product.HasAssociations or []:
@@ -43,9 +43,9 @@ def get_constrained_elements(constraint: ifcopenshell.entity_instance) -> set[if
Retrieves the elements constrained by a `constraint`.
:param product: The IFC element.
:type product: ifcopenshell.entity_instance.entity_instance
:type product: ifcopenshell.entity_instance
:return: Set of elements constrained by a `constrant`.
:rtype: set[ifcopenshell.entity_instance.entity_instance]
:rtype: set[ifcopenshell.entity_instance]
"""
elements = set()
for rel in constraint.file.get_inverse(constraint):
@@ -59,9 +59,9 @@ def get_metrics(constraint: ifcopenshell.entity_instance) -> list[ifcopenshell.e
Retrieves the list of nested constraints for a IfcObjective `constraint`.
:param product: IfcObjective constraint.
:type product: ifcopenshell.entity_instance.entity_instance
:type product: ifcopenshell.entity_instance
:return: List of nested constraints.
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
"""
metrics = []
@@ -16,7 +16,6 @@
# 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 __future__ import annotations
import numpy as np
import ifcopenshell
from typing import Any, Union
@@ -31,7 +30,7 @@ class Clipping:
operand_type: str = "IfcHalfSpaceSolid"
@classmethod
def parse(cls, raw_data: Any) -> Union[ifcopenshell.entity_instance, Clipping, None]:
def parse(cls, raw_data: Any) -> Union[ifcopenshell.entity_instance, "Clipping", None]:
"""Parse various formats into a clipping object
`raw_data` can be either:
@@ -16,7 +16,6 @@
# 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 __future__ import annotations
import ifcopenshell
import ifcopenshell.util.element
from typing import Any, Callable, Optional, Union, Literal, overload
@@ -41,7 +40,7 @@ def get_pset(
occurrence, not the type's pset.
:param element: The IFC Element entity
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
:param name: The name of the pset
:type name: str
:param prop: The name of the property
@@ -129,7 +128,7 @@ def get_psets(
occurrence, not the type's pset.
:param element: The IFC Element entity
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
:param psets_only: Default as False. Set to true if only property sets are needed.
:type psets_only: bool,optional
:param qtos_only: Default as False. Set to true if only quantities are needed.
@@ -419,7 +418,7 @@ def get_predefined_type(element: ifcopenshell.entity_instance) -> str:
considered first.
:param element: The IFC Element entity
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
:return: The predefined type of the element
:rtype: str
@@ -449,9 +448,9 @@ def get_type(element: ifcopenshell.entity_instance) -> ifcopenshell.entity_insta
"""Retrieves the construction type element of an element occurrence
:param element: The element occurrence
:type: ifcopenshell.entity_instance.entity_instance
:type: ifcopenshell.entity_instance
:return: The related type element
:rtype: ifcopenshell.entity_instance.entity_instance
:rtype: ifcopenshell.entity_instance
Example:
@@ -474,9 +473,9 @@ def get_types(type: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_in
"""Get all the occurrences of a type element
:param type: The type element
:type type: ifcopenshell.entity_instance.entity_instance
:type type: ifcopenshell.entity_instance
:return: A list of occurrences of that type
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -496,9 +495,9 @@ def get_shape_aspects(element: ifcopenshell.entity_instance) -> list[ifcopenshel
"""Gets element shape aspects
:param element: The element to get the shape aspects of.
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
:return: The associated shape aspects of the element.
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -531,7 +530,7 @@ def get_material(
constituent), or a material set usage.
:param element: The element to get the material of.
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
:param should_skip_usage: If set to True, if the material is a material set
usage, the material set itself will be returned. Useful if you don't
care about occurrence usage parameters. If False, the usage will be
@@ -541,7 +540,7 @@ def get_material(
types will be considered.
:type should_inherit: bool
:return: The associated material of the element or `None`.
:rtype: Union[ifcopenshell.entity_instance.entity_instance, None]
:rtype: Union[ifcopenshell.entity_instance, None]
Example:
@@ -575,11 +574,11 @@ def get_materials(
returned as a list.
:param element: The element to get the materials of.
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
:param should_inherit: If True, any inherited materials from associated
types will be considered.
:return: The associated materials of the element.
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -609,9 +608,9 @@ def get_styles(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entit
Styles may be retreived from the material or the body representation.
:param element: The element to get the styles of.
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
:return: A list of surface styles
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -656,11 +655,11 @@ def get_elements_by_material(
usage.
:param ifc_file: The IFC file
:type ifc_file: ifcopenshell.file.file
:type ifc_file: ifcopenshell.file
:param material: The IFC Material entity
:type material: ifcopenshell.entity_instance.entity_instance
:type material: ifcopenshell.entity_instance
:return: A list of elements using the to the material
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -697,11 +696,11 @@ def get_elements_by_style(
"""Retrieves the elements whose geometric representation uses a style
:param ifc_file: The IFC file
:type ifc_file: ifcopenshell.file.file
:type ifc_file: ifcopenshell.file
:param style: The IfcPresentationStyle entity
:type style: ifcopenshell.entity_instance.entity_instance
:type style: ifcopenshell.entity_instance
:return: The elements related to the style
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -739,11 +738,11 @@ def get_elements_by_representation(
"""Gets all elements using a geometric representation
:param ifc_file: The IFC file
:type ifc_file: ifcopenshell.file.file
:type ifc_file: ifcopenshell.file
:param representation: The IfcShapeRepresentation representation
:type representation: ifcopenshell.entity_instance.entity_instance
:type representation: ifcopenshell.entity_instance
:return: The elements using the geometric representation
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -773,11 +772,11 @@ def get_elements_by_layer(
"""Get all the elements that are used by a presentation layer
:param ifc_file: The IFC file
:type ifc_file: ifcopenshell.file.file
:type ifc_file: ifcopenshell.file
:param layer: The IfcPresentationLayerAssignment layer
:type layer: ifcopenshell.entity_instance.entity_instance
:type layer: ifcopenshell.entity_instance
:return: The elements using the geometric representation
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
"""
results = set()
for item in layer.AssignedItems or []:
@@ -799,11 +798,11 @@ def get_layers(
traditional CAD presentation layer.
:param ifc_file: The IFC file object
:type ifc_file: ifcopenshell.file.file
:type ifc_file: ifcopenshell.file
:param element: The IFC element to interrogate
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
:return: A list of IfcPresentationLayerAssignment
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -837,7 +836,7 @@ def get_container(
Retrieves the spatial structure container of an element.
:param element: The IFC element
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
:param should_get_direct: If True, a result is only returned if the element
is directly contained in a spatial structure element. If False, an
indirect spatial container may be returned, such as if an element is a
@@ -848,7 +847,7 @@ def get_container(
example, you may be after the storey, not a space.
:type ifc_class: str, optional
:return: The direct or indirect container of the element or None.
:rtype: ifcopenshell.entity_instance.entity_instance
:rtype: ifcopenshell.entity_instance
Example:
@@ -893,9 +892,9 @@ def get_referenced_structures(element: ifcopenshell.entity_instance) -> list[ifc
as stairs, doors, etc.
:param element: The IFC element
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
:return: A list of IfcSpatialElement
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -911,9 +910,9 @@ def get_structure_referenced_elements(structure: ifcopenshell.entity_instance) -
"""Retreives a set of elements referenced by a structure
:param structure: IfcSpatialElement
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
:return: A set of referenced elements, IfcSpatialReferenceSelect
:rtype: set[ifcopenshell.entity_instance.entity_instance]
:rtype: set[ifcopenshell.entity_instance]
Example:
@@ -935,9 +934,9 @@ def get_decomposition(element: ifcopenshell.entity_instance, is_recursive=True)
parts of an aggreate, all openings, and all fills of any openings.
:param element: The IFC element
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
:return: The decomposition of the element
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -979,9 +978,9 @@ def get_grouped_by(element: ifcopenshell.entity_instance) -> list[ifcopenshell.e
"""Retrieves all subelements of an element based on the group.
:param element: The IFC element
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
:return: All subelements of the group
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -1007,7 +1006,7 @@ def get_groups(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entit
:param element: The IFC element
:return: List of IfcGroups element is assigned to.
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -1028,9 +1027,9 @@ def get_aggregate(element: ifcopenshell.entity_instance) -> ifcopenshell.entity_
Retrieves the aggregate parent of an element.
:param element: The IFC element
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
:return: The aggregate of the element
:rtype: ifcopenshell.entity_instance.entity_instance
:rtype: ifcopenshell.entity_instance
Example:
@@ -1049,9 +1048,9 @@ def get_nest(element: ifcopenshell.entity_instance) -> ifcopenshell.entity_insta
Retrieves the nest parent of an element.
:param element: The IFC element
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
:return: The nested whole of the element
:rtype: ifcopenshell.entity_instance.entity_instance
:rtype: ifcopenshell.entity_instance
Example:
@@ -1073,9 +1072,9 @@ def get_parts(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entity
Retrieves the parts of an element that have an aggregation relationship.
:param element: The IFC element
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
:return: The parts of the element
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -1099,7 +1098,7 @@ def get_components(element: ifcopenshell.entity_instance, include_ports=False) -
:param include_ports: Default as False. Set to true if you also want to get ports.
:type include_ports: bool,optional
:return: The components of the element
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
Example:
@@ -1142,9 +1141,9 @@ def get_referenced_elements(reference: ifcopenshell.entity_instance) -> set[ifco
"""Get all elements with assigned `reference`
:param reference: IfcExternalReference subtype reference
:type reference: ifcopenshell.entity_instance.entity_instance
:type reference: ifcopenshell.entity_instance
:return: The elements with assigned `reference`
:rtype: set[ifcopenshell.entity_instance.entity_instance]
:rtype: set[ifcopenshell.entity_instance]
Example:
@@ -1223,7 +1222,7 @@ def batch_remove_deep2(ifc_file: ifcopenshell.file) -> None:
on existing variables in memory.
:param ifc_file: The IFC file object
:type ifc_file: ifcopenshell.file.file
:type ifc_file: ifcopenshell.file
:rtype: None
Example:
@@ -1250,9 +1249,9 @@ def unbatch_remove_deep2(ifc_file: ifcopenshell.file) -> ifcopenshell.file:
See documentation for batch_remove_deep2.
:param ifc_file: The IFC file object
:type ifc_file: ifcopenshell.file.file
:type ifc_file: ifcopenshell.file
:return: A newly loaded file with the elements removed.
:rtype: ifcopenshell.file.file
:rtype: ifcopenshell.file
"""
ifc_string = ifc_file.to_string()
lines = iter(ifc_string.split("\n"))
@@ -1305,13 +1304,13 @@ def remove_deep2(
subgraph but are protected from deletion.
:param ifc_file: The IFC file object
:type ifc_file: ifcopenshell.file.file
:type ifc_file: ifcopenshell.file
:param also_consider: elements to also consider as a part of a subgraph
:type also_consider: list[ifcopenshell.entity_instance.entity_instance], optional
:type also_consider: list[ifcopenshell.entity_instance], optional
:param do_not_delete: elements to protect from deletion
:type do_not_delete: list[ifcopenshell.entity_instance.entity_instance], optional
:type do_not_delete: list[ifcopenshell.entity_instance], optional
:param element: The starting element that defines the subgraph
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
"""
# ifc_file.batch()
to_delete = set()
@@ -1358,11 +1357,11 @@ def copy(ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance) ->
GlobalIds are regenerated.
:param ifc_file: The IFC file object
:type ifc_file: ifcopenshell.file.file
:type ifc_file: ifcopenshell.file
:param element: The IFC element to copy
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
:return: The newly copied element
:rtype: ifcopenshell.entity_instance.entity_instance
:rtype: ifcopenshell.entity_instance
"""
new = ifc_file.create_entity(element.is_a())
for i, attribute in enumerate(element):
@@ -1388,9 +1387,9 @@ def copy_deep(
GlobalIds are regenerated.
:param ifc_file: The IFC file object
:type ifc_file: ifcopenshell.file.file
:type ifc_file: ifcopenshell.file
:param element: The IFC element to copy
:type element: ifcopenshell.entity_instance.entity_instance
:type element: ifcopenshell.entity_instance
:param exclude: An optional list of strings of IFC class names to not copy.
If any of the subelement is this class, it will not be copied and the
original instance will be referenced.
@@ -1401,9 +1400,9 @@ def copy_deep(
:param copied_entities: A dictionary of IDs as keys and entities as values
to reuse when coming across the same entity twice. This can typically
be left as None.
:type copied_entities: dict[int:ifcopenshell.entity_instance.entity_instance], optional
:type copied_entities: dict[int:ifcopenshell.entity_instance], optional
:return: The newly copied element
:rtype: ifcopenshell.entity_instance.entity_instance
:rtype: ifcopenshell.entity_instance
"""
if copied_entities is None:
copied_entities = {}
@@ -1,29 +0,0 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.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/>.
from pathlib import Path
def guess_format(path: Path) -> "str | None":
"""Try to guess format using file extension"""
if path.suffix.lower() in (".ifczip", ".zip"):
return ".ifcZIP"
elif path.suffix.lower() in (".ifcxml", ".xml"):
return ".ifcXML"
elif path.suffix.lower() in (".ifcsqlite", ".sqlite", ".db"):
return ".ifcSQLite"
@@ -147,7 +147,7 @@ def auto_xyz2enh(ifc_file, x, y, z):
https://www.buildingsmart.org/standards/bsi-standards/standards-library/
:param ifc_file: The IFC file
:type ifc_file: ifcopenshell.file.file
:type ifc_file: ifcopenshell.file
:param x: The X local engineering coordinate provided in project length units.
:type x: float
:param y: The Y local engineering coordinate provided in project length units.
@@ -215,7 +215,7 @@ def auto_enh2xyz(ifc_file, easting, northing, height):
https://www.buildingsmart.org/standards/bsi-standards/standards-library/
:param ifc_file: The IFC file
:type ifc_file: ifcopenshell.file.file
:type ifc_file: ifcopenshell.file
:param easting: The global easting map coordinate provided in map units.
:type easting: float
:param northing: The global northing map coordinate provided in map units.
@@ -283,7 +283,7 @@ def auto_z2e(ifc_file, z):
https://www.buildingsmart.org/standards/bsi-standards/standards-library/
:param ifc_file: The IFC file
:type ifc_file: ifcopenshell.file.file
:type ifc_file: ifcopenshell.file
:param z: The Z local engineering coordinate provided in project length units.
:type z: float
:return: The elevation in project length units.
@@ -587,7 +587,7 @@ def get_grid_north(ifc_file):
https://www.buildingsmart.org/standards/bsi-standards/standards-library/
:param ifc_file: The IFC file
:type ifc_file: ifcopenshell.file.file
:type ifc_file: ifcopenshell.file
:return: An angle to grid north in decimal degrees
:rtype: float
"""
@@ -623,7 +623,7 @@ def get_true_north(ifc_file):
instead.
:param ifc_file: The IFC file
:type ifc_file: ifcopenshell.file.file
:type ifc_file: ifcopenshell.file
:return: An angle to true north in decimal degrees
:rtype: float
"""
@@ -60,7 +60,7 @@ def get_axis2placement(placement: ifcopenshell.entity_instance) -> MatrixType:
should use ``get_local_placement`` instead.
:param placement: The IfcLocalPlacement enitity
:type placement: ifcopenshell.entity_instance.entity_instance
:type placement: ifcopenshell.entity_instance
:return: A 4x4 numpy matrix
:rtype: MatrixType
"""
@@ -118,7 +118,7 @@ def get_local_placement(placement: ifcopenshell.entity_instance) -> MatrixType:
matrix = ifcopenshell.util.placement.get_local_placement(placement)
:param placement: The IfcLocalPlacement entity
:type placement: ifcopenshell.entity_instance.entity_instance
:type placement: ifcopenshell.entity_instance
:return: A 4x4 numpy matrix
:rtype: MatrixType
"""
@@ -138,7 +138,7 @@ def get_cartesiantransformationoperator3d(inst: ifcopenshell.entity_instance) ->
``get_mappeditem_transformation`` instead.
:param item: The IfcCartesianTransformationOperator entity
:type item: ifcopenshell.entity_instance.entity_instance
:type item: ifcopenshell.entity_instance
:return: A 4x4 numpy transformation matrix
:rtype: MatrixType
"""
@@ -184,7 +184,7 @@ def get_mappeditem_transformation(item: ifcopenshell.entity_instance) -> MatrixT
transformation matrix.
:param item: The IfcMappedItem entity
:type item: ifcopenshell.entity_instance.entity_instance
:type item: ifcopenshell.entity_instance
:return: A 4x4 numpy transformation matrix
:rtype: MatrixType
"""
@@ -201,7 +201,7 @@ def get_storey_elevation(storey: ifcopenshell.entity_instance) -> float:
its placement, or as a fallback the ``Elevation`` attribute.
:param storey: The IfcBuildingStorey entity
:type storey: ifcopenshell.entity_instance.entity_instance
:type storey: ifcopenshell.entity_instance
:return: The elevation in project units
:rtype: float
"""
@@ -16,7 +16,6 @@
# 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 __future__ import annotations
import re
import pathlib
import ifcopenshell
@@ -24,12 +23,12 @@ import ifcopenshell.util.schema
import ifcopenshell.util.type
from ifcopenshell.entity_instance import entity_instance
from functools import lru_cache
from typing import List, Generator, Optional
from typing import List, Optional
templates: dict[str, PsetQto] = {}
templates: dict[str, "PsetQto"] = {}
def get_template(schema: str) -> PsetQto:
def get_template(schema: str) -> "PsetQto":
global templates
if schema not in templates:
templates[schema] = PsetQto(schema)
@@ -88,9 +88,9 @@ def resolve_representation(representation: ifcopenshell.entity_instance) -> ifco
"""Resolve possibly mapped representation.
:param representation: IfcRepresentation
:type representation: ifcopenshell.entity_instance.entity_instance
:type representation: ifcopenshell.entity_instance
:return: Representation resolved from mappings
:rtype: ifcopenshell.entity_instance.entity_instance
:rtype: ifcopenshell.entity_instance
"""
if len(representation.Items) == 1 and representation.Items[0].is_a("IfcMappedItem"):
return resolve_representation(representation.Items[0].MappingSource.MappedRepresentation)
@@ -287,17 +287,17 @@ def filter_elements(
Filter elements based on the provided `query`.
:param ifc_file: The IFC file object
:type ifc_file: ifcopenshell.file.file
:type ifc_file: ifcopenshell.file
:param query: Query to execute
:type query: str
:param elements: Base set of IFC elements for the query.
If provided, new elements found for the current query will be added to `elements`.
Elements explicitly excluded in the `query` will also be excluded from `elements`
:type elements: set[ifcopenshell.entity_instance.entity_instance], optional
:type elements: set[ifcopenshell.entity_instance], optional
:param edit_in_place: If `True`, mutate the provided `elements` in place. Defaults to `False`
:type edit_in_place: bool
:return: Set of filtered elements
:rtype: set[ifcopenshell.entity_instance.entity_instance]
:rtype: set[ifcopenshell.entity_instance]
Example:
@@ -161,7 +161,7 @@ def get_element_bbox_centroid(element: ifcopenshell.entity_instance, geometry) -
is more efficient to use ``get_shape_bbox_centroid``.
:param element: The element occurrence
:type: ifcopenshell.entity_instance.entity_instance
:type: ifcopenshell.entity_instance
:param geometry: Geometry output calculated by IfcOpenShell
:type geometry: geometry
:return: A tuple representing the XYZ centroid
@@ -271,7 +271,7 @@ def get_element_vertices(element: ifcopenshell.entity_instance, geometry) -> npt
Results are a nested numpy array e.g. [[v1x, v1y, v1z], [v2x, v2y, v2z], ...]
:param element: The element occurrence
:type: ifcopenshell.entity_instance.entity_instance
:type: ifcopenshell.entity_instance
:param geometry: Geometry output calculated by IfcOpenShell
:type geometry: geometry
:return: A numpy array listing all the vertices. Each vertex is a numpy array with XYZ coordinates.
@@ -347,7 +347,7 @@ def get_element_bottom_elevation(element: ifcopenshell.entity_instance, geometry
``get_shape_bottom_elevation``.
:param element: The element occurrence
:type: ifcopenshell.entity_instance.entity_instance
:type: ifcopenshell.entity_instance
:param geometry: Geometry output calculated by IfcOpenShell
:type geometry: geometry
:return: The Z value
@@ -363,7 +363,7 @@ def get_element_top_elevation(element: ifcopenshell.entity_instance, geometry) -
``get_shape_top_elevation``.
:param element: The element occurrence
:type: ifcopenshell.entity_instance.entity_instance
:type: ifcopenshell.entity_instance
:param geometry: Geometry output calculated by IfcOpenShell
:type geometry: geometry
:return: The Z value
@@ -656,9 +656,9 @@ def get_profiles(element: ifcopenshell.entity_instance) -> list[ifcopenshell.ent
solid extrusions. This is useful for later doing 2D take-off from profiles.
:param element: The element occurrence
:type: ifcopenshell.entity_instance.entity_instance
:type: ifcopenshell.entity_instance
:return: A list of profiles
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
"""
material = ifcopenshell.util.element.get_material(element, should_skip_usage=True)
if material and material.is_a("IfcMaterialProfileSet"):
@@ -670,9 +670,9 @@ def get_extrusions(element: ifcopenshell.entity_instance) -> list[ifcopenshell.e
"""Gets all extruded area solids used to define an element's model body geometry
:param element: The element occurrence
:type: ifcopenshell.entity_instance.entity_instance
:type: ifcopenshell.entity_instance
:return: A list of extrusion representation items
:rtype: list[ifcopenshell.entity_instance.entity_instance]
:rtype: list[ifcopenshell.entity_instance]
"""
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
if not representation:
@@ -398,7 +398,7 @@ def get_project_unit(ifc_file: ifcopenshell.file, unit_type: str) -> Union[ifcop
"""Get the default project unit of a particular unit type
:param ifc_file: The IFC file.
:type ifc_file: ifcopenshell.file.file
:type ifc_file: ifcopenshell.file
:param unit_type: The type of unit, taken from the list of IFC unit types,
such as "LENGTHUNIT".
:type unit_type: str
@@ -536,9 +536,9 @@ def convert_unit(value: float, from_unit: ifcopenshell.entity_instance, to_unit:
:param value: The numeric value you want to convert
:type value: float
:param from_unit: The IfcNamedUnit to confirm from.
:type from_unit: ifcopenshell.entity_instance.entity_instance
:type from_unit: ifcopenshell.entity_instance
:param to_unit: The IfcNamedUnit to confirm from.
:type to_unit: ifcopenshell.entity_instance.entity_instance
:type to_unit: ifcopenshell.entity_instance
:return: The converted value.
:rtype: float
"""
@@ -599,7 +599,7 @@ def calculate_unit_scale(ifc_file: ifcopenshell.file, unit_type: str = "LENGTHUN
si_meters / unit_scale = ifc_project_length
:param ifc_file: The IFC file.
:type ifc_file: ifcopenshell.file.file
:type ifc_file: ifcopenshell.file
:param unit_type: The type of SI unit, defaults to "LENGTHUNIT"
:type unit_type: str
:returns: The scale factor
@@ -32,8 +32,6 @@ Available flags:
- ``--fields``: Output more detailed information about failed entities (available only with ``--json``).
"""
from __future__ import print_function
import os
import sys
import json
+1 -1
View File
@@ -23,5 +23,5 @@ Documentation = "https://docs.ifcopenshell.org"
Issues = "https://github.com/IfcOpenShell/IfcOpenShell/issues"
[tool.setuptools.packages.find]
include = ["ifcpatch"]
include = ["ifcpatch*"]
exclude = ["test*"]