mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-27 18:57:17 +00:00
Write docs on IOS geometry processing. See #671.
This commit is contained in:
@@ -125,8 +125,8 @@ elements starting at item number 30,000 and ending at item number 50,000. This
|
|||||||
allows you to arbitrarily break down large models into submodels. This can be
|
allows you to arbitrarily break down large models into submodels. This can be
|
||||||
combined with other filters.
|
combined with other filters.
|
||||||
|
|
||||||
`Beta versions of Blender 3.3 <https://builder.blender.org/download/patch/>`__
|
Using Blender 3.3 and above will result in a faster load time (~50%) compared to
|
||||||
may be used which will result in a faster load time (~50%).
|
older Blender versions.
|
||||||
|
|
||||||
Coordination only models
|
Coordination only models
|
||||||
------------------------
|
------------------------
|
||||||
|
|||||||
@@ -12,5 +12,5 @@ system, as well as high level analysis and authoring functions.
|
|||||||
ifcopenshell-python/installation
|
ifcopenshell-python/installation
|
||||||
ifcopenshell-python/hello_world
|
ifcopenshell-python/hello_world
|
||||||
ifcopenshell-python/code_examples
|
ifcopenshell-python/code_examples
|
||||||
ifcopenshell-python/geometry_iterator
|
ifcopenshell-python/geometry_processing
|
||||||
ifcopenshell-python/developer_guide
|
ifcopenshell-python/developer_guide
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
Geometry iterator
|
|
||||||
=================
|
|
||||||
|
|
||||||
IfcOpenShell provides a geometry iterator function to efficiently process
|
|
||||||
geometry in an IFC model. The iterator is always used in IfcConvert, and may
|
|
||||||
also be invoked in C++ or in Python.
|
|
||||||
|
|
||||||
The geometry iterator makes it easy to collect possible geometry in a model,
|
|
||||||
supports multicore processing, and implements caching and reuse to improve the
|
|
||||||
efficiency of geometry processing. It is also possible to process geometry one
|
|
||||||
by one using ``create_shape()``, but is significantly less efficient.
|
|
||||||
|
|
||||||
By default, the geometry iterator processes all 3D geometry in a model from all
|
|
||||||
elements, and returns a list of X Y Z vertex ordinates in a flattend list, as
|
|
||||||
well as a flattend list of triangulated faces denoted by vertex indices.
|
|
||||||
|
|
||||||
There are a variety of configuration settings to get different output. For
|
|
||||||
example, you may filter elements from processing, extract 2D data, or return
|
|
||||||
non-triangulated OpenCASCADE BReps. For more information on the various
|
|
||||||
settings, see :doc:`Geometry Settings<../ifcopenshell/geometry_settings>`.
|
|
||||||
|
|
||||||
Here is a simple example in Python:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
import multiprocessing
|
|
||||||
import ifcopenshell
|
|
||||||
import ifcopenshell.geom
|
|
||||||
|
|
||||||
ifc_file = ifcopenshell.open('model.ifc')
|
|
||||||
|
|
||||||
settings = ifcopenshell.geom.settings()
|
|
||||||
iterator = ifcopenshell.geom.iterator(settings, ifc_file, multiprocessing.cpu_count())
|
|
||||||
if iterator.initialize():
|
|
||||||
while True:
|
|
||||||
shape = iterator.get()
|
|
||||||
# Get the current IFC element we are iterating over
|
|
||||||
element = ifc_file.by_guid(shape.guid)
|
|
||||||
# Indices of vertices per triangle face e.g. [f1v1, f1v2, f1v3, f2v1, f2v2, f2v3, ...]
|
|
||||||
faces = shape.geometry.faces
|
|
||||||
# X Y Z of vertices in flattened list e.g. [v1x, v1y, v1z, v2x, v2y, v2z, ...]
|
|
||||||
verts = shape.geometry.verts
|
|
||||||
# Material names and colour style information that are relevant to this shape
|
|
||||||
materials = shape.geometry.materials
|
|
||||||
# Indices of material applied per triangle face e.g. [f1m, f2m, ...]
|
|
||||||
material_ids = shape.geometry.material_ids
|
|
||||||
|
|
||||||
# Since the lists are flattened, you may prefer to group them per
|
|
||||||
# face like so depending on your geometry kernel
|
|
||||||
grouped_verts = [[verts[i], verts[i + 1], verts[i + 2]] for i in range(0, len(verts), 3)]
|
|
||||||
grouped_faces = [[faces[i], faces[i + 1], faces[i + 2]] for i in range(0, len(faces), 3)]
|
|
||||||
if not iterator.next():
|
|
||||||
break
|
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
Geometry processing
|
||||||
|
===================
|
||||||
|
|
||||||
|
Geometry is specified in many ways in IFC. Some geometry is defined explicitly
|
||||||
|
with coordinates, vertices, and faces. Some geometry is defined implicitly with
|
||||||
|
equations, boolean operations, and parametric shapes.
|
||||||
|
|
||||||
|
Individual processing
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
The simplest way to process any geometry in a standardised fashion is to use the
|
||||||
|
IfcOpenShell ``create_shape()`` function. This will provide a list of vertices,
|
||||||
|
edges, and faces, or alternatively an OpenCASCADE BRep.
|
||||||
|
|
||||||
|
Here is a simple example of processing a single wall into a list of vertices and
|
||||||
|
faces. In this example, a ``shape`` variable is returned, which holds geometry
|
||||||
|
related information in ``shape.geometry``:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import ifcopenshell
|
||||||
|
import ifcopenshell.geom
|
||||||
|
|
||||||
|
ifc_file = ifcopenshell.open('model.ifc')
|
||||||
|
element = ifc_file.by_type('IfcWall')[0]
|
||||||
|
|
||||||
|
settings = ifcopenshell.geom.settings()
|
||||||
|
shape = ifcopenshell.geom.create_shape(settings, element)
|
||||||
|
|
||||||
|
# The GUID of the element we processed
|
||||||
|
print(shape.guid)
|
||||||
|
|
||||||
|
# The ID of the element we processed
|
||||||
|
print(shape.id)
|
||||||
|
|
||||||
|
# The element we are processing
|
||||||
|
print(ifc_file.by_guid(shape.guid))
|
||||||
|
|
||||||
|
# A unique geometry ID, useful to check whether or not two geometries are
|
||||||
|
# identical for caching and reuse. The naming scheme is:
|
||||||
|
# IfcShapeRepresentation.id{-layerset-LayerSet.id}{-material-Material.id}{-openings-[Opening n.id ...]}{-world-coords}
|
||||||
|
print(shape.geometry.id())
|
||||||
|
|
||||||
|
# Indices of vertices per triangle face e.g. [f1v1, f1v2, f1v3, f2v1, f2v2, f2v3, ...]
|
||||||
|
faces = shape.geometry.faces
|
||||||
|
|
||||||
|
# X Y Z of vertices in flattened list e.g. [v1x, v1y, v1z, v2x, v2y, v2z, ...]
|
||||||
|
verts = shape.geometry.verts
|
||||||
|
|
||||||
|
# Since the lists are flattened, you may prefer to group them per face like so depending on your geometry kernel
|
||||||
|
grouped_verts = [[verts[i], verts[i + 1], verts[i + 2]] for i in range(0, len(verts), 3)]
|
||||||
|
grouped_faces = [[faces[i], faces[i + 1], faces[i + 2]] for i in range(0, len(faces), 3)]
|
||||||
|
|
||||||
|
# A list of styles that are relevant to this shape
|
||||||
|
styles = shape.geometry.materials
|
||||||
|
|
||||||
|
for style in styles:
|
||||||
|
# Each style is named after the entity class if a default
|
||||||
|
# material is applied. Otherwise, it is named "surface-style-{SurfaceStyle.name}"
|
||||||
|
# All non-alphanumeric characters are replaced with a "-".
|
||||||
|
print(style.original_name)
|
||||||
|
|
||||||
|
# A more human readable name
|
||||||
|
print(style.name)
|
||||||
|
|
||||||
|
# Each style may have diffuse colour RGB codes
|
||||||
|
if style.has_diffuse:
|
||||||
|
print(style.diffuse)
|
||||||
|
|
||||||
|
# Each style may have transparency data
|
||||||
|
if style.has_transparency:
|
||||||
|
print(style.transparency)
|
||||||
|
|
||||||
|
# Indices of material applied per triangle face e.g. [f1m, f2m, ...]
|
||||||
|
material_ids = shape.geometry.material_ids
|
||||||
|
|
||||||
|
Alternatively, you may choose to retrieve an OpenCASCADE BRep:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import ifcopenshell
|
||||||
|
import ifcopenshell.geom
|
||||||
|
|
||||||
|
ifc_file = ifcopenshell.open('model.ifc')
|
||||||
|
element = ifc_file.by_type('IfcWall')[0]
|
||||||
|
|
||||||
|
settings = ifcopenshell.geom.settings()
|
||||||
|
settings.set(settings.USE_PYTHON_OPENCASCADE, True)
|
||||||
|
|
||||||
|
try:
|
||||||
|
shape = geom.create_shape(settings, element)
|
||||||
|
geometry = shape.geometry # see #1124
|
||||||
|
# These are methods of the TopoDS_Shape class from pythonOCC
|
||||||
|
shape_gpXYZ = geometry.Location().Transformation().TranslationPart()
|
||||||
|
# These are methods of the gpXYZ class from pythonOCC
|
||||||
|
print(shape_gpXYZ.X(), shape_gpXYZ.Y(), shape_gpXYZ.Z())
|
||||||
|
except:
|
||||||
|
print("Shape creation failed")
|
||||||
|
|
||||||
|
When an entire element is passed into ``create_shape()``, the 3D representation
|
||||||
|
is processed by default with all openings applied. However, it is also possible
|
||||||
|
to only process a single shape representation with no openings, representation
|
||||||
|
item, or profile definition.
|
||||||
|
|
||||||
|
In these scenarios, a ``geometry`` is returned directly, equivalent to
|
||||||
|
``shape.geometry`` in the example above.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
ifc_file = ifcopenshell.open('model.ifc')
|
||||||
|
element = ifc_file.by_type('IfcWall')[0]
|
||||||
|
|
||||||
|
# Process a shape representation
|
||||||
|
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body")
|
||||||
|
|
||||||
|
# Note: geometry is returned directly, equivalent to shape.geometry when passing in an element
|
||||||
|
geometry = geom.create_shape(settings, body)
|
||||||
|
|
||||||
|
# Process a representation item
|
||||||
|
geometry = geom.create_shape(settings, ifc_file.by_type("IfcExtrudedAreaSolid")[0])
|
||||||
|
|
||||||
|
# Process a profile
|
||||||
|
geometry = geom.create_shape(settings, ifc_file.by_type("IfcProfileDef")[0])
|
||||||
|
|
||||||
|
Geometry iterator
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
IfcOpenShell provides a geometry iterator function to efficiently process
|
||||||
|
geometry in an IFC model. The iterator is always used in IfcConvert, and may
|
||||||
|
also be invoked in C++ or in Python. It offers the same features as the
|
||||||
|
``create_shape()`` function for `Individual processing`_.
|
||||||
|
|
||||||
|
The geometry iterator makes it easy to collect possible geometry in a model,
|
||||||
|
supports multicore processing, and implements caching and reuse to improve the
|
||||||
|
efficiency of geometry processing. For any bulk geometry processing, it is
|
||||||
|
always recommended to use the iterator.
|
||||||
|
|
||||||
|
By default, the geometry iterator processes all 3D geometry in a model from all
|
||||||
|
elements, and returns a list of X Y Z vertex ordinates in a flattened list, as
|
||||||
|
well as a flattened list of triangulated faces denoted by vertex indices.
|
||||||
|
|
||||||
|
There are a variety of configuration settings to get different output. For
|
||||||
|
example, you may filter elements from processing, extract 2D data, or return
|
||||||
|
non-triangulated OpenCASCADE BReps. For more information on the various
|
||||||
|
settings, see :doc:`Geometry Settings<../ifcopenshell/geometry_settings>`.
|
||||||
|
|
||||||
|
Here is a simple example in Python:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import multiprocessing
|
||||||
|
import ifcopenshell
|
||||||
|
import ifcopenshell.geom
|
||||||
|
|
||||||
|
ifc_file = ifcopenshell.open('model.ifc')
|
||||||
|
|
||||||
|
settings = ifcopenshell.geom.settings()
|
||||||
|
iterator = ifcopenshell.geom.iterator(settings, ifc_file, multiprocessing.cpu_count())
|
||||||
|
if iterator.initialize():
|
||||||
|
while True:
|
||||||
|
shape = iterator.get()
|
||||||
|
faces = shape.geometry.faces
|
||||||
|
verts = shape.geometry.verts
|
||||||
|
materials = shape.geometry.materials
|
||||||
|
material_ids = shape.geometry.material_ids
|
||||||
|
# ... write code to process geometry here ...
|
||||||
|
if not iterator.next():
|
||||||
|
break
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The iterator can only be used to process whole elements, not individual
|
||||||
|
shape representations, representation items, and profiles.
|
||||||
|
|
||||||
|
Manual parsing
|
||||||
|
--------------
|
||||||
|
|
||||||
|
IfcOpenShell lets you traverse any IFC entity graph. This means it is possible
|
||||||
|
for you to manually browse through the ``Representation`` attribute of IFC
|
||||||
|
elements, and parse the corresponding IFC shape representations yourself instead
|
||||||
|
of using generic geometric processing such as `Individual processing`_ and the
|
||||||
|
`Geometry iterator`_.
|
||||||
|
|
||||||
|
This approach requires an in-depth understanding of IFC geometry
|
||||||
|
representations, as well as its many caveats with units and transformations, but
|
||||||
|
can be very simple and extremely fast to extract specific types of geometry. For
|
||||||
|
example, if you know you are dealing with IfcCircle geometry, you can
|
||||||
|
specifically pinpoint the Radius parameter.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
||||||
|
|
||||||
|
for circle in ifc_file.by_type("IfcCircle"):
|
||||||
|
# In project length units
|
||||||
|
print(circle.Radius)
|
||||||
|
|
||||||
|
# In SI meters
|
||||||
|
print(circle.Radius * unit_scale)
|
||||||
|
|
||||||
|
Given the advanced nature of manual processing, it is generally not recommended
|
||||||
|
except in specific tasks.
|
||||||
@@ -41,8 +41,8 @@ utility:
|
|||||||
Exactly how it is run depends on the recipe. A recipe may require zero or more
|
Exactly how it is run depends on the recipe. A recipe may require zero or more
|
||||||
arguments which are specific to the recipe. Here's an example which runs the
|
arguments which are specific to the recipe. Here's an example which runs the
|
||||||
`ExtractElements` recipe, which, as the same suggests, extracts out elements.
|
`ExtractElements` recipe, which, as the same suggests, extracts out elements.
|
||||||
This recipe expects one argument, which uses the [IFC Query
|
This recipe expects one argument, which uses the `IFC Query
|
||||||
syntax](https://wiki.osarch.org/index.php?title=IfcOpenShell_code_examples#IFC_Query_Syntax).
|
syntax <https://wiki.osarch.org/index.php?title=IfcOpenShell_code_examples#IFC_Query_Syntax>`_.
|
||||||
In this example, we'll extract out all `IfcWall` elements.
|
In this example, we'll extract out all `IfcWall` elements.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|||||||
Reference in New Issue
Block a user