mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-20 06:58:56 +00:00
#2319 Add documentation for IfcDiff
This commit is contained in:
+35
-12
@@ -34,6 +34,38 @@ from deepdiff import DeepDiff
|
|||||||
|
|
||||||
|
|
||||||
class IfcDiff:
|
class IfcDiff:
|
||||||
|
"""Main IfcDiff application
|
||||||
|
|
||||||
|
If you are using IfcDiff as a library, this is the class you should use.
|
||||||
|
|
||||||
|
:param old_file: Filepath to the old file
|
||||||
|
:type old_file: string
|
||||||
|
:param new_file: Filepath to the new file
|
||||||
|
:type new_file: string
|
||||||
|
:param output_file: Filepath to the output JSON file to store the diff
|
||||||
|
results
|
||||||
|
:type output_file: string
|
||||||
|
:param relationships: List of relationships to check. An empty list means
|
||||||
|
that only geometry and attributes are compared.
|
||||||
|
:type relationships: list[string]
|
||||||
|
:param is_shallow: True if you want only the first difference to be listed.
|
||||||
|
False if you want all differences to be checked. Choosing False means
|
||||||
|
that comparisons will take longer.
|
||||||
|
:type is_shallow: bool
|
||||||
|
:param filter_elements: An IFC filter query if you only want to compare a
|
||||||
|
subset of elements. For example: ``.IfcWall`` to only compare walls.
|
||||||
|
:type filter_elements: string
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
from ifcdiff import IfcDiff
|
||||||
|
|
||||||
|
ifc_diff = IfcDiff("/path/to/old.ifc", "/path/to/new.ifc", "/path/to/diff.json")
|
||||||
|
ifc_diff.diff()
|
||||||
|
print(ifc_diff.change_register)
|
||||||
|
ifc_diff.export()
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, old_file, new_file, output_file, relationships=None, is_shallow=True, filter_elements=None):
|
def __init__(self, old_file, new_file, output_file, relationships=None, is_shallow=True, filter_elements=None):
|
||||||
self.old_file = old_file
|
self.old_file = old_file
|
||||||
self.new_file = new_file
|
self.new_file = new_file
|
||||||
@@ -101,7 +133,6 @@ class IfcDiff:
|
|||||||
},
|
},
|
||||||
diff_file,
|
diff_file,
|
||||||
indent=4,
|
indent=4,
|
||||||
cls=DiffEncoder,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
@@ -173,9 +204,9 @@ class IfcDiff:
|
|||||||
def diff_element_geometry(self, old, new):
|
def diff_element_geometry(self, old, new):
|
||||||
old_placement = ifcopenshell.util.placement.get_local_placement(old.ObjectPlacement)
|
old_placement = ifcopenshell.util.placement.get_local_placement(old.ObjectPlacement)
|
||||||
new_placement = ifcopenshell.util.placement.get_local_placement(new.ObjectPlacement)
|
new_placement = ifcopenshell.util.placement.get_local_placement(new.ObjectPlacement)
|
||||||
if not np.allclose(old_placement[:,3], new_placement[:,3], atol=self.precision):
|
if not np.allclose(old_placement[:, 3], new_placement[:, 3], atol=self.precision):
|
||||||
return True
|
return True
|
||||||
if not np.allclose(old_placement[0:3,0:3], new_placement[0:3,0:3], atol=1e-2):
|
if not np.allclose(old_placement[0:3, 0:3], new_placement[0:3, 0:3], atol=1e-2):
|
||||||
return True
|
return True
|
||||||
old_openings = [o.RelatedOpeningElement.GlobalId for o in getattr(old, "HasOpenings", []) or []]
|
old_openings = [o.RelatedOpeningElement.GlobalId for o in getattr(old, "HasOpenings", []) or []]
|
||||||
new_openings = [o.RelatedOpeningElement.GlobalId for o in getattr(new, "HasOpenings", []) or []]
|
new_openings = [o.RelatedOpeningElement.GlobalId for o in getattr(new, "HasOpenings", []) or []]
|
||||||
@@ -218,7 +249,7 @@ class IfcDiff:
|
|||||||
new_item.get_info_2(recursive=True),
|
new_item.get_info_2(recursive=True),
|
||||||
custom_operators=[DiffTerminator()] if self.is_shallow else [],
|
custom_operators=[DiffTerminator()] if self.is_shallow else [],
|
||||||
math_epsilon=self.precision,
|
math_epsilon=self.precision,
|
||||||
exclude_regex_paths=[r".*id']$"]
|
exclude_regex_paths=[r".*id']$"],
|
||||||
)
|
)
|
||||||
except:
|
except:
|
||||||
return True
|
return True
|
||||||
@@ -249,14 +280,6 @@ class DiffTerminator:
|
|||||||
raise Exception("Terminated")
|
raise Exception("Terminated")
|
||||||
|
|
||||||
|
|
||||||
class DiffEncoder(json.JSONEncoder):
|
|
||||||
def default(self, obj):
|
|
||||||
try:
|
|
||||||
return json.JSONEncoder.default(self, obj)
|
|
||||||
except:
|
|
||||||
return str(obj)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(description="Show the difference between two IFC files")
|
parser = argparse.ArgumentParser(description="Show the difference between two IFC files")
|
||||||
parser.add_argument("old", type=str, help="The old IFC file")
|
parser.add_argument("old", type=str, help="The old IFC file")
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ extensions = ["autoapi.extension"]
|
|||||||
autoapi_type = 'python'
|
autoapi_type = 'python'
|
||||||
|
|
||||||
# autoapi works by reading source code instead of importing modules
|
# autoapi works by reading source code instead of importing modules
|
||||||
autoapi_dirs = ['../ifcopenshell']
|
autoapi_dirs = ['../ifcopenshell', '../../ifcdiff']
|
||||||
|
|
||||||
# autoapi_options doesn't have show-module-summary, as it tends to create one
|
# 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
|
# page per function which contradicts the presentation of showing all functions
|
||||||
|
|||||||
@@ -1,16 +1,124 @@
|
|||||||
IfcDiff
|
IfcDiff
|
||||||
=======
|
=======
|
||||||
|
|
||||||
This documentation is free software! You are free to contribute and help write
|
IfcDiff is both a CLI utility and library that lets you compare the changes
|
||||||
this document.
|
between two IFC models. Changes are made on the assumption that the GlobalId of
|
||||||
|
an element in one model is consistent with the same element in another model.
|
||||||
|
You may compare geometric changes, and changes in various IFC relationships and
|
||||||
|
properties. IfcDiff supports comparing across different IFC schema versions.
|
||||||
|
|
||||||
.. toctree::
|
Changes will be sorted into three lists:
|
||||||
:maxdepth: 1
|
|
||||||
:caption: Contents:
|
|
||||||
|
|
||||||
Indices and tables
|
- **Added**: a list of GlobalIds of elements present in the new file but not
|
||||||
------------------
|
present in the old file.
|
||||||
|
- **Deleted**: a list of GlobalIds of elements present in the old file but not
|
||||||
|
present in the new file.
|
||||||
|
- **Changed**: A list of GlobalIds of elements present in both the old and new
|
||||||
|
file, but changes were detected. A list of changes are provided.
|
||||||
|
|
||||||
* :ref:`genindex`
|
There are different methods of installation, depending on your situation.
|
||||||
* :ref:`modindex`
|
|
||||||
* :ref:`search`
|
1. **Source installation** is recommended for users wanting to use the latest
|
||||||
|
code as a library or a CLI utility.
|
||||||
|
2. **Using the BlenderBIM Add-on** is recommended for non-developers wanting a
|
||||||
|
graphical interface.
|
||||||
|
|
||||||
|
Source installation
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
1. :doc:`Install IfcOpenShell <ifcopenshell-python/installation>`
|
||||||
|
2. `Clone the source code <https://github.com/IfcOpenShell/IfcOpenShell/tree/v0.7.0/src/ifcdiff>`_.
|
||||||
|
3. ``pip install -r requirements.txt``
|
||||||
|
|
||||||
|
Here is a minimal example of how to use IfcDiff as a Python module or CLI
|
||||||
|
utility:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
$ python -m ifcdiff -h
|
||||||
|
usage: ifcdiff.py [-h] [-o OUTPUT] [-r RELATIONSHIPS] old new
|
||||||
|
|
||||||
|
Show the difference between two IFC files
|
||||||
|
|
||||||
|
positional arguments:
|
||||||
|
old The old IFC file
|
||||||
|
new The new IFC file
|
||||||
|
|
||||||
|
options:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
-o OUTPUT, --output OUTPUT
|
||||||
|
The JSON diff file to output. Defaults to diff.json
|
||||||
|
-r RELATIONSHIPS, --relationships RELATIONSHIPS
|
||||||
|
A list of space-separated relationships, chosen from "type", "property", "container", "aggregate", "classification"
|
||||||
|
$ python -m ifcdiff old.ifc new.ifc
|
||||||
|
$ cat diff.json
|
||||||
|
|
||||||
|
Here is a minimal example of how to use IfcDiff as a library:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from ifcdiff import IfcDiff
|
||||||
|
|
||||||
|
ifc_diff = IfcDiff("/path/to/old.ifc", "/path/to/new.ifc", "/path/to/diff.json")
|
||||||
|
ifc_diff.diff()
|
||||||
|
print(ifc_diff.change_register)
|
||||||
|
ifc_diff.export()
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
For more information on how to use IfcDiff as a library, check out the :doc:`API
|
||||||
|
reference <autoapi/ifcdiff/index>`.
|
||||||
|
|
||||||
|
|
||||||
|
Using the BlenderBIM Add-on
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
The BlenderBIM Add-on is a Blender based graphical interface to IfcOpenShell.
|
||||||
|
Other than providing a graphical IFC authoring platform, it also comes with
|
||||||
|
IfcOpenShell, its utilities, and a Python shell built-in. This means you don't
|
||||||
|
need to install Python first, and you also can compare your IfcOpenShell
|
||||||
|
scripting to what you see with a visual model viewer, or use a graphical
|
||||||
|
interface to access the IfcOpenShell utilities.
|
||||||
|
|
||||||
|
1. Install the BlenderBIM Add-on by following the `BlenderBIM Add-on
|
||||||
|
installation documentation
|
||||||
|
<https://blenderbim.org/docs/users/installation.html>`_.
|
||||||
|
|
||||||
|
2. Launch Blender. Change to the **Scene Properties** tab in the **Properties
|
||||||
|
Panel**. Scroll down to the **IFC Quality Control > IFC Diff** panel.
|
||||||
|
|
||||||
|
3. Browse to your old IFC file, new IFC file.
|
||||||
|
|
||||||
|
4. Optionally add any relationships you want to check.
|
||||||
|
|
||||||
|
5. Optionally type in a filter query.
|
||||||
|
|
||||||
|
6. Press **Execute IFC Diff**
|
||||||
|
|
||||||
|
TODO: add pictures and make this clearer for non-developers.
|
||||||
|
|
||||||
|
Geometry changes
|
||||||
|
----------------
|
||||||
|
|
||||||
|
IfcDiff compares geometry changes using the underlying IFC geometric definition.
|
||||||
|
This means that if a shape is described in one file as an extrusion, and as a
|
||||||
|
mesh in another file, it is considered to be a change in geometry, even if they
|
||||||
|
resolve to be the same boundary representation.
|
||||||
|
|
||||||
|
Geometric tolerance is defined using the precision defined in the new IFC model.
|
||||||
|
|
||||||
|
Relationships
|
||||||
|
-------------
|
||||||
|
|
||||||
|
By default, IfcDiff only compares changes in attributes and geometry. You may
|
||||||
|
wish to optionally specify more relationships to compare. You may choose from:
|
||||||
|
|
||||||
|
- **type**: detects changes in the type relationship, such as when an
|
||||||
|
occurrence now belongs to a different type.
|
||||||
|
- **property**: detects changes in property sets, properties, quantity sets,
|
||||||
|
and quantities. Also includes detected changes in inherited properties.
|
||||||
|
- **container**: detects changes in the spatial container, handling indirect
|
||||||
|
containment such as when an element is part of an aggregate.
|
||||||
|
- **aggregate**: detects changes in aggregation.
|
||||||
|
- **classification**: detects changes in classification references. Also
|
||||||
|
includes detected changes in inherited classifications.
|
||||||
|
|||||||
@@ -91,9 +91,10 @@ Using the BlenderBIM Add-on
|
|||||||
|
|
||||||
The BlenderBIM Add-on is a Blender based graphical interface to IfcOpenShell.
|
The BlenderBIM Add-on is a Blender based graphical interface to IfcOpenShell.
|
||||||
Other than providing a graphical IFC authoring platform, it also comes with
|
Other than providing a graphical IFC authoring platform, it also comes with
|
||||||
IfcOpenShell and a Python shell built-in. This means you don't need to install
|
IfcOpenShell, its utilities, and a Python shell built-in. This means you don't
|
||||||
Python first, and you also can compare your IfcOpenShell scripting to what you
|
need to install Python first, and you also can compare your IfcOpenShell
|
||||||
see with a visual model viewer.
|
scripting to what you see with a visual model viewer, or use a graphical
|
||||||
|
interface to access the IfcOpenShell utilities.
|
||||||
|
|
||||||
1. Install the BlenderBIM Add-on by following the `BlenderBIM Add-on
|
1. Install the BlenderBIM Add-on by following the `BlenderBIM Add-on
|
||||||
installation documentation
|
installation documentation
|
||||||
|
|||||||
Reference in New Issue
Block a user