mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-08 08:51:35 +00:00
Compare commits
250 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 16f2b0a0d2 | |||
| 6dd22fda82 | |||
| 1e772a7ea9 | |||
| 7e14d4389e | |||
| 852e3e28ee | |||
| e962872549 | |||
| f16b2e59ae | |||
| 844428fefd | |||
| a53ffd2662 | |||
| fd02665e5e | |||
| fa3fdcd273 | |||
| e6499ef3b1 | |||
| cf1de365e7 | |||
| 3bdf429c30 | |||
| 1bef19a87a | |||
| e07189e6b1 | |||
| f851a7188f | |||
| d8d82eb6ec | |||
| 89e97e5d7c | |||
| 388c717317 | |||
| 20eb913b65 | |||
| 6ca5c90517 | |||
| 5e2d5129bb | |||
| 226a02adfc | |||
| 03a82fe301 | |||
| b40a21743b | |||
| 2562d6c208 | |||
| cab7716bdf | |||
| 83af36dc60 | |||
| 34fd334fcb | |||
| 839dd9aed6 | |||
| 0f0d060177 | |||
| 6dc9ff6fa3 | |||
| c2da3b9e82 | |||
| 621859453a | |||
| 01ab21a69a | |||
| 9c81735cbd | |||
| 659f05bda3 | |||
| 59020a22ee | |||
| 693444d4d2 | |||
| 93a33a8507 | |||
| e1b1940d83 | |||
| 9a2e5d698a | |||
| 71dcc96ac2 | |||
| 2422da4048 | |||
| f6403c81e1 | |||
| de78c6c5dc | |||
| f24c996bc1 | |||
| 3dbb52a4f3 | |||
| d9c4920d37 | |||
| dcf331a78d | |||
| 09679050c2 | |||
| d13a7b613b | |||
| 61fba3f406 | |||
| b8001ea05d | |||
| 4163f817a6 | |||
| 2a0471ec27 | |||
| 418b78cdd5 | |||
| c1c738390f | |||
| 766d45e0cb | |||
| df88474bc5 | |||
| 481515f5ae | |||
| a33f5b6e17 | |||
| 10bec3eee0 | |||
| da0af77570 | |||
| a6094f50b9 | |||
| c3f1b41860 | |||
| 4122759f1a | |||
| a583339492 | |||
| f12e980bfe | |||
| 4979deb111 | |||
| c575352d20 | |||
| 2f8fa3282b | |||
| 993e322a8e | |||
| 61ccd8a7cf | |||
| 450baf224f | |||
| 7b2197fa37 | |||
| cde1c5f2ee | |||
| 33772a4710 | |||
| 178c34fb22 | |||
| 17ecc43f78 | |||
| 72999e04d9 | |||
| f191b1fdd2 | |||
| d095bfecde | |||
| 2e1699beea | |||
| 5c07c8dc95 | |||
| 0fa05faee8 | |||
| 21e8a1e8e6 | |||
| 2e6601b3e7 | |||
| 634932e6e7 | |||
| a041d289c6 | |||
| 01f8882311 | |||
| f2bdfbd049 | |||
| c7bf03e8f8 | |||
| 18e451b874 | |||
| f4d58b3969 | |||
| 76a3146b70 | |||
| fe70acb541 | |||
| a52901344c | |||
| d0e26f07fc | |||
| 5270710fc2 | |||
| ed8cc620ea | |||
| 9b13ed3f38 | |||
| 801c7da40f | |||
| 4be7da1a43 | |||
| a0db3a3406 | |||
| 18f8d7b3a3 | |||
| 010e05308d | |||
| 973fa9ccb5 | |||
| 0d42a293ad | |||
| 6716423a68 | |||
| a02a06a0e3 | |||
| d3438335a2 | |||
| a0bb589ed3 | |||
| 056bcd12d0 | |||
| fe699e0a81 | |||
| 4eee9a1936 | |||
| 8c1710cae1 | |||
| e2d3b3734f | |||
| b243572d23 | |||
| 3224a2cf83 | |||
| a2d91f9331 | |||
| 0301e2fb1b | |||
| 0036bd2dc2 | |||
| 0877bb0ac3 | |||
| e62ce005dc | |||
| b6e2d78bfa | |||
| bf292cccd0 | |||
| 83c4b6a642 | |||
| 2dc5cd44b7 | |||
| fcbe93c4c2 | |||
| 89b3b96f1e | |||
| 16a82f035f | |||
| b562508f5b | |||
| a13042f227 | |||
| 3cbb47a831 | |||
| 7d806296c1 | |||
| d6bd0c861b | |||
| 8164c90ba0 | |||
| fff6f97651 | |||
| 6a5d5dcb12 | |||
| bb3dc351b8 | |||
| 90946e0877 | |||
| 7895835ca3 | |||
| 7caa4e3e1d | |||
| d721dabf3b | |||
| ac8cf298fa | |||
| 9087bc65a7 | |||
| ccf4e84e18 | |||
| 0f1db1267b | |||
| 431e993ba3 | |||
| d912e73282 | |||
| 106da12444 | |||
| 579d3713fd | |||
| 89a015724b | |||
| 8b63959509 | |||
| 0a8791e04e | |||
| 318779196b | |||
| d076fa588b | |||
| 6190771817 | |||
| 206a9cf5d0 | |||
| d4b51a82e7 | |||
| a749775045 | |||
| 26ed16ba52 | |||
| 7b4d8734ed | |||
| 455d382a9e | |||
| c9313c8e02 | |||
| b44a88d203 | |||
| 921c3eb2d3 | |||
| d5efe45b0b | |||
| b8a7b5426d | |||
| 89bea19b75 | |||
| 5c0eb05482 | |||
| c9ff455812 | |||
| fdf1b29682 | |||
| f3af39546b | |||
| 44ddc5e6dc | |||
| c7ddc0643e | |||
| 3a9e90f94f | |||
| db6630c1f8 | |||
| c20afd24a5 | |||
| 7b82bfb477 | |||
| 3e00139a87 | |||
| 23beb5691c | |||
| c6a265adf8 | |||
| 94d214808e | |||
| a58b2ede63 | |||
| e5c20a009d | |||
| b590747db9 | |||
| 2532ba30e4 | |||
| 9096895bdb | |||
| 82143f226e | |||
| 22a8d9a17b | |||
| 4385f3b14d | |||
| 3cba242295 | |||
| 822fa91f4d | |||
| 266d6f4c97 | |||
| 8406c5243c | |||
| 810d3eab1e | |||
| 17f6e67706 | |||
| f5c32adff1 | |||
| bb43dec90f | |||
| 0e5edbcd84 | |||
| 68fc361d96 | |||
| 06b4fcb066 | |||
| 85d5d86c84 | |||
| 78f4d7d592 | |||
| 92bc7b13cb | |||
| e518146bd6 | |||
| e9eb7db620 | |||
| 1068070037 | |||
| 3d302619c5 | |||
| 48febb7eff | |||
| feaa13a809 | |||
| 76cbb79c75 | |||
| 6aabbd4a55 | |||
| 48676a733f | |||
| f8c45b2a99 | |||
| 1ec14118fe | |||
| 381f711103 | |||
| b748c0a573 | |||
| c4e8a409de | |||
| 28863f90b9 | |||
| 4f60c7d48c | |||
| f70b37137d | |||
| 49d491704e | |||
| a3f17cd4e7 | |||
| b96cf38e17 | |||
| 5a994ebe28 | |||
| ffc008228d | |||
| 77ba3f5a80 | |||
| 04d4095ffe | |||
| 569fa49796 | |||
| 7abe2df066 | |||
| 9b64c6f4b9 | |||
| 771f78a671 | |||
| 3d6b330366 | |||
| 37d4e9bcbd | |||
| 7390faa654 | |||
| b7d4eb62d5 | |||
| 40a60386c8 | |||
| 9bf9f82b3b | |||
| b37a684eb9 | |||
| c97cf661a2 | |||
| 53f625346f | |||
| 608c7d9841 | |||
| 955190b517 | |||
| 462425f61d | |||
| 0a0f44b674 | |||
| 9f9a0ea3dc |
+10
@@ -0,0 +1,10 @@
|
||||
# Dependency and build folders created by the build scripts
|
||||
/deps*/
|
||||
/build*/
|
||||
/install*/
|
||||
/win/BuildDepsCache*.txt
|
||||
# IfcExpressParser residue
|
||||
/src/ifcexpressparser/__pycache__
|
||||
/src/ifcexpressparser/express_parser.py
|
||||
# Python test residue
|
||||
/test/__pycache__
|
||||
@@ -1,65 +0,0 @@
|
||||
IfcOpenShell
|
||||
============
|
||||
open source (LGPL) software library for working with the IFC file format
|
||||
|
||||
|
||||
http://IfcOpenShell.org
|
||||
|
||||
|
||||
Compiling on Windows
|
||||
====================
|
||||
Users are advised to use the Visual Studio .sln file in the win/ folder.
|
||||
For Windows users a prebuilt Open CASCADE version is available from the
|
||||
http://opencascade.org website. Download and install this version and
|
||||
provide the paths to the Open CASCADE header and library files to MS
|
||||
Visual Studio C++.
|
||||
|
||||
For building the Autodesk 3ds Max plugin, the 3ds Max SDK needs to be
|
||||
installed as well as 3ds Max itself. Please provide the include and
|
||||
library paths to Visual Studio.
|
||||
|
||||
For building the IfcPython wrapper, SWIG needs to be installed. Please
|
||||
download the latest swigwin version from http://www.swig.org/download.html.
|
||||
After extracting the .zip file, please add the extracted folder to the PATH
|
||||
environment variable. Python needs to be installed, please provide the
|
||||
include and library paths to Visual Studio.
|
||||
|
||||
|
||||
|
||||
Compiling on *nix
|
||||
====================
|
||||
Users are advised to build IfcOpenShell using the cmake file provided in
|
||||
the cmake/ folder. There might be an Open CASCADE package in your operating
|
||||
system's software repository. If not, you will need to compile Open
|
||||
CASCADE yourself. See http://opencascade.org.
|
||||
|
||||
For building the IfcPython wrapper, SWIG and Python development are
|
||||
required.
|
||||
|
||||
To build IfcOpenShell please take the following steps:
|
||||
$ cd /path/to/IfcOpenShell/cmake
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
Optionally:
|
||||
$ OCC_INCLUDE_PATH="/path/to/OpenCASCADE/include"
|
||||
$ OCC_LIBRARY_PATH="/path/to/OpenCASCADE/lib"
|
||||
$ export OCC_INCLUDE_PATH
|
||||
$ export OCC_LIBRARY_PATH
|
||||
$ cmake ../
|
||||
$ make
|
||||
|
||||
If all worked out correctly you can now use IfcOpenShell. For example:
|
||||
$ wget ftp://ftp.dds.no/pub/ifc/Munkerud/Munkerud_hus6_BE.zip
|
||||
$ unzip Munkerud_hus6_BE.zip
|
||||
$ ./IfcObj Munkerud_hus6_BE.ifc
|
||||
$ less Munkerud_hus6_BE.obj
|
||||
Or:
|
||||
$ wget ftp://ftp.dds.no/pub/ifc/Munkerud/Munkerud_hus6_BE.zip
|
||||
$ unzip Munkerud_hus6_BE.zip
|
||||
$ python
|
||||
>>> import IfcImport
|
||||
>>> IfcImport.Init('Munkerud_hus6_BE.ifc')
|
||||
>>> geom = IfcImport.Get()
|
||||
>>> geom.name
|
||||
>>> for v in geom.mesh.verts: v
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
IfcOpenShell
|
||||
============
|
||||
Open source (LGPL) software library for working with the IFC ([IFC2x3 TC1] and [IFC4]) file format.
|
||||
|
||||
[http://ifcopenshell.org](http://ifcopenshell.org)
|
||||
[http://academy.ifcopenshell.org](http://academy.ifcopenshell.org)
|
||||
|
||||
|
||||
Prerequisites
|
||||
=============
|
||||
* Git, CMake (2.6 or newer), Visual Studio 2008 or newer with C++ toolset (Windows), or GCC (*nix, Clang untested).
|
||||
|
||||
|
||||
Dependencies
|
||||
============
|
||||
* [Boost](http://www.boost.org/)
|
||||
* Open Cascade - *optional*, but required for building IfcGeom
|
||||
([official](http://www.opencascade.org/getocc/download/loadocc/) or [community edition](https://github.com/tpaviot/oce))
|
||||
For converting IFC representation items into BRep solids and tesselated meshes
|
||||
* [ICU](http://site.icu-project.org/) - *optional*
|
||||
For handling code pages and Unicode in the parser
|
||||
* [OpenCOLLADA](https://github.com/khronosGroup/OpenCOLLADA/) - *optional*
|
||||
For IfcConvert to be able to write tessellated Collada (.dae) files
|
||||
* [SWIG](http://www.swig.org/), [Python](https://www.python.org/) libraries - *optional*
|
||||
For building the IfcOpenShell Python interface and the Blender add-on
|
||||
* 3ds Max SDK - *optional*
|
||||
For building the 3ds Max plug-in
|
||||
|
||||
|
||||
Compiling on Windows
|
||||
====================
|
||||
Users are advised to build IfcOpenShell using the CMake file provided in
|
||||
the cmake/ folder.
|
||||
|
||||
The preferred way to fetch and build this project's dependencies is to use the build scripts
|
||||
in win/ folder. **See [win/readme.md] for more information**. Instructions in a nutshell
|
||||
(**assuming Visual Studio 2015 x64 environment variables set**):
|
||||
|
||||
> git clone https://github.com/IfcOpenShell/IfcOpenShell.git
|
||||
> cd IfcOpenShell\win
|
||||
> build-deps.cmd
|
||||
> run-cmake.bat
|
||||
|
||||
You can now open and build the solution file in Visual Studio:
|
||||
|
||||
> ..\build-vs2015-x64\IfcOpenShell.sln
|
||||
|
||||
As the scripts default to using the `RelWithDebInfo` configuration, and a freshly created solution by CMake defaults
|
||||
to `Debug`, make sure to switch the used build configuration. Build the `INSTALL` project (right-click -> Project
|
||||
Only) to deploy the headers and binaries into a single location if wanted/needed.
|
||||
|
||||
Alternatively, one can use the utility batch files to build and install the project easily from the command-line:
|
||||
|
||||
> build-ifcopenshell.cmd
|
||||
> install-ifcopenshell.cmd
|
||||
|
||||
Alternatively, the old Visual Studio solution and project files requiring manual work can
|
||||
be found from the win/sln folder.
|
||||
|
||||
|
||||
Compiling on *nix
|
||||
=================
|
||||
Users are advised to build IfcOpenShell using the CMake file provided in
|
||||
the cmake/ folder. There might be an Open CASCADE package in your operating
|
||||
system's software repository. If not, you will need to compile Open
|
||||
CASCADE yourself. See http://opencascade.org.
|
||||
|
||||
For building the IfcPython wrapper, SWIG and Python development are
|
||||
required.
|
||||
|
||||
Additionally, on Ubuntu (and possibly other linux flavors) the following steps
|
||||
install some of the prerequisites:
|
||||
|
||||
$ sudo apt-get install git swig cmake gcc g++ libftgl-dev libtbb2 libtbb-dev libboost-all-dev libgl1-mesa-dev libfreetype6-dev
|
||||
$ git clone https://github.com/tpaviot/oce.git
|
||||
$ cd oce
|
||||
$ mkdir build && cd build
|
||||
$ cmake ..
|
||||
$ make
|
||||
$ sudo make install
|
||||
|
||||
To build IfcOpenShell please take the following steps:
|
||||
|
||||
$ cd /path/to/IfcOpenShell/cmake
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
Optionally:
|
||||
$ OCC_INCLUDE_PATH="/path/to/OpenCASCADE/include"
|
||||
$ OCC_LIBRARY_PATH="/path/to/OpenCASCADE/lib"
|
||||
$ export OCC_INCLUDE_PATH
|
||||
$ export OCC_LIBRARY_PATH
|
||||
$ cmake ../
|
||||
$ make
|
||||
|
||||
If all worked out correctly you can now use IfcOpenShell. See the examples below.
|
||||
|
||||
Usage examples
|
||||
==============
|
||||
|
||||
**Invoking IfcConvert from the command line**
|
||||
|
||||
$ wget ftp://ftp.dds.no/pub/ifc/Munkerud/Munkerud_hus6_BE.zip
|
||||
$ unzip Munkerud_hus6_BE.zip
|
||||
$ ./IfcConvert Munkerud_hus6_BE.ifc
|
||||
$ less Munkerud_hus6_BE.obj
|
||||
|
||||
**Using the IfcOpenShell Python interface**
|
||||
|
||||
$ wget -O duplex.zip http://projects.buildingsmartalliance.org/files/?artifact_id=4278
|
||||
$ unzip duplex.zip
|
||||
$ python
|
||||
>>> import ifcopenshell
|
||||
>>> f = ifcopenshell.open("Duplex_A_20110907_optimized.ifc")
|
||||
>>>
|
||||
>>> # Accessing entity instances by type:
|
||||
>>> f.by_type("ifcwall")[:2]
|
||||
[#91=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FL9r',#1,'Basic Wall:Interior - Partition (92mm Stud):144586',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5198,#18806,'144586'), #92=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FLIE',#1,'Basic Wall:Interior - Partition (92mm Stud):143921',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5206,#18805,'143921')]
|
||||
>>> wall = _[0]
|
||||
>>> len(wall) # number of EXPRESS attributes
|
||||
8
|
||||
>>>
|
||||
>>> # Accessing EXPRESS attributes by name:
|
||||
>>> wall.GlobalId
|
||||
'2O2Fr$t4X7Zf8NOew3FL9r'
|
||||
>>> wall.Name = "My wall"
|
||||
>>> wall.NonExistingAttr
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
File ".\ifcopenshell.py", line 14, in __getattr__
|
||||
except: raise AttributeError("entity instance of type '%s' has no attribute'%s'"%(self.wrapped_data.is_a(), name)) from None
|
||||
AttributeError: entity instance of type 'IfcWallStandardCase' has no attribute 'NonExistingAttr'
|
||||
>>> wall.GlobalId = 3
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
File ".\ifcopenshell.py", line 26, in __setattr__
|
||||
self[self.wrapped_data.get_argument_index(key)] = value
|
||||
File ".\ifcopenshell.py", line 30, in __setitem__
|
||||
self.wrapped_data.set_argument(idx, entity_instance.map_value(value))
|
||||
File ".\ifc_wrapper.py", line 118, in <lambda>
|
||||
set_argument = lambda self,x,y: self._set_argument(x) if y is None else self
|
||||
._set_argument(x,y)
|
||||
File ".\ifc_wrapper.py", line 114, in _set_argument
|
||||
def _set_argument(self, *args): return _ifc_wrapper.entity_instance__set_argument(self, *args)
|
||||
RuntimeError: INT is not a valid type for 'GlobalId'
|
||||
>>> # Creating new entity instances
|
||||
>>> f.createIfcCartesianPoint(Coordinates=(1.0,1.5,2.0))
|
||||
#27530=IfcCartesianPoint((1.,1.5,2.))
|
||||
>>>
|
||||
>>> # Working with GlobalId attributes:
|
||||
>>> import uuid
|
||||
>>> ifcopenshell.guid.compress(uuid.uuid1().hex)
|
||||
'3x4C8Q_6qHuv$P$FYkANRX'
|
||||
>>> new_guid = _
|
||||
>>> owner_hist = f.by_type("IfcOwnerHistory")[0]
|
||||
>>> new_wall = f.createIfcWallStandardCase(new_guid, owner_hist, None, None, Tag='my_tag')
|
||||
>>> new_wall.ObjectType = ''
|
||||
>>> new_wall.ObjectPlacement = new_wall.Representation = None
|
||||
>>>
|
||||
>>> # Accessing entity instances by instance id or GlobalId:
|
||||
>>> f[92]
|
||||
#92=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FLIE',#1,'Basic Wall:Interior - Partition (92mm Stud):143921',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5206,#18805,'143921')
|
||||
>>> f['2O2Fr$t4X7Zf8NOew3FLIE']
|
||||
#92=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FLIE',#1,'Basic Wall:Interior - Partition (92mm Stud):143921',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5206,#18805,'143921')
|
||||
>>>
|
||||
>>> # Writing IFC-SPF files to disk:
|
||||
>>> f.write("out.ifc")
|
||||
|
||||
[win/readme.md]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/win/readme.md "win/readme.md"
|
||||
[IFC2x3 TC1]: http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc2x3-tc1-release "IFC2x3 TC1"
|
||||
[IFC4]: http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc4-release "IFC4"
|
||||
+406
-178
@@ -1,17 +1,90 @@
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 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 #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
cmake_minimum_required (VERSION 2.8.5)
|
||||
|
||||
project (IfcOpenShell)
|
||||
|
||||
OPTION(UNICODE_SUPPORT "Build IfcOpenShell with Unicode support (requires ICU)." ON)
|
||||
OPTION(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON)
|
||||
OPTION(HDF5_SUPPORT "Enable HDF5 support (requires HDF5, zlib)" ON)
|
||||
OPTION(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF)
|
||||
#TODO OPTION(IFCCONVERT_DOUBLE_PRECISION "IfcConvert: Use double precision floating-point numbers." OFF)
|
||||
OPTION(USE_IFC4 "Use IFC 4 instead of IFC 2x3 (full rebuild recommended when switching this)" OFF)
|
||||
OPTION(BUILD_IFCPYTHON "Build IfcPython." ON)
|
||||
OPTION(BUILD_EXAMPLES "Build example applications." ON)
|
||||
OPTION(USE_VLD "Use Visual Leak Detector for debugging memory leaks, MSVC-only." OFF)
|
||||
# TODO QtViewer is deprecated ATM as it uses the 0.4 API
|
||||
# OPTION(BUILD_QTVIEWER "Build IfcOpenShell Qt GUI Viewer (requires Qt 4 framework)." OFF)
|
||||
|
||||
|
||||
# Create cache entries if absent for environment variables
|
||||
MACRO(UNIFY_ENVVARS_AND_CACHE VAR)
|
||||
IF ((NOT DEFINED ${VAR}) AND (NOT "$ENV{${VAR}}" STREQUAL ""))
|
||||
SET(${VAR} "$ENV{${VAR}}" CACHE STRING "${VAR}" FORCE)
|
||||
ENDIF()
|
||||
ENDMACRO()
|
||||
|
||||
UNIFY_ENVVARS_AND_CACHE(OCC_INCLUDE_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(OCC_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(ICU_INCLUDE_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(ICU_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_INCLUDE_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(HDF5_INCLUDE_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(HDF5_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(PCRE_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE)
|
||||
|
||||
# Find Boost
|
||||
IF(MSVC)
|
||||
SET(Boost_USE_STATIC_LIBS ON)
|
||||
SET(Boost_USE_STATIC_RUNTIME ON)
|
||||
SET(Boost_USE_MULTITHREADED ON)
|
||||
ENDIF()
|
||||
FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options)
|
||||
MESSAGE(STATUS "Boost include files found in ${Boost_INCLUDE_DIRS}")
|
||||
MESSAGE(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}")
|
||||
|
||||
# Find Open CASCADE header files
|
||||
IF("$ENV{OCC_INCLUDE_DIR}" STREQUAL "")
|
||||
# Usage:
|
||||
# SET(SOME_LIRARIES foo bar)
|
||||
# ADD_DEBUG_VARIANTS(SOME_LIRARIES "${SOME_LIRARIES}" "d")
|
||||
# "foo bar" -> "optimized foo debug food optimized bar debug bard"
|
||||
FUNCTION(ADD_DEBUG_VARIANTS NAME LIBRARIES POSTFIX)
|
||||
SET(LIBRARIES_STR "${LIBRARIES}")
|
||||
SET(LIBRARIES "")
|
||||
FOREACH(lib ${LIBRARIES_STR})
|
||||
SET(LIBRARIES "${LIBRARIES} optimized ${lib}")
|
||||
SET(LIBRARIES "${LIBRARIES} debug ${lib}${POSTFIX}")
|
||||
ENDFOREACH()
|
||||
STRING(STRIP ${LIBRARIES} LIBRARIES) # leading and trailing whitespace cause confusion
|
||||
SEPARATE_ARGUMENTS(LIBRARIES) # "optimized <lib> debug <lib>" needs to be a list instead of a string
|
||||
SET(${NAME} ${LIBRARIES} PARENT_SCOPE)
|
||||
ENDFUNCTION()
|
||||
|
||||
# Find Open CASCADE
|
||||
IF("${OCC_INCLUDE_DIR}" STREQUAL "")
|
||||
SET(OCC_INCLUDE_DIR "/usr/include/opencascade/" CACHE FILEPATH "Open CASCADE header files")
|
||||
MESSAGE(STATUS "Looking for opencascade include files in: ${OCC_INCLUDE_DIR}")
|
||||
MESSAGE(STATUS "Use OCC_INCLUDE_DIR to specify another directory")
|
||||
ELSE()
|
||||
SET(OCC_INCLUDE_DIR $ENV{OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files")
|
||||
SET(OCC_INCLUDE_DIR ${OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files")
|
||||
MESSAGE(STATUS "Looking for opencascade include files in: ${OCC_INCLUDE_DIR}")
|
||||
ENDIF()
|
||||
|
||||
@@ -22,214 +95,369 @@ ELSE()
|
||||
MESSAGE(FATAL_ERROR "Unable to find header files, aborting")
|
||||
ENDIF()
|
||||
|
||||
# Find Open CASCADE library files
|
||||
IF("$ENV{OCC_LIBRARY_DIR}" STREQUAL "")
|
||||
SET(OPENCASCADE_LIBRARIES
|
||||
TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO
|
||||
TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset
|
||||
)
|
||||
|
||||
IF(MSVC)
|
||||
ADD_DEBUG_VARIANTS(OPENCASCADE_LIBRARIES "${OPENCASCADE_LIBRARIES}" "d")
|
||||
ENDIF()
|
||||
|
||||
IF("${OCC_LIBRARY_DIR}" STREQUAL "")
|
||||
SET(OCC_LIBRARY_DIR "/usr/lib/" CACHE FILEPATH "Open CASCADE library files")
|
||||
MESSAGE(STATUS "Looking for opencascade library files in: ${OCC_LIBRARY_DIR}")
|
||||
MESSAGE(STATUS "Use OCC_LIBRARY_DIR to specify another directory")
|
||||
ELSE()
|
||||
SET(OCC_LIBRARY_DIR $ENV{OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files")
|
||||
SET(OCC_LIBRARY_DIR ${OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files")
|
||||
MESSAGE(STATUS "Looking for opencascade library files in: ${OCC_LIBRARY_DIR}")
|
||||
ENDIF()
|
||||
|
||||
FIND_LIBRARY(libTKernel "TKernel" ${OCC_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64)
|
||||
FIND_LIBRARY(libTKernel NAMES TKernel TKerneld PATHS ${OCC_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64)
|
||||
IF(libTKernel)
|
||||
MESSAGE(STATUS "Library files found")
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "Unable to find library files, aborting")
|
||||
ENDIF()
|
||||
|
||||
IF("$ENV{ICU_INCLUDE_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No ICU include directory specified")
|
||||
ElSE()
|
||||
SET(ICU_INCLUDE_DIR CACHE FILEPATH "ICU header files")
|
||||
IF(UNICODE_SUPPORT)
|
||||
# Find ICU
|
||||
IF("${ICU_INCLUDE_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No ICU include directory specified")
|
||||
ElSE()
|
||||
SET(ICU_INCLUDE_DIR "${ICU_INCLUDE_DIR}" CACHE FILEPATH "ICU header files")
|
||||
ENDIF()
|
||||
|
||||
IF("${ICU_LIBRARY_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No ICU library directory specified")
|
||||
ElSE()
|
||||
SET(ICU_LIBRARY_DIR "${ICU_LIBRARY_DIR}" CACHE FILEPATH "ICU library files")
|
||||
ENDIF()
|
||||
|
||||
FIND_LIBRARY(icu NAMES icuuc icuucd PATHS /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR})
|
||||
|
||||
IF(icu)
|
||||
ADD_DEFINITIONS(-DHAVE_ICU)
|
||||
MESSAGE(STATUS "ICU libraries found")
|
||||
# NOTE icudata appears to be icudt on Windows/MSVC and icudata on others
|
||||
# dl is included to resolve dlopen and friends symbols
|
||||
IF(MSVC)
|
||||
SET(ICU_LIBRARIES icuuc icudt)
|
||||
ADD_DEBUG_VARIANTS(ICU_LIBRARIES "${ICU_LIBRARIES}" "d")
|
||||
ADD_DEFINITIONS(-DU_STATIC_IMPLEMENTATION) # required for static ICU
|
||||
ELSE()
|
||||
SET(ICU_LIBRARIES icuuc icudata dl)
|
||||
ENDIF()
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "UNICODE_SUPPORT enabled, but unable to find ICU. Disable UNICODE_SUPPORT or fix ICU paths to proceed.")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF("$ENV{ICU_LIBRARY_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No ICU library directory specified")
|
||||
ElSE()
|
||||
SET(ICU_LIBRARY_DIR CACHE FILEPATH "ICU library files")
|
||||
IF(COLLADA_SUPPORT)
|
||||
# Find OpenCOLLADA
|
||||
IF("${OPENCOLLADA_INCLUDE_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No OpenCOLLADA include directory specified")
|
||||
SET(OPENCOLLADA_INCLUDE_DIR "/usr/local/include/opencollada" CACHE FILEPATH "OpenCOLLADA header files")
|
||||
ElSE()
|
||||
SET(OPENCOLLADA_INCLUDE_DIR "${OPENCOLLADA_INCLUDE_DIR}" CACHE FILEPATH "OpenCOLLADA header files")
|
||||
ENDIF()
|
||||
|
||||
IF("${OPENCOLLADA_LIBRARY_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No OpenCOLLADA library directory specified")
|
||||
SET(OPENCOLLADA_LIBRARY_DIR "/usr/local/lib/opencollada" CACHE FILEPATH "OpenCOLLADA library files")
|
||||
ElSE()
|
||||
SET(OPENCOLLADA_LIBRARY_DIR "${OPENCOLLADA_LIBRARY_DIR}" CACHE FILEPATH "OpenCOLLADA library files")
|
||||
ENDIF()
|
||||
|
||||
SET(OPENCOLLADA_INCLUDE_DIRS "${OPENCOLLADA_INCLUDE_DIR}/COLLADABaseUtils" "${OPENCOLLADA_INCLUDE_DIR}/COLLADAStreamWriter")
|
||||
|
||||
FIND_FILE(COLLADASWStreamWriter_h "COLLADASWStreamWriter.h" ${OPENCOLLADA_INCLUDE_DIRS})
|
||||
IF(COLLADASWStreamWriter_h)
|
||||
MESSAGE(STATUS "OpenCOLLADA header files found")
|
||||
ADD_DEFINITIONS(-DWITH_OPENCOLLADA)
|
||||
SET(OPENCOLLADA_LIBRARIES
|
||||
GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader
|
||||
OpenCOLLADAStreamWriter UTF buffer ftoa pcre
|
||||
)
|
||||
IF(NOT "${PCRE_LIBRARY_DIR}" STREQUAL "")
|
||||
SET(OPENCOLLADA_LIBRARY_DIR ${OPENCOLLADA_LIBRARY_DIR} ${PCRE_LIBRARY_DIR})
|
||||
ENDIF()
|
||||
IF(MSVC)
|
||||
ADD_DEBUG_VARIANTS(OPENCOLLADA_LIBRARIES "${OPENCOLLADA_LIBRARIES}" "d")
|
||||
ENDIF()
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find OpenCOLLADA. Disable COLLADA_SUPPORT or fix OpenCOLLADA paths to proceed.")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
FIND_LIBRARY(icu "icuuc" /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR})
|
||||
if(HDF5_SUPPORT)
|
||||
IF("${HDF5_INCLUDE_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No HDF5 include directory specified")
|
||||
ElSE()
|
||||
SET(HDF5_INCLUDE_DIR "${HDF5_INCLUDE_DIR}" CACHE FILEPATH "HDF5 header files")
|
||||
ENDIF()
|
||||
|
||||
IF("${HDF5_LIBRARY_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No HDF5 library directory specified")
|
||||
ElSE()
|
||||
SET(HDF5_LIBRARY_DIR "${HDF5_LIBRARY_DIR}" CACHE FILEPATH "HDF5 library files")
|
||||
ENDIF()
|
||||
|
||||
IF(WIN32)
|
||||
# An additional lib- prefix is added by HDF5 to denote static libraries
|
||||
SET(HDF5_LIBRARIES libhdf5_cpp libhdf5 libzlib)
|
||||
ELSE()
|
||||
SET(HDF5_LIBRARIES hdf5_cpp hdf5 z szip)
|
||||
ENDIF()
|
||||
endif()
|
||||
|
||||
IF(icu)
|
||||
MESSAGE(STATUS "ICU libraries found")
|
||||
ADD_DEFINITIONS(-DHAVE_ICU)
|
||||
ELSE()
|
||||
MESSAGE(STATUS "Unable to find ICU library files, continuing")
|
||||
# TODO Are these needed on other platforms still or can these be removed for good?
|
||||
IF (NOT WIN32)
|
||||
INCLUDE(CheckIncludeFileCXX)
|
||||
|
||||
MACRO(CHECK_ADD_OCE_OCC_DEF INCLUDE)
|
||||
STRING(REPLACE . _ STR ${INCLUDE})
|
||||
STRING(TOUPPER ${STR} STR)
|
||||
CHECK_INCLUDE_FILE_CXX("${INCLUDE}" FOUND_${STR})
|
||||
IF(FOUND_${STR})
|
||||
ADD_DEFINITIONS(-DOCE_HAVE_${STR})
|
||||
ADD_DEFINITIONS(-DHAVE_${STR})
|
||||
ENDIF(FOUND_${STR})
|
||||
ENDMACRO()
|
||||
|
||||
CHECK_ADD_OCE_OCC_DEF(limits)
|
||||
CHECK_ADD_OCE_OCC_DEF(climits)
|
||||
CHECK_ADD_OCE_OCC_DEF(limits.h)
|
||||
CHECK_ADD_OCE_OCC_DEF(fstream)
|
||||
CHECK_ADD_OCE_OCC_DEF(fstream.h)
|
||||
CHECK_ADD_OCE_OCC_DEF(iomanip)
|
||||
CHECK_ADD_OCE_OCC_DEF(iomanip.h)
|
||||
CHECK_ADD_OCE_OCC_DEF(iostream)
|
||||
CHECK_ADD_OCE_OCC_DEF(iostream.h)
|
||||
ENDIF()
|
||||
|
||||
IF("$ENV{OPENCOLLADA_INCLUDE_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No OpenCOLLADA include directory specified")
|
||||
SET(OPENCOLLADA_INCLUDE_DIR "/usr/local/include/opencollada" CACHE FILEPATH "OpenCOLLADA header files")
|
||||
ElSE()
|
||||
SET(OPENCOLLADA_INCLUDE_DIR "$ENV{OPENCOLLADA_INCLUDE_DIR}" CACHE FILEPATH "OpenCOLLADA header files")
|
||||
ENDIF()
|
||||
|
||||
IF("$ENV{OPENCOLLADA_LIBRARY_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No OpenCOLLADA library directory specified")
|
||||
SET(OPENCOLLADA_LIBRARY_DIR "/usr/local/lib/opencollada" CACHE FILEPATH "OpenCOLLADA library files")
|
||||
ElSE()
|
||||
SET(OPENCOLLADA_LIBRARY_DIR "$ENV{OPENCOLLADA_LIBRARY_DIR}" CACHE FILEPATH "OpenCOLLADA library files")
|
||||
ENDIF()
|
||||
|
||||
SET(OPENCOLLADA_INCLUDE_DIRS "${OPENCOLLADA_INCLUDE_DIR}/COLLADABaseUtils" "${OPENCOLLADA_INCLUDE_DIR}/COLLADAStreamWriter")
|
||||
|
||||
FIND_FILE(COLLADASWStreamWriter_h "COLLADASWStreamWriter.h" ${OPENCOLLADA_INCLUDE_DIRS})
|
||||
IF(COLLADASWStreamWriter_h)
|
||||
MESSAGE(STATUS "OpenCOLLADA header files found")
|
||||
ADD_DEFINITIONS(-DWITH_OPENCOLLADA)
|
||||
SET(OPENCOLLADA_LIBRARIES
|
||||
GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils
|
||||
OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader
|
||||
OpenCOLLADAStreamWriter UTF buffer ftoa pcre
|
||||
)
|
||||
ELSE()
|
||||
MESSAGE(STATUS "OpenCOLLADA header files not found, continuing without COLLADA support")
|
||||
ENDIF()
|
||||
|
||||
INCLUDE(CheckIncludeFileCXX)
|
||||
|
||||
MACRO(CHECK_ADD_OCE_OCC_DEF INCLUDE)
|
||||
STRING(REPLACE . _ STR ${INCLUDE})
|
||||
STRING(TOUPPER ${STR} STR)
|
||||
CHECK_INCLUDE_FILE_CXX("${INCLUDE}" FOUND_${STR})
|
||||
IF(FOUND_${STR})
|
||||
ADD_DEFINITIONS(-DOCE_HAVE_${STR})
|
||||
ADD_DEFINITIONS(-DHAVE_${STR})
|
||||
ENDIF(FOUND_${STR})
|
||||
ENDMACRO(CHECK_ADD_OCE_OCC_DEF)
|
||||
|
||||
CHECK_ADD_OCE_OCC_DEF(limits)
|
||||
CHECK_ADD_OCE_OCC_DEF(climits)
|
||||
CHECK_ADD_OCE_OCC_DEF(limits.h)
|
||||
CHECK_ADD_OCE_OCC_DEF(fstream)
|
||||
CHECK_ADD_OCE_OCC_DEF(fstream.h)
|
||||
CHECK_ADD_OCE_OCC_DEF(iomanip)
|
||||
CHECK_ADD_OCE_OCC_DEF(iomanip.h)
|
||||
CHECK_ADD_OCE_OCC_DEF(iostream)
|
||||
CHECK_ADD_OCE_OCC_DEF(iostream.h)
|
||||
|
||||
IF(NOT CMAKE_BUILD_TYPE)
|
||||
SET(CMAKE_BUILD_TYPE "Release")
|
||||
ENDIF(NOT CMAKE_BUILD_TYPE)
|
||||
SET(CMAKE_BUILD_TYPE "Release")
|
||||
ENDIF()
|
||||
|
||||
# NOTE: RelWithDebInfo and Release use O2 (= /Ox /Gl /Gy/ = Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy) by default,
|
||||
# with the exception with RelWithDebInfo has /Ob1 instead. /Ob2 has been observed to improve the performance
|
||||
# of IfcConvert significantly.
|
||||
# TODO Setting of /GL and /LTCG don't seem to apply for static libraries (IfcGeom, IfcParse)
|
||||
if(ENABLE_BUILD_OPTIMIZATIONS)
|
||||
if(MSVC)
|
||||
# C++
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /GL")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
|
||||
# Linker
|
||||
# /OPT:REF enables also /OPT:ICF and disables INCREMENTAL
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
|
||||
# /OPT:NOICF is recommended when /DEBUG is used (http://msdn.microsoft.com/en-us/library/xe4t6fc1.aspx)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
|
||||
else()
|
||||
#TODO GCC (& Clang?) optimizations
|
||||
message(STATUS "ENABLE_BUILD_OPTIMIZATIONS not implemented for GCC/non-MSVC compilers.)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
IF(MSVC)
|
||||
ADD_DEFINITIONS(-D_UNICODE)
|
||||
ElSE(MSVC)
|
||||
ADD_DEFINITIONS(-fPIC -Wno-non-virtual-dtor)
|
||||
ENDIF(MSVC)
|
||||
|
||||
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} /usr/inc /usr/local/inc /usr/local/include/oce ${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS})
|
||||
|
||||
ADD_LIBRARY(IfcParse STATIC
|
||||
../src/ifcparse/Ifc2x3-latebound.cpp
|
||||
../src/ifcparse/Ifc2x3.cpp
|
||||
../src/ifcparse/Ifc4-latebound.cpp
|
||||
../src/ifcparse/Ifc4.cpp
|
||||
../src/ifcparse/IfcCharacterDecoder.cpp
|
||||
../src/ifcparse/IfcGuidHelper.cpp
|
||||
../src/ifcparse/IfcHierarchyHelper.cpp
|
||||
../src/ifcparse/IfcLateBoundEntity.cpp
|
||||
../src/ifcparse/IfcParse.cpp
|
||||
../src/ifcparse/IfcSIPrefix.cpp
|
||||
../src/ifcparse/IfcSpfHeader.cpp
|
||||
../src/ifcparse/IfcUtil.cpp
|
||||
../src/ifcparse/IfcWrite.cpp
|
||||
)
|
||||
|
||||
ADD_LIBRARY(IfcGeom STATIC
|
||||
../src/ifcgeom/IfcGeomCurves.cpp
|
||||
../src/ifcgeom/IfcGeomFaces.cpp
|
||||
../src/ifcgeom/IfcGeomFunctions.cpp
|
||||
../src/ifcgeom/IfcGeomHelpers.cpp
|
||||
../src/ifcgeom/IfcGeomMaterial.cpp
|
||||
../src/ifcgeom/IfcGeomRenderStyles.cpp
|
||||
../src/ifcgeom/IfcGeomRepresentation.cpp
|
||||
../src/ifcgeom/IfcGeomShapes.cpp
|
||||
../src/ifcgeom/IfcGeomWires.cpp
|
||||
../src/ifcgeom/IfcRegister.cpp
|
||||
)
|
||||
|
||||
IF(icu)
|
||||
TARGET_LINK_LIBRARIES(IfcParse icuuc)
|
||||
IF(USE_VLD)
|
||||
ADD_DEFINITIONS(-DUSE_VLD)
|
||||
ENDIF()
|
||||
# Enforce Unicode for CRT and Win32 API calls
|
||||
ADD_DEFINITIONS(-D_UNICODE -DUNICODE)
|
||||
# Disable warnings about unsafe C functions; we could use the safe C99 & C11 versions if we have no need for supporting old compilers.
|
||||
ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS)
|
||||
ADD_DEFINITIONS(-bigobj) # required for building the big ifcXXX.objs, https://msdn.microsoft.com/en-us/library/ms173499.aspx
|
||||
# Bump up the warning level from the default 3 to 4.
|
||||
ADD_DEFINITIONS(-W4)
|
||||
IF(MSVC_VERSION GREATER 1800) # > 2013
|
||||
# Disable overeager and false positives causing C4458 ("declaration of 'indentifier' hides class member"), at least for now.
|
||||
ADD_DEFINITIONS(-wd4458)
|
||||
ENDIF()
|
||||
# Link against the static VC runtime
|
||||
FOREACH(flag CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL
|
||||
CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
|
||||
IF(${flag} MATCHES "/MD")
|
||||
STRING(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}")
|
||||
ENDIF()
|
||||
IF(${flag} MATCHES "/MDd")
|
||||
STRING(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}")
|
||||
ENDIF()
|
||||
ENDFOREACH()
|
||||
ElSE()
|
||||
ADD_DEFINITIONS(-fPIC -Wno-non-virtual-dtor)
|
||||
ENDIF()
|
||||
|
||||
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS}
|
||||
${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${HDF5_INCLUDE_DIR}
|
||||
)
|
||||
if(NOT WIN32)
|
||||
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} /usr/inc /usr/local/inc /usr/local/include/oce)
|
||||
endif()
|
||||
|
||||
function(files_for_ifc_version IFC_VERSION RESULT_NAME)
|
||||
set(IFC_PARSE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcparse)
|
||||
set(${RESULT_NAME}
|
||||
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.h
|
||||
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}enum.h
|
||||
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}-latebound.h
|
||||
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.cpp
|
||||
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}-latebound.cpp
|
||||
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}-schema.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endfunction()
|
||||
|
||||
if(COMPILE_SCHEMA)
|
||||
find_package(PythonInterp)
|
||||
|
||||
IF(NOT PYTHONINTERP_FOUND)
|
||||
MESSAGE(FATAL_ERROR "A Python interpreter is necessary when COMPILE_SCHEMA is enabled. Disable COMPILE_SCHEMA or fix Python paths to proceed.")
|
||||
ENDIF()
|
||||
|
||||
set(IFC_RELEASE_NOT_USED "2x3" "4")
|
||||
|
||||
# Install pyparsing if necessary
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST)
|
||||
if ("${PYTHON_PACKAGE_LIST}" STREQUAL "")
|
||||
execute_process(COMMAND pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST)
|
||||
if ("${PYTHON_PACKAGE_LIST}" STREQUAL "")
|
||||
message(WARNING "Failed to find pip. Pip is required to automatically install pyparsing")
|
||||
endif()
|
||||
endif()
|
||||
string(FIND "${PYTHON_PACKAGE_LIST}" pyparsing PYPARSING_FOUND)
|
||||
if ("${PYPARSING_FOUND}" STREQUAL "-1")
|
||||
message(STATUS "Installing pyparsing")
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip "install" --user pyparsing RESULT_VARIABLE SUCCESS)
|
||||
if (NOT "${SUCCESS}" STREQUAL "0")
|
||||
execute_process(COMMAND pip "install" --user pyparsing RESULT_VARIABLE SUCCESS)
|
||||
if (NOT "${SUCCESS}" STREQUAL "0")
|
||||
message(WARNING "Failed to automatically install pyparsing. Please install manually")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Python interpreter with pyparsing found")
|
||||
endif()
|
||||
|
||||
# Bootstrap the parser
|
||||
message(STATUS "Compiling schema, this will take a while...")
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} bootstrap.py express.bnf
|
||||
WORKING_DIRECTORY ../src/ifcexpressparser
|
||||
OUTPUT_FILE express_parser.py
|
||||
RESULT_VARIABLE SUCCESS)
|
||||
|
||||
if (NOT "${SUCCESS}" STREQUAL "0")
|
||||
MESSAGE(FATAL_ERROR "Failed to bootstrap parser. Make sure pyparsing is installed")
|
||||
endif()
|
||||
|
||||
# Generate code
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} ../ifcexpressparser/express_parser.py ../../${COMPILE_SCHEMA}
|
||||
WORKING_DIRECTORY ../src/ifcparse
|
||||
OUTPUT_VARIABLE COMPILED_SCHEMA_NAME)
|
||||
|
||||
# Prevent the schema that had just been compiled from being excluded
|
||||
if("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC2X3")
|
||||
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "2x3")
|
||||
add_definitions(-DUSE_IFC2x3)
|
||||
elseif("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC4")
|
||||
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "4")
|
||||
add_definitions(-DUSE_IFC4)
|
||||
endif()
|
||||
else()
|
||||
if(USE_IFC4)
|
||||
add_definitions(-DUSE_IFC4)
|
||||
set(IFC_RELEASE_NOT_USED "2x3")
|
||||
else()
|
||||
add_definitions(-DUSE_IFC2x3) # TODO Make all caps? i.e. USE_IFC2X3
|
||||
set(IFC_RELEASE_NOT_USED "4")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# IfcParse
|
||||
file(GLOB IFCPARSE_H_FILES ../src/ifcparse/*.h)
|
||||
file(GLOB IFCPARSE_CPP_FILES ../src/ifcparse/*.cpp)
|
||||
|
||||
foreach(IFC_RELEASE ${IFC_RELEASE_NOT_USED})
|
||||
files_for_ifc_version(${IFC_RELEASE} SOURCE_FILES_NOT_USED)
|
||||
foreach(SOURCE_FILE ${SOURCE_FILES_NOT_USED})
|
||||
list(REMOVE_ITEM IFCPARSE_CPP_FILES ${SOURCE_FILE})
|
||||
list(REMOVE_ITEM IFCPARSE_H_FILES ${SOURCE_FILE})
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
set(IFCPARSE_FILES ${IFCPARSE_CPP_FILES} ${IFCPARSE_H_FILES})
|
||||
|
||||
ADD_LIBRARY(IfcParse STATIC ${IFCPARSE_FILES})
|
||||
|
||||
IF(UNICODE_SUPPORT)
|
||||
TARGET_LINK_LIBRARIES(IfcParse ${ICU_LIBRARIES})
|
||||
ENDIF()
|
||||
|
||||
if(HDF5_SUPPORT)
|
||||
TARGET_LINK_LIBRARIES(IfcParse ${HDF5_LIBRARIES})
|
||||
endif()
|
||||
|
||||
# IfcGeom
|
||||
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/*.h)
|
||||
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp)
|
||||
|
||||
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES})
|
||||
ADD_LIBRARY(IfcGeom STATIC ${IFCGEOM_FILES})
|
||||
|
||||
TARGET_LINK_LIBRARIES(IfcGeom IfcParse)
|
||||
|
||||
LINK_DIRECTORIES (${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} ${OPENCOLLADA_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS})
|
||||
|
||||
ADD_EXECUTABLE(IfcConvert
|
||||
../src/ifcconvert/ColladaSerializer.cpp
|
||||
../src/ifcconvert/IfcConvert.cpp
|
||||
../src/ifcconvert/OpenCascadeBasedSerializer.cpp
|
||||
../src/ifcconvert/WavefrontObjSerializer.cpp
|
||||
../src/ifcconvert/XmlSerializer.cpp
|
||||
LINK_DIRECTORIES(${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} ${OPENCOLLADA_LIBRARY_DIR}
|
||||
${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS} ${HDF5_LIBRARY_DIR}
|
||||
)
|
||||
if(NOT WIN32)
|
||||
LINK_DIRECTORIES(${LINK_DIRECTORIES} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64)
|
||||
endif()
|
||||
|
||||
TARGET_LINK_LIBRARIES (IfcConvert IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES})
|
||||
file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp)
|
||||
file(GLOB IFCCONVERT_H_FILES ../src/ifcconvert/*.h)
|
||||
set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES})
|
||||
ADD_EXECUTABLE(IfcConvert ${IFCCONVERT_FILES})
|
||||
|
||||
ADD_EXECUTABLE(IfcGeomServer
|
||||
../src/ifcgeomserver/IfcGeomServer.cpp
|
||||
)
|
||||
# Make sure cross-referenced symbols between static OCC libraries get
|
||||
# resolved. Also add thread and rt libraries.
|
||||
get_filename_component(libTKernelExt ${libTKernel} EXT)
|
||||
if("${libTKernelExt}" STREQUAL ".a")
|
||||
find_package(Threads)
|
||||
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} rt dl)
|
||||
endif()
|
||||
|
||||
TARGET_LINK_LIBRARIES (IfcGeomServer IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset)
|
||||
TARGET_LINK_LIBRARIES(IfcConvert IfcParse IfcGeom ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${ICU_LIBRARIES})
|
||||
|
||||
# Build python wrapper using separate CMakeLists.txt
|
||||
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
|
||||
# IfcGeomServer
|
||||
file(GLOB CPP_FILES ../src/ifcgeomserver/*.cpp)
|
||||
file(GLOB H_FILES ../src/ifcgeomserver/*.h)
|
||||
set(SOURCE_FILES ${CPP_FILES} ${H_FILES})
|
||||
ADD_EXECUTABLE(IfcGeomServer ${SOURCE_FILES})
|
||||
|
||||
# Build IfcParseExamples using separate CMakeLists.txt
|
||||
ADD_SUBDIRECTORY(../src/examples examples)
|
||||
TARGET_LINK_LIBRARIES(IfcGeomServer IfcParse IfcGeom ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBRARIES})
|
||||
|
||||
# ADD_SUBDIRECTORY(../src/qtviewer qtviewer)
|
||||
IF(BUILD_IFCPYTHON)
|
||||
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
|
||||
ENDIF()
|
||||
|
||||
IF(BUILD_EXAMPLES)
|
||||
ADD_SUBDIRECTORY(../src/examples examples)
|
||||
ENDIF()
|
||||
|
||||
IF(HDF5_SUPPORT)
|
||||
ADD_SUBDIRECTORY(../src/hdf5_usecases hdf5_usecases)
|
||||
ENDIF()
|
||||
|
||||
if(NOT MSVC)
|
||||
add_definitions(-std=c++14)
|
||||
endif()
|
||||
|
||||
# CMake installation targets
|
||||
SET(include_files_geom
|
||||
../src/ifcgeom/IfcGeom.h
|
||||
../src/ifcgeom/IfcGeomElement.h
|
||||
../src/ifcgeom/IfcGeomIterator.h
|
||||
../src/ifcgeom/IfcGeomIteratorSettings.h
|
||||
../src/ifcgeom/IfcGeomMaterial.h
|
||||
../src/ifcgeom/IfcGeomRenderStyles.h
|
||||
../src/ifcgeom/IfcGeomRepresentation.h
|
||||
../src/ifcgeom/IfcRegister.h
|
||||
../src/ifcgeom/IfcRegisterConvertCurve.h
|
||||
../src/ifcgeom/IfcRegisterConvertFace.h
|
||||
../src/ifcgeom/IfcRegisterConvertShape.h
|
||||
../src/ifcgeom/IfcRegisterConvertShapes.h
|
||||
../src/ifcgeom/IfcRegisterConvertWire.h
|
||||
../src/ifcgeom/IfcRegisterCreateCache.h
|
||||
../src/ifcgeom/IfcRegisterDef.h
|
||||
../src/ifcgeom/IfcRegisterGeomHeader.h
|
||||
../src/ifcgeom/IfcRegisterIsShapeCollection.h
|
||||
../src/ifcgeom/IfcRegisterPurgeCache.h
|
||||
../src/ifcgeom/IfcRegisterUndef.h
|
||||
../src/ifcgeom/IfcRepresentationShapeItem.h
|
||||
)
|
||||
SET(include_files_parse
|
||||
../src/ifcparse/Ifc2x3-latebound.h
|
||||
../src/ifcparse/Ifc2x3.h
|
||||
../src/ifcparse/Ifc2x3enum.h
|
||||
../src/ifcparse/Ifc4-latebound.h
|
||||
../src/ifcparse/Ifc4.h
|
||||
../src/ifcparse/Ifc4enum.h
|
||||
../src/ifcparse/IfcCharacterDecoder.h
|
||||
../src/ifcparse/IfcEntityDescriptor.h
|
||||
../src/ifcparse/IfcException.h
|
||||
../src/ifcparse/IfcFile.h
|
||||
../src/ifcparse/IfcHierarchyHelper.h
|
||||
../src/ifcparse/IfcLateBoundEntity.h
|
||||
../src/ifcparse/IfcParse.h
|
||||
../src/ifcparse/IfcSIPrefix.h
|
||||
../src/ifcparse/IfcSpfHeader.h
|
||||
../src/ifcparse/IfcSpfStream.h
|
||||
../src/ifcparse/IfcUtil.h
|
||||
../src/ifcparse/IfcWritableEntity.h
|
||||
../src/ifcparse/IfcWrite.h
|
||||
../src/ifcparse/SharedPointer.h
|
||||
)
|
||||
INSTALL(FILES ${include_files_geom} DESTINATION include/ifcgeom)
|
||||
INSTALL(FILES ${include_files_parse} DESTINATION include/ifcparse)
|
||||
INSTALL(TARGETS IfcConvert DESTINATION bin)
|
||||
INSTALL(FILES ${IFCPARSE_H_FILES} DESTINATION include/ifcparse)
|
||||
INSTALL(FILES ${IFCGEOM_H_FILES} DESTINATION include/ifcgeom)
|
||||
INSTALL(TARGETS IfcConvert IfcGeomServer DESTINATION bin)
|
||||
INSTALL(TARGETS IfcParse IfcGeom DESTINATION lib)
|
||||
|
||||
Executable
+372
@@ -0,0 +1,372 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 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 #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
###############################################################################
|
||||
# #
|
||||
# This script builds IfcOpenShell and its dependencies #
|
||||
# #
|
||||
# Prerequisites for this script to function correctly: #
|
||||
# * git * bzip2 * tar * c(++) compilers * yacc * autoconf #
|
||||
# on debian 7.8 these can be obtained with: #
|
||||
# $ apt-get install git bzip2 bizon autoconf gcc g++ #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
set -e
|
||||
|
||||
PROJECT_NAME=IfcOpenShell
|
||||
OCE_VERSION=0.16
|
||||
PYTHON_VERSIONS=(2.7.9 3.3.6 3.4.2)
|
||||
BOOST_VERSION=1.55.0
|
||||
PCRE_VERSION=8.38
|
||||
LIBXML_VERSION=2.9.3
|
||||
CMAKE_VERSION=3.4.1
|
||||
ICU_VERSION=56.1
|
||||
|
||||
# Helper function for coloured printing
|
||||
|
||||
BLACK_ON_WHITE="\033[0;30;107m"
|
||||
RED="\033[31m"
|
||||
GREEN="\033[32m"
|
||||
YELLOW="\033[33m"
|
||||
MAGENTA="\033[35m"
|
||||
function cecho {
|
||||
printf "$1$2\033[0m\n"
|
||||
}
|
||||
|
||||
# Set defaults for missing empty environment variables
|
||||
|
||||
if [ -z "$IFCOS_NUM_BUILD_PROCS" ]; then
|
||||
IFCOS_NUM_BUILD_PROCS=$(expr $(sysctl -n hw.ncpu 2> /dev/null || cat /proc/cpuinfo | grep processor | wc -l) + 1)
|
||||
fi
|
||||
|
||||
if [ -z "$TARGET_ARCH" ]; then
|
||||
TARGET_ARCH="$(uname -m)"
|
||||
fi
|
||||
|
||||
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||
CMAKE_DIR="$SCRIPT_DIR/../../cmake/"
|
||||
|
||||
if [ -z "$DEPS_DIR" ]; then
|
||||
DEPS_DIR="$SCRIPT_DIR/../../build/$(uname)/"
|
||||
[ -d $DEPS_DIR ] || mkdir -p $DEPS_DIR
|
||||
DEPS_DIR=`readlink -f $DEPS_DIR`
|
||||
fi
|
||||
|
||||
if [ -z "$BUILD_CFG" ]; then
|
||||
BUILD_CFG="RelWithDebInfo"
|
||||
fi
|
||||
|
||||
if [ -z "$BUILD_TYPE" ]; then
|
||||
BUILD_TYPE=Build
|
||||
fi
|
||||
|
||||
# Print build configuration information
|
||||
|
||||
cecho $BLACK_ON_WHITE "This script fetches and builds $PROJECT_NAME and its dependencies"
|
||||
echo ""
|
||||
cecho $GREEN "Script configuration:"
|
||||
|
||||
cecho $MAGENTA "* Target Architecture = $TARGET_ARCH"
|
||||
echo " - Whether 32-bit (i686) or 64-bit (x86_64) will be built."
|
||||
cecho $MAGENTA "* Dependency Directory = $DEPS_DIR"
|
||||
echo " - The directory where $PROJECT_NAME dependencies are installed."
|
||||
cecho $MAGENTA "* Build Config Type = $BUILD_CFG"
|
||||
echo " - The used build configuration type for the dependencies."
|
||||
echo " Defaults to RelWithDebInfo if not specified."
|
||||
|
||||
if [ "$BUILD_CFG" = "MinSizeRel" ]; then
|
||||
cecho $RED " WARNING: MinSizeRel build can suffer from a significant performance loss."
|
||||
fi
|
||||
|
||||
cecho $MAGENTA "* IFCOS_NUM_BUILD_PROCS = $IFCOS_NUM_BUILD_PROCS"
|
||||
echo " - How many compiler processes may be run in parallel."
|
||||
|
||||
echo ""
|
||||
|
||||
# Check that required tools are in PATH
|
||||
|
||||
for cmd in git bunzip2 tar cc c++ autoconf yacc
|
||||
do
|
||||
which $cmd > /dev/null || { cecho $RED "Required tool '$cmd' not installed or not added to PATH" ; exit 1 ; }
|
||||
done
|
||||
|
||||
which curl > /dev/null && DOWNLOAD="curl -sLO"
|
||||
which wget > /dev/null && DOWNLOAD="wget -q --no-check-certificate"
|
||||
|
||||
if [ -z "$DOWNLOAD" ]; then
|
||||
cecho $RED "No download application found, tried: curl, wget"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create log directory and file
|
||||
|
||||
mkdir -p $DEPS_DIR/logs
|
||||
LOG_FILE=$DEPS_DIR/logs/`date +"%Y%m%d"`.log
|
||||
|
||||
BOOST_VERSION_UNDERSCORE=${BOOST_VERSION//./_}
|
||||
ICU_VERSION_UNDERSCORE=${ICU_VERSION//./_}
|
||||
CMAKE_VERSION_2=${CMAKE_VERSION:0:3}
|
||||
|
||||
OCE_LOCATION=https://github.com/tpaviot/oce/archive/OCE-$OCE_VERSION.tar.gz
|
||||
BOOST_LOCATION=http://downloads.sourceforge.net/project/boost/boost/$BOOST_VERSION/boost_$BOOST_VERSION_UNDERSCORE.tar.bz2
|
||||
OPENCOLLADA_LOCATION=https://github.com/KhronosGroup/OpenCOLLADA.git
|
||||
OPENCOLLADA_COMMIT=f99d59e73e565a41715eaebc00c7664e1ee5e628
|
||||
|
||||
# Helper functions
|
||||
|
||||
function download {
|
||||
[ -f $2 ] || $DOWNLOAD $1$2
|
||||
}
|
||||
|
||||
function run_autoconf {
|
||||
if [ ! -f configure ]; then
|
||||
pushd . >>$LOG_FILE 2>&1
|
||||
cd ..
|
||||
./autogen.sh >>$LOG_FILE 2>&1
|
||||
popd >>$LOG_FILE 2>&1
|
||||
fi
|
||||
../configure $2 --prefix=$DEPS_DIR/install/$1 >>$LOG_FILE 2>&1
|
||||
}
|
||||
|
||||
function run_cmake {
|
||||
if [ -z "$3" ]; then
|
||||
P=..
|
||||
else
|
||||
P=$3
|
||||
fi
|
||||
$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake $P $2 -DCMAKE_BUILD_TYPE=$BUILD_TYPE >>$LOG_FILE 2>&1
|
||||
}
|
||||
|
||||
function run_icu {
|
||||
PLATFORM=`uname -s`
|
||||
if [ $PLATFORM == "Darwin" ]; then
|
||||
PLATFORM=MacOSX
|
||||
fi
|
||||
../source/runConfigureICU $PLATFORM $2 --prefix=$DEPS_DIR/install/$1 >>$LOG_FILE 2>&1
|
||||
}
|
||||
|
||||
function git_clone {
|
||||
[ -d $2 ] || git clone $1 >>$LOG_FILE 2>&1
|
||||
if [ ! -z "$3" ]; then
|
||||
cd $2
|
||||
git checkout $3
|
||||
cd ..
|
||||
fi
|
||||
}
|
||||
|
||||
function build_dependency {
|
||||
if [ -e $DEPS_DIR/install/$1 ]; then
|
||||
echo "Found existing $1"
|
||||
return
|
||||
fi
|
||||
mkdir -p $DEPS_DIR/build/
|
||||
cd $DEPS_DIR/build/
|
||||
printf "\rFetching $1... "
|
||||
$6 $4 $5 $7
|
||||
if [ -d $5 ]; then
|
||||
DEP_NAME=$5
|
||||
else
|
||||
DEP_NAME=`tar --exclude="*/*" -tf $5`
|
||||
[ -z $DEP_NAME ] && DEP_NAME=`tar -tf $5 2> /dev/null | head -n 1 | cut -f1 -d /`
|
||||
[ -d $DEP_NAME ] || tar -xf $5
|
||||
fi
|
||||
cd $DEP_NAME
|
||||
if [ "$2" != "bjam" ]; then
|
||||
[ -d build ] && rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
printf "\rConfiguring $1..."
|
||||
run_$2 $1 "$3"
|
||||
printf "\rBuilding $1... "
|
||||
make -j$IFCOS_NUM_BUILD_PROCS >>$LOG_FILE 2>&1
|
||||
printf "\rInstalling $1... "
|
||||
make install >>$LOG_FILE 2>&1
|
||||
printf "\rInstalled $1 \n"
|
||||
else
|
||||
printf "\rConfiguring $1..."
|
||||
./bootstrap.sh >>$LOG_FILE 2>&1
|
||||
printf "\rBuilding $1... "
|
||||
./b2 $3 >>$LOG_FILE 2>&1
|
||||
printf "\rInstalling $1... "
|
||||
cp -R boost $DEPS_DIR/install/boost-$BOOST_VERSION/ >>$LOG_FILE 2>&1
|
||||
printf "\rInstalled $1 \n"
|
||||
fi
|
||||
}
|
||||
|
||||
cecho $GREEN "Collecting dependencies:"
|
||||
|
||||
# Set compiler flags for 32bit builds on 64bit system
|
||||
|
||||
if [ "$TARGET_ARCH" == "i686" ] && [ "$(uname -m)" == "x86_64" ]; then
|
||||
ADDITIONAL_ARGS="-m32 -arch i386"
|
||||
fi
|
||||
|
||||
if [ "$(uname)" == "Darwin" ]; then
|
||||
ADDITIONAL_ARGS="-macosx_version_min 10.6 $ADDITIONAL_ARGS"
|
||||
fi
|
||||
|
||||
# If the linker supports GC sections, set it up to reduce binary file size
|
||||
# -fPIC is required for the shared libraries to work
|
||||
|
||||
if man ld 2> /dev/null | grep gc-sections &> /dev/null; then
|
||||
export CXXFLAGS="$CXXFLAGS -fPIC -fdata-sections -ffunction-sections -fvisibility=hidden -fvisibility-inlines-hidden $ADDITIONAL_ARGS"
|
||||
export CFLAGS="$CFLAGS -fPIC -fdata-sections -ffunction-sections -fvisibility=hidden $ADDITIONAL_ARGS"
|
||||
export LDFLAGS="$LDFLAGS -Wl,--gc-sections $ADDITIONAL_ARGS"
|
||||
export CXXFLAGS_MINIMAL="$CXXFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
|
||||
export CFLAGS_MINIMAL="$CFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
|
||||
else
|
||||
export CXXFLAGS="$CXXFLAGS -fPIC -fvisibility=hidden -fvisibility-inlines-hidden $ADDITIONAL_ARGS"
|
||||
export CFLAGS="$CFLAGS -fPIC -fvisibility=hidden -fvisibility-inlines-hidden $ADDITIONAL_ARGS"
|
||||
export LDFLAGS="$LDFLAGS -s -death_code $ADDITIONAL_ARGS"
|
||||
export CXXFLAGS_MINIMAL="$CXXFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
|
||||
export CFLAGS_MINIMAL="$CFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
|
||||
fi
|
||||
|
||||
# Some dependencies need a more recent CMake version than most distros provide
|
||||
build_dependency cmake-$CMAKE_VERSION autoconf "" https://cmake.org/files/v$CMAKE_VERSION_2/ cmake-$CMAKE_VERSION.tar.gz download
|
||||
|
||||
# Extract compiler flags from CMake to harmonize settings with other autoconf dependencies
|
||||
CMAKE_FLAG_EXTRACT_DIR=ifcopenshell_cmake_test_`cat /dev/urandom | env LC_CTYPE=C tr -dc 'a-zA-Z0-9' | head -c 32`
|
||||
[ -e $CMAKE_FLAG_EXTRACT_DIR ] && rm -rf $CMAKE_FLAG_EXTRACT_DIR
|
||||
mkdir $CMAKE_FLAG_EXTRACT_DIR
|
||||
cd $CMAKE_FLAG_EXTRACT_DIR
|
||||
BUILD_CFG_UPPER=${BUILD_CFG^^}
|
||||
for FL in C CXX LD; do
|
||||
echo "
|
||||
message(\"\${CMAKE_${FL}_FLAGS_${BUILD_CFG_UPPER}}\")
|
||||
" > CMakeLists.txt
|
||||
declare ${FL}FLAGS="`$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake . 2>&1 >/dev/null`"
|
||||
declare ${FL}FLAGS_MINIMAL="`$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake . 2>&1 >/dev/null`"
|
||||
done
|
||||
cd ..
|
||||
rm -rf $CMAKE_FLAG_EXTRACT_DIR
|
||||
|
||||
build_dependency pcre-$PCRE_VERSION autoconf "--disable-shared" ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ pcre-$PCRE_VERSION.tar.bz2 download
|
||||
|
||||
# An issue exists with swig-1.3 and python >= 3.2
|
||||
# Therefore, build a recent copy from source
|
||||
build_dependency swig autoconf "--with-pcre-prefix=$DEPS_DIR/install/pcre-$PCRE_VERSION" https://github.com/swig/swig.git swig git_clone rel-3.0.8
|
||||
|
||||
build_dependency oce-$OCE_VERSION cmake "-DOCE_DISABLE_TKSERVICE_FONT=ON -DOCE_TESTING=OFF -DOCE_BUILD_SHARED_LIB=OFF -DOCE_DISABLE_X11=ON -DOCE_VISUALISATION=OFF -DOCE_OCAF=OFF -DOCE_INSTALL_PREFIX=$DEPS_DIR/install/oce-$OCE_VERSION/" https://github.com/tpaviot/oce/archive/ OCE-$OCE_VERSION.tar.gz download
|
||||
build_dependency libxml2-$LIBXML_VERSION autoconf "--without-python --disable-shared" ftp://xmlsoft.org/libxml2/ libxml2-$LIBXML_VERSION.tar.gz download
|
||||
build_dependency OpenCOLLADA cmake "
|
||||
-DLIBXML2_INCLUDE_DIR=$DEPS_DIR/install/libxml2-$LIBXML_VERSION/include/libxml2
|
||||
-DLIBXML2_LIBRARIES=$DEPS_DIR/install/libxml2-$LIBXML_VERSION/lib/libxml2.a
|
||||
-DPCRE_INCLUDE_DIR=$DEPS_DIR/install/pcre-$PCRE_VERSION/include
|
||||
-DPCRE_PCREPOSIX_LIBRARY=$DEPS_DIR/install/pcre-$PCRE_VERSION/lib/libpcreposix.a
|
||||
-DPCRE_PCRE_LIBRARY=$DEPS_DIR/install/pcre-$PCRE_VERSION/lib/libpcre.a
|
||||
-DCMAKE_INSTALL_PREFIX=$DEPS_DIR/install/OpenCOLLADA/" https://github.com/KhronosGroup/OpenCOLLADA.git OpenCOLLADA git_clone
|
||||
|
||||
# Python should not be built with -fvisibility=hidden, from experience that introduces segfaults
|
||||
|
||||
OLD_CXX_FLAGS=$CXXFLAGS
|
||||
OLD_C_FLAGS=$CFLAGS
|
||||
OLD_LD_FLAGS=$LDFLAGS
|
||||
export CXXFLAGS=$CXXFLAGS_MINIMAL
|
||||
export CFLAGS=$CFLAGS_MINIMAL
|
||||
export LDFLAGS=$LDFLAGS_MINIMAL
|
||||
|
||||
for PYTHON_VERSION in "${PYTHON_VERSIONS[@]}"; do
|
||||
build_dependency python-$PYTHON_VERSION autoconf "" http://www.python.org/ftp/python/$PYTHON_VERSION/ Python-$PYTHON_VERSION.tgz download
|
||||
done
|
||||
|
||||
export CXXFLAGS=$OLD_CXX_FLAGS
|
||||
export CFLAGS=$OLD_C_FLAGS
|
||||
export LDFLAGS=$OLD_LD_FLAGS
|
||||
|
||||
if [ "$(uname)" == "Darwin" ] && [ "$1" == "32" ]; then
|
||||
BOOST_ADDRESS_MODEL="toolset=darwin architecture=x86 target-os=darwin address-model=32"
|
||||
fi
|
||||
build_dependency boost-$BOOST_VERSION bjam "--stagedir=$DEPS_DIR/install/boost-$BOOST_VERSION --with-program_options link=static $BOOST_ADDRESS_MODEL stage" http://downloads.sourceforge.net/project/boost/boost/$BOOST_VERSION/ boost_$BOOST_VERSION_UNDERSCORE.tar.bz2 download
|
||||
|
||||
build_dependency icu-$ICU_VERSION icu "--enable-static --disable-shared" http://download.icu-project.org/files/icu4c/$ICU_VERSION/ icu4c-${ICU_VERSION_UNDERSCORE}-src.tgz download
|
||||
|
||||
cecho $GREEN "Building IfcOpenShell:"
|
||||
|
||||
IFCOS_DIR=$DEPS_DIR/build/ifcopenshell
|
||||
[ -d $IFCOS_DIR ] && rm -rf $IFCOS_DIR
|
||||
mkdir -p $IFCOS_DIR
|
||||
cd $IFCOS_DIR
|
||||
|
||||
mkdir -p executables
|
||||
cd executables
|
||||
|
||||
printf "\rConfiguring executables..."
|
||||
|
||||
run_cmake "" "
|
||||
-DBOOST_ROOT=$DEPS_DIR/install/boost-$BOOST_VERSION
|
||||
-DOCC_INCLUDE_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/include/oce
|
||||
-DOCC_LIBRARY_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/lib
|
||||
-DOPENCOLLADA_INCLUDE_DIR=$DEPS_DIR/install/OpenCOLLADA/include/opencollada
|
||||
-DOPENCOLLADA_LIBRARY_DIR=$DEPS_DIR/install/OpenCOLLADA/lib/opencollada
|
||||
-DICU_INCLUDE_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/include
|
||||
-DICU_LIBRARY_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/lib
|
||||
-DPCRE_LIBRARY_DIR=$DEPS_DIR/install/pcre-$PCRE_VERSION/lib
|
||||
-DBUILD_IFCPYTHON=OFF
|
||||
" $CMAKE_DIR
|
||||
|
||||
printf "\rBuilding executables... "
|
||||
|
||||
make -j$IFCOS_NUM_BUILD_PROCS >>$LOG_FILE 2>&1
|
||||
|
||||
strip -s IfcConvert IfcGeomServer
|
||||
|
||||
cd ..
|
||||
|
||||
for PYTHON_VERSION in "${PYTHON_VERSIONS[@]}"; do
|
||||
|
||||
printf "\rConfiguring python $PYTHON_VERSION wrapper..."
|
||||
|
||||
mkdir -p python-$PYTHON_VERSION
|
||||
cd python-$PYTHON_VERSION
|
||||
|
||||
PYTHON_LIBRARY=`ls $DEPS_DIR/install/python-$PYTHON_VERSION/lib/libpython*.a`
|
||||
PYTHON_INCLUDE=`ls -d $DEPS_DIR/install/python-$PYTHON_VERSION/include/python*`
|
||||
PYTHON_EXECUTABLE=$DEPS_DIR/install/python-$PYTHON_VERSION/bin/python
|
||||
export PYTHON_LIBRARY_BASENAME=`basename $PYTHON_LIBRARY`
|
||||
|
||||
run_cmake "" "
|
||||
-DBOOST_ROOT=$DEPS_DIR/install/boost-$BOOST_VERSION
|
||||
-DOCC_INCLUDE_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/include/oce
|
||||
-DOCC_LIBRARY_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/lib
|
||||
-DOPENCOLLADA_INCLUDE_DIR=$DEPS_DIR/install/OpenCOLLADA/include/opencollada
|
||||
-DOPENCOLLADA_LIBRARY_DIR=$DEPS_DIR/install/OpenCOLLADA/lib/opencollada
|
||||
-DICU_INCLUDE_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/include
|
||||
-DICU_LIBRARY_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/lib
|
||||
-DPYTHON_LIBRARY=$PYTHON_LIBRARY
|
||||
-DPYTHON_EXECUTABLE=$PYTHON_EXECUTABLE
|
||||
-DPYTHON_INCLUDE_DIR=$PYTHON_INCLUDE
|
||||
-DSWIG_EXECUTABLE=$DEPS_DIR/install/swig/bin/swig
|
||||
" $CMAKE_DIR
|
||||
|
||||
# This still needs to be tested
|
||||
# test "$(uname)" == "Darwin" && sed -i~ "s/-o/-flat_namespace -undefined suppress -o/" ifcwrap/CMakeFiles/_ifcopenshell_wrapper.dir/link.txt
|
||||
|
||||
printf "\rBuilding python $PYTHON_VERSION wrapper... "
|
||||
|
||||
make -j$IFCOS_NUM_BUILD_PROCS _ifcopenshell_wrapper >>$LOG_FILE 2>&1
|
||||
|
||||
strip -s \
|
||||
-K PyInit__ifcopenshell_wrapper \
|
||||
ifcwrap/_ifcopenshell_wrapper.so
|
||||
|
||||
done
|
||||
|
||||
printf "\rBuilt IfcOpenShell... \n\n"
|
||||
@@ -1,5 +1,24 @@
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 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 #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
ADD_EXECUTABLE(IfcParseExamples IfcParseExamples.cpp)
|
||||
TARGET_LINK_LIBRARIES (IfcParseExamples IfcParse)
|
||||
TARGET_LINK_LIBRARIES(IfcParseExamples IfcParse)
|
||||
|
||||
ADD_EXECUTABLE(IfcOpenHouse IfcOpenHouse.cpp)
|
||||
TARGET_LINK_LIBRARIES (IfcOpenHouse IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKOffset)
|
||||
TARGET_LINK_LIBRARIES(IfcOpenHouse IfcParse IfcGeom ${OPENCASCADE_LIBRARIES})
|
||||
|
||||
@@ -41,16 +41,20 @@
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
#endif
|
||||
|
||||
// Some convenience typedefs and definitions.
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
typedef std::pair<double, double> XY;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
// The creation of Nurbs-surface for the IfcSite mesh, to be implemented lateron
|
||||
void createGroundShape(TopoDS_Shape& shape);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int main() {
|
||||
|
||||
// The IfcHierarchyHelper is a subclass of the regular IfcFile that provides several
|
||||
// convenience functions for working with geometry in IFC files.
|
||||
@@ -195,43 +199,46 @@ int main(int argc, char** argv) {
|
||||
file.addBuildingProduct(north_wall);
|
||||
file.setSurfaceColour(north_wall->Representation(), wall_colour);
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* clipped_wall_body_rep = file.addEmptyRepresentation();
|
||||
file.addBox(clipped_wall_body_rep, 5000, 360, 6000);
|
||||
// The east wall geometry is clipped using two IfcHalfSpaceSolids, created from an
|
||||
// 'axis 3d placement' that specifies the plane against which the geometry is clipped.
|
||||
file.clipRepresentation(clipped_wall_body_rep, file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false);
|
||||
file.clipRepresentation(clipped_wall_body_rep, file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false);
|
||||
// Two identical representations are created for the two remaining walls. Mapped items
|
||||
// are not used, because it is not allowed by the standard for wall body representations.
|
||||
// MappedItems are not allowed for Axis representations as per CV-2x3-161
|
||||
IfcSchema::IfcProductDefinitionShape* clipped_wall_body_reps[2];
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
IfcSchema::IfcShapeRepresentation* body = file.addEmptyRepresentation();
|
||||
file.addBox(body, 5000, 360, 6000);
|
||||
// The wall geometry is clipped using two IfcHalfSpaceSolids, created from an
|
||||
// 'axis 3d placement' that specifies the plane against which the geometry is clipped.
|
||||
file.clipRepresentation(body, file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false);
|
||||
file.clipRepresentation(body, file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false);
|
||||
file.setSurfaceColour(body, wall_colour);
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* axis = file.addEmptyRepresentation("Axis", "Curve2D");
|
||||
file.addAxis(axis, 5000);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
|
||||
reps->push(body);
|
||||
reps->push(axis);
|
||||
clipped_wall_body_reps[i] = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
|
||||
}
|
||||
|
||||
// Now create a wall on the east of the building, again starting with just a box shape
|
||||
IfcSchema::IfcWallStandardCase* east_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
S("East wall"), null, null, file.addLocalPlacement(storey_placement, 4820, 2500, 0, 0, 0, 1, 0, 1, 0), file.addMappedItem(clipped_wall_body_rep), null
|
||||
S("East wall"), null, null, file.addLocalPlacement(storey_placement, 4820, 2500, 0, 0, 0, 1, 0, 1, 0), clipped_wall_body_reps[0], null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
|
||||
#endif
|
||||
);
|
||||
file.addBuildingProduct(east_wall);
|
||||
|
||||
file.setSurfaceColour(clipped_wall_body_rep, wall_colour);
|
||||
|
||||
// The east wall is copied to the west location of the house
|
||||
IfcSchema::IfcWallStandardCase* west_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
S("West wall"), null, null, file.addLocalPlacement(storey_placement, -4820, 2500, 0, 0, 0, 1, 0, -1, 0), file.addMappedItem(clipped_wall_body_rep), null
|
||||
S("West wall"), null, null, file.addLocalPlacement(storey_placement, -4820, 2500, 0, 0, 0, 1, 0, -1, 0), clipped_wall_body_reps[1], null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
|
||||
#endif
|
||||
);
|
||||
file.addBuildingProduct(west_wall);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
// CV-2x3-161: MappedItems are not allowed for Axis representations
|
||||
IfcSchema::IfcWallStandardCase* wall = i == 0 ? east_wall : west_wall;
|
||||
IfcSchema::IfcShapeRepresentation* wall_axis_rep = file.addEmptyRepresentation("Axis", "Curve2D");
|
||||
file.addAxis(wall_axis_rep, 5000);
|
||||
IfcSchema::IfcRepresentation::list::ptr reps = wall->Representation()->Representations();
|
||||
reps->push(wall_axis_rep);
|
||||
wall->Representation()->setRepresentations(reps);
|
||||
}
|
||||
|
||||
// The west wall is assigned an opening element we created for the south wall, opening elements are
|
||||
// not shared accross building elements, even if they share the same representation. Hence, the east
|
||||
// wall will not feature this opening.
|
||||
@@ -381,6 +388,10 @@ int main(int argc, char** argv) {
|
||||
file.setSurfaceColour(door->Representation(), 0.9, 0.9, 0.9);
|
||||
file.addEntity(new IfcSchema::IfcRelFillsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, door_opening, door));
|
||||
|
||||
IfcSchema::IfcDoorStyle* door_style = new IfcSchema::IfcDoorStyle(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("Door type"), null, null, null, null, null,
|
||||
IfcSchema::IfcDoorStyleOperationEnum::IfcDoorStyleOperation_SINGLE_SWING_LEFT, IfcSchema::IfcDoorStyleConstructionEnum::IfcDoorStyleConstruction_WOOD, false, false);
|
||||
file.addRelatedObject<IfcSchema::IfcRelDefinesByType>(door_style, door);
|
||||
|
||||
// Surface styles are assigned to representation items, hence there is no real limitation to
|
||||
// assign different colours within the same representation. However, some viewers have
|
||||
// difficulties rendering products with representation items with different surface styles.
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
#endif
|
||||
|
||||
using namespace IfcSchema;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
static int i = 0;
|
||||
|
||||
void create_product_from_item(IfcHierarchyHelper& file, IfcSchema::IfcRepresentationItem* item, const std::string& s) {
|
||||
@@ -43,16 +43,16 @@ void create_product_from_item(IfcHierarchyHelper& file, IfcSchema::IfcRepresenta
|
||||
file.addBuildingProduct(product);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement(120 * i++));
|
||||
product->setObjectPlacement(file.addLocalPlacement(0, 120 * i++));
|
||||
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
items->push(item);
|
||||
|
||||
if (s == "GeometricSet") {
|
||||
IfcSchema::IfcGeometricSet* set = new IfcSchema::IfcGeometricSet(items->generalize());
|
||||
file.addEntity(set);
|
||||
items = IfcSchema::IfcRepresentationItem::list(new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
items = IfcSchema::IfcRepresentationItem::list::ptr(new IfcSchema::IfcRepresentationItem::list());
|
||||
items->push(set);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ void create_product_from_item(IfcHierarchyHelper& file, IfcSchema::IfcRepresenta
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), s, items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
|
||||
@@ -109,11 +109,11 @@ void create_products_from_curve(IfcHierarchyHelper& file, IfcSchema::IfcBoundedC
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "IfcArbitraryOpenProfileDef.ifc";
|
||||
IfcHierarchyHelper file;
|
||||
file.filename(filename);
|
||||
file.header().file_name().name(filename);
|
||||
|
||||
double coords1[] = {-50.0, 0.0};
|
||||
double coords2[] = { 50.0, 0.0};
|
||||
IfcSchema::IfcCartesianPoint::list points (new IfcTemplatedEntityList<IfcSchema::IfcCartesianPoint>());
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list());
|
||||
points->push(new IfcSchema::IfcCartesianPoint(std::vector<double>(coords1, coords1+2)));
|
||||
points->push(new IfcSchema::IfcCartesianPoint(std::vector<double>(coords2, coords2+2)));
|
||||
file.addEntities(points->generalize());
|
||||
@@ -126,8 +126,8 @@ int main(int argc, char** argv) {
|
||||
file.addEntity(ellipse);
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
trim1->push(new IfcWrite::IfcSelectHelper( 0., Ifc2x3::Type::IfcParameterValue));
|
||||
trim2->push(new IfcWrite::IfcSelectHelper(180., Ifc2x3::Type::IfcParameterValue));
|
||||
trim1->push(new IfcSchema::IfcParameterValue( 0.));
|
||||
trim2->push(new IfcSchema::IfcParameterValue(180.));
|
||||
IfcSchema::IfcTrimmedCurve* trim = new IfcSchema::IfcTrimmedCurve(ellipse, trim1, trim2, true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
file.addEntity(trim);
|
||||
|
||||
|
||||
@@ -32,19 +32,19 @@
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "IfcCompositeProfileDef.ifc";
|
||||
IfcHierarchyHelper file;
|
||||
file.filename(filename);
|
||||
file.header().file_name().name(filename);
|
||||
|
||||
double coords1[] = {100.0, 0.0};
|
||||
double coords2[] = {200.0, 0.0};
|
||||
double coords3[] = {300.0, 0.0};
|
||||
|
||||
IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list());
|
||||
|
||||
IfcSchema::IfcCartesianTransformationOperator2D* transform1 = new IfcSchema::IfcCartesianTransformationOperator2D(file.addDoublet<IfcSchema::IfcDirection>(1, 0), file.addDoublet<IfcSchema::IfcDirection>(0, -1), file.addDoublet<IfcSchema::IfcCartesianPoint>(40, 0), null);
|
||||
IfcSchema::IfcCartesianTransformationOperator2D* transform2 = new IfcSchema::IfcCartesianTransformationOperator2D(file.addDoublet<IfcSchema::IfcDirection>(0, -1), file.addDoublet<IfcSchema::IfcDirection>(1, 0), file.addDoublet<IfcSchema::IfcCartesianPoint>(40, 0), 0.3);
|
||||
@@ -98,15 +98,15 @@ int main(int argc, char** argv) {
|
||||
file.addEntity(composite);
|
||||
file.addEntity(solid);
|
||||
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
|
||||
items->push(solid);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("SweptSolid"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
class Node {
|
||||
private:
|
||||
@@ -135,7 +135,7 @@ public:
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "IfcCsgPrimitive.ifc";
|
||||
IfcHierarchyHelper file;
|
||||
file.filename(filename);
|
||||
file.header().file_name().name(filename);
|
||||
|
||||
IfcSchema::IfcRepresentationItem* csg1 = Node::Box(8000.,6000.,3000.).subtract(
|
||||
Node::Box(7600.,5600.,2800.).move(200.,200.,200.)
|
||||
@@ -171,8 +171,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement());
|
||||
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
|
||||
items->push(csg1);
|
||||
items->push(csg2);
|
||||
@@ -180,7 +180,7 @@ int main(int argc, char** argv) {
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("CSG"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
typedef struct {
|
||||
double r1;
|
||||
@@ -58,7 +58,7 @@ void create_testcase_for(IfcHierarchyHelper& file, const EllipsePie& pie, Ifc2x3
|
||||
Ifc2x3::IfcCartesianPoint* p2 = new Ifc2x3::IfcCartesianPoint(coords2);
|
||||
Ifc2x3::IfcCartesianPoint* p3 = new Ifc2x3::IfcCartesianPoint(coords3);
|
||||
|
||||
Ifc2x3::IfcCartesianPoint::list points(new IfcTemplatedEntityList<Ifc2x3::IfcCartesianPoint>());
|
||||
Ifc2x3::IfcCartesianPoint::list::ptr points(new Ifc2x3::IfcCartesianPoint::list());
|
||||
points->push(p3);
|
||||
points->push(p1);
|
||||
points->push(p2);
|
||||
@@ -70,8 +70,8 @@ void create_testcase_for(IfcHierarchyHelper& file, const EllipsePie& pie, Ifc2x3
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
if (pref == Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER) {
|
||||
trim1->push(new IfcWrite::IfcSelectHelper(pie.t1, Ifc2x3::Type::IfcParameterValue));
|
||||
trim2->push(new IfcWrite::IfcSelectHelper(pie.t2, Ifc2x3::Type::IfcParameterValue));
|
||||
trim1->push(new Ifc2x3::IfcParameterValue(pie.t1));
|
||||
trim2->push(new Ifc2x3::IfcParameterValue(pie.t2));
|
||||
} else {
|
||||
trim1->push(p2);
|
||||
trim2->push(p3);
|
||||
@@ -79,7 +79,7 @@ void create_testcase_for(IfcHierarchyHelper& file, const EllipsePie& pie, Ifc2x3
|
||||
Ifc2x3::IfcTrimmedCurve* trim = new Ifc2x3::IfcTrimmedCurve(ellipse, trim1, trim2, true, pref);
|
||||
file.addEntity(trim);
|
||||
|
||||
Ifc2x3::IfcCompositeCurveSegment::list segments(new IfcTemplatedEntityList<Ifc2x3::IfcCompositeCurveSegment>());
|
||||
Ifc2x3::IfcCompositeCurveSegment::list::ptr segments(new Ifc2x3::IfcCompositeCurveSegment::list());
|
||||
Ifc2x3::IfcCompositeCurveSegment* s2 = new Ifc2x3::IfcCompositeCurveSegment(Ifc2x3::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, trim);
|
||||
|
||||
Ifc2x3::IfcPolyline* poly = new Ifc2x3::IfcPolyline(points);
|
||||
@@ -100,22 +100,22 @@ void create_testcase_for(IfcHierarchyHelper& file, const EllipsePie& pie, Ifc2x3
|
||||
file.addBuildingProduct(product);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement(200 * i++));
|
||||
product->setObjectPlacement(file.addLocalPlacement(0, 200 * i++));
|
||||
|
||||
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(profile,
|
||||
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
|
||||
|
||||
file.addEntity(solid);
|
||||
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
|
||||
items->push(solid);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("SweptSolid"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 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 *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Example that generates various forms of IfcFace *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
static int x = 0;
|
||||
|
||||
void create_testcase(IfcHierarchyHelper& file, IfcSchema::IfcFace* face, const std::string& name) {
|
||||
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
|
||||
faces->push(face);
|
||||
IfcSchema::IfcOpenShell* shell = new IfcSchema::IfcOpenShell(faces);
|
||||
|
||||
IfcSchema::IfcConnectedFaceSet::list::ptr shells(new IfcSchema::IfcConnectedFaceSet::list);
|
||||
shells->push(shell);
|
||||
IfcSchema::IfcFaceBasedSurfaceModel* model = new IfcSchema::IfcFaceBasedSurfaceModel(shells);
|
||||
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, name, null, null, 0, 0, null, null);
|
||||
file.addBuildingProduct(product);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement(0, 1000 * x++, 0));
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
|
||||
|
||||
items->push(model);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getRepresentationContext("Model"), S("Body"), S("SurfaceModel"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
file.addEntity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
IfcHierarchyHelper file;
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "polyloop");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint* point1 = file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, 0., 0.);
|
||||
IfcSchema::IfcCartesianPoint* point2 = file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, 0., 0.);
|
||||
IfcSchema::IfcVertexPoint* vertex1 = new IfcSchema::IfcVertexPoint(point1);
|
||||
IfcSchema::IfcVertexPoint* vertex2 = new IfcSchema::IfcVertexPoint(point2);
|
||||
IfcSchema::IfcCircle* circle = new IfcSchema::IfcCircle(file.addPlacement2d(), 400.);
|
||||
IfcSchema::IfcEdgeCurve* edge1 = new IfcSchema::IfcEdgeCurve(vertex1, vertex2, circle, true);
|
||||
IfcSchema::IfcEdgeCurve* edge2 = new IfcSchema::IfcEdgeCurve(vertex2, vertex1, circle, true);
|
||||
IfcSchema::IfcOrientedEdge* oriented_edge1 = new IfcSchema::IfcOrientedEdge(edge1, true);
|
||||
IfcSchema::IfcOrientedEdge* oriented_edge2 = new IfcSchema::IfcOrientedEdge(edge2, true);
|
||||
IfcSchema::IfcOrientedEdge::list::ptr edges(new IfcSchema::IfcOrientedEdge::list);
|
||||
edges->push(oriented_edge1);
|
||||
edges->push(oriented_edge2);
|
||||
IfcSchema::IfcEdgeLoop* loop = new IfcSchema::IfcEdgeLoop(edges);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "circle");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* outer_bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points2 (new IfcSchema::IfcCartesianPoint::list);
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-300, -300, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, -300, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, +300, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-300, +300, 0));
|
||||
IfcSchema::IfcPolyLoop* loop2 = new IfcSchema::IfcPolyLoop(points2);
|
||||
IfcSchema::IfcFaceBound* inner_bound1 = new IfcSchema::IfcFaceBound(loop2, false);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points3 (new IfcSchema::IfcCartesianPoint::list);
|
||||
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, +300, 0));
|
||||
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+300, +300, 0));
|
||||
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+300, -300, 0));
|
||||
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, -300, 0));
|
||||
IfcSchema::IfcPolyLoop* loop3 = new IfcSchema::IfcPolyLoop(points3);
|
||||
IfcSchema::IfcFaceBound* inner_bound2 = new IfcSchema::IfcFaceBound(loop3, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(inner_bound1);
|
||||
bounds->push(outer_bound);
|
||||
bounds->push(inner_bound2);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "polyloop with holes");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, +400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* bound1 = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points2 (new IfcSchema::IfcCartesianPoint::list);
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, +400, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, -400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop2 = new IfcSchema::IfcPolyLoop(points2);
|
||||
IfcSchema::IfcFaceOuterBound* bound2 = new IfcSchema::IfcFaceOuterBound(loop2, false);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound1);
|
||||
bounds->push(bound2);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "multiple outer boundaries (invalid)");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 1e-6));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "imprecise polyloop");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint* point1 = file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, 0., 0.);
|
||||
IfcSchema::IfcCartesianPoint* point2 = file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, 0., 0.);
|
||||
IfcSchema::IfcVertexPoint* vertex1 = new IfcSchema::IfcVertexPoint(point1);
|
||||
IfcSchema::IfcVertexPoint* vertex2 = new IfcSchema::IfcVertexPoint(point2);
|
||||
IfcSchema::IfcCircle* circle = new IfcSchema::IfcCircle(file.addPlacement2d(), 400.);
|
||||
IfcSchema::IfcEdgeCurve* edge1 = new IfcSchema::IfcEdgeCurve(vertex1, vertex2, circle, true);
|
||||
IfcSchema::IfcEdgeCurve* edge2 = new IfcSchema::IfcEdgeCurve(vertex2, vertex1, circle, true);
|
||||
IfcSchema::IfcOrientedEdge* oriented_edge1 = new IfcSchema::IfcOrientedEdge(edge1, true);
|
||||
IfcSchema::IfcOrientedEdge* oriented_edge2 = new IfcSchema::IfcOrientedEdge(edge2, true);
|
||||
IfcSchema::IfcOrientedEdge::list::ptr edges(new IfcSchema::IfcOrientedEdge::list);
|
||||
edges->push(oriented_edge1);
|
||||
edges->push(oriented_edge2);
|
||||
IfcSchema::IfcEdgeLoop* loop = new IfcSchema::IfcEdgeLoop(edges);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr trim1(new IfcSchema::IfcCartesianPoint::list);
|
||||
IfcSchema::IfcCartesianPoint::list::ptr trim2(new IfcSchema::IfcCartesianPoint::list);
|
||||
trim1->push(point1);
|
||||
trim2->push(point2);
|
||||
IfcSchema::IfcTrimmedCurve* trimmed_curve = new IfcSchema::IfcTrimmedCurve(circle, trim1->generalize(), trim2->generalize(), true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);
|
||||
IfcSchema::IfcArbitraryOpenProfileDef* profile = new IfcSchema::IfcArbitraryOpenProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_CURVE, boost::none, trimmed_curve);
|
||||
IfcSchema::IfcAxis1Placement* place = new IfcSchema::IfcAxis1Placement(file.addTriplet<IfcSchema::IfcCartesianPoint>(0., 0., 0.), file.addTriplet<IfcSchema::IfcDirection>(1., 0., 0.));
|
||||
IfcSchema::IfcSurfaceOfRevolution* surface = new IfcSchema::IfcSurfaceOfRevolution(profile, file.addPlacement3d(), place);
|
||||
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFaceSurface(bounds, surface, true);
|
||||
create_testcase(file, face, "face surface");
|
||||
}
|
||||
const std::string filename = "faces.ifc";
|
||||
file.header().file_name().name(filename);
|
||||
std::ofstream f(filename.c_str());
|
||||
f << file;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,85 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 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 *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Example that generates an IfcTriangulatedFaceSet *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../ifcparse/Ifc4.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
#include "suzanne_geometry.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
template <typename T>
|
||||
std::vector< std::vector<T> > create_vector_from_array(const T* arr, unsigned size) {
|
||||
std::vector< std::vector<T> > result;
|
||||
result.reserve(size);
|
||||
|
||||
for (unsigned i = 0; i < size; ) {
|
||||
std::vector<T> ts; ts.reserve(3);
|
||||
for (unsigned j = 0; j < 3; ++i, ++j) {
|
||||
ts.push_back(arr[i]);
|
||||
}
|
||||
result.push_back(ts);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
IfcHierarchyHelper file;
|
||||
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, S("Blender's Suzanne"), null, null, 0, 0, null, null);
|
||||
file.addBuildingProduct(product);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement());
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
|
||||
|
||||
std::vector< std::vector< double > > vertices_vector = create_vector_from_array(vertices, sizeof(vertices) / sizeof(vertices[0]));
|
||||
std::vector< std::vector< int > > indices_vector = create_vector_from_array(indices, sizeof(indices) / sizeof(indices[0]));
|
||||
|
||||
IfcSchema::IfcCartesianPointList3D* coordinates = new IfcSchema::IfcCartesianPointList3D(vertices_vector);
|
||||
IfcSchema::IfcTriangulatedFaceSet* faceset = new IfcSchema::IfcTriangulatedFaceSet(coordinates, null, null, indices_vector, null);
|
||||
|
||||
items->push(faceset);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getRepresentationContext("Model"), S("Body"), S("SurfaceModel"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
file.addEntity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
|
||||
const std::string filename = "tesselated_faceset.ifc";
|
||||
file.header().file_name().name(filename);
|
||||
std::ofstream f(filename.c_str());
|
||||
f << file;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 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 #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
ADD_EXECUTABLE(hdf5_federate federate.cpp)
|
||||
TARGET_LINK_LIBRARIES(hdf5_federate IfcParse ${ICU_LIBRARIES} ${Boost_LIBRARIES})
|
||||
|
||||
ADD_EXECUTABLE(hdf5_lod lod.cpp)
|
||||
TARGET_LINK_LIBRARIES(hdf5_lod IfcParse IfcGeom ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBRARIES})
|
||||
@@ -0,0 +1,361 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 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 *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../../../src/ifcparse/IfcHdf5File.h"
|
||||
#include "../../../src/ifcparse/IfcWritableEntity.h"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
#include "multifile_instance_locator.h"
|
||||
|
||||
#pragma warning(disable:4100)
|
||||
|
||||
// A comparison operator that is used to isolate the shared hierarchy
|
||||
class ifc_inst_cmp {
|
||||
public:
|
||||
|
||||
// For these we simply assume that only a single instance exists
|
||||
bool operator()(IfcSchema::IfcSite* a, IfcSchema::IfcSite* b) const { return false; }
|
||||
bool operator()(IfcSchema::IfcProject* a, IfcSchema::IfcProject* b) const { return false; }
|
||||
bool operator()(IfcSchema::IfcBuilding* a, IfcSchema::IfcBuilding* b) const { return false; }
|
||||
bool operator()(IfcSchema::IfcPostalAddress* a, IfcSchema::IfcPostalAddress* b) const { return false; }
|
||||
bool operator()(IfcSchema::IfcUnitAssignment* a, IfcSchema::IfcUnitAssignment* b) const { return false; }
|
||||
|
||||
bool operator()(IfcSchema::IfcConversionBasedUnit* a, IfcSchema::IfcConversionBasedUnit* b) const {
|
||||
return a->Name() < b->Name();
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcDimensionalExponents* a, IfcSchema::IfcDimensionalExponents* b) const {
|
||||
// For every attribute (which are all integers) check equality
|
||||
|
||||
unsigned num_attrs = a->data().getArgumentCount();
|
||||
for (unsigned i = 0; i < num_attrs; ++i) {
|
||||
const int v1 = *a->data().getArgument(i);
|
||||
const int v2 = *b->data().getArgument(i);
|
||||
if (v1 != v2) {
|
||||
return v1 < v2;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcMeasureWithUnit* a, IfcSchema::IfcMeasureWithUnit* b) const {
|
||||
// Assume the value component is enough to differentiate
|
||||
|
||||
double v1 = *a->ValueComponent()->data().getArgument(0);
|
||||
double v2 = *b->ValueComponent()->data().getArgument(0);
|
||||
return v1 < v2;
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcGeometricRepresentationSubContext* a, IfcSchema::IfcGeometricRepresentationSubContext* b) const {
|
||||
return a->ContextType() < b->ContextType();
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcGeometricRepresentationContext* a, IfcSchema::IfcGeometricRepresentationContext* b) const {
|
||||
return a->ContextType() < b->ContextType();
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcSIUnit* a, IfcSchema::IfcSIUnit* b) const {
|
||||
// Assume same units accross files
|
||||
|
||||
return a->UnitType() < b->UnitType();
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcBuildingStorey* a, IfcSchema::IfcBuildingStorey* b) const {
|
||||
return a->Name() < b->Name();
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcCartesianPoint* a, IfcSchema::IfcCartesianPoint* b) const {
|
||||
return a->Coordinates() < b->Coordinates();
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcDirection* a, IfcSchema::IfcDirection* b) const {
|
||||
return a->DirectionRatios() < b->DirectionRatios();
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcAxis2Placement3D* a, IfcSchema::IfcAxis2Placement3D* b) const {
|
||||
if (a->Location()->Coordinates() != b->Location()->Coordinates()) {
|
||||
return (*this)(a->Location(), b->Location());
|
||||
}
|
||||
if (b->hasAxis()) {
|
||||
if (!a->hasAxis()) {
|
||||
return true;
|
||||
} else {
|
||||
return (*this)(a->Axis(), b->Axis());
|
||||
}
|
||||
}
|
||||
if (b->hasRefDirection()) {
|
||||
if (!a->hasRefDirection()) {
|
||||
return true;
|
||||
} else {
|
||||
return (*this)(a->RefDirection(), b->RefDirection());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcLocalPlacement* a, IfcSchema::IfcLocalPlacement* b) const {
|
||||
if (b->hasPlacementRelTo()) {
|
||||
if (!a->hasPlacementRelTo()) {
|
||||
return true;
|
||||
} else {
|
||||
return (*this)(a->PlacementRelTo(), b->PlacementRelTo());
|
||||
}
|
||||
}
|
||||
return (*this)(a->RelativePlacement(), b->RelativePlacement());
|
||||
}
|
||||
|
||||
bool operator()(IfcUtil::IfcBaseClass* a, IfcUtil::IfcBaseClass* b) const {
|
||||
if (a->declaration().type() != b->declaration().type()) {
|
||||
return a->declaration().type() < b->declaration().type();
|
||||
// throw std::runtime_error("Types not matching");
|
||||
}
|
||||
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcSite) { return (*this)((IfcSchema::IfcSite*) a, (IfcSchema::IfcSite*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcConversionBasedUnit) { return (*this)((IfcSchema::IfcConversionBasedUnit*) a, (IfcSchema::IfcConversionBasedUnit*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcDimensionalExponents) { return (*this)((IfcSchema::IfcDimensionalExponents*) a, (IfcSchema::IfcDimensionalExponents*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcMeasureWithUnit) { return (*this)((IfcSchema::IfcMeasureWithUnit*) a, (IfcSchema::IfcMeasureWithUnit*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcProject) { return (*this)((IfcSchema::IfcProject*) a, (IfcSchema::IfcProject*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcBuilding) { return (*this)((IfcSchema::IfcBuilding*) a, (IfcSchema::IfcBuilding*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcPostalAddress) { return (*this)((IfcSchema::IfcPostalAddress*) a, (IfcSchema::IfcPostalAddress*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcUnitAssignment) { return (*this)((IfcSchema::IfcUnitAssignment*) a, (IfcSchema::IfcUnitAssignment*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcGeometricRepresentationSubContext) { return (*this)((IfcSchema::IfcGeometricRepresentationSubContext*) a, (IfcSchema::IfcGeometricRepresentationSubContext*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcGeometricRepresentationContext) { return (*this)((IfcSchema::IfcGeometricRepresentationContext*) a, (IfcSchema::IfcGeometricRepresentationContext*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcSIUnit) { return (*this)((IfcSchema::IfcSIUnit*) a, (IfcSchema::IfcSIUnit*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcBuildingStorey) { return (*this)((IfcSchema::IfcBuildingStorey*) a, (IfcSchema::IfcBuildingStorey*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcCartesianPoint) { return (*this)((IfcSchema::IfcCartesianPoint*) a, (IfcSchema::IfcCartesianPoint*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcDirection) { return (*this)((IfcSchema::IfcDirection*) a, (IfcSchema::IfcDirection*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcAxis2Placement3D) { return (*this)((IfcSchema::IfcAxis2Placement3D*) a, (IfcSchema::IfcAxis2Placement3D*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcLocalPlacement) { return (*this)((IfcSchema::IfcLocalPlacement*) a, (IfcSchema::IfcLocalPlacement*) b); }
|
||||
|
||||
// Should these be removed if an owner history is created manually?
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcPerson) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcOrganization) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcPersonAndOrganization) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcOwnerHistory) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcApplication) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
|
||||
|
||||
std::cerr << "Unexpected type: " + IfcSchema::Type::ToString(a->declaration().type()) << std::endl;
|
||||
throw std::runtime_error("Unexpected type: " + IfcSchema::Type::ToString(a->declaration().type()));
|
||||
}
|
||||
};
|
||||
|
||||
// Usage: hdf5_federate Office_A_20110811_optimized.ifc Office_S_20110811_optimized.ifc Office_MEP_20110811_optimized.ifc
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
// A set of datatypes for the shared hierarchy
|
||||
std::set<IfcSchema::Type::Enum> shared {
|
||||
IfcSchema::Type::IfcSite,
|
||||
IfcSchema::Type::IfcConversionBasedUnit,
|
||||
IfcSchema::Type::IfcDimensionalExponents,
|
||||
IfcSchema::Type::IfcMeasureWithUnit,
|
||||
IfcSchema::Type::IfcProject,
|
||||
IfcSchema::Type::IfcBuilding,
|
||||
IfcSchema::Type::IfcPostalAddress,
|
||||
IfcSchema::Type::IfcUnitAssignment,
|
||||
IfcSchema::Type::IfcGeometricRepresentationSubContext,
|
||||
IfcSchema::Type::IfcGeometricRepresentationContext,
|
||||
IfcSchema::Type::IfcSIUnit,
|
||||
IfcSchema::Type::IfcBuildingStorey
|
||||
};
|
||||
|
||||
// Open the set of input files
|
||||
std::vector<IfcParse::IfcFile*> files;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
files.push_back(new IfcParse::IfcFile());
|
||||
files.back()->Init(argv[i]);
|
||||
}
|
||||
|
||||
// Detect shared instances
|
||||
std::set<IfcUtil::IfcBaseClass*> shared_instances;
|
||||
|
||||
for (auto& ty : shared) {
|
||||
std::cout << IfcSchema::Type::ToString(ty) << std::endl;
|
||||
|
||||
for (auto& file : files) {
|
||||
IfcEntityList::ptr insts = file->entitiesByType(ty);
|
||||
std::vector<IfcUtil::IfcBaseClass*> no_subtypes;
|
||||
std::copy_if(insts->begin(), insts->end(), std::back_inserter(no_subtypes), [ty](IfcUtil::IfcBaseClass* inst) {
|
||||
return inst->declaration().type() == ty;
|
||||
});
|
||||
|
||||
std::set<IfcUtil::IfcBaseClass*, ifc_inst_cmp> insts_unique(no_subtypes.begin(), no_subtypes.end());
|
||||
|
||||
if (insts_unique.size() != no_subtypes.size()) {
|
||||
throw std::runtime_error("Non-unique instances encountered within file");
|
||||
}
|
||||
|
||||
shared_instances.insert(insts_unique.begin(), insts_unique.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Follow forward references for shared instances
|
||||
std::set<IfcUtil::IfcBaseClass*> shared_instances_and_refs;
|
||||
|
||||
for (auto& inst : shared_instances) {
|
||||
IfcEntityList::ptr insts = inst->data().file->traverse(inst);
|
||||
|
||||
// Filter out simple types
|
||||
std::vector<IfcUtil::IfcBaseClass*> insts_without_types;
|
||||
std::copy_if(insts->begin(), insts->end(), std::back_inserter(insts_without_types), [](IfcUtil::IfcBaseClass* inst) {
|
||||
return inst->declaration().as_entity() != nullptr;
|
||||
});
|
||||
|
||||
shared_instances_and_refs.insert(insts_without_types.begin(), insts_without_types.end());
|
||||
}
|
||||
|
||||
time_t now_;
|
||||
time(&now_);
|
||||
int now = (int)now_;
|
||||
|
||||
// Create a novel ownerhistory for the shared hierarchy
|
||||
IfcSchema::IfcPerson* person = new IfcSchema::IfcPerson(std::string("tfk"), std::string("Krijnen"), std::string("Thomas"), boost::none, boost::none, boost::none, boost::none, boost::none);
|
||||
IfcSchema::IfcOrganization* org = new IfcSchema::IfcOrganization(std::string("TU/e"), "Eindhoven University of Technology", boost::none, boost::none, boost::none);
|
||||
IfcSchema::IfcPersonAndOrganization* pando = new IfcSchema::IfcPersonAndOrganization(person, org, boost::none);
|
||||
IfcSchema::IfcApplication* appl = new IfcSchema::IfcApplication(org, "v1", "IfcOpenShell-HDF5", "IfcOpenShell-HDF5");
|
||||
IfcSchema::IfcOwnerHistory* owner_history = new IfcSchema::IfcOwnerHistory(pando, appl, IfcSchema::IfcStateEnum::IfcState_READONLY, IfcSchema::IfcChangeActionEnum::IfcChangeAction_ADDED, now, pando, appl, now);
|
||||
|
||||
std::vector<IfcUtil::IfcBaseClass*> replacements{ person, org, pando, appl, owner_history};
|
||||
|
||||
std::vector<IfcUtil::IfcBaseClass*> shared_instances_and_refs_vector(shared_instances_and_refs.begin(), shared_instances_and_refs.end());
|
||||
|
||||
IfcParse::IfcFile temp;
|
||||
for (int i = 0; i < 0x1000001; ++i) temp.FreshId();
|
||||
|
||||
std::for_each(replacements.begin(), replacements.end(), [&shared_instances_and_refs_vector, &temp](IfcUtil::IfcBaseClass* new_inst) {
|
||||
temp.addEntity(new_inst);
|
||||
|
||||
shared_instances_and_refs_vector.erase(
|
||||
std::remove_if(shared_instances_and_refs_vector.begin(), shared_instances_and_refs_vector.end(), [new_inst](IfcUtil::IfcBaseClass* orig_inst) {
|
||||
return orig_inst->declaration().type() == new_inst->declaration().type();
|
||||
}),
|
||||
shared_instances_and_refs_vector.end()
|
||||
);
|
||||
|
||||
shared_instances_and_refs_vector.push_back(new_inst);
|
||||
});
|
||||
|
||||
shared_instances_and_refs.clear();
|
||||
shared_instances_and_refs.insert(shared_instances_and_refs_vector.begin(), shared_instances_and_refs_vector.end());
|
||||
|
||||
// Assign the new ownerhistory to rooted elements in the shared hierarchy
|
||||
std::for_each(shared_instances_and_refs.begin(), shared_instances_and_refs.end(), [owner_history](IfcUtil::IfcBaseClass* inst) {
|
||||
const IfcParse::entity* e = inst->declaration().as_entity();
|
||||
if (e) {
|
||||
auto attributes = e->all_attributes();
|
||||
int index = 0;
|
||||
std::for_each(attributes.begin(), attributes.end(), [&index, inst, owner_history](const IfcParse::entity::attribute* attr) {
|
||||
const IfcParse::named_type* nt = attr->type_of_attribute()->as_named_type();
|
||||
if (nt) {
|
||||
const IfcParse::entity* e2 = nt->declared_type()->as_entity();
|
||||
if (e2 && e2->type() == IfcSchema::Type::IfcOwnerHistory) {
|
||||
IfcWrite::IfcWritableEntity* writable = new IfcWrite::IfcWritableEntity(&inst->data());
|
||||
writable->setArgument(index, owner_history);
|
||||
inst->data(writable);
|
||||
}
|
||||
}
|
||||
index++;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
std::set<IfcUtil::IfcBaseClass*, ifc_inst_cmp> shared_instances_and_refs_unique(shared_instances_and_refs.begin(), shared_instances_and_refs.end());
|
||||
|
||||
// Serialize models into different groups
|
||||
|
||||
IfcParse::Hdf5Settings settings;
|
||||
settings.profile() = IfcParse::Hdf5Settings::standard_referenced;
|
||||
settings.compress() = true;
|
||||
settings.chunk_size() = 1024;
|
||||
|
||||
std::vector<std::string> names;
|
||||
std::vector<std::pair<std::string::const_iterator, std::string::const_iterator>> fixes;
|
||||
std::string common_prefix, common_postfix;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
names.push_back(argv[i]);
|
||||
fixes.push_back({ names.back().begin(), names.back().end() - 1 });
|
||||
}
|
||||
|
||||
while (true) {
|
||||
std::vector<char> chars;
|
||||
std::transform(fixes.begin(), fixes.end(), std::back_inserter(chars), [](auto& pair) {
|
||||
if (pair.first == pair.second) return '\0';
|
||||
return (*pair.first++);
|
||||
});
|
||||
auto pred = std::bind(std::equal_to<char>(), std::placeholders::_1, chars.front());
|
||||
if (chars.front() != 0 && std::all_of(chars.begin()+1, chars.end(), pred)) {
|
||||
common_prefix.push_back(chars.front());
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
std::vector<char> chars;
|
||||
std::transform(fixes.begin(), fixes.end(), std::back_inserter(chars), [](auto& pair) {
|
||||
if (pair.first == pair.second) return '\0';
|
||||
return (*pair.second--);
|
||||
});
|
||||
auto pred = std::bind(std::equal_to<char>(), std::placeholders::_1, chars.front());
|
||||
if (chars.front() != 0 && std::all_of(chars.begin() + 1, chars.end(), pred)) {
|
||||
common_postfix.insert(common_postfix.begin(), chars.front());
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
H5::H5File file(common_prefix + common_postfix + ".hdf", H5F_ACC_TRUNC);
|
||||
H5::Group group1 = file.createGroup("population");
|
||||
|
||||
IfcParse::IfcHdf5File ifc_hdf5(file, get_schema(), settings);
|
||||
IfcParse::IfcSpfHeader header;
|
||||
header.set_default();
|
||||
|
||||
IfcParse::instance_enumerator shared_insts_enum(&header, shared_instances_and_refs_unique.begin(), shared_instances_and_refs_unique.end());
|
||||
|
||||
multifile_instance_locator* locator = new multifile_instance_locator(file, group1, [&shared_instances_and_refs_unique](IfcUtil::IfcBaseClass* inst) {
|
||||
auto it = shared_instances_and_refs_unique.find(inst);
|
||||
if (it == shared_instances_and_refs_unique.end()) {
|
||||
return inst;
|
||||
} else {
|
||||
return *it;
|
||||
}
|
||||
}, shared_instances_and_refs_unique.begin(), shared_instances_and_refs_unique.end());
|
||||
|
||||
ifc_hdf5.write_schema();
|
||||
ifc_hdf5.write_population(group1, shared_insts_enum, locator);
|
||||
|
||||
int n = 0;
|
||||
for (auto f : files) {
|
||||
auto filename = argv[n++ + 1];
|
||||
H5::Group discipline_group = file.createGroup(filename);
|
||||
H5::Group child_group = discipline_group.createGroup("population");
|
||||
|
||||
locator->next(filename, child_group, f);
|
||||
IfcParse::instance_enumerator inst_enum(&f->header(), locator->full_begin(), locator->full_end());
|
||||
|
||||
ifc_hdf5.write_population(child_group, inst_enum, locator);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,472 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 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 *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../../../src/ifcparse/IfcHdf5File.h"
|
||||
#include "../../../src/ifcgeom/IfcGeom.h"
|
||||
#include "../../../src/ifcparse/IfcWritableEntity.h"
|
||||
|
||||
#include <Bnd_Box.hxx>
|
||||
#include <BRepBndLib.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <TopoDS_Compound.hxx>
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
#include <BRepBuilderAPI_GTransform.hxx>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "multifile_instance_locator.h"
|
||||
|
||||
void generate_bounding_boxes(IfcParse::IfcFile& f, const std::string& fn) {
|
||||
IfcGeom::Kernel kernel;
|
||||
auto unit_factor = kernel.initializeUnits(*f.entitiesByType<IfcSchema::IfcUnitAssignment>()->begin());
|
||||
|
||||
IfcGeom::IteratorSettings settings;
|
||||
settings.convert_back_units() = true;
|
||||
settings.disable_triangulation() = true;
|
||||
settings.disable_opening_subtractions() = true;
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape::list::ptr defs_ = f.entitiesByType<IfcSchema::IfcProductDefinitionShape>();
|
||||
std::vector<IfcSchema::IfcProductDefinitionShape*> defs(defs_->begin(), defs_->end());
|
||||
// Make sure to sort by id to have new definitions lining up in the same order
|
||||
std::sort(defs.begin(), defs.end(), [](IfcSchema::IfcProductDefinitionShape* a, IfcSchema::IfcProductDefinitionShape* b) {
|
||||
return a->data().id() < b->data().id();
|
||||
});
|
||||
|
||||
std::ofstream str(fn.c_str(), std::ios_base::binary);
|
||||
|
||||
int N = defs.size(), n = 0;
|
||||
|
||||
std::cerr << "boxes:" << std::endl;
|
||||
|
||||
// In newer versions of IfcOpenShell this is a method Kernel::apply_transformation()
|
||||
auto apply_transformation = [](const TopoDS_Shape& s, const gp_GTrsf& gt) {
|
||||
if (gt.Form() == gp_Other) {
|
||||
return BRepBuilderAPI_GTransform(s, gt, true).Shape();
|
||||
}
|
||||
gp_Trsf t = gt.Trsf();
|
||||
if (t.Form() == gp_Identity) {
|
||||
return s;
|
||||
} else {
|
||||
/// @todo set to 1. and exactly 1. or use epsilon?
|
||||
if (t.ScaleFactor() != 1.) {
|
||||
return BRepBuilderAPI_Transform(s, t, true).Shape();
|
||||
} else {
|
||||
return s.Moved(t);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// In newer versions of IfcOpenShell this is a method BRep::as_compound()
|
||||
auto brep_as_compound = [&apply_transformation](const IfcGeom::Representation::BRep& brep) {
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++it) {
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
gp_GTrsf trsf = it->Placement();
|
||||
|
||||
if (brep.settings().convert_back_units()) {
|
||||
gp_Trsf scale;
|
||||
scale.SetScaleFactor(1.0 / brep.settings().unit_magnitude());
|
||||
trsf.PreMultiply(scale);
|
||||
}
|
||||
|
||||
const TopoDS_Shape moved_shape = apply_transformation(s, trsf);
|
||||
builder.Add(compound, moved_shape);
|
||||
}
|
||||
return compound;
|
||||
};
|
||||
|
||||
// Generate non-aa bounding boxes in local coordinates as a tuple of six doubles from existing IfcProductDefinitionShape instances
|
||||
std::for_each(defs.begin(), defs.end(), [&kernel, &brep_as_compound, &str, N, &n, &settings](IfcSchema::IfcProductDefinitionShape* def) {
|
||||
Bnd_Box box;
|
||||
|
||||
auto prods = def->data().getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>();
|
||||
if (prods->size() != 1) return;
|
||||
|
||||
IfcSchema::IfcProduct* prod = *prods->begin();
|
||||
|
||||
auto reps = def->Representations();
|
||||
|
||||
std::for_each(reps->begin(), reps->end(), [&kernel, &brep_as_compound, &settings, &box, prod](auto rep) {
|
||||
if (rep->RepresentationIdentifier() == "Body") {
|
||||
IfcGeom::BRepElement<double>* elem = kernel.create_brep_for_representation_and_product<double>(settings, rep, prod);
|
||||
BRepBndLib::AddClose(brep_as_compound(elem->geometry()), box);
|
||||
delete elem;
|
||||
}
|
||||
});
|
||||
|
||||
const size_t name = def->data().id();
|
||||
|
||||
double xyz[6];
|
||||
box.Get(xyz[0], xyz[1], xyz[2], xyz[3], xyz[4], xyz[5]);
|
||||
|
||||
str.write((char*)&name, sizeof(size_t));
|
||||
str.write((char*)xyz, sizeof(double) * 6);
|
||||
|
||||
if (n++ % 1000 == 0) {
|
||||
std::cerr << "\r" << n * 100 / N << std::flush;
|
||||
}
|
||||
});
|
||||
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void find_geometric_types(IfcParse::IfcFile& f, const std::string& tfn) {
|
||||
std::ofstream str(tfn.c_str(), std::ios_base::binary);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape::list::ptr defs_ = f.entitiesByType<IfcSchema::IfcProductDefinitionShape>();
|
||||
std::vector<IfcSchema::IfcProductDefinitionShape*> defs(defs_->begin(), defs_->end());
|
||||
// Make sure to sort by id to have new definitions lining up in the same order
|
||||
std::sort(defs.begin(), defs.end(), [](IfcSchema::IfcProductDefinitionShape* a, IfcSchema::IfcProductDefinitionShape* b) {
|
||||
return a->data().id() < b->data().id();
|
||||
});
|
||||
|
||||
// Initial choice of geometric types
|
||||
std::set<IfcSchema::Type::Enum> geometric_types{
|
||||
IfcSchema::Type::IfcStyledItem, IfcSchema::Type::IfcMaterialDefinitionRepresentation, IfcSchema::Type::IfcStyledRepresentation,
|
||||
IfcSchema::Type::IfcSurfaceStyleRendering, IfcSchema::Type::IfcSurfaceStyle, IfcSchema::Type::IfcPresentationLayerAssignment,
|
||||
IfcSchema::Type::IfcPresentationStyleAssignment, IfcSchema::Type::IfcColourRgb
|
||||
};
|
||||
std::set<IfcSchema::Type::Enum> other_types;
|
||||
|
||||
// Find all instances
|
||||
std::set<IfcUtil::IfcBaseClass*> geometric_instances;
|
||||
|
||||
for (auto ty : geometric_types) {
|
||||
auto insts = f.entitiesByType(ty);
|
||||
std::for_each(insts->begin(), insts->end(), [&geometric_instances](IfcUtil::IfcBaseClass* inst) {
|
||||
geometric_instances.insert(inst);
|
||||
});
|
||||
}
|
||||
|
||||
int N, n;
|
||||
|
||||
// Not referenced. Revit generates unused IfcExtrudedAreaSolids some times.
|
||||
auto repitems = f.entitiesByType(IfcSchema::Type::IfcRepresentationItem);
|
||||
std::for_each(repitems->begin(), repitems->end(), [&f, &geometric_instances](IfcUtil::IfcBaseClass* inst) {
|
||||
auto invs = f.getInverse(inst->data().id(), IfcSchema::Type::UNDEFINED, -1);
|
||||
if (invs->size() == 0) {
|
||||
auto refs = f.traverse(inst);
|
||||
std::for_each(refs->begin(), refs->end(), [&geometric_instances](IfcUtil::IfcBaseClass* inst2) {
|
||||
if (inst2->declaration().as_entity()) {
|
||||
geometric_instances.insert(inst2);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Recurse over forward attributes
|
||||
auto vist_geometric = [&f, &geometric_types, &geometric_instances, &N, &n](IfcUtil::IfcBaseEntity* def) {
|
||||
auto refs = f.traverse(def);
|
||||
geometric_instances.insert(refs->begin(), refs->end());
|
||||
std::for_each(refs->begin(), refs->end(), [&geometric_types](IfcUtil::IfcBaseClass* inst) {
|
||||
if (inst->declaration().as_entity()) {
|
||||
geometric_types.insert(inst->declaration().type());
|
||||
}
|
||||
});
|
||||
if (n++ % 1000 == 0) {
|
||||
std::cerr << "\r" << (n * 100 / N) << std::flush;
|
||||
}
|
||||
};
|
||||
|
||||
n = 0;
|
||||
N = defs.size();
|
||||
|
||||
std::for_each(defs.begin(), defs.end(), vist_geometric);
|
||||
|
||||
// Include connection geometry (e.g space boundaries) as well
|
||||
auto connection_geom = f.entitiesByType<IfcSchema::IfcConnectionGeometry>();
|
||||
|
||||
n = 0;
|
||||
N = connection_geom->size();
|
||||
|
||||
std::for_each(connection_geom->begin(), connection_geom->end(), vist_geometric);
|
||||
|
||||
// Traverse again all instances, but now to detect which geometric types are fully and only shared by geometric instances
|
||||
std::function<void(IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*)> fn;
|
||||
fn = [&f, &geometric_instances, &other_types, &fn](IfcUtil::IfcBaseClass* root, IfcUtil::IfcBaseClass* inst) {
|
||||
if (geometric_instances.find(inst) == geometric_instances.end()) {
|
||||
auto ty = inst->declaration().type();
|
||||
|
||||
other_types.insert(ty);
|
||||
auto refs = f.traverse(inst, 1);
|
||||
std::for_each(refs->begin() + 1, refs->end(), [&fn, root](IfcUtil::IfcBaseClass* inst) {
|
||||
if (inst->declaration().as_entity()) {
|
||||
fn(root, inst);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
N = std::distance(f.begin(), f.end());
|
||||
n = 0;
|
||||
|
||||
std::for_each(f.begin(), f.end(), [&fn, N, &n](const auto& pair) {
|
||||
fn(pair.second, pair.second);
|
||||
if (n++ % 1000 == 0) {
|
||||
std::cerr << "\r" << n * 100 / N << std::flush;
|
||||
}
|
||||
});
|
||||
|
||||
std::set<IfcSchema::Type::Enum> only_geometric;
|
||||
std::set_difference(geometric_types.begin(), geometric_types.end(),
|
||||
other_types.begin(), other_types.end(),
|
||||
std::inserter(only_geometric, only_geometric.begin()));
|
||||
|
||||
only_geometric.erase(IfcSchema::Type::IfcGeometricRepresentationContext);
|
||||
only_geometric.erase(IfcSchema::Type::IfcGeometricRepresentationSubContext);
|
||||
|
||||
std::cerr << "\nOnly geometric:" << std::endl;
|
||||
|
||||
for (auto ty : only_geometric) {
|
||||
std::cerr << IfcSchema::Type::ToString(ty) << std::endl;
|
||||
const size_t name = ty;
|
||||
str.write((char*)&name, sizeof(size_t));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const std::string cache_fn = argv[1] + std::string(".boxes.bin");
|
||||
const std::string types_fn = argv[1] + std::string(".types.bin");
|
||||
|
||||
if (argc == 2 && !ifstream(cache_fn).good()) {
|
||||
std::string command = std::string("\"\"") + argv[0] + "\" \"" + argv[1] + "\" -b\"";
|
||||
if (system(command.c_str()) != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc == 2 && !ifstream(types_fn).good()) {
|
||||
std::string command = std::string("\"\"") + argv[0] + "\" \"" + argv[1] + "\" -t\"";
|
||||
if (system(command.c_str()) != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
IfcParse::IfcFile f;
|
||||
f.Init(argv[1]);
|
||||
|
||||
if (argc == 3 && std::string(argv[2]) == "-b") {
|
||||
generate_bounding_boxes(f, cache_fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc == 3 && std::string(argv[2]) == "-t") {
|
||||
find_geometric_types(f, types_fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::set<IfcSchema::Type::Enum> only_geometric;
|
||||
{
|
||||
std::ifstream str(types_fn.c_str(), std::ios_base::binary);
|
||||
while (!str.eof()) {
|
||||
size_t name;
|
||||
str.read((char*)&name, sizeof(size_t));
|
||||
only_geometric.insert((IfcSchema::Type::Enum) name);
|
||||
}
|
||||
}
|
||||
|
||||
std::set<IfcSchema::Type::Enum> property_types {
|
||||
IfcSchema::Type::IfcRelDefines,
|
||||
IfcSchema::Type::IfcPropertySetDefinition,
|
||||
IfcSchema::Type::IfcTypeObject,
|
||||
IfcSchema::Type::IfcProperty,
|
||||
IfcSchema::Type::IfcPhysicalQuantity,
|
||||
IfcSchema::Type::IfcRelAssociatesClassification,
|
||||
IfcSchema::Type::IfcClassification,
|
||||
IfcSchema::Type::IfcClassificationReference,
|
||||
IfcSchema::Type::IfcRelAssociatesMaterial,
|
||||
IfcSchema::Type::IfcMaterialList,
|
||||
IfcSchema::Type::IfcMaterialLayerSetUsage,
|
||||
IfcSchema::Type::IfcMaterialLayerSet,
|
||||
IfcSchema::Type::IfcMaterialLayer,
|
||||
IfcSchema::Type::IfcMaterial
|
||||
};
|
||||
|
||||
std::vector<IfcUtil::IfcBaseClass*> new_defs, old_defs, old_prop_defs, old_geom_defs, old_box_defs, all_old_defs, all_defs;
|
||||
|
||||
std::for_each(only_geometric.begin(), only_geometric.end(), [&f, &old_geom_defs](IfcSchema::Type::Enum t) {
|
||||
auto insts = f.entitiesByType(t);
|
||||
std::for_each(insts->begin(), insts->end(), [t, &old_geom_defs](IfcUtil::IfcBaseClass* inst) {
|
||||
if (inst->declaration().type() == t) {
|
||||
old_geom_defs.push_back(inst);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
std::for_each(f.begin(), f.end(), [&only_geometric, &old_defs, &old_prop_defs, &property_types](const auto& pair) {
|
||||
IfcUtil::IfcBaseClass* inst = pair.second;
|
||||
|
||||
// This is checked the other way around to include subtypes
|
||||
bool is_property = false;
|
||||
for (auto pty : property_types) {
|
||||
if (inst->declaration().is(pty)) {
|
||||
is_property = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto ty = inst->declaration().type();
|
||||
|
||||
if (is_property) {
|
||||
old_prop_defs.push_back(inst);
|
||||
} else if (only_geometric.find(ty) == only_geometric.end()) {
|
||||
old_defs.push_back(inst);
|
||||
}
|
||||
});
|
||||
|
||||
IfcSchema::IfcRepresentationContext* context = 0;
|
||||
auto reps = (*f.entitiesByType<IfcSchema::IfcProductDefinitionShape>()->begin())->Representations();
|
||||
std::for_each(reps->begin(), reps->end(), [&context](auto rep) {
|
||||
IfcGeom::IfcRepresentationShapeItems items;
|
||||
if (rep->RepresentationIdentifier() == "Body") {
|
||||
context = rep->ContextOfItems();
|
||||
}
|
||||
});
|
||||
|
||||
auto id = f.FreshId();
|
||||
int num_points_added = 0;
|
||||
|
||||
// Create bounding box representation from the 6-tuple definitions
|
||||
{
|
||||
std::ifstream str(cache_fn.c_str(), std::ios_base::binary);
|
||||
while (!str.eof()) {
|
||||
size_t name;
|
||||
double xyz[6];
|
||||
|
||||
str.read((char*)&name, sizeof(size_t));
|
||||
str.read((char*)xyz, sizeof(double) * 6);
|
||||
|
||||
IfcSchema::IfcCartesianPoint* corner = new IfcSchema::IfcCartesianPoint(std::vector<double>{xyz[0], xyz[1], xyz[2]});;
|
||||
IfcSchema::IfcBoundingBox* bbox = new IfcSchema::IfcBoundingBox(corner, xyz[3] - xyz[0], xyz[4] - xyz[1], xyz[5] - xyz[2]);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
|
||||
items->push(bbox);
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(context, std::string("Body"), std::string("BoundingBox"), items);
|
||||
IfcSchema::IfcRepresentation::list::ptr new_reps(new IfcSchema::IfcRepresentation::list);
|
||||
new_reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* new_def = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, new_reps);
|
||||
|
||||
corner->data().isWritable()->setId(id++);
|
||||
|
||||
// NB: Corner is added to existing definitions
|
||||
old_defs.push_back(corner); ++num_points_added;
|
||||
new_defs.push_back(bbox);
|
||||
new_defs.push_back(rep);
|
||||
new_defs.push_back(new_def);
|
||||
}
|
||||
}
|
||||
|
||||
std::for_each(new_defs.begin(), new_defs.end(), [&id](auto new_def) {
|
||||
new_def->data().isWritable()->setId(id++);
|
||||
});
|
||||
|
||||
auto iden = [](IfcUtil::IfcBaseClass* inst) { return inst; };
|
||||
|
||||
std::set<IfcSchema::Type::Enum> old_new_geom_types;
|
||||
|
||||
std::vector<std::vector<IfcUtil::IfcBaseClass*>*> all_vectors = std::vector<std::vector<IfcUtil::IfcBaseClass*>*>{ &new_defs, &old_prop_defs, &old_defs, &old_geom_defs };
|
||||
for (auto vec_ : all_vectors) {
|
||||
auto& vec = *vec_;
|
||||
for (auto& inst : vec) {
|
||||
old_new_geom_types.insert(inst->declaration().type());
|
||||
}
|
||||
}
|
||||
|
||||
// Generate proper buckets of data and serialize
|
||||
|
||||
all_old_defs.insert(all_old_defs.end(), old_defs.begin(), old_defs.end());
|
||||
all_old_defs.insert(all_old_defs.end(), old_prop_defs.begin(), old_prop_defs.end());
|
||||
all_old_defs.insert(all_old_defs.end(), old_geom_defs.begin(), old_geom_defs.end());
|
||||
all_defs.insert(all_defs.end(), all_old_defs.begin(), all_old_defs.end());
|
||||
all_defs.insert(all_defs.end(), new_defs.begin(), new_defs.end());
|
||||
old_box_defs.insert(old_box_defs.end(), old_defs.begin(), old_defs.end());
|
||||
old_box_defs.insert(old_box_defs.end(), new_defs.begin(), new_defs.end());
|
||||
auto contexts = f.entitiesByType<IfcSchema::IfcRepresentationContext>();
|
||||
old_box_defs.insert(old_box_defs.end(), contexts->begin(), contexts->end());
|
||||
|
||||
{
|
||||
int num_insts1 = std::distance(all_old_defs.begin(), all_old_defs.end());
|
||||
int num_insts2 = std::distance(f.begin(), f.end());
|
||||
if ((num_insts1 - num_points_added) != num_insts2) {
|
||||
std::cerr << "Missign instances " << num_insts1 << " - " << num_points_added << " != " << num_insts2 << std::endl;
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
multifile_instance_locator* locator = new multifile_instance_locator(
|
||||
old_new_geom_types.begin(), old_new_geom_types.end(),
|
||||
all_old_defs.begin(), all_old_defs.end());
|
||||
|
||||
IfcParse::Hdf5Settings settings;
|
||||
settings.profile() = IfcParse::Hdf5Settings::padded;
|
||||
settings.compress() = true;
|
||||
settings.chunk_size() = 1024;
|
||||
|
||||
H5::H5File hdf(argv[1] + std::string(".hdf"), H5F_ACC_TRUNC);
|
||||
H5::H5File geom_hdf(argv[1] + std::string("-geometry.hdf"), H5F_ACC_TRUNC);
|
||||
H5::H5File box_hdf(argv[1] + std::string("-bounding-boxes.hdf"), H5F_ACC_TRUNC);
|
||||
H5::H5File prop_hdf(argv[1] + std::string("-properties.hdf"), H5F_ACC_TRUNC);
|
||||
|
||||
hdf.createGroup("geometry").close();
|
||||
hdf.createGroup("bounding-boxes").close();
|
||||
hdf.createGroup("properties").close();
|
||||
|
||||
hdf.mount("geometry", geom_hdf, H5::PropList::DEFAULT);
|
||||
hdf.mount("bounding-boxes", box_hdf, H5::PropList::DEFAULT);
|
||||
hdf.mount("properties", prop_hdf, H5::PropList::DEFAULT);
|
||||
|
||||
H5::Group main_population = hdf.createGroup("population");
|
||||
H5::Group geom_population = hdf.createGroup("geometry/population");
|
||||
H5::Group box_population = hdf.createGroup("bounding-boxes/population");
|
||||
H5::Group prop_population = hdf.createGroup("properties/population");
|
||||
|
||||
{
|
||||
IfcParse::IfcHdf5File ifc_hdf5(hdf, get_schema(), settings);
|
||||
IfcParse::instance_categorizer categorizer(all_defs.begin(), all_defs.end());
|
||||
ifc_hdf5.write_schema(&categorizer);
|
||||
|
||||
{
|
||||
IfcParse::instance_enumerator enumerator(&f.header(), old_defs.begin(), old_defs.end());
|
||||
ifc_hdf5.write_population(main_population, enumerator, locator);
|
||||
}
|
||||
|
||||
{
|
||||
IfcParse::instance_enumerator enumerator(&f.header(), old_geom_defs.begin(), old_geom_defs.end());
|
||||
ifc_hdf5.write_population(geom_population, enumerator, locator);
|
||||
}
|
||||
|
||||
{
|
||||
IfcParse::instance_enumerator enumerator(&f.header(), old_prop_defs.begin(), old_prop_defs.end());
|
||||
ifc_hdf5.write_population(prop_population, enumerator, locator);
|
||||
}
|
||||
|
||||
{
|
||||
// locator is setup with all_old_defs, need to switch to new_defs + old_defs for the cartesian points
|
||||
// NB: also geom rep context
|
||||
locator->next(box_population, old_box_defs.begin(), old_box_defs.end());
|
||||
|
||||
IfcParse::instance_enumerator enumerator(&f.header(), new_defs.begin(), new_defs.end());
|
||||
ifc_hdf5.write_population(box_population, enumerator, locator);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 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 *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
class multifile_instance_locator : public IfcParse::abstract_instance_locator {
|
||||
public:
|
||||
typedef std::function<IfcUtil::IfcBaseClass*(IfcUtil::IfcBaseClass*)> mapping_t;
|
||||
typedef std::pair<
|
||||
std::vector<IfcSchema::Type::Enum>,
|
||||
std::vector< std::vector<IfcUtil::IfcBaseEntity*> >
|
||||
> population_t;
|
||||
typedef std::vector<IfcUtil::IfcBaseClass*>::const_iterator full_const_iterator;
|
||||
|
||||
private:
|
||||
H5::H5File* root_file_;
|
||||
|
||||
mapping_t mapping_;
|
||||
std::set<IfcUtil::IfcBaseClass*> initial_population_set_;
|
||||
std::set<IfcSchema::Type::Enum> initial_types_included_set_;
|
||||
|
||||
population_t initial_population_;
|
||||
population_t subsequent_population_;
|
||||
std::vector<IfcUtil::IfcBaseClass*> subsequent_minus_initial_;
|
||||
|
||||
H5::Group* initial_group_;
|
||||
H5::Group* subsequent_group_;
|
||||
H5::H5File* subsequent_file_;
|
||||
std::string root_;
|
||||
|
||||
public:
|
||||
|
||||
template <typename ForwardIterator>
|
||||
multifile_instance_locator(H5::H5File& root_file, H5::Group& group, mapping_t mapping, ForwardIterator b, ForwardIterator e)
|
||||
: root_file_(&root_file)
|
||||
, mapping_(mapping)
|
||||
, initial_group_(&group)
|
||||
, subsequent_group_(nullptr)
|
||||
{
|
||||
initial_population_set_.insert(b, e);
|
||||
|
||||
std::set<IfcSchema::Type::Enum> names_set;
|
||||
std::for_each(b, e, [this, &names_set](IfcUtil::IfcBaseClass* inst) {
|
||||
IfcSchema::Type::Enum ty = inst->declaration().type();
|
||||
if (names_set.find(ty) == names_set.end()) {
|
||||
initial_population_.first.push_back(ty);
|
||||
names_set.insert(ty);
|
||||
}
|
||||
});
|
||||
|
||||
std::sort(initial_population_.first.begin(), initial_population_.first.end());
|
||||
|
||||
std::for_each(this->begin(), this->end(), [this, &b, &e](IfcSchema::Type::Enum t) {
|
||||
std::vector<IfcUtil::IfcBaseEntity*> by_type;
|
||||
|
||||
std::for_each(b, e, [t,&by_type](IfcUtil::IfcBaseClass* inst) {
|
||||
if (inst->declaration().type() == t && inst->declaration().as_entity()) {
|
||||
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
|
||||
}
|
||||
});
|
||||
|
||||
std::sort(by_type.begin(), by_type.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
|
||||
return i1->data().id() < i2->data().id();
|
||||
});
|
||||
|
||||
initial_population_.second.emplace_back(by_type);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename ForwardIteratorTypes, typename ForwardIteratorInsts>
|
||||
multifile_instance_locator(ForwardIteratorTypes types_all_begin, ForwardIteratorTypes types_all_end, ForwardIteratorInsts insts_begin, ForwardIteratorInsts insts_end)
|
||||
: subsequent_group_(nullptr)
|
||||
{
|
||||
initial_population_.first.assign(types_all_begin, types_all_end);
|
||||
std::sort(initial_population_.first.begin(), initial_population_.first.end());
|
||||
|
||||
std::for_each(this->begin(), this->end(), [this, &insts_begin, &insts_end](IfcSchema::Type::Enum t) {
|
||||
std::vector<IfcUtil::IfcBaseEntity*> by_type;
|
||||
|
||||
std::for_each(insts_begin, insts_end, [t, &by_type](IfcUtil::IfcBaseClass* inst) {
|
||||
if (inst->declaration().type() == t && inst->declaration().as_entity()) {
|
||||
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
|
||||
}
|
||||
});
|
||||
|
||||
std::sort(by_type.begin(), by_type.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
|
||||
return i1->data().id() < i2->data().id();
|
||||
});
|
||||
|
||||
initial_population_.second.emplace_back(by_type);
|
||||
});
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
if (subsequent_group_) {
|
||||
return subsequent_population_.first.begin();
|
||||
} else {
|
||||
return initial_population_.first.begin();
|
||||
}
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
if (subsequent_group_) {
|
||||
return subsequent_population_.first.end();
|
||||
} else {
|
||||
return initial_population_.first.end();
|
||||
}
|
||||
}
|
||||
|
||||
full_const_iterator full_begin() const {
|
||||
return subsequent_minus_initial_.begin();
|
||||
}
|
||||
|
||||
full_const_iterator full_end() const {
|
||||
return subsequent_minus_initial_.end();
|
||||
}
|
||||
|
||||
const std::vector<IfcUtil::IfcBaseEntity*>& instances(IfcSchema::Type::Enum t) {
|
||||
if (subsequent_group_) {
|
||||
return subsequent_population_.second[std::lower_bound(begin(), end(), t) - begin()];
|
||||
} else {
|
||||
return initial_population_.second[std::lower_bound(begin(), end(), t) - begin()];
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<int, int> operator()(IfcUtil::IfcBaseClass* v) {
|
||||
if (IfcSchema::Type::IsSimple(v->declaration().type())) {
|
||||
throw std::exception("Simple type not expected here");
|
||||
}
|
||||
|
||||
IfcSchema::Type::Enum t = v->declaration().type();
|
||||
|
||||
// This remains constant for subsequent model serializations?
|
||||
auto& dataset_names = initial_population_.first;
|
||||
auto tt = std::lower_bound(dataset_names.begin(), dataset_names.end(), t);
|
||||
int a = std::distance(dataset_names.begin(), tt);
|
||||
int b;
|
||||
|
||||
const std::vector<IfcUtil::IfcBaseEntity*>& insts = instances(t);
|
||||
|
||||
auto it = std::lower_bound(insts.begin(), insts.end(), v, [](IfcUtil::IfcBaseClass* other, IfcUtil::IfcBaseClass* val) {
|
||||
// An ordering based on ID is not equivalent to an ordering based on pointer address!
|
||||
return other->data().id() < val->data().id();
|
||||
});
|
||||
|
||||
if (it == insts.end()) {
|
||||
throw std::runtime_error("Unable to find instance");
|
||||
}
|
||||
|
||||
b = std::distance(insts.begin(), it);
|
||||
|
||||
return std::make_pair(a, b);
|
||||
}
|
||||
|
||||
void make_reference(IfcUtil::IfcBaseClass* v, void*& ptr) {
|
||||
v = mapping_(v);
|
||||
IfcSchema::Type::Enum t = v->declaration().type();
|
||||
|
||||
population_t* pop;
|
||||
H5::Group* group;
|
||||
boost::optional<std::string> current_root;
|
||||
|
||||
if (initial_population_set_.find(v) != initial_population_set_.end()) {
|
||||
pop = &initial_population_;
|
||||
group = initial_group_;
|
||||
current_root = boost::none;
|
||||
} else {
|
||||
pop = &subsequent_population_;
|
||||
group = subsequent_group_;
|
||||
current_root = root_;
|
||||
}
|
||||
|
||||
int a = std::lower_bound(pop->first.begin(), pop->first.end(), t) - pop->first.begin();
|
||||
auto& vec = pop->second[a];
|
||||
|
||||
hsize_t coord = std::lower_bound(vec.begin(), vec.end(), v, [](IfcUtil::IfcBaseClass* other, IfcUtil::IfcBaseClass* val) {
|
||||
return other->data().id() < val->data().id();
|
||||
}) - vec.begin();
|
||||
|
||||
hsize_t dims = instances(v->declaration().type()).size();
|
||||
H5::DataSpace space(1, &dims);
|
||||
space.selectElements(H5S_SELECT_SET, 1, &coord);
|
||||
const std::string path = IfcSchema::Type::ToString(pop->first[a]);
|
||||
|
||||
std::string full_path = group->getObjName() + "/" + path + "_objects" + "/" + path + "_instances";
|
||||
|
||||
root_file_->reference(ptr, full_path, space);
|
||||
ptr = static_cast<uint8_t*>(ptr) + sizeof(hdset_reg_ref_t);
|
||||
}
|
||||
|
||||
template <typename ForwardIt>
|
||||
void next(H5::Group& group, ForwardIt insts_begin, ForwardIt insts_end) {
|
||||
subsequent_group_ = &group;
|
||||
|
||||
subsequent_population_.first = initial_population_.first;
|
||||
subsequent_population_.second.clear();
|
||||
|
||||
std::for_each(this->begin(), this->end(), [this, &insts_begin, &insts_end](IfcSchema::Type::Enum t) {
|
||||
std::vector<IfcUtil::IfcBaseEntity*> by_type;
|
||||
|
||||
std::for_each(insts_begin, insts_end, [t, &by_type](IfcUtil::IfcBaseClass* inst) {
|
||||
if (inst->declaration().type() == t && inst->declaration().as_entity()) {
|
||||
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
|
||||
}
|
||||
});
|
||||
|
||||
std::sort(by_type.begin(), by_type.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
|
||||
return i1->data().id() < i2->data().id();
|
||||
});
|
||||
|
||||
subsequent_population_.second.emplace_back(by_type);
|
||||
});
|
||||
}
|
||||
|
||||
void next(const std::string& name, H5::Group& group, IfcParse::IfcFile* f) {
|
||||
subsequent_group_ = &group;
|
||||
root_ = name;
|
||||
|
||||
subsequent_population_.first.clear();
|
||||
subsequent_population_.second.clear();
|
||||
subsequent_minus_initial_.clear();
|
||||
|
||||
auto f_begin = f->begin();
|
||||
auto f_end = f->end();
|
||||
|
||||
std::set<IfcSchema::Type::Enum> names_set;
|
||||
std::for_each(f_begin, f_end, [this, &names_set](auto& pair) {
|
||||
IfcUtil::IfcBaseClass* inst = mapping_(pair.second);
|
||||
if (initial_population_set_.find(inst) == initial_population_set_.end()) {
|
||||
IfcSchema::Type::Enum ty = inst->declaration().type();
|
||||
if (names_set.find(ty) == names_set.end()) {
|
||||
subsequent_population_.first.push_back(ty);
|
||||
names_set.insert(ty);
|
||||
}
|
||||
subsequent_minus_initial_.push_back(inst);
|
||||
}
|
||||
});
|
||||
|
||||
auto& names = subsequent_population_.first;
|
||||
std::sort(names.begin(), names.end());
|
||||
|
||||
auto& vecs = subsequent_population_.second;
|
||||
vecs.resize(names.size());
|
||||
|
||||
std::for_each(f_begin, f_end, [this, &names, &vecs](auto& pair) {
|
||||
IfcUtil::IfcBaseClass* inst = mapping_(pair.second);
|
||||
if (initial_population_set_.find(inst) == initial_population_set_.end() && inst->declaration().as_entity()) {
|
||||
IfcSchema::Type::Enum ty = inst->declaration().type();
|
||||
auto a = std::lower_bound(names.begin(), names.end(), ty) - names.begin();
|
||||
auto& by_type = vecs[a];
|
||||
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
|
||||
}
|
||||
});
|
||||
|
||||
std::for_each(vecs.begin(), vecs.end(), [](auto& vec) {
|
||||
std::sort(vec.begin(), vec.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
|
||||
return i1->data().id() < i2->data().id();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -66,7 +66,7 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
||||
settings = ifcopenshell_geom.settings()
|
||||
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, blender_booleans)
|
||||
iterator = ifcopenshell_geom.iterator(settings, filename)
|
||||
valid_file = iterator.findContext()
|
||||
valid_file = iterator.initialize()
|
||||
if not valid_file:
|
||||
return False
|
||||
print("Done reading file")
|
||||
|
||||
@@ -28,7 +28,7 @@ std::string collada_id(const std::string& s) {
|
||||
id.reserve(s.size());
|
||||
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
|
||||
const std::string::value_type c = *it;
|
||||
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_')) {
|
||||
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_') || ( c == '-')) {
|
||||
id.push_back(c);
|
||||
}
|
||||
}
|
||||
@@ -39,8 +39,8 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const
|
||||
COLLADASW::FloatSource source(mSW);
|
||||
source.setId(mesh_id + suffix);
|
||||
source.setArrayId(mesh_id + suffix + COLLADASW::LibraryGeometries::ARRAY_ID_SUFFIX);
|
||||
source.setAccessorStride(strlen(coords));
|
||||
source.setAccessorCount(floats.size() / 3);
|
||||
source.setAccessorStride((unsigned long)strlen(coords));
|
||||
source.setAccessorCount((unsigned long)floats.size() / 3);
|
||||
for (unsigned int i = 0; i < source.getAccessorStride(); ++i) {
|
||||
source.getParameterNameList().push_back(std::string(1, coords[i]));
|
||||
}
|
||||
@@ -51,12 +51,7 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const
|
||||
source.finish();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials) {
|
||||
// The goal of the IfcGeom::Iterator is to filter out empty geometries, but
|
||||
// since this function would crash trying to deference the material_ids in
|
||||
// that case, a hard return statement is added just in case.
|
||||
if (indices.empty()) return;
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials) {
|
||||
openMesh(mesh_id);
|
||||
|
||||
// The normals vector can be empty for example when the WELD_VERTICES setting is used.
|
||||
@@ -73,13 +68,13 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str
|
||||
vertices.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::POSITION, "#" + mesh_id + COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX));
|
||||
vertices.add();
|
||||
|
||||
std::vector<int>::const_iterator index_range_start = indices.begin();
|
||||
std::vector<int>::const_iterator index_range_start = faces.begin();
|
||||
std::vector<int>::const_iterator material_it = material_ids.begin();
|
||||
int previous_material_id = -1;
|
||||
for (std::vector<int>::const_iterator it = indices.begin(); ; it += 3) {
|
||||
for (std::vector<int>::const_iterator it = faces.begin(); !faces.empty(); it += 3) {
|
||||
const int current_material_id = *(material_it++);
|
||||
const int num_triangles = std::distance(index_range_start, it) / 3;
|
||||
if ((previous_material_id != current_material_id && num_triangles > 0) || (it == indices.end())) {
|
||||
const unsigned long num_triangles = (unsigned long)std::distance(index_range_start, it) / 3;
|
||||
if ((previous_material_id != current_material_id && num_triangles > 0) || (it == faces.end())) {
|
||||
COLLADASW::Triangles triangles(mSW);
|
||||
triangles.setMaterial(materials[previous_material_id].name());
|
||||
triangles.setCount(num_triangles);
|
||||
@@ -101,11 +96,44 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str
|
||||
index_range_start = it;
|
||||
}
|
||||
previous_material_id = current_material_id;
|
||||
if (it == indices.end()) {
|
||||
if (it == faces.end()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::set<int> faces_set (faces.begin(), faces.end());
|
||||
typedef std::vector< std::pair<int, std::vector<unsigned long> > > linelist_t;
|
||||
linelist_t linelist;
|
||||
|
||||
int num_lines = 0;
|
||||
for ( std::vector<int>::const_iterator it = edges.begin(); it != edges.end(); ++num_lines) {
|
||||
const int i1 = *(it++);
|
||||
const int i2 = *(it++);
|
||||
|
||||
if (faces_set.find(i1) != faces_set.end() || faces_set.find(i2) != faces_set.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int current_material_id = *(material_it++);
|
||||
if ((previous_material_id != current_material_id) || (num_lines == 0)) {
|
||||
linelist.resize(linelist.size() + 1);
|
||||
}
|
||||
|
||||
linelist.rbegin()->second.push_back(i1);
|
||||
linelist.rbegin()->second.push_back(i2);
|
||||
}
|
||||
|
||||
for (linelist_t::const_iterator it = linelist.begin(); it != linelist.end(); ++it) {
|
||||
COLLADASW::Lines lines(mSW);
|
||||
lines.setMaterial(materials[it->first].name());
|
||||
lines.setCount((unsigned long)it->second.size());
|
||||
int offset = 0;
|
||||
lines.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX, "#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++));
|
||||
lines.prepareToAppendValues();
|
||||
lines.appendValues(it->second);
|
||||
lines.finish();
|
||||
}
|
||||
|
||||
closeMesh();
|
||||
closeGeometry();
|
||||
}
|
||||
@@ -219,7 +247,7 @@ void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_n
|
||||
asset.add();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::write(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& _materials) {
|
||||
void ColladaSerializer::ColladaExporter::write(const std::string& unique_id, const std::string& type, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& _materials) {
|
||||
std::vector<std::string> material_references;
|
||||
for (std::vector<IfcGeom::Material>::const_iterator it = _materials.begin(); it != _materials.end(); ++it) {
|
||||
const IfcGeom::Material& material = *it;
|
||||
@@ -228,17 +256,7 @@ void ColladaSerializer::ColladaExporter::write(const std::string& guid, const st
|
||||
}
|
||||
material_references.push_back(collada_id(material.name()));
|
||||
}
|
||||
deferreds.push_back(DeferredObject(guid, name, type, obj_id, matrix, vertices, normals, indices, material_ids, _materials, material_references));
|
||||
}
|
||||
|
||||
const std::string ColladaSerializer::ColladaExporter::DeferredObject::Name() const {
|
||||
std::stringstream ss;
|
||||
if (!this->name.empty()) {
|
||||
ss << this->obj_id << "_" << this->name;
|
||||
} else {
|
||||
ss << this->guid;
|
||||
}
|
||||
return collada_id(ss.str());
|
||||
deferreds.push_back(DeferredObject(unique_id, type, matrix, vertices, normals, faces, edges, material_ids, _materials, material_references));
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::endDocument() {
|
||||
@@ -246,13 +264,13 @@ void ColladaSerializer::ColladaExporter::endDocument() {
|
||||
// only at this point all objects are written to the stream.
|
||||
materials.write();
|
||||
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
|
||||
const std::string object_name = it->Name();
|
||||
geometries.write(object_name, it->type, it->vertices, it->normals, it->indices, it->material_ids, it->materials);
|
||||
const std::string object_name = it->unique_id + "-representation";
|
||||
geometries.write(object_name, it->type, it->vertices, it->normals, it->faces, it->edges, it->material_ids, it->materials);
|
||||
}
|
||||
geometries.close();
|
||||
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
|
||||
const std::string object_name = it->Name();
|
||||
scene.add(object_name + "-instance", object_name, object_name, it->material_references, it->matrix);
|
||||
const std::string object_name = it->unique_id;
|
||||
scene.add(object_name, object_name, object_name + "-representation", it->material_references, it->matrix);
|
||||
}
|
||||
scene.write();
|
||||
stream.endDocument();
|
||||
@@ -268,7 +286,7 @@ void ColladaSerializer::writeHeader() {
|
||||
|
||||
void ColladaSerializer::write(const IfcGeom::TriangulationElement<double>* o) {
|
||||
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
|
||||
exporter.write(o->guid(), o->name(), o->type(), o->id(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.material_ids(), mesh.materials());
|
||||
exporter.write(o->unique_id(), o->type(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.edges(), mesh.material_ids(), mesh.materials());
|
||||
}
|
||||
|
||||
void ColladaSerializer::finalize() {
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
#ifndef COLLADASERIALIZER_H
|
||||
#define COLLADASERIALIZER_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4201 4512)
|
||||
#endif
|
||||
#include <COLLADASWStreamWriter.h>
|
||||
#include <COLLADASWPrimitves.h>
|
||||
#include <COLLADASWLibraryGeometries.h>
|
||||
@@ -34,6 +38,9 @@
|
||||
#include <COLLADASWLibraryMaterials.h>
|
||||
#include <COLLADASWBaseInputElement.h>
|
||||
#include <COLLADASWAsset.h>
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
@@ -41,23 +48,29 @@
|
||||
|
||||
class ColladaSerializer : public GeometrySerializer
|
||||
{
|
||||
// TODO The vast amount of implement details of ColladaSerializer could be hidden to the cpp file.
|
||||
private:
|
||||
class ColladaExporter
|
||||
{
|
||||
private:
|
||||
class ColladaGeometries : public COLLADASW::LibraryGeometries
|
||||
{
|
||||
ColladaGeometries(const ColladaGeometries&); //N/A
|
||||
ColladaGeometries& operator =(const ColladaGeometries&); //N/A
|
||||
public:
|
||||
explicit ColladaGeometries(COLLADASW::StreamWriter& stream)
|
||||
: COLLADASW::LibraryGeometries(&stream)
|
||||
{}
|
||||
void addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<double>& floats, const char* coords = "XYZ");
|
||||
void write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials);
|
||||
void write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials);
|
||||
void close();
|
||||
};
|
||||
class ColladaScene : public COLLADASW::LibraryVisualScenes
|
||||
{
|
||||
private:
|
||||
ColladaScene(const ColladaScene&); //N/A
|
||||
ColladaScene& operator =(const ColladaScene&); //N/A
|
||||
|
||||
const std::string scene_id;
|
||||
bool scene_opened;
|
||||
public:
|
||||
@@ -71,9 +84,13 @@ private:
|
||||
};
|
||||
class ColladaMaterials : public COLLADASW::LibraryMaterials
|
||||
{
|
||||
ColladaMaterials(const ColladaMaterials&); //N/A
|
||||
ColladaMaterials& operator =(const ColladaMaterials&); //N/A
|
||||
private:
|
||||
class ColladaEffects : public COLLADASW::LibraryEffects
|
||||
{
|
||||
ColladaEffects(const ColladaEffects&); //N/A
|
||||
ColladaEffects& operator =(const ColladaEffects&); //N/A
|
||||
public:
|
||||
explicit ColladaEffects(COLLADASW::StreamWriter& stream)
|
||||
: COLLADASW::LibraryEffects(&stream)
|
||||
@@ -94,31 +111,29 @@ private:
|
||||
};
|
||||
class DeferredObject {
|
||||
public:
|
||||
std::string guid, name, type;
|
||||
int obj_id;
|
||||
std::string unique_id, type;
|
||||
std::vector<double> matrix;
|
||||
std::vector<double> vertices;
|
||||
std::vector<double> normals;
|
||||
std::vector<int> indices;
|
||||
std::vector<int> faces;
|
||||
std::vector<int> edges;
|
||||
std::vector<int> material_ids;
|
||||
std::vector<IfcGeom::Material> materials;
|
||||
std::vector<std::string> material_references;
|
||||
DeferredObject(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<double>& matrix, const std::vector<double>& vertices,
|
||||
const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids,
|
||||
DeferredObject(const std::string& unique_id, const std::string& type, const std::vector<double>& matrix, const std::vector<double>& vertices,
|
||||
const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int>& material_ids,
|
||||
const std::vector<IfcGeom::Material>& materials, const std::vector<std::string>& material_references)
|
||||
: guid(guid)
|
||||
, name(name)
|
||||
: unique_id(unique_id)
|
||||
, type(type)
|
||||
, obj_id(obj_id)
|
||||
, matrix(matrix)
|
||||
, vertices(vertices)
|
||||
, normals(normals)
|
||||
, indices(indices)
|
||||
, faces(faces)
|
||||
, edges(edges)
|
||||
, material_ids(material_ids)
|
||||
, materials(materials)
|
||||
, material_references(material_references)
|
||||
{}
|
||||
const std::string Name() const;
|
||||
};
|
||||
COLLADABU::NativeString filename;
|
||||
COLLADASW::StreamWriter stream;
|
||||
@@ -136,7 +151,7 @@ private:
|
||||
std::vector<DeferredObject> deferreds;
|
||||
virtual ~ColladaExporter() {}
|
||||
void startDocument(const std::string& unit_name, float unit_magnitude);
|
||||
void write(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& materials);
|
||||
void write(const std::string& unique_id, const std::string& type, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& materials);
|
||||
void endDocument();
|
||||
};
|
||||
ColladaExporter exporter;
|
||||
@@ -150,7 +165,7 @@ public:
|
||||
bool ready();
|
||||
void writeHeader();
|
||||
void write(const IfcGeom::TriangulationElement<double>* o);
|
||||
void write(const IfcGeom::BRepElement<double>* o) {}
|
||||
void write(const IfcGeom::BRepElement<double>* /*o*/) {}
|
||||
void finalize();
|
||||
bool isTesselated() const { return true; }
|
||||
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
|
||||
|
||||
+151
-23
@@ -26,12 +26,19 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
|
||||
#define BOOST_MPL_LIMIT_LIST_SIZE 30
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <time.h>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "../ifcparse/Hdf5Settings.h"
|
||||
#include "../ifcparse/IfcHdf5File.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
@@ -40,6 +47,16 @@
|
||||
#include "../ifcconvert/StepSerializer.h"
|
||||
#include "../ifcconvert/WavefrontObjSerializer.h"
|
||||
#include "../ifcconvert/XmlSerializer.h"
|
||||
#include "../ifcconvert/SvgSerializer.h"
|
||||
|
||||
#include <IGESControl_Controller.hxx>
|
||||
#include <Standard_Version.hxx>
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
#endif
|
||||
|
||||
static std::string DEFAULT_EXTENSION = "obj";
|
||||
|
||||
void printVersion() {
|
||||
std::cerr << "IfcOpenShell IfcConvert " << IFCOPENSHELL_VERSION << std::endl;
|
||||
@@ -52,11 +69,14 @@ void printUsage(const boost::program_options::options_description& generic_optio
|
||||
<< "Converts the geometry in an IFC file into one of the following formats:" << std::endl
|
||||
<< " .obj WaveFront OBJ (a .mtl file is also created)" << std::endl;
|
||||
#ifdef WITH_OPENCOLLADA
|
||||
std::cerr << " .dae Collada Digital Assets Exchange" << std::endl;
|
||||
std::cerr << " .dae Collada Digital Asset Exchange" << std::endl;
|
||||
#endif
|
||||
std::cerr << " .stp STEP Standard for the Exchange of Product Data" << std::endl
|
||||
<< " .igs IGES Initial Graphics Exchange Specification" << std::endl
|
||||
<< " .xml XML Property definitions and decomposition tree" << std::endl
|
||||
<< " .svg SVG Scalable Vector Graphics (2d floor plan)" << std::endl
|
||||
<< " .hdf HDF5 Efficient binary IFC serialization" << std::endl
|
||||
<< " .ifc IFC-SPF Standard p21 IFC serialization" << std::endl
|
||||
<< std::endl
|
||||
<< "Command line options" << std::endl << generic_options << std::endl
|
||||
<< "Advanced options" << std::endl << geom_options << std::endl;
|
||||
@@ -86,9 +106,22 @@ int main(int argc, char** argv) {
|
||||
("input-file", boost::program_options::value<std::string>(), "input IFC file")
|
||||
("output-file", boost::program_options::value<std::string>(), "output geometry file");
|
||||
|
||||
std::string bounds, hdf5_profile;
|
||||
uint32_t hdf5_chunk_size;
|
||||
|
||||
std::vector<std::string> entity_vector;
|
||||
std::vector<std::string> hdf5_ref_attributes;
|
||||
std::vector<std::string> hdf5_mount_points;
|
||||
|
||||
boost::program_options::options_description geom_options;
|
||||
geom_options.add_options()
|
||||
("plan",
|
||||
"Specifies whether to include curves in the output result. Typically "
|
||||
"these are representations of type Plan or Axis. Excluded by default.")
|
||||
("model",
|
||||
"Specifies whether to include surfaces and solids in the output result. "
|
||||
"Typically these are representations of type Body or Facetation. "
|
||||
"Included by default.")
|
||||
("weld-vertices",
|
||||
"Specifies whether vertices are welded, meaning that the coordinates "
|
||||
"vector will only contain unique xyz-triplets. This results in a "
|
||||
@@ -108,18 +141,34 @@ int main(int argc, char** argv) {
|
||||
"This is a potentially time consuming operation, but guarantees a "
|
||||
"consistent orientation of surface normals, even if the faces are not "
|
||||
"properly oriented in the IFC file.")
|
||||
#if OCC_VERSION_HEX < 0x60900
|
||||
// In Open CASCADE version prior to 6.9.0 boolean operations with multiple
|
||||
// arguments where not introduced yet and a work-around was implemented to
|
||||
// subtract multiple openings as a single compound. This hack is obsolete
|
||||
// for newer versions of Open CASCADE.
|
||||
("merge-boolean-operands",
|
||||
"Specifies whether to merge all IfcOpeningElement operands into a single "
|
||||
"operand before applying the subtraction operation. This may "
|
||||
"introduce a performance improvement at the risk of failing, in "
|
||||
"which case the subtraction is applied one-by-one.")
|
||||
("force-ccw-face-orientation",
|
||||
"Recompute topological face normals using Newell's Method to "
|
||||
"guarantee that face vertices are defined in a Counter Clock "
|
||||
"Wise order, even if the faces are not part of a closed shell.")
|
||||
#endif
|
||||
("disable-opening-subtractions",
|
||||
"Specifies whether to disable the boolean subtraction of "
|
||||
"IfcOpeningElement Representations from their RelatingElements.")
|
||||
("bounds", boost::program_options::value<std::string>(&bounds),
|
||||
"Specifies the bounding rectangle, for example 512x512, to which the "
|
||||
"output will be scaled. Only used when converting to SVG.")
|
||||
("hdf5-profile", boost::program_options::value<std::string>(&hdf5_profile), "")
|
||||
("hdf5-compress", "")
|
||||
("hdf5-fix-cartesian-point", "")
|
||||
("hdf5-fix-global-id", "")
|
||||
("hdf5-instantiate-inverse", "")
|
||||
("hdf5-instantiate-select", "")
|
||||
("hdf5-mount", boost::program_options::value< std::vector<std::string> >(&hdf5_mount_points)->multitoken(),
|
||||
"")
|
||||
("hdf5-chunk-size", boost::program_options::value(&hdf5_chunk_size), "")
|
||||
("hdf5-ref-attributes", boost::program_options::value< std::vector<std::string> >(&hdf5_ref_attributes)->multitoken(),
|
||||
"")
|
||||
("include",
|
||||
"Specifies that the entities listed after --entities are to be included")
|
||||
("exclude",
|
||||
@@ -165,25 +214,31 @@ int main(int argc, char** argv) {
|
||||
const bool use_world_coords = vmap.count("use-world-coords") != 0;
|
||||
const bool convert_back_units = vmap.count("convert-back-units") != 0;
|
||||
const bool sew_shells = vmap.count("sew-shells") != 0;
|
||||
#if OCC_VERSION_HEX < 0x60900
|
||||
const bool merge_boolean_operands = vmap.count("merge-boolean-operands") != 0;
|
||||
const bool force_ccw_face_orientation = vmap.count("force-ccw-face-orientation") != 0;
|
||||
#endif
|
||||
const bool disable_opening_subtractions = vmap.count("disable-opening-subtractions") != 0;
|
||||
const bool include_entities = vmap.count("include") != 0;
|
||||
bool include_entities = vmap.count("include") != 0;
|
||||
const bool include_plan = vmap.count("plan") != 0;
|
||||
const bool include_model = vmap.count("model") != 0 || (!include_plan);
|
||||
boost::optional<int> bounding_width, bounding_height;
|
||||
if (vmap.count("bounds") == 1) {
|
||||
int w, h;
|
||||
if (sscanf(bounds.c_str(), "%ux%u", &w, &h) == 2) {
|
||||
bounding_width = w;
|
||||
bounding_height = h;
|
||||
} else {
|
||||
std::cerr << "[Error] Invalid use of --bounds" << std::endl;
|
||||
printUsage(generic_options, geom_options);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the set ifc types to be ignored from the command line.
|
||||
std::set<std::string> entities;
|
||||
for (std::vector<std::string>::const_iterator it = entity_vector.begin(); it != entity_vector.end(); ++it) {
|
||||
std::string lowercase_type = *it;
|
||||
for (std::string::iterator c = lowercase_type.begin(); c != lowercase_type.end(); ++c) {
|
||||
*c = tolower(*c);
|
||||
}
|
||||
entities.insert(lowercase_type);
|
||||
}
|
||||
|
||||
// If no entities are specified these are the defaults to skip from output
|
||||
if (entity_vector.empty()) {
|
||||
entities.insert("ifcopeningelement");
|
||||
entities.insert("ifcspace");
|
||||
const std::string& mixed_case_type = *it;
|
||||
entities.insert(boost::to_lower_copy(mixed_case_type));
|
||||
}
|
||||
|
||||
const std::string input_filename = vmap["input-file"].as<std::string>();
|
||||
@@ -191,7 +246,7 @@ int main(int argc, char** argv) {
|
||||
// to maintain backwards compatibility with the obsolete IfcObj executable.
|
||||
const std::string output_filename = vmap.count("output-file") == 1
|
||||
? vmap["output-file"].as<std::string>()
|
||||
: change_extension(input_filename, "obj");
|
||||
: change_extension(input_filename, DEFAULT_EXTENSION);
|
||||
|
||||
if (output_filename.size() < 5) {
|
||||
printUsage(generic_options, geom_options);
|
||||
@@ -199,8 +254,17 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
std::string output_extension = output_filename.substr(output_filename.size()-4);
|
||||
for (std::string::iterator c = output_extension.begin(); c != output_extension.end(); ++c) {
|
||||
*c = tolower(*c);
|
||||
boost::to_lower(output_extension);
|
||||
|
||||
// If no entities are specified these are the defaults to skip from output
|
||||
if (entity_vector.empty()) {
|
||||
if (output_extension == ".svg") {
|
||||
entities.insert("ifcspace");
|
||||
include_entities = true;
|
||||
} else {
|
||||
entities.insert("ifcopeningelement");
|
||||
entities.insert("ifcspace");
|
||||
}
|
||||
}
|
||||
|
||||
Logger::SetOutput(&std::cout, &log_stream);
|
||||
@@ -221,6 +285,56 @@ int main(int argc, char** argv) {
|
||||
} catch (...) {}
|
||||
write_log();
|
||||
return exit_code;
|
||||
} else if (output_extension == ".hdf") {
|
||||
int exit_code = 1;
|
||||
// try {
|
||||
IfcParse::IfcFile f;
|
||||
if (!f.Init(input_filename)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file");
|
||||
} else {
|
||||
IfcParse::Hdf5Settings settings;
|
||||
settings.compress() = vmap.count("hdf5-compress") != 0;
|
||||
settings.fix_cartesian_point() = vmap.count("hdf5-fix-cartesian-point") != 0;
|
||||
settings.fix_global_id() = vmap.count("hdf5-fix-global-id") != 0;
|
||||
settings.instantiate_inverse() = vmap.count("hdf5-instantiate-inverse") != 0;
|
||||
settings.instantiate_select() = vmap.count("hdf5-instantiate-select") != 0;
|
||||
std::sort(hdf5_ref_attributes.begin(), hdf5_ref_attributes.end());
|
||||
settings.ref_attributes() = hdf5_ref_attributes;
|
||||
if (vmap.count("hdf5-chunk-size") == 1) {
|
||||
settings.chunk_size() = hdf5_chunk_size;
|
||||
}
|
||||
if (vmap.count("hdf5-profile") == 1) {
|
||||
settings.profile() = IfcParse::Hdf5Settings::ProfileFromString(hdf5_profile);
|
||||
}
|
||||
f.write_hdf5(output_filename, settings);
|
||||
exit_code = 0;
|
||||
}
|
||||
// } catch (...) {}
|
||||
write_log();
|
||||
// std::cin.get();
|
||||
return exit_code;
|
||||
} else if (output_extension == ".ifc") {
|
||||
bool success = false;
|
||||
const std::string input_extension = input_filename.substr(input_filename.size() - 4);
|
||||
if (input_extension == ".ifc") {
|
||||
IfcParse::IfcFile f;
|
||||
if (f.Init(input_filename)) {
|
||||
std::ofstream of(output_filename.c_str());
|
||||
of << f;
|
||||
success = true;
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file");
|
||||
}
|
||||
} else if (input_extension == ".hdf") {
|
||||
std::ofstream fs(output_filename.c_str());
|
||||
IfcParse::IfcHdf5File::convert_to_spf(input_filename, fs, hdf5_mount_points);
|
||||
success = true;
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unknown input extension");
|
||||
}
|
||||
|
||||
write_log();
|
||||
return success ? 0 : 1;
|
||||
}
|
||||
|
||||
IfcGeom::IteratorSettings settings;
|
||||
@@ -230,9 +344,12 @@ int main(int argc, char** argv) {
|
||||
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, weld_vertices);
|
||||
settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, sew_shells);
|
||||
settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, convert_back_units);
|
||||
#if OCC_VERSION_HEX < 0x60900
|
||||
settings.set(IfcGeom::IteratorSettings::FASTER_BOOLEANS, merge_boolean_operands);
|
||||
settings.set(IfcGeom::IteratorSettings::FORCE_CCW_FACE_ORIENTATION, force_ccw_face_orientation);
|
||||
#endif
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, disable_opening_subtractions);
|
||||
settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, include_plan);
|
||||
settings.set(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES, !include_model);
|
||||
|
||||
GeometrySerializer* serializer;
|
||||
if (output_extension == ".obj") {
|
||||
@@ -253,6 +370,15 @@ int main(int argc, char** argv) {
|
||||
// See: http://tracker.dev.opencascade.org/view.php?id=23679
|
||||
IGESControl_Controller::Init();
|
||||
serializer = new IgesSerializer(output_filename);
|
||||
} else if (output_extension == ".svg") {
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
|
||||
serializer = new SvgSerializer(output_filename);
|
||||
if (bounding_width && bounding_height) {
|
||||
((SvgSerializer*) serializer)->setBoundingRectangle(
|
||||
static_cast<double>(*bounding_width),
|
||||
static_cast<double>(*bounding_height)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unknown output filename extension");
|
||||
write_log();
|
||||
@@ -289,12 +415,14 @@ int main(int argc, char** argv) {
|
||||
time_t start,end;
|
||||
time(&start);
|
||||
|
||||
if (!context_iterator.findContext()) {
|
||||
if (!context_iterator.initialize()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file or no geometrical entities found");
|
||||
write_log();
|
||||
return 1;
|
||||
}
|
||||
|
||||
serializer->setFile(context_iterator.getFile());
|
||||
|
||||
if (convert_back_units) {
|
||||
serializer->setUnitNameAndMagnitude(context_iterator.getUnitName(), static_cast<const float>(context_iterator.getUnitMagnitude()));
|
||||
} else {
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#ifndef IGESSERIALIZER_H
|
||||
#define IGESSERIALIZER_H
|
||||
|
||||
#include <IGESControl_Controller.hxx>
|
||||
#include <IGESControl_Writer.hxx>
|
||||
#include <Interface_Static.hxx>
|
||||
|
||||
@@ -43,9 +42,10 @@ public:
|
||||
void finalize() {
|
||||
writer.Write(out_filename.c_str());
|
||||
}
|
||||
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
|
||||
void setUnitNameAndMagnitude(const std::string& /*name*/, float magnitude) {
|
||||
const char* symbol = getSymbolForUnitMagnitude(magnitude);
|
||||
if (symbol) {
|
||||
Interface_Static::SetCVal("xstep.cascade.unit", symbol);
|
||||
Interface_Static::SetCVal("write.iges.unit", symbol);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,20 +40,14 @@ void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement<double>* o) {
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) {
|
||||
gp_GTrsf gtrsf = it->Placement();
|
||||
|
||||
const std::vector<double>& matrix = o->transformation().matrix().data();
|
||||
|
||||
// Convert the matrix back into a transformation object. The tolerance values
|
||||
// are taken into consideration to reconstruct the form of the transformation.
|
||||
gp_Trsf o_trsf;
|
||||
o_trsf.SetValues(
|
||||
matrix[0], matrix[3], matrix[6], matrix[ 9],
|
||||
matrix[1], matrix[4], matrix[7], matrix[10],
|
||||
matrix[2], matrix[5], matrix[8], matrix[11]
|
||||
#if OCC_VERSION_HEX < 0x60800
|
||||
, Precision::Angular(), Precision::Confusion()
|
||||
#endif
|
||||
);
|
||||
const gp_Trsf& o_trsf = o->transformation().data();
|
||||
gtrsf.PreMultiply(o_trsf);
|
||||
|
||||
if (o->geometry().settings().convert_back_units()) {
|
||||
gp_Trsf scale;
|
||||
scale.SetScaleFactor(1.0 / o->geometry().settings().unit_magnitude());
|
||||
gtrsf.PreMultiply(scale);
|
||||
}
|
||||
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
|
||||
|
||||
@@ -25,8 +25,10 @@
|
||||
#include "../ifcconvert/GeometrySerializer.h"
|
||||
|
||||
class OpenCascadeBasedSerializer : public GeometrySerializer {
|
||||
OpenCascadeBasedSerializer(const OpenCascadeBasedSerializer&); //N/A
|
||||
OpenCascadeBasedSerializer& operator =(const OpenCascadeBasedSerializer&); //N/A
|
||||
protected:
|
||||
const std::string& out_filename;
|
||||
const std::string out_filename;
|
||||
const char* getSymbolForUnitMagnitude(float mag);
|
||||
public:
|
||||
explicit OpenCascadeBasedSerializer(const std::string& out_filename)
|
||||
@@ -35,10 +37,9 @@ public:
|
||||
{}
|
||||
virtual ~OpenCascadeBasedSerializer() {}
|
||||
void writeHeader() {}
|
||||
void writeMaterial(const IfcGeom::SurfaceStyle& style) {}
|
||||
bool ready();
|
||||
virtual void writeShape(const TopoDS_Shape& shape) = 0;
|
||||
void write(const IfcGeom::TriangulationElement<double>* o) {}
|
||||
void write(const IfcGeom::TriangulationElement<double>* /*o*/) {}
|
||||
void write(const IfcGeom::BRepElement<double>* o);
|
||||
bool isTesselated() const { return false; }
|
||||
void setFile(IfcParse::IfcFile*) {}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#ifndef STEPSERIALIZER_H
|
||||
#define STEPSERIALIZER_H
|
||||
|
||||
#include <STEPControl_Controller.hxx>
|
||||
#include <STEPControl_Writer.hxx>
|
||||
#include <Interface_Static.hxx>
|
||||
|
||||
@@ -49,9 +48,10 @@ public:
|
||||
writer.Write(out_filename.c_str());
|
||||
std::cout.rdbuf(sb);
|
||||
}
|
||||
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
|
||||
void setUnitNameAndMagnitude(const std::string& /*name*/, float magnitude) {
|
||||
const char* symbol = getSymbolForUnitMagnitude(magnitude);
|
||||
if (symbol) {
|
||||
Interface_Static::SetCVal("xstep.cascade.unit", symbol);
|
||||
Interface_Static::SetCVal("write.step.unit", symbol);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 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 *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file defines default materials for several IFC datatypes *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef SURFACESTYLE_H
|
||||
#define SURFACESTYLE_H
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <array>
|
||||
|
||||
class SurfaceStyle {
|
||||
public:
|
||||
class ColorComponent {
|
||||
private:
|
||||
std::array<double, 3> data;
|
||||
public:
|
||||
ColorComponent(double r, double g, double b) {
|
||||
data[0] = r; data[1] = g; data[2] = b;
|
||||
}
|
||||
const double& R() const { return data[0]; }
|
||||
const double& G() const { return data[1]; }
|
||||
const double& B() const { return data[2]; }
|
||||
double& R() { return data[0]; }
|
||||
double& G() { return data[1]; }
|
||||
double& B() { return data[2]; }
|
||||
};
|
||||
private:
|
||||
std::string name;
|
||||
ColorComponent diffuse, specular, ambient;
|
||||
double transparency;
|
||||
double specularity;
|
||||
public:
|
||||
SurfaceStyle(const std::string& name,
|
||||
double dr = 0.7, double dg = 0.7, double db = 0.7,
|
||||
double sr = 0.2, double sg = 0.2, double sb = 0.2,
|
||||
double ar = 0.1, double ag = 0.1, double ab = 0.1,
|
||||
double Ns = 10.0, double Tr = 1.0)
|
||||
: name(name)
|
||||
, diffuse(dr, dg, db)
|
||||
, specular(sr, sg, sb)
|
||||
, ambient(ar, ag, ab)
|
||||
, transparency(Tr)
|
||||
, specularity(Ns)
|
||||
{}
|
||||
const std::string& Name() const { return name; }
|
||||
const ColorComponent& Diffuse() const { return diffuse; }
|
||||
const ColorComponent& Specular() const { return specular; }
|
||||
const ColorComponent& Ambient() const { return ambient; }
|
||||
double Transparency() const { return transparency; }
|
||||
double Specularity() const { return specularity; }
|
||||
};
|
||||
|
||||
SurfaceStyle GetDefaultMaterial(const std::string& s);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,355 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Copyright 2015 IfcOpenShell and ROOT B.V. *
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 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 *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
|
||||
#include <gp_Pln.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
#include <BRepBuilderAPI_GTransform.hxx>
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepAlgo_Section.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <BRepAlgoAPI_Section.hxx>
|
||||
#include <ShapeAnalysis_FreeBounds.hxx>
|
||||
#include <TopTools_HSequenceOfShape.hxx>
|
||||
|
||||
#include <Geom_Curve.hxx>
|
||||
#include <Geom_Line.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include <gp_Ax22d.hxx>
|
||||
#include <Standard_Version.hxx>
|
||||
#include "../ifcparse/IfcGlobalId.h"
|
||||
|
||||
#include "SvgSerializer.h"
|
||||
|
||||
const double PI2 = M_PI * 2.;
|
||||
|
||||
bool SvgSerializer::ready() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void SvgSerializer::write(path_object& p, const TopoDS_Wire& wire) {
|
||||
/* ShapeFix_Wire fix;
|
||||
Handle(ShapeExtend_WireData) data = new ShapeExtend_WireData;
|
||||
for (TopExp_Explorer edges(result, TopAbs_EDGE); edges.More(); edges.Next()) {
|
||||
data->Add(edges.Current());
|
||||
}
|
||||
fix.Load(data);
|
||||
fix.FixReorder();
|
||||
fix.FixConnected();
|
||||
const TopoDS_Wire fixed_wire = fix.Wire(); */
|
||||
|
||||
bool first = true;
|
||||
util::string_buffer path;
|
||||
path.add(" <path style=\"stroke:black; fill:none;\" d=\"");
|
||||
for (TopExp_Explorer edges(wire, TopAbs_EDGE); edges.More(); edges.Next()) {
|
||||
const TopoDS_Edge& edge = TopoDS::Edge(edges.Current());
|
||||
|
||||
double u1, u2;
|
||||
Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, u1, u2);
|
||||
|
||||
const bool reversed = edge.Orientation() == TopAbs_REVERSED;
|
||||
|
||||
gp_Pnt p1, p2;
|
||||
curve->D0(u1, p1);
|
||||
curve->D0(u2, p2);
|
||||
|
||||
if (reversed) {
|
||||
std::swap(p1, p2);
|
||||
}
|
||||
|
||||
if (first) {
|
||||
path.add("M");
|
||||
addXCoordinate(path.add(p1.X()));
|
||||
path.add(",");
|
||||
addYCoordinate(path.add(p1.Y()));
|
||||
|
||||
growBoundingBox(p1.X(), p1.Y());
|
||||
}
|
||||
|
||||
growBoundingBox(p2.X(), p2.Y());
|
||||
|
||||
Handle(Standard_Type) ty = curve->DynamicType();
|
||||
|
||||
if (ty == STANDARD_TYPE(Geom_Circle) || ty == STANDARD_TYPE(Geom_Ellipse)) {
|
||||
Handle(Geom_Conic) conic = Handle(Geom_Conic)::DownCast(curve);
|
||||
const bool mirrored = conic->Position().Axis().Direction().Z() < 0;
|
||||
|
||||
double r1, r2;
|
||||
bool larger_arc_segment = (fmod(u2 - u1 + PI2, PI2) > M_PI);
|
||||
bool positive_direction = (u2 > u1);
|
||||
|
||||
if (mirrored != reversed) {
|
||||
// In case the local coordinate system is mirrored
|
||||
// the direction is reversed.
|
||||
positive_direction = !positive_direction;
|
||||
}
|
||||
|
||||
if (ty == STANDARD_TYPE(Geom_Circle)) {
|
||||
Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(curve);
|
||||
r1 = r2 = circle->Radius();
|
||||
} else {
|
||||
Handle(Geom_Ellipse) ellipse = Handle(Geom_Ellipse)::DownCast(curve);
|
||||
r1 = ellipse->MajorRadius();
|
||||
r2 = ellipse->MinorRadius();
|
||||
}
|
||||
|
||||
// Calculate the angle between 2d vecs to have signed result
|
||||
const gp_Dir& d = conic->Position().XDirection();
|
||||
const gp_Dir2d d2(d.X(), d.Y());
|
||||
const double ang = d2.Angle(gp::DX2d());
|
||||
|
||||
// Write radii
|
||||
path.add(" A");
|
||||
addSizeComponent(path.add(r1));
|
||||
path.add(",");
|
||||
addSizeComponent(path.add(r2));
|
||||
|
||||
// Write X-axis rotation
|
||||
{ std::stringstream ss; ss << " " << ang << " ";
|
||||
path.add(ss.str()); }
|
||||
|
||||
// Write large-arc-flag and sweep-flag
|
||||
path.add(std::string(1, '0'+static_cast<int>(larger_arc_segment)));
|
||||
path.add(",");
|
||||
path.add(std::string(1, '0'+static_cast<int>(positive_direction)));
|
||||
|
||||
path.add(" ");
|
||||
|
||||
// Write arc end point
|
||||
xcoords.push_back(path.add(p2.X()));
|
||||
path.add(",");
|
||||
ycoords.push_back(path.add(p2.Y()));
|
||||
} else {
|
||||
// Either a Geom_Line or something unimplemented,
|
||||
// drawn as a straight line segment.
|
||||
path.add(" L");
|
||||
xcoords.push_back(path.add(p2.X()));
|
||||
path.add(",");
|
||||
ycoords.push_back(path.add(p2.Y()));
|
||||
}
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
path.add("\"/>\n");
|
||||
p.second.push_back(path);
|
||||
}
|
||||
|
||||
SvgSerializer::path_object& SvgSerializer::start_path(IfcSchema::IfcBuildingStorey* storey, const std::string& id) {
|
||||
SvgSerializer::path_object& p = paths.insert(std::make_pair(storey, path_object()))->second;
|
||||
p.first = id;
|
||||
return p;
|
||||
}
|
||||
|
||||
void SvgSerializer::write(const IfcGeom::BRepElement<double>* o) {
|
||||
IfcSchema::IfcBuildingStorey* storey = 0;
|
||||
IfcSchema::IfcObjectDefinition* obdef = static_cast<IfcSchema::IfcObjectDefinition*>(file->entityById(o->id()));
|
||||
|
||||
#ifndef USE_IFC4
|
||||
typedef IfcSchema::IfcRelDecomposes decomposition_element;
|
||||
#else
|
||||
typedef IfcSchema::IfcRelAggregates decomposition_element;
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
// Iterate over the decomposing element to find the parent IfcBuildingStorey
|
||||
decomposition_element::list::ptr decomposes = obdef->Decomposes();
|
||||
if (!decomposes->size()) {
|
||||
if (obdef->declaration().is(IfcSchema::Type::IfcElement)) {
|
||||
IfcSchema::IfcRelContainedInSpatialStructure::list::ptr containment = ((IfcSchema::IfcElement*)obdef)->ContainedInStructure();
|
||||
if (!containment->size()) {
|
||||
break;
|
||||
}
|
||||
for (IfcSchema::IfcRelContainedInSpatialStructure::list::it it = containment->begin(); it != containment->end(); ++it) {
|
||||
IfcSchema::IfcRelContainedInSpatialStructure* container = *it;
|
||||
if (container->RelatingStructure() != obdef) {
|
||||
obdef = container->RelatingStructure();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
for (decomposition_element::list::it it = decomposes->begin(); it != decomposes->end(); ++it) {
|
||||
decomposition_element* decompose = *it;
|
||||
if (decompose->RelatingObject() != obdef) {
|
||||
obdef = decompose->RelatingObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (obdef->declaration().is(IfcSchema::Type::IfcBuildingStorey)) {
|
||||
storey = static_cast<IfcSchema::IfcBuildingStorey*>(obdef);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!storey) return;
|
||||
|
||||
path_object& p = start_path(storey, nameElement(o));
|
||||
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) {
|
||||
gp_GTrsf gtrsf = it->Placement();
|
||||
|
||||
const gp_Trsf& o_trsf = o->transformation().data();
|
||||
gtrsf.PreMultiply(o_trsf);
|
||||
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
|
||||
bool trsf_valid = false;
|
||||
gp_Trsf trsf;
|
||||
try {
|
||||
trsf = gtrsf.Trsf();
|
||||
trsf_valid = true;
|
||||
} catch (...) {}
|
||||
|
||||
const TopoDS_Shape moved_shape = trsf_valid
|
||||
? BRepBuilderAPI_Transform(s, trsf, true).Shape()
|
||||
: BRepBuilderAPI_GTransform(s, gtrsf, true).Shape();
|
||||
|
||||
const double inf = std::numeric_limits<double>::infinity();
|
||||
double zmin = inf;
|
||||
double zmax = -inf;
|
||||
{TopExp_Explorer exp(moved_shape, TopAbs_VERTEX);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
const TopoDS_Vertex& vertex = TopoDS::Vertex(exp.Current());
|
||||
gp_Pnt pnt = BRep_Tool::Pnt(vertex);
|
||||
if (pnt.Z() < zmin) { zmin = pnt.Z(); }
|
||||
if (pnt.Z() > zmax) { zmax = pnt.Z(); }
|
||||
}}
|
||||
|
||||
if (section_height) {
|
||||
if (zmin > section_height || zmax < section_height) continue;
|
||||
} else {
|
||||
if (zmin == inf || (zmax - zmin) < 1.) continue;
|
||||
}
|
||||
|
||||
const double cut_z = section_height.get_value_or(zmin + 1.);
|
||||
|
||||
// Create a horizontal cross section 1 meter above the bottom point of the shape
|
||||
TopoDS_Shape result = BRepAlgoAPI_Section(moved_shape, gp_Pln(gp_Pnt(0, 0, cut_z), gp::DZ()));
|
||||
|
||||
Handle(TopTools_HSequenceOfShape) edges = new TopTools_HSequenceOfShape();
|
||||
Handle(TopTools_HSequenceOfShape) wires = new TopTools_HSequenceOfShape();
|
||||
{TopExp_Explorer exp(result, TopAbs_EDGE);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
edges->Append(exp.Current());
|
||||
}}
|
||||
ShapeAnalysis_FreeBounds::ConnectEdgesToWires(edges, 1e-5, false, wires);
|
||||
|
||||
gp_Pnt prev;
|
||||
|
||||
for (int i = 1; i <= wires->Length(); ++i) {
|
||||
const TopoDS_Wire& wire = TopoDS::Wire(wires->Value(i));
|
||||
write(p, wire);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SvgSerializer::setBoundingRectangle(double width, double height) {
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->rescale = true;
|
||||
}
|
||||
|
||||
void SvgSerializer::finalize() {
|
||||
|
||||
if (rescale) {
|
||||
// Scale the resulting image to a bounding rectangle specified by command line arguments
|
||||
const double dx = xmax - xmin;
|
||||
const double dy = ymax - ymin;
|
||||
|
||||
double sc = 1.;
|
||||
|
||||
if (dx / width > dy / height) {
|
||||
sc = width / dx;
|
||||
} else {
|
||||
sc = height / dy;
|
||||
}
|
||||
|
||||
const double cx = xmin * sc;
|
||||
const double cy = ymin * sc;
|
||||
|
||||
{std::vector< boost::shared_ptr<util::string_buffer::float_item> >::const_iterator it;
|
||||
for (it = xcoords.begin(); it != xcoords.end(); ++it) {
|
||||
double& v = (*it)->value();
|
||||
v = v * sc - cx;
|
||||
}
|
||||
for (it = ycoords.begin(); it != ycoords.end(); ++it) {
|
||||
double& v = (*it)->value();
|
||||
v = v * sc - cy;
|
||||
}
|
||||
for (it = radii.begin(); it != radii.end(); ++it) {
|
||||
(*it)->value() *= sc;
|
||||
}}
|
||||
}
|
||||
|
||||
std::multimap<IfcSchema::IfcBuildingStorey*, path_object>::const_iterator it;
|
||||
|
||||
IfcSchema::IfcBuildingStorey* previous = 0;
|
||||
bool first = true;
|
||||
for (it = paths.begin(); it != paths.end(); ++it) {
|
||||
if (it->first != previous || first) {
|
||||
if (!first) {
|
||||
svg_file << " </g>\n";
|
||||
}
|
||||
std::ostringstream oss;
|
||||
svg_file << " <g " << nameElement(it->first) << ">\n";
|
||||
}
|
||||
svg_file << " <g " << it->second.first << ">\n";
|
||||
std::vector<util::string_buffer>::const_iterator jt;
|
||||
for (jt = it->second.second.begin(); jt != it->second.second.end(); ++jt) {
|
||||
svg_file << jt->str();
|
||||
}
|
||||
svg_file << " </g>\n";
|
||||
previous = it->first;
|
||||
first = false;
|
||||
}
|
||||
|
||||
svg_file << " </g>\n";
|
||||
svg_file << "</svg>" << std::endl;
|
||||
}
|
||||
|
||||
void SvgSerializer::writeHeader() {
|
||||
svg_file << "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n";
|
||||
}
|
||||
|
||||
std::string SvgSerializer::nameElement(const IfcGeom::Element<double>* elem) {
|
||||
std::ostringstream oss;
|
||||
const std::string type = "product";
|
||||
oss << "id=\"" << type << "-" << elem->unique_id() << "\"";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string SvgSerializer::nameElement(const IfcSchema::IfcProduct* elem) {
|
||||
std::ostringstream oss;
|
||||
const std::string type = elem->declaration().is(IfcSchema::Type::IfcBuildingStorey) ? "storey" : "product";
|
||||
oss << "id=\"product-" << IfcParse::IfcGlobalId(elem->GlobalId()).formatted() << "\"";
|
||||
return oss.str();
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Copyright 2015 IfcOpenShell and ROOT B.V. *
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 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 *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef SVGSERIALIZER_H
|
||||
#define SVGSERIALIZER_H
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <limits>
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
#include "../ifcconvert/GeometrySerializer.h"
|
||||
#include "../ifcconvert/util.h"
|
||||
|
||||
class SvgSerializer : public GeometrySerializer {
|
||||
public:
|
||||
typedef std::pair<std::string, std::vector<util::string_buffer> > path_object;
|
||||
protected:
|
||||
std::ofstream svg_file;
|
||||
double xmin, ymin, xmax, ymax, width, height;
|
||||
boost::optional<double> section_height;
|
||||
bool rescale;
|
||||
std::multimap<IfcSchema::IfcBuildingStorey*, path_object> paths;
|
||||
std::vector< boost::shared_ptr<util::string_buffer::float_item> > xcoords;
|
||||
std::vector< boost::shared_ptr<util::string_buffer::float_item> > ycoords;
|
||||
std::vector< boost::shared_ptr<util::string_buffer::float_item> > radii;
|
||||
IfcParse::IfcFile* file;
|
||||
public:
|
||||
explicit SvgSerializer(const std::string& out_filename)
|
||||
: GeometrySerializer()
|
||||
, svg_file(out_filename.c_str())
|
||||
, xmin(+std::numeric_limits<double>::infinity())
|
||||
, xmax(-std::numeric_limits<double>::infinity())
|
||||
, ymin(+std::numeric_limits<double>::infinity())
|
||||
, ymax(-std::numeric_limits<double>::infinity())
|
||||
, rescale(false)
|
||||
, file(0)
|
||||
{}
|
||||
virtual void addXCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { xcoords.push_back(fi); }
|
||||
virtual void addYCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { ycoords.push_back(fi); }
|
||||
virtual void addSizeComponent(const boost::shared_ptr<util::string_buffer::float_item>& fi) { radii.push_back(fi); }
|
||||
virtual void growBoundingBox(double x, double y) { if (x < xmin) xmin = x; if (x > xmax) xmax = x; if (y < ymin) ymin = y; if (y > ymax) ymax = y; }
|
||||
virtual ~SvgSerializer() {}
|
||||
virtual void writeHeader();
|
||||
virtual bool ready();
|
||||
virtual void write(const IfcGeom::TriangulationElement<double>* /*o*/) {}
|
||||
virtual void write(const IfcGeom::BRepElement<double>* o);
|
||||
virtual void write(path_object& p, const TopoDS_Wire& wire);
|
||||
virtual path_object& start_path(IfcSchema::IfcBuildingStorey* storey, const std::string& id);
|
||||
virtual bool isTesselated() const { return false; }
|
||||
virtual void finalize();
|
||||
virtual void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
|
||||
virtual void setFile(IfcParse::IfcFile* f) { file = f; }
|
||||
virtual void setBoundingRectangle(double width, double height);
|
||||
virtual void setSectionHeight(double h) { section_height = h; }
|
||||
virtual std::string nameElement(const IfcGeom::Element<double>* elem);
|
||||
virtual std::string nameElement(const IfcSchema::IfcProduct* elem);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -17,12 +17,13 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <limits>
|
||||
#include <iomanip>
|
||||
|
||||
#include "../ifcgeom/IfcGeomRenderStyles.h"
|
||||
|
||||
#include "WavefrontObjSerializer.h"
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
bool WaveFrontOBJSerializer::ready() {
|
||||
return obj_stream.is_open() && mtl_stream.is_open();
|
||||
}
|
||||
@@ -67,22 +68,21 @@ void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style) {
|
||||
}
|
||||
void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<double>* o) {
|
||||
|
||||
std::string tmp = o->name().empty() ? o->guid() : o->name();
|
||||
|
||||
std::replace( tmp.begin(), tmp.end(), ' ', '_');
|
||||
const std::string name = tmp;
|
||||
obj_stream << "g " << name << "\n";
|
||||
obj_stream << "g " << o->unique_id() << "\n";
|
||||
obj_stream << "s 1" << "\n";
|
||||
|
||||
obj_stream << std::setprecision(std::numeric_limits<double>::digits10);
|
||||
|
||||
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
|
||||
|
||||
const int vcount = mesh.verts().size() / 3;
|
||||
const int vcount = (int)mesh.verts().size() / 3;
|
||||
for ( std::vector<double>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) {
|
||||
const double x = *(it++);
|
||||
const double y = *(it++);
|
||||
const double z = *(it++);
|
||||
obj_stream << "v " << x << " " << y << " " << z << "\n";
|
||||
}
|
||||
|
||||
for ( std::vector<double>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) {
|
||||
const double x = *(it++);
|
||||
const double y = *(it++);
|
||||
@@ -111,6 +111,38 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<double>*
|
||||
const int v2 = *(it++)+vcount_total;
|
||||
const int v3 = *(it++)+vcount_total;
|
||||
obj_stream << "f " << v1 << "//" << v1 << " " << v2 << "//" << v2 << " " << v3 << "//" << v3 << "\n";
|
||||
|
||||
}
|
||||
vcount_total += vcount;
|
||||
|
||||
std::set<int> faces_set (mesh.faces().begin(), mesh.faces().end());
|
||||
const std::vector<int>& edges = mesh.edges();
|
||||
|
||||
for ( std::vector<int>::const_iterator it = edges.begin(); it != edges.end(); ) {
|
||||
const int i1 = *(it++);
|
||||
const int i2 = *(it++);
|
||||
|
||||
if (faces_set.find(i1) != faces_set.end() || faces_set.find(i2) != faces_set.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int material_id = *(material_it++);
|
||||
|
||||
if (material_id != previous_material_id) {
|
||||
const IfcGeom::Material& material = mesh.materials()[material_id];
|
||||
const std::string material_name = material.name();
|
||||
obj_stream << "usemtl " << material_name << "\n";
|
||||
if (materials.find(material_name) == materials.end()) {
|
||||
writeMaterial(material);
|
||||
materials.insert(material_name);
|
||||
}
|
||||
previous_material_id = material_id;
|
||||
}
|
||||
|
||||
const int v1 = i1 + vcount_total;
|
||||
const int v2 = i2 + vcount_total;
|
||||
|
||||
obj_stream << "l " << v1 << " " << v2 << "\n";
|
||||
}
|
||||
|
||||
vcount_total += vcount;
|
||||
}
|
||||
|
||||
@@ -46,10 +46,10 @@ public:
|
||||
void writeHeader();
|
||||
void writeMaterial(const IfcGeom::Material& style);
|
||||
void write(const IfcGeom::TriangulationElement<double>* o);
|
||||
void write(const IfcGeom::BRepElement<double>* o) {}
|
||||
void write(const IfcGeom::BRepElement<double>* /*o*/) {}
|
||||
void finalize() {}
|
||||
bool isTesselated() const { return true; }
|
||||
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {}
|
||||
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
|
||||
void setFile(IfcParse::IfcFile*) {}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 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 *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
@@ -7,6 +26,8 @@
|
||||
|
||||
#include "XmlSerializer.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using boost::property_tree::ptree;
|
||||
using namespace IfcSchema;
|
||||
|
||||
@@ -37,17 +58,17 @@ boost::optional<std::string> format_attribute(const Argument* argument, IfcUtil:
|
||||
stream << v;
|
||||
value = stream.str();
|
||||
break; }
|
||||
case IfcUtil::Argument_ENTITY: {
|
||||
case IfcUtil::Argument_ENTITY_INSTANCE: {
|
||||
IfcUtil::IfcBaseClass* e = *argument;
|
||||
if (Type::IsSimple(e->type())) {
|
||||
if (Type::IsSimple(e->declaration().type())) {
|
||||
IfcUtil::IfcBaseType* f = (IfcUtil::IfcBaseType*) e;
|
||||
value = format_attribute(f->getArgument(0), f->getArgumentType(0));
|
||||
} else if (e->is(IfcSchema::Type::IfcSIUnit) || e->is(IfcSchema::Type::IfcConversionBasedUnit)) {
|
||||
value = format_attribute(f->data().getArgument(0), f->data().getArgument(0)->type());
|
||||
} else if (e->declaration().is(IfcSchema::Type::IfcSIUnit) || e->declaration().is(IfcSchema::Type::IfcConversionBasedUnit)) {
|
||||
// Some string concatenation to have a unit name as a XML attribute.
|
||||
|
||||
std::string unit_name;
|
||||
|
||||
if (e->is(IfcSchema::Type::IfcSIUnit)) {
|
||||
if (e->declaration().is(IfcSchema::Type::IfcSIUnit)) {
|
||||
IfcSchema::IfcSIUnit* unit = (IfcSchema::IfcSIUnit*) e;
|
||||
unit_name = IfcSchema::IfcSIUnitName::ToString(unit->Name());
|
||||
if (unit->hasPrefix()) {
|
||||
@@ -58,7 +79,8 @@ boost::optional<std::string> format_attribute(const Argument* argument, IfcUtil:
|
||||
unit_name = unit->Name();
|
||||
}
|
||||
|
||||
for (std::string::iterator c = unit_name.begin(); c != unit_name.end(); ++c) *c = tolower(*c);
|
||||
// TODO add toLower() and toUpper() string helper functions for the project
|
||||
std::transform(unit_name.begin(), unit_name.end(), unit_name.begin(), ::tolower);
|
||||
|
||||
value = unit_name;
|
||||
}
|
||||
@@ -71,18 +93,20 @@ boost::optional<std::string> format_attribute(const Argument* argument, IfcUtil:
|
||||
// over the entity attributes and writes them as xml attributes of the node.
|
||||
ptree& format_entity_instance(IfcUtil::IfcBaseEntity* instance, ptree& tree, bool as_link = false) {
|
||||
ptree child;
|
||||
const unsigned n = instance->getArgumentCount();
|
||||
const unsigned n = instance->data().getArgumentCount();
|
||||
std::vector<const IfcParse::entity::attribute*> attributes = instance->declaration().all_attributes();
|
||||
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
const Argument* argument = instance->getArgument(i);
|
||||
const Argument* argument = instance->data().getArgument(i);
|
||||
if (argument->isNull()) continue;
|
||||
|
||||
std::string argument_name = instance->getArgumentName(i);
|
||||
std::string argument_name = attributes[i]->name();
|
||||
std::map<std::string, std::string>::const_iterator argument_name_it;
|
||||
argument_name_it = argument_name_map.find(argument_name);
|
||||
if (argument_name_it != argument_name_map.end()) {
|
||||
argument_name = argument_name_it->second;
|
||||
}
|
||||
const IfcUtil::ArgumentType argument_type = instance->getArgumentType(i);
|
||||
const IfcUtil::ArgumentType argument_type = instance->data().getArgument(i)->type();
|
||||
|
||||
boost::optional<std::string> value;
|
||||
try {
|
||||
@@ -101,7 +125,7 @@ ptree& format_entity_instance(IfcUtil::IfcBaseEntity* instance, ptree& tree, boo
|
||||
}
|
||||
}
|
||||
}
|
||||
return tree.add_child(Type::ToString(instance->type()), child);
|
||||
return tree.add_child(Type::ToString(instance->declaration().type()), child);
|
||||
}
|
||||
|
||||
// A function to be called recursively. Template specialization is used
|
||||
@@ -119,7 +143,7 @@ typename V::list::ptr get_related(T* t, F f, G g) {
|
||||
typename V::list::ptr acc(new typename V::list);
|
||||
for (typename U::list::it it = li->begin(); it != li->end(); ++it) {
|
||||
U* u = *it;
|
||||
acc->push((*u.*g)());
|
||||
acc->push((*u.*g)()->template as<V>());
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
@@ -130,7 +154,7 @@ template <>
|
||||
void descend(IfcProduct* product, ptree& tree) {
|
||||
ptree& child = format_entity_instance(product, tree);
|
||||
|
||||
if (product->is(Type::IfcSpatialStructureElement)) {
|
||||
if (product->declaration().is(Type::IfcSpatialStructureElement)) {
|
||||
IfcSpatialStructureElement* structure = (IfcSpatialStructureElement*) product;
|
||||
|
||||
IfcProduct::list::ptr elements = get_related
|
||||
@@ -142,13 +166,19 @@ void descend(IfcProduct* product, ptree& tree) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_IFC2x3
|
||||
IfcObjectDefinition::list::ptr structures = get_related
|
||||
<IfcProduct, IfcRelDecomposes, IfcObjectDefinition>
|
||||
(product, &IfcProduct::IsDecomposedBy, &IfcRelDecomposes::RelatedObjects);
|
||||
#else
|
||||
IfcObjectDefinition::list::ptr structures = get_related
|
||||
<IfcProduct, IfcRelAggregates, IfcObjectDefinition>
|
||||
(product, &IfcProduct::IsDecomposedBy, &IfcRelAggregates::RelatedObjects);
|
||||
#endif
|
||||
|
||||
for (IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
|
||||
IfcObjectDefinition* ob = *it;
|
||||
if (ob->is(Type::IfcSpatialStructureElement)) {
|
||||
if (ob->declaration().is(Type::IfcSpatialStructureElement)) {
|
||||
descend((IfcProduct*)ob, child);
|
||||
} else {
|
||||
descend(ob, child);
|
||||
@@ -161,7 +191,7 @@ void descend(IfcProduct* product, ptree& tree) {
|
||||
|
||||
for (IfcPropertySetDefinition::list::it it = property_sets->begin(); it != property_sets->end(); ++it) {
|
||||
IfcPropertySetDefinition* pset = *it;
|
||||
if (pset->is(Type::IfcPropertySet)) {
|
||||
if (pset->declaration().is(Type::IfcPropertySet)) {
|
||||
format_entity_instance(pset, child, true);
|
||||
}
|
||||
}
|
||||
@@ -172,13 +202,19 @@ template <>
|
||||
void descend(IfcProject* project, ptree& tree) {
|
||||
ptree& child = format_entity_instance(project, tree);
|
||||
|
||||
#ifdef USE_IFC2x3
|
||||
IfcObjectDefinition::list::ptr structures = get_related
|
||||
<IfcProject, IfcRelDecomposes, IfcObjectDefinition>
|
||||
(project, &IfcProject::IsDecomposedBy, &IfcRelDecomposes::RelatedObjects);
|
||||
#else
|
||||
IfcObjectDefinition::list::ptr structures = get_related
|
||||
<IfcProject, IfcRelAggregates, IfcObjectDefinition>
|
||||
(project, &IfcProduct::IsDecomposedBy, &IfcRelAggregates::RelatedObjects);
|
||||
#endif
|
||||
|
||||
for (IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
|
||||
IfcObjectDefinition* ob = *it;
|
||||
if (ob->is(Type::IfcSpatialStructureElement)) {
|
||||
if (ob->declaration().is(Type::IfcSpatialStructureElement)) {
|
||||
descend((IfcProduct*)ob, child);
|
||||
} else {
|
||||
descend(ob, child);
|
||||
@@ -190,7 +226,7 @@ void descend(IfcProject* project, ptree& tree) {
|
||||
void format_properties(IfcProperty::list::ptr properties, ptree& node) {
|
||||
for (IfcProperty::list::it it = properties->begin(); it != properties->end(); ++it) {
|
||||
IfcProperty* p = *it;
|
||||
if (p->is(Type::IfcComplexProperty)) {
|
||||
if (p->declaration().is(Type::IfcComplexProperty)) {
|
||||
IfcComplexProperty* complex = (IfcComplexProperty*) p;
|
||||
format_properties(complex->HasProperties(), node);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 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 *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
|
||||
#include "../ifcconvert/util.h"
|
||||
|
||||
using namespace util;
|
||||
|
||||
boost::shared_ptr<string_buffer::string_item> string_buffer::add(const std::string& s) {
|
||||
boost::shared_ptr<string_item> i = boost::shared_ptr<string_item>(new string_item(s));
|
||||
items.push_back(i);
|
||||
return i;
|
||||
}
|
||||
boost::shared_ptr<string_buffer::float_item> string_buffer::add(const double& d) {
|
||||
boost::shared_ptr<float_item> i = boost::shared_ptr<float_item>(new float_item(d));
|
||||
items.push_back(i);
|
||||
return i;
|
||||
}
|
||||
std::string string_buffer::str() const {
|
||||
std::stringstream ss;
|
||||
for (std::vector< boost::shared_ptr<item> >::const_iterator it = items.begin(); it != items.end(); ++it) {
|
||||
ss << (**it).str();
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 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 *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCCONVERT_UTIL_H
|
||||
#define IFCCONVERT_UTIL_H
|
||||
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace util {
|
||||
class string_buffer {
|
||||
public:
|
||||
class item {
|
||||
public:
|
||||
virtual std::string str() const = 0;
|
||||
};
|
||||
class string_item : public item {
|
||||
std::string s;
|
||||
public:
|
||||
string_item(const std::string& s) : s(s) {}
|
||||
void assign(const std::string& s) { this->s = s; }
|
||||
const std::string& value() const { return s; }
|
||||
std::string& value() { return s; }
|
||||
std::string str() const { return s; }
|
||||
};
|
||||
class float_item : public item {
|
||||
double d;
|
||||
public:
|
||||
float_item(const double& d) : d(d) {}
|
||||
void assign(const double& d) { this->d = d; }
|
||||
const double& value() const { return d; }
|
||||
double& value() { return d; }
|
||||
std::string str() const { std::stringstream ss; ss << d; return ss.str(); }
|
||||
};
|
||||
private:
|
||||
std::vector< boost::shared_ptr<item> > items;
|
||||
void clear();
|
||||
void assign(const std::vector< boost::shared_ptr<item> >& other);
|
||||
public:
|
||||
boost::shared_ptr<string_item> add(const std::string& s);
|
||||
boost::shared_ptr<float_item> add(const double& d);
|
||||
std::string str() const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -4,6 +4,8 @@ the IFC schema and will most likely fail on any other Express schema.
|
||||
|
||||
The code can be invoked in the following way and results in two header files
|
||||
and a single implementation file named according to the schema name in the
|
||||
Express file. A python 3 interpreter with the pyparsing library is required.
|
||||
Express file. A python 3 interpreter with the pyparsing [1] library is required.
|
||||
|
||||
$ python bootstrap.py express.bnf > express_parser.py && python express_parser.py IFC2X3_TC1.exp
|
||||
|
||||
[1] http://pyparsing.wikispaces.com/Download+and+Installation
|
||||
|
||||
@@ -115,7 +115,7 @@ actions = {
|
||||
'general_aggregation_types' : "lambda t: AggregationType(t)",
|
||||
'select_type' : "lambda t: SelectType(t)",
|
||||
'binary_type' : "lambda t: BinaryType(t)",
|
||||
'subtype_declaration' : "lambda t: SubtypeExpression(t)",
|
||||
'subtype_declaration' : "lambda t: SubTypeExpression(t)",
|
||||
'derive_clause' : "lambda t: AttributeList('derive', t)",
|
||||
'derived_attr' : "lambda t: DerivedAttribute(t)",
|
||||
'inverse_clause' : "lambda t: AttributeList('inverse', t)",
|
||||
@@ -158,29 +158,45 @@ for id in to_emit:
|
||||
stmt = "Suppress%s" % stmt
|
||||
statements.append("%s << %s" % (id, stmt))
|
||||
|
||||
print ("""import sys
|
||||
from pyparsing import *
|
||||
from nodes import *
|
||||
print ("""import os
|
||||
import sys
|
||||
import pickle
|
||||
|
||||
%s
|
||||
cache_file = sys.argv[1] + ".cache.dat"
|
||||
if os.path.exists(cache_file):
|
||||
with open(cache_file, "rb") as f:
|
||||
mapping = pickle.load(f)
|
||||
else:
|
||||
from pyparsing import *
|
||||
from nodes import *
|
||||
|
||||
import schema
|
||||
import mapping
|
||||
|
||||
%s
|
||||
|
||||
syntax.ignore("--" + restOfLine)
|
||||
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
|
||||
ast = syntax.parseFile(sys.argv[1])
|
||||
schema = schema.Schema(ast)
|
||||
mapping = mapping.Mapping(schema)
|
||||
|
||||
import schema
|
||||
import mapping
|
||||
with open(cache_file, "wb") as f:
|
||||
pickle.dump(mapping, f, protocol=0)
|
||||
|
||||
import header
|
||||
import enum_header
|
||||
import implementation
|
||||
import latebound_header
|
||||
import latebound_implementation
|
||||
|
||||
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
|
||||
ast = syntax.parseFile(sys.argv[1])
|
||||
schema = schema.Schema(ast)
|
||||
mapping = mapping.Mapping(schema)
|
||||
import schema_class
|
||||
|
||||
header.Header(mapping).emit()
|
||||
enum_header.EnumHeader(mapping).emit()
|
||||
implementation.Implementation(mapping).emit()
|
||||
latebound_header.LateBoundHeader(mapping).emit()
|
||||
latebound_implementation.LateBoundImplementation(mapping).emit()
|
||||
"""%('\n'.join(statements)))
|
||||
schema_class.SchemaClass(mapping).emit()
|
||||
|
||||
sys.stdout.write(mapping.schema.name)
|
||||
"""%('\n '.join(statements)))
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 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 #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
class Base(object):
|
||||
"""
|
||||
A base class for all code generation classes. Currently only working around
|
||||
some python 2/3 incompatibilities in terms of unicode file handling.
|
||||
"""
|
||||
def emit(self):
|
||||
import platform
|
||||
if tuple(map(int, platform.python_version_tuple())) < (2, 8):
|
||||
from io import open as unicode_open
|
||||
unicode_type = unicode
|
||||
else:
|
||||
unicode_open = open
|
||||
unicode_type = lambda x, *args, **kwargs: x
|
||||
f = unicode_open(self.file_name, 'w', encoding='utf-8')
|
||||
f.write(unicode_type(repr(self), encoding='utf-8', errors='ignore'))
|
||||
f.close()
|
||||
@@ -27,11 +27,17 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import re,csv
|
||||
import re
|
||||
import os
|
||||
import csv
|
||||
|
||||
from builtins import open
|
||||
|
||||
try: from html.entities import entitydefs
|
||||
except: from htmlentitydefs import entitydefs
|
||||
|
||||
make_absolute = lambda fn: os.path.join(os.path.dirname(os.path.realpath(__file__)), fn)
|
||||
|
||||
name_to_oid = {}
|
||||
oid_to_desc = {}
|
||||
oid_to_name = {}
|
||||
@@ -39,18 +45,19 @@ oid_to_pid = {}
|
||||
regices = list(zip([re.compile(s,re.M) for s in [r'<[\w\n=" \-/\.;_\t:%#,\?\(\)]+>',r'(\n[\t ]*){2,}',r'^[\t ]+']],['','\n\n',' ']))
|
||||
|
||||
definition_files = ['DocEntity.csv', 'DocEnumeration.csv', 'DocDefined.csv', 'DocSelect.csv']
|
||||
definition_files = map(make_absolute, definition_files)
|
||||
for fn in definition_files:
|
||||
with open(fn) as f:
|
||||
with open(fn, encoding='utf-8', errors='ignore') as f:
|
||||
for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'):
|
||||
name_to_oid[name] = oid
|
||||
oid_to_name[oid] = name
|
||||
oid_to_desc[oid] = desc
|
||||
|
||||
with open('DocEntityAttributes.csv') as f:
|
||||
with open(make_absolute('DocEntityAttributes.csv'), encoding='utf-8', errors='ignore') as f:
|
||||
for pid, x, oid in csv.reader(f, delimiter=';', quotechar='"'):
|
||||
oid_to_pid[oid] = pid
|
||||
|
||||
with open('DocAttribute.csv') as f:
|
||||
with open(make_absolute('DocAttribute.csv'), encoding='utf-8', errors='ignore') as f:
|
||||
for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'):
|
||||
pid = oid_to_pid[oid]
|
||||
pname = oid_to_name[pid]
|
||||
|
||||
@@ -18,10 +18,11 @@
|
||||
###############################################################################
|
||||
|
||||
import templates
|
||||
import codegen
|
||||
|
||||
class EnumHeader:
|
||||
class EnumHeader(codegen.Base):
|
||||
def __init__(self, mapping):
|
||||
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]))
|
||||
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]), key=lambda s: s.lower())
|
||||
|
||||
self.str = templates.enum_header % {
|
||||
'schema_name_upper' : mapping.schema.name.upper(),
|
||||
@@ -30,9 +31,9 @@ class EnumHeader:
|
||||
}
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
self.file_name = '%senum.h'%self.schema_name
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return self.str
|
||||
def emit(self):
|
||||
f = open('%senum.h'%self.schema_name, 'w', encoding='utf-8')
|
||||
f.write(str(self))
|
||||
f.close()
|
||||
|
||||
@@ -17,10 +17,11 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import codegen
|
||||
import templates
|
||||
import documentation
|
||||
|
||||
class Header:
|
||||
class Header(codegen.Base):
|
||||
def __init__(self, mapping):
|
||||
declarations = []
|
||||
|
||||
@@ -95,17 +96,17 @@ class Header:
|
||||
argument_start = argument_count - len(type.attributes)
|
||||
|
||||
argument_name_function_body_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return "%s"; '%(i+argument_start, attr.name) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
|
||||
argument_name_function_body_tail = (" return %s::getArgumentName(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcException("argument out of range"); '
|
||||
argument_name_function_body_tail = (" return %s::getArgumentName(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
|
||||
|
||||
argument_name_function_body = argument_name_function_body_switch_stmt + argument_name_function_body_tail
|
||||
|
||||
argument_type_function_body_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return %s; '%(i+argument_start, mapping.make_argument_type(attr)) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
|
||||
argument_type_function_body_tail = (" return %s::getArgumentType(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcException("argument out of range"); '
|
||||
argument_type_function_body_tail = (" return %s::getArgumentType(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
|
||||
|
||||
argument_type_function_body = argument_type_function_body_switch_stmt + argument_type_function_body_tail
|
||||
|
||||
argument_entity_function_body_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return %s; '%(i+argument_start, mapping.make_argument_entity(attr)) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
|
||||
argument_entity_function_body_tail = (" return %s::getArgumentEntity(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcException("argument out of range"); '
|
||||
argument_entity_function_body_tail = (" return %s::getArgumentEntity(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
|
||||
|
||||
argument_entity_function_body = argument_entity_function_body_switch_stmt + argument_entity_function_body_tail
|
||||
|
||||
@@ -123,10 +124,9 @@ class Header:
|
||||
}
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
self.file_name = '%s.h'%self.schema_name
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return self.str
|
||||
def emit(self):
|
||||
f = open('%s.h'%self.schema_name, 'w', encoding='utf-8')
|
||||
f.write(str(self))
|
||||
f.close()
|
||||
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import codegen
|
||||
import templates
|
||||
|
||||
class Implementation:
|
||||
class Implementation(codegen.Base):
|
||||
def __init__(self, mapping):
|
||||
enumeration_functions = []
|
||||
entity_implementations = []
|
||||
@@ -72,10 +73,10 @@ class Implementation:
|
||||
def find_template(arg):
|
||||
simple = mapping.schema.is_simpletype(arg['list_instance_type'])
|
||||
select = arg['list_instance_type'] == "IfcUtil::IfcBaseClass"
|
||||
express = arg['list_instance_type'] in mapping.express_to_cpp_typemapping
|
||||
express = mapping.flatten_type_string(arg['list_instance_type']) in mapping.express_to_cpp_typemapping
|
||||
if arg['is_enum']: return templates.get_attr_stmt_enum
|
||||
elif arg['is_nested']: return templates.get_attr_stmt_nested_array
|
||||
elif arg['is_array'] and not (select or simple or express): return templates.get_attr_stmt_array
|
||||
elif arg['is_nested'] and arg['is_templated_list']: return templates.get_attr_stmt_nested_array
|
||||
elif arg['is_templated_list'] and not (select or simple or express): return templates.get_attr_stmt_array
|
||||
elif arg['non_optional_type'].endswith('*'): return templates.get_attr_stmt_entity
|
||||
else: return templates.get_attr_stmt
|
||||
|
||||
@@ -96,7 +97,7 @@ class Implementation:
|
||||
select = arg['list_instance_type'] == "IfcUtil::IfcBaseClass"
|
||||
express = arg['list_instance_type'] in mapping.express_to_cpp_typemapping
|
||||
if arg['is_enum']: return templates.set_attr_stmt_enum
|
||||
elif arg['is_array'] and not (select or simple or express): return templates.set_attr_stmt_array
|
||||
elif arg['is_templated_list'] and not (select or simple or express): return templates.set_attr_stmt_array
|
||||
else: return templates.set_attr_stmt
|
||||
|
||||
tmpl = find_template(arg)
|
||||
@@ -158,7 +159,7 @@ class Implementation:
|
||||
schema_entity_statements += [templates.schema_entity_stmt%locals() for name, type in mapping.schema.simpletypes.items()]
|
||||
schema_entity_statements += [templates.schema_entity_stmt%locals() for name, type in mapping.schema.entities.items()]
|
||||
|
||||
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]))
|
||||
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]), key=lambda s: s.lower())
|
||||
max_len = max(map(len, enumerable_types))
|
||||
type_name_strings = catc(map(stringify, enumerable_types))
|
||||
string_map_statements = [templates.string_map_statement % {
|
||||
@@ -189,24 +190,35 @@ class Implementation:
|
||||
constructor = templates.constructor_single_initlist if superclass \
|
||||
else templates.constructor
|
||||
|
||||
simpletype_impl_cast = templates.simpletype_impl_cast_templated if mapping.is_templated_list(type) \
|
||||
else templates.simpletype_impl_cast
|
||||
|
||||
simpletype_impl_constructor = templates.simpletype_impl_constructor_templated if mapping.is_templated_list(type) \
|
||||
else templates.simpletype_impl_constructor
|
||||
|
||||
def compose(params):
|
||||
class_name, attr_type, superclass, superclass_init, name, tmpl, return_type, args, body = params
|
||||
underlying_type = mapping.list_instance_type(type)
|
||||
arguments = ",".join(args)
|
||||
body = body % locals()
|
||||
return tmpl % locals()
|
||||
|
||||
simple_type_impl.append(templates.simpletype_impl_comment % {'name': class_name})
|
||||
simple_type_impl.extend(map(compose, map(lambda x: (class_name, attr_type, superclass, "(IfcAbstractEntity*)0")+x, (
|
||||
('getArgumentType', templates.const_function, 'IfcUtil::ArgumentType', ('unsigned int i',), templates.simpletype_impl_argument_type ),
|
||||
('getArgument', templates.const_function, 'Argument*', ('unsigned int i',), templates.simpletype_impl_argument ),
|
||||
('is', templates.const_function, 'bool', ('Type::Enum v',), simpletype_impl_is ),
|
||||
('type', templates.const_function, 'Type::Enum', (), templates.simpletype_impl_type ),
|
||||
#('getArgumentType', templates.const_function, 'IfcUtil::ArgumentType', ('unsigned int i',), templates.simpletype_impl_argument_type ),
|
||||
#('getArgument', templates.const_function, 'Argument*', ('unsigned int i',), templates.simpletype_impl_argument ),
|
||||
#('is', templates.const_function, 'bool', ('Type::Enum v',), simpletype_impl_is ),
|
||||
#('type', templates.const_function, 'Type::Enum', (), templates.simpletype_impl_type ),
|
||||
('Class', templates.function, 'Type::Enum', (), templates.simpletype_impl_class ),
|
||||
('declaration', templates.const_function, 'const IfcParse::type_declaration&', (), templates.simpletype_impl_declaration ),
|
||||
('', constructor, '', ('IfcAbstractEntity* e',), templates.simpletype_impl_explicit_constructor),
|
||||
('', constructor, '', ("%s v" % type_str,), templates.simpletype_impl_constructor ),
|
||||
('', templates.cast_function, type_str, (), templates.simpletype_impl_cast )
|
||||
('', constructor, '', ("%s v" % type_str,), simpletype_impl_constructor ),
|
||||
('', templates.cast_function, type_str, (), simpletype_impl_cast )
|
||||
))))
|
||||
simple_type_impl.append('')
|
||||
|
||||
external_definitions = ["extern entity* %s_type;" % n for n in mapping.schema.entities.keys() ] + \
|
||||
["extern type_declaration* %s_type;" % n for n in mapping.schema.simpletypes.keys()]
|
||||
|
||||
self.str = templates.implementation % {
|
||||
'schema_name_upper' : mapping.schema.name.upper(),
|
||||
@@ -219,14 +231,14 @@ class Implementation:
|
||||
'simple_type_statement' : simple_type_statements,
|
||||
'parent_type_statements' : catnl(parent_type_statements),
|
||||
'entity_implementations' : catnl(entity_implementations),
|
||||
'simple_type_impl' : catnl(simple_type_impl)
|
||||
'simple_type_impl' : catnl(simple_type_impl),
|
||||
'external_definitions' : catnl(external_definitions)
|
||||
}
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
self.file_name = '%s.cpp'%self.schema_name
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return self.str
|
||||
def emit(self):
|
||||
f = open('%s.cpp'%self.schema_name, 'w', encoding='utf-8')
|
||||
f.write(str(self))
|
||||
f.close()
|
||||
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import codegen
|
||||
import templates
|
||||
|
||||
class LateBoundHeader:
|
||||
class LateBoundHeader(codegen.Base):
|
||||
def __init__(self, mapping):
|
||||
self.str = templates.lb_header % {
|
||||
'schema_name_upper' : mapping.schema.name.upper(),
|
||||
@@ -27,9 +28,9 @@ class LateBoundHeader:
|
||||
}
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
self.file_name = '%s-latebound.h'%self.schema_name
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return self.str
|
||||
def emit(self):
|
||||
f = open('%s-latebound.h'%self.schema_name, 'w', encoding='utf-8')
|
||||
f.write(str(self))
|
||||
f.close()
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import codegen
|
||||
import templates
|
||||
|
||||
class LateBoundImplementation:
|
||||
class LateBoundImplementation(codegen.Base):
|
||||
def __init__(self, mapping):
|
||||
schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
@@ -110,10 +111,9 @@ class LateBoundImplementation:
|
||||
}
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
self.file_name = '%s-latebound.cpp'%self.schema_name
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return self.str
|
||||
def emit(self):
|
||||
f = open('%s-latebound.cpp'%self.schema_name, 'w', encoding='utf-8')
|
||||
f.write(str(self))
|
||||
f.close()
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import nodes
|
||||
import templates
|
||||
|
||||
@@ -24,12 +27,19 @@ class Mapping:
|
||||
|
||||
express_to_cpp_typemapping = {
|
||||
'boolean' : 'bool',
|
||||
'logical' : 'bool',
|
||||
'logical' : 'boost::logic::tribool',
|
||||
'integer' : 'int',
|
||||
'real' : 'double',
|
||||
'number' : 'double',
|
||||
'string' : 'std::string'
|
||||
'string' : 'std::string',
|
||||
'binary' : 'boost::dynamic_bitset<>'
|
||||
}
|
||||
|
||||
supported_argument_types = set([
|
||||
'INT', 'BOOL', 'TRIBOOL', 'DOUBLE', 'STRING', 'BINARY', 'ENUMERATION', 'ENTITY_INSTANCE',
|
||||
'AGGREGATE_OF_INT', 'AGGREGATE_OF_BOOL', 'AGGREGATE_OF_TRIBOOL', 'AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_STRING', 'AGGREGATE_OF_BINARY', 'AGGREGATE_OF_ENTITY_INSTANCE',
|
||||
'AGGREGATE_OF_AGGREGATE_OF_INT', 'AGGREGATE_OF_AGGREGATE_OF_BOOL', 'AGGREGATE_OF_AGGREGATE_OF_TRIBOOL', 'AGGREGATE_OF_AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE',
|
||||
])
|
||||
|
||||
def __init__(self, schema):
|
||||
self.schema = schema
|
||||
@@ -44,17 +54,17 @@ class Mapping:
|
||||
def simple_type_parent(self, type):
|
||||
parent = self.schema.types[type].type.type
|
||||
if isinstance(parent, nodes.AggregationType): parent = None
|
||||
return None if parent in self.express_to_cpp_typemapping else parent
|
||||
return None if str(parent) in self.express_to_cpp_typemapping else parent
|
||||
|
||||
def make_type_string(self, type):
|
||||
if isinstance(type, str):
|
||||
return self.express_to_cpp_typemapping.get(type, type)
|
||||
if isinstance(type, (str, nodes.BinaryType)):
|
||||
return self.express_to_cpp_typemapping.get(str(type), type)
|
||||
else:
|
||||
is_list = self.schema.is_entity(type.type)
|
||||
is_nested_list = isinstance(type.type, nodes.AggregationType)
|
||||
tmpl = templates.list_list_type if is_nested_list else templates.list_type if is_list else templates.array_type
|
||||
return tmpl % {
|
||||
'instance_type' : self.make_type_string(type.type),
|
||||
'instance_type' : self.make_type_string(self.flatten_type_string(type.type)),
|
||||
'lower' : type.bounds.lower,
|
||||
'upper' : type.bounds.upper,
|
||||
}
|
||||
@@ -70,41 +80,40 @@ class Mapping:
|
||||
def make_argument_entity(self, attr):
|
||||
type = attr.type if hasattr(attr, 'type') else attr
|
||||
while isinstance(type, nodes.AggregationType): type = type.type
|
||||
if type in self.express_to_cpp_typemapping or isinstance(type, nodes.BinaryType): return "Type::UNDEFINED"
|
||||
if str(type) in self.express_to_cpp_typemapping: return "Type::UNDEFINED"
|
||||
else: return "Type::%s" % type
|
||||
|
||||
def make_argument_type(self, attr):
|
||||
def _make_argument_type(type):
|
||||
if type in self.express_to_cpp_typemapping:
|
||||
return self.express_to_cpp_typemapping.get(type, type).split('::')[-1].upper()
|
||||
elif self.schema.is_entity(type):
|
||||
return "ENTITY"
|
||||
elif self.schema.is_type(type):
|
||||
return _make_argument_type(self.schema.types[type].type.type)
|
||||
if self.schema.is_entity(type) or isinstance(type, nodes.SelectType):
|
||||
return "ENTITY_INSTANCE"
|
||||
elif isinstance(type, nodes.BinaryType):
|
||||
return "UNKNOWN"
|
||||
return "BINARY"
|
||||
elif isinstance(type, nodes.EnumerationType):
|
||||
return "ENUMERATION"
|
||||
elif isinstance(type, nodes.SelectType):
|
||||
return "ENTITY"
|
||||
elif isinstance(type, nodes.AggregationType):
|
||||
ty = _make_argument_type(type.type)
|
||||
if ty == "UNKNOWN": return "UNKNOWN"
|
||||
return "%s_LIST"%ty if ty.startswith("ENTITY") else ("VECTOR_%s"%ty)
|
||||
else: raise ValueError
|
||||
supported = {'INT', 'BOOL', 'DOUBLE', 'STRING', 'VECTOR_INT', 'VECTOR_DOUBLE', 'VECTOR_STRING', 'ENTITY', 'ENTITY_LIST', 'ENTITY_LIST_LIST', 'ENUMERATION'}
|
||||
return "AGGREGATE_OF_" + ty
|
||||
elif str(type) in self.express_to_cpp_typemapping:
|
||||
return self.express_to_cpp_typemapping.get(str(type), type).split('::')[-1].upper()
|
||||
elif self.schema.is_type(type):
|
||||
return _make_argument_type(self.schema.types[type].type.type)
|
||||
else:
|
||||
raise ValueError("Unable to map type %r for attribute %r" % (type, attr))
|
||||
ty = _make_argument_type(attr.type if hasattr(attr, 'type') else attr)
|
||||
if ty not in supported: ty = 'UNKNOWN'
|
||||
if ty not in self.supported_argument_types:
|
||||
print("Attribute %r (%s) mapped as 'unknown'" % (attr, ty), file=sys.stderr)
|
||||
ty = 'UNKNOWN'
|
||||
return "IfcUtil::Argument_%s" % ty
|
||||
|
||||
def get_type_dep(self, type):
|
||||
if isinstance(type, str):
|
||||
return self.express_to_cpp_typemapping.get(type, type)
|
||||
return self.express_to_cpp_typemapping.get(str(type), type)
|
||||
else:
|
||||
return self.get_type_dep(type.type)
|
||||
|
||||
def get_parameter_type(self, attr, allow_optional, allow_entities, allow_pointer = True):
|
||||
|
||||
attr_type = self.flatten_type(attr.type)
|
||||
type_str = self.express_to_cpp_typemapping.get(str(attr_type), attr_type)
|
||||
|
||||
@@ -115,10 +124,11 @@ class Mapping:
|
||||
elif isinstance(type_str, nodes.AggregationType):
|
||||
is_nested_list = isinstance(attr_type.type, nodes.AggregationType)
|
||||
ty = self.get_parameter_type(attr_type.type if is_nested_list else attr_type, False, allow_entities, False)
|
||||
if True and self.schema.is_select(attr_type.type):
|
||||
if self.schema.is_select(attr_type.type):
|
||||
type_str = templates.untyped_list
|
||||
elif self.schema.is_simpletype(ty) or ty in self.express_to_cpp_typemapping.values():
|
||||
type_str = templates.array_type % {
|
||||
elif self.schema.is_simpletype(ty) or str(ty) in self.express_to_cpp_typemapping.values():
|
||||
tmpl = templates.nested_array_type if is_nested_list else templates.array_type
|
||||
type_str = tmpl % {
|
||||
'instance_type' : ty,
|
||||
'lower' : attr_type.bounds.lower,
|
||||
'upper' : attr_type.bounds.upper
|
||||
@@ -151,23 +161,28 @@ class Mapping:
|
||||
return c + ([str(s) for s in t.derive.elements] if t.derive else [])
|
||||
|
||||
def list_instance_type(self, attr):
|
||||
f = lambda v : 'IfcUtil::IfcBaseClass' if self.schema.is_select(v) else v
|
||||
if self.is_array(attr.type):
|
||||
if not isinstance(attr.type, str) and self.is_array(attr.type.type):
|
||||
if isinstance(attr.type.type, str):
|
||||
return f(attr.type.type)
|
||||
else: return f(attr.type.type.type)
|
||||
attr_type = attr.type if isinstance(attr, nodes.ExplicitAttribute) else attr
|
||||
if isinstance(attr_type, str): return None
|
||||
f = lambda v : 'IfcUtil::IfcBaseClass' if self.schema.is_select(v) else str(v)
|
||||
if self.is_array(attr_type):
|
||||
if not isinstance(attr_type, str) and self.is_array(attr_type.type):
|
||||
if isinstance(attr_type.type, str):
|
||||
return f(attr_type.type)
|
||||
else: return f(attr_type.type.type)
|
||||
else:
|
||||
if isinstance(attr.type, str):
|
||||
return f(attr.type)
|
||||
else: return f(attr.type.type)
|
||||
if isinstance(attr_type, str):
|
||||
return f(attr_type)
|
||||
else: return f(attr_type.type)
|
||||
return None
|
||||
|
||||
def is_templated_list(self, attr):
|
||||
attr_type = attr.type if isinstance(attr, nodes.ExplicitAttribute) else attr
|
||||
if isinstance(attr, str): return False
|
||||
ty = self.list_instance_type(attr)
|
||||
arr = self.is_array(attr.type)
|
||||
if ty is None: return False
|
||||
arr = self.is_array(attr_type)
|
||||
simple = self.schema.is_simpletype(ty)
|
||||
express = ty in self.express_to_cpp_typemapping
|
||||
express = self.flatten_type_string(ty) in self.express_to_cpp_typemapping
|
||||
select = ty == 'IfcUtil::IfcBaseClass'
|
||||
return arr and not simple and not express and not select
|
||||
|
||||
|
||||
@@ -44,15 +44,17 @@ class TypeDeclaration(Node):
|
||||
class EntityDeclaration(Node):
|
||||
name = property(lambda self: self.tokens[1])
|
||||
attributes = property(lambda self: self.tokens_of_type(ExplicitAttribute))
|
||||
abstract = property(lambda self: self.single_token_of_type(SuperTypeExpression) is not None and \
|
||||
self.single_token_of_type(SuperTypeExpression).abstract)
|
||||
def init(self):
|
||||
assert self.tokens[0] == 'entity'
|
||||
s = self.single_token_of_type(SubtypeExpression)
|
||||
s = self.single_token_of_type(SubTypeExpression)
|
||||
self.inverse = self.single_token_of_type(AttributeList, 'type', 'inverse')
|
||||
self.derive = self.single_token_of_type(AttributeList, 'type', 'derive')
|
||||
self.supertypes = s.types if s else []
|
||||
def __repr__(self):
|
||||
builder = ""
|
||||
builder += "Entity(%s)" % (self.name)
|
||||
builder += "%sEntity(%s)" % ("Abstract " if self.abstract else "", self.name)
|
||||
if len(self.supertypes):
|
||||
builder += "\n Supertypes: %s"%(",".join(self.supertypes))
|
||||
if len(self.attributes):
|
||||
@@ -106,12 +108,20 @@ class SelectType(Node):
|
||||
class SubSuperTypeExpression(Node):
|
||||
type = property(lambda self: self.tokens[0])
|
||||
types = property(lambda self: self.tokens[3::2])
|
||||
abstract = False
|
||||
def init(self):
|
||||
assert self.type == self.class_type
|
||||
if self.tokens[0] == 'abstract':
|
||||
self.tokens = self.tokens[1:]
|
||||
self.abstract = True
|
||||
assert self.type == self.type_relationship
|
||||
|
||||
|
||||
class SubtypeExpression(SubSuperTypeExpression):
|
||||
class_type = 'subtype'
|
||||
class SubTypeExpression(SubSuperTypeExpression):
|
||||
type_relationship = 'subtype'
|
||||
|
||||
|
||||
class SuperTypeExpression(SubSuperTypeExpression):
|
||||
type_relationship = 'supertype'
|
||||
|
||||
|
||||
class AttributeList(Node):
|
||||
@@ -127,7 +137,7 @@ class AttributeList(Node):
|
||||
|
||||
class InverseAttribute(Node):
|
||||
name = property(lambda self: self.tokens[0])
|
||||
type = property(lambda self: self.tokens[2])
|
||||
type = property(lambda self: None if len(self.tokens) == 6 else self.tokens[2])
|
||||
bounds = property(lambda self: None if len(self.tokens) == 6 else self.tokens[3])
|
||||
entity = property(lambda self: self.tokens[-4])
|
||||
attribute = property(lambda self: self.tokens[-2])
|
||||
@@ -149,7 +159,7 @@ class BinaryType(Node):
|
||||
def init(self):
|
||||
pass
|
||||
def __repr__(self):
|
||||
return "BINARY"
|
||||
return "binary"
|
||||
|
||||
|
||||
class BoundSpecification(Node):
|
||||
|
||||
@@ -18,29 +18,34 @@
|
||||
###############################################################################
|
||||
|
||||
import nodes
|
||||
import platform
|
||||
import collections
|
||||
|
||||
if tuple(map(int, platform.python_version_tuple())) < (2, 7):
|
||||
import ordereddict
|
||||
collections.OrderedDict = ordereddict.OrderedDict
|
||||
|
||||
class Schema:
|
||||
def is_enumeration(self, v):
|
||||
return v in self.enumerations
|
||||
return str(v) in self.enumerations
|
||||
def is_select(self, v):
|
||||
return v in self.selects
|
||||
return str(v) in self.selects
|
||||
def is_simpletype(self, v):
|
||||
return v in self.simpletypes
|
||||
return str(v) in self.simpletypes
|
||||
def is_type(self, v):
|
||||
return v in self.types
|
||||
return str(v) in self.types
|
||||
def is_entity(self, v):
|
||||
return v in self.entities
|
||||
return str(v) in self.entities
|
||||
def __init__(self, parsetree):
|
||||
self.name = parsetree[1]
|
||||
|
||||
sort = lambda d: collections.OrderedDict(sorted(d.items()))
|
||||
sort = lambda d: collections.OrderedDict(sorted(d))
|
||||
|
||||
self.types = sort({t.name:t for t in parsetree if isinstance(t, nodes.TypeDeclaration)})
|
||||
self.entities = sort({t.name:t for t in parsetree if isinstance(t, nodes.EntityDeclaration)})
|
||||
self.types = sort([(t.name,t) for t in parsetree if isinstance(t, nodes.TypeDeclaration)])
|
||||
self.entities = sort([(t.name,t) for t in parsetree if isinstance(t, nodes.EntityDeclaration)])
|
||||
|
||||
of_type = lambda *types: sort({a: b.type.type for a,b in self.types.items() if any(isinstance(b.type.type, ty) for ty in types)})
|
||||
of_type = lambda *types: sort([(a, b.type.type) for a,b in self.types.items() if any(isinstance(b.type.type, ty) for ty in types)])
|
||||
|
||||
self.enumerations = of_type(nodes.EnumerationType)
|
||||
self.selects = of_type(nodes.SelectType)
|
||||
self.simpletypes = of_type(str, nodes.AggregationType)
|
||||
self.simpletypes = of_type(str, nodes.AggregationType, nodes.BinaryType)
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 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 #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import operator
|
||||
|
||||
import nodes
|
||||
import codegen
|
||||
import templates
|
||||
|
||||
class SchemaClass(codegen.Base):
|
||||
def __init__(self, mapping):
|
||||
|
||||
class UnmetDependenciesException(Exception): pass
|
||||
|
||||
schema_name = mapping.schema.name
|
||||
declared_types = []
|
||||
|
||||
def get_declared_type(type, emitted_names=None):
|
||||
if isinstance(type, nodes.AggregationType):
|
||||
aggr_type = type.aggregate_type
|
||||
make_bound = lambda b: -1 if b == '?' else int(b)
|
||||
bound1, bound2 = map(make_bound, (type.bounds.lower, type.bounds.upper))
|
||||
decl_type = get_declared_type(type.type, emitted_names)
|
||||
return "new aggregation_type(aggregation_type::%(aggr_type)s_type, %(bound1)d, %(bound2)d, %(decl_type)s)" % locals()
|
||||
elif isinstance(type, nodes.BinaryType):
|
||||
return "new simple_type(simple_type::binary_type)"
|
||||
elif isinstance(type, str):
|
||||
if mapping.schema.is_type(type) or mapping.schema.is_entity(type):
|
||||
if emitted_names is None or type in emitted_types:
|
||||
return "new named_type(%s_type)" % type
|
||||
else:
|
||||
raise UnmetDependenciesException(type)
|
||||
else:
|
||||
return "new simple_type(simple_type::%s_type)" % type
|
||||
|
||||
def find_inverse_name_and_index(entity_name, attribute_name):
|
||||
attributes_per_subtype = []
|
||||
while True:
|
||||
entity = mapping.schema.entities[entity_name]
|
||||
attr_names = list(map(operator.attrgetter('name'), entity.attributes))
|
||||
if len(attr_names):
|
||||
attributes_per_subtype.append((entity_name, attr_names))
|
||||
if len(entity.supertypes) != 1: break
|
||||
entity_name = entity.supertypes[0]
|
||||
index = 0
|
||||
for et, attrs in attributes_per_subtype[::-1]:
|
||||
try: return et, attrs.index(attribute_name)
|
||||
except: pass
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
statements = ['',
|
||||
'#include "../ifcparse/IfcSchema.h"',
|
||||
'',
|
||||
'using namespace IfcParse;'
|
||||
'']
|
||||
|
||||
collections_by_type = (('entity', mapping.schema.entities ),
|
||||
('type_declaration', mapping.schema.simpletypes ),
|
||||
('select_type', mapping.schema.selects ),
|
||||
('enumeration_type', mapping.schema.enumerations))
|
||||
|
||||
for cpp_type, collection in collections_by_type:
|
||||
for name in collection.keys():
|
||||
statements.append('%(cpp_type)s* %(name)s_type = 0;' % locals())
|
||||
|
||||
statements.append("""
|
||||
#if defined(__clang__)
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("O0")
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma optimize("", off)
|
||||
#endif
|
||||
""")
|
||||
|
||||
statements.append('schema_definition* populate_schema() {')
|
||||
|
||||
emitted_types = set()
|
||||
# while len(emitted_types) < len(set(mapping.schema.simpletypes.keys()) - {"IfcPropertySetDefinitionSet"}):
|
||||
while len(emitted_types) < len(set(mapping.schema.simpletypes.keys()) - {"IfcPropertySetDefinitionSet"}):
|
||||
for name, type in mapping.schema.simpletypes.items():
|
||||
if name in emitted_types: continue
|
||||
|
||||
# No support for types refering to entities :(
|
||||
if name == "IfcPropertySetDefinitionSet": continue
|
||||
|
||||
try:
|
||||
declared_type = get_declared_type(type, emitted_types)
|
||||
except UnmetDependenciesException:
|
||||
continue
|
||||
|
||||
statements.append(' %(name)s_type = new type_declaration(IfcSchema::Type::%(name)s, %(declared_type)s);' % locals())
|
||||
emitted_types.add(name)
|
||||
|
||||
declared_types.append('%(name)s_type' % locals())
|
||||
|
||||
for name, enum in mapping.schema.enumerations.items():
|
||||
statements.append(' {')
|
||||
statements.append(' std::vector<std::string> items; items.reserve(%d);' % len(enum.values))
|
||||
statements.extend(map(lambda v: ' items.push_back("%s");' % v, sorted(enum.values)))
|
||||
statements.append(' %(name)s_type = new enumeration_type(IfcSchema::Type::%(name)s, items);' % locals())
|
||||
statements.append(' }')
|
||||
|
||||
declared_types.append('%(name)s_type' % locals())
|
||||
|
||||
emitted_entities = set()
|
||||
while len(emitted_entities) < len(mapping.schema.entities):
|
||||
for name, type in mapping.schema.entities.items():
|
||||
if name in emitted_entities: continue
|
||||
if len(type.supertypes) == 0 or set(type.supertypes) < emitted_entities:
|
||||
supertype = '0' if len(type.supertypes) == 0 else '%s_type' % type.supertypes[0]
|
||||
statements.append(' %(name)s_type = new entity(IfcSchema::Type::%(name)s, %(supertype)s);' % locals())
|
||||
emitted_entities.add(name)
|
||||
|
||||
declared_types.append('%(name)s_type' % locals())
|
||||
|
||||
emmited = emitted_types | emitted_entities | set(mapping.schema.enumerations.keys())
|
||||
|
||||
emitted_selects = set()
|
||||
while len(emitted_selects) < len(mapping.schema.selects):
|
||||
for name, type in mapping.schema.selects.items():
|
||||
if name in emitted_selects: continue
|
||||
type_values = sorted(set(type.values) - {"IfcPropertySetDefinitionSet"})
|
||||
if set(type_values) < emmited:
|
||||
statements.append(' {')
|
||||
statements.append(' std::vector<const declaration*> items; items.reserve(%d);' % len(type_values))
|
||||
statements.extend(map(lambda v: ' items.push_back(%s_type);' % v, sorted(type_values)))
|
||||
statements.append(' %(name)s_type = new select_type(IfcSchema::Type::%(name)s, items);' % locals())
|
||||
statements.append(' }')
|
||||
emitted_selects.add(name)
|
||||
emmited.add(name)
|
||||
|
||||
declared_types.append('%(name)s_type' % locals())
|
||||
|
||||
num_declarations = len(declared_types)
|
||||
|
||||
for name, type in mapping.schema.entities.items():
|
||||
derived = set(mapping.derived_in_supertype(type))
|
||||
attribute_names = list(map(operator.attrgetter('name'), mapping.arguments(type)))
|
||||
|
||||
statements.append(' {')
|
||||
statements.append(' std::vector<const entity::attribute*> attributes; attributes.reserve(%d);' % len(type.attributes))
|
||||
for attr in type.attributes:
|
||||
attr_name, optional = attr.name, str(attr.optional).lower()
|
||||
decl_type = get_declared_type(attr.type)
|
||||
statements.append(' attributes.push_back(new entity::attribute("%(attr_name)s", %(decl_type)s, %(optional)s));' % locals())
|
||||
statements.append(' std::vector<bool> derived; derived.reserve(%d);' % len(attribute_names))
|
||||
statements.append(' ' + " ".join(map(lambda b: 'derived.push_back(%s);' % str(b in derived).lower(), attribute_names)))
|
||||
statements.append(' %(name)s_type->set_attributes(attributes, derived);' % locals())
|
||||
statements.append(' }')
|
||||
|
||||
for name, type in mapping.schema.entities.items():
|
||||
if type.inverse:
|
||||
statements.append(' {')
|
||||
statements.append(' std::vector<const entity::inverse_attribute*> attributes; attributes.reserve(%d);' % len(type.inverse.elements))
|
||||
for attr in type.inverse.elements:
|
||||
if attr.bounds:
|
||||
make_bound = lambda b: -1 if b == '?' else int(b)
|
||||
bound1, bound2 = map(make_bound, (attr.bounds.lower, attr.bounds.upper))
|
||||
else:
|
||||
bound1, bound2 = -1, -1
|
||||
attr_name, aggr_type, entity_ref = attr.name, attr.type, attr.entity
|
||||
if aggr_type is None: aggr_type = 'unspecified'
|
||||
attribute_entity, attribute_entity_index = find_inverse_name_and_index(entity_ref, attr.attribute)
|
||||
statements.append(' attributes.push_back(new entity::inverse_attribute("%(attr_name)s", entity::inverse_attribute::%(aggr_type)s_type, %(bound1)d, %(bound2)d, %(entity_ref)s_type, %(attribute_entity)s_type->attributes()[%(attribute_entity_index)d]));' % locals())
|
||||
statements.append(' %(name)s_type->set_inverse_attributes(attributes);' % locals())
|
||||
statements.append(' }')
|
||||
|
||||
statements.append('')
|
||||
statements.append(' std::vector<const declaration*> declarations; declarations.reserve(%(num_declarations)d);' % locals())
|
||||
for type_name in declared_types:
|
||||
statements.append(' declarations.push_back(%(type_name)s);' % locals())
|
||||
|
||||
statements.append(' return new schema_definition("%(schema_name)s", declarations, true);' % locals())
|
||||
|
||||
statements.extend(('}',''))
|
||||
|
||||
statements.append("""
|
||||
#if defined(__clang__)
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
#pragma GCC pop_options
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma optimize("", on)
|
||||
#endif
|
||||
""")
|
||||
|
||||
statements.extend(('const schema_definition& get_schema() {',
|
||||
'',
|
||||
' static const schema_definition* s = populate_schema();',
|
||||
' return *s;',
|
||||
'}','',''))
|
||||
|
||||
self.str = "\n".join(statements)
|
||||
|
||||
self.file_name = '%s-schema.cpp'%self.schema_name
|
||||
|
||||
def __repr__(self):
|
||||
return self.str
|
||||
@@ -23,14 +23,21 @@ header = """
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcSchema.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/%(schema_name)senum.h"
|
||||
|
||||
const IfcParse::schema_definition& get_schema();
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4100)
|
||||
#endif
|
||||
|
||||
#define IfcSchema %(schema_name)s
|
||||
|
||||
namespace %(schema_name)s {
|
||||
@@ -47,6 +54,10 @@ void InitStringMap();
|
||||
IfcUtil::IfcBaseClass* SchemaEntity(IfcAbstractEntity* e = 0);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
"""
|
||||
|
||||
@@ -103,14 +114,20 @@ namespace Type {
|
||||
|
||||
implementation= """
|
||||
#include "../ifcparse/%(schema_name)s.h"
|
||||
#include "../ifcparse/IfcSchema.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/IfcWrite.h"
|
||||
#include "../ifcparse/IfcWritableEntity.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
using namespace %(schema_name)s;
|
||||
using namespace IfcParse;
|
||||
using namespace IfcWrite;
|
||||
|
||||
// External definitions
|
||||
%(external_definitions)s
|
||||
|
||||
IfcUtil::IfcBaseClass* %(schema_name)s::SchemaEntity(IfcAbstractEntity* e) {
|
||||
switch(e->type()) {
|
||||
%(schema_entity_statements)s
|
||||
@@ -179,6 +196,14 @@ enumeration_descriptor_map_t enumeration_descriptor_map;
|
||||
inverse_map_t inverse_map;
|
||||
derived_map_t derived_map;
|
||||
|
||||
#if defined(__clang__)
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("O0")
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma optimize("", off)
|
||||
#endif
|
||||
|
||||
void InitDescriptorMap() {
|
||||
IfcEntityDescriptor* current;
|
||||
%(entity_descriptors)s
|
||||
@@ -196,6 +221,13 @@ void InitDerivedMap() {
|
||||
%(derived_field_statements)s
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
#pragma GCC pop_options
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma optimize("", on)
|
||||
#endif
|
||||
|
||||
int Type::GetAttributeIndex(Enum t, const std::string& a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
@@ -252,49 +284,49 @@ std::pair<const char*, int> Type::GetEnumerationIndex(Enum t, const std::string&
|
||||
}
|
||||
|
||||
std::pair<Type::Enum, unsigned> Type::GetInverseAttribute(Enum t, const std::string& a) {
|
||||
if (inverse_map.empty()) ::InitInverseMap();
|
||||
inverse_map_t::const_iterator it;
|
||||
inverse_map_t::mapped_type::const_iterator jt;
|
||||
while (true) {
|
||||
if (inverse_map.empty()) ::InitInverseMap();
|
||||
inverse_map_t::const_iterator it;
|
||||
inverse_map_t::mapped_type::const_iterator jt;
|
||||
for(;;) {
|
||||
it = inverse_map.find(t);
|
||||
if (it != inverse_map.end()) {
|
||||
jt = it->second.find(a);
|
||||
if (jt != it->second.end()) {
|
||||
return jt->second;
|
||||
}
|
||||
}
|
||||
jt = it->second.find(a);
|
||||
if (jt != it->second.end()) {
|
||||
return jt->second;
|
||||
}
|
||||
}
|
||||
if ((t = Parent(t)) == -1) break;
|
||||
}
|
||||
throw IfcException("Attribute not found");
|
||||
}
|
||||
|
||||
std::set<std::string> Type::GetInverseAttributeNames(Enum t) {
|
||||
if (inverse_map.empty()) ::InitInverseMap();
|
||||
inverse_map_t::const_iterator it;
|
||||
inverse_map_t::mapped_type::const_iterator jt;
|
||||
if (inverse_map.empty()) ::InitInverseMap();
|
||||
inverse_map_t::const_iterator it;
|
||||
inverse_map_t::mapped_type::const_iterator jt;
|
||||
|
||||
std::set<std::string> return_value;
|
||||
std::set<std::string> return_value;
|
||||
|
||||
while (true) {
|
||||
for (;;) {
|
||||
it = inverse_map.find(t);
|
||||
if (it != inverse_map.end()) {
|
||||
for (jt = it->second.begin(); jt != it->second.end(); ++jt) {
|
||||
return_value.insert(jt->first);
|
||||
}
|
||||
}
|
||||
for (jt = it->second.begin(); jt != it->second.end(); ++jt) {
|
||||
return_value.insert(jt->first);
|
||||
}
|
||||
}
|
||||
if ((t = Parent(t)) == -1) break;
|
||||
}
|
||||
|
||||
return return_value;
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
void Type::PopulateDerivedFields(IfcWrite::IfcWritableEntity* e) {
|
||||
std::map<Type::Enum, std::set<int> >::const_iterator i = derived_map.find(e->type());
|
||||
if (i != derived_map.end()) {
|
||||
for (std::set<int>::const_iterator it = i->second.begin(); it != i->second.end(); ++it) {
|
||||
e->setArgumentDerived(*it);
|
||||
}
|
||||
}
|
||||
if (i != derived_map.end()) {
|
||||
for (std::set<int>::const_iterator it = i->second.begin(); it != i->second.end(); ++it) {
|
||||
e->setArgumentDerived(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
@@ -317,10 +349,7 @@ derived_field_statement_attrs = 'idxs.insert(%d); '
|
||||
simpletype = """%(documentation)s
|
||||
class %(name)s : public %(superclass)s {
|
||||
public:
|
||||
virtual IfcUtil::ArgumentType getArgumentType(unsigned int i) const;
|
||||
virtual Argument* getArgument(unsigned int i) const;
|
||||
bool is(Type::Enum v) const;
|
||||
Type::Enum type() const;
|
||||
virtual const IfcParse::type_declaration& declaration() const;
|
||||
static Type::Enum Class();
|
||||
explicit %(name)s (IfcAbstractEntity* e);
|
||||
%(name)s (%(type)s v);
|
||||
@@ -329,15 +358,18 @@ public:
|
||||
"""
|
||||
|
||||
simpletype_impl_comment = "// Function implementations for %(name)s"
|
||||
simpletype_impl_argument_type = "if (i == 0) { return %(attr_type)s; } else { throw IfcParse::IfcException(\"argument out of range\"); }"
|
||||
simpletype_impl_argument = "return entity->getArgument(i);"
|
||||
simpletype_impl_argument_type = "if (i == 0) { return %(attr_type)s; } else { throw IfcParse::IfcAttributeOutOfRangeException(\"Argument index out of range\"); }"
|
||||
simpletype_impl_argument = "return data_->getArgument(i);"
|
||||
simpletype_impl_is_with_supertype = "return v == Type::%(class_name)s || %(superclass)s::is(v);"
|
||||
simpletype_impl_is_without_supertype = "return v == %(class_name)s::Class();"
|
||||
simpletype_impl_type = "return Type::%(class_name)s;"
|
||||
simpletype_impl_class = "return Type::%(class_name)s;"
|
||||
simpletype_impl_explicit_constructor = "entity = e;"
|
||||
simpletype_impl_constructor = "IfcWritableEntity* e = new IfcWritableEntity(Type::%(class_name)s); e->setArgument(0, v); entity = e;"
|
||||
simpletype_impl_cast = "return *entity->getArgument(0);"
|
||||
simpletype_impl_explicit_constructor = "data_ = e;"
|
||||
simpletype_impl_constructor = "IfcWritableEntity* e = new IfcWritableEntity(Type::%(class_name)s); e->setArgument(0, v); data_ = e;"
|
||||
simpletype_impl_constructor_templated = "IfcWritableEntity* e = new IfcWritableEntity(Type::%(class_name)s); e->setArgument(0, v->generalize()); data_ = e;"
|
||||
simpletype_impl_cast = "return *data_->getArgument(0);"
|
||||
simpletype_impl_cast_templated = "IfcEntityList::ptr es = *data_->getArgument(0); return es->as<%(underlying_type)s>();"
|
||||
simpletype_impl_declaration = "return *%(class_name)s_type;"
|
||||
|
||||
select = """%(documentation)s
|
||||
typedef IfcUtil::IfcBaseClass %(name)s;
|
||||
@@ -354,13 +386,7 @@ const char* ToString(%(name)s v);
|
||||
entity = """%(documentation)s
|
||||
class %(name)s %(superclass)s{
|
||||
public:
|
||||
%(attributes)s virtual unsigned int getArgumentCount() const { return %(argument_count)d; }
|
||||
virtual IfcUtil::ArgumentType getArgumentType(unsigned int i) const {%(argument_type_function_body)s}
|
||||
virtual Type::Enum getArgumentEntity(unsigned int i) const {%(argument_entity_function_body)s}
|
||||
virtual const char* getArgumentName(unsigned int i) const {%(argument_name_function_body)s}
|
||||
virtual Argument* getArgument(unsigned int i) const { return entity->getArgument(i); }
|
||||
%(inverse)s bool is(Type::Enum v) const;
|
||||
Type::Enum type() const;
|
||||
%(attributes)s %(inverse)s virtual const IfcParse::entity& declaration() const;
|
||||
static Type::Enum Class();
|
||||
%(name)s (IfcAbstractEntity* e);
|
||||
%(name)s (%(constructor_arguments)s);
|
||||
@@ -382,11 +408,12 @@ const char* %(name)s::ToString(%(name)s v) {
|
||||
"""
|
||||
|
||||
entity_implementation = """// Function implementations for %(name)s
|
||||
%(attributes)s%(inverse)sbool %(name)s::is(Type::Enum v) const { return v == Type::%(name)s%(parent_type_test)s; }
|
||||
Type::Enum %(name)s::type() const { return Type::%(name)s; }
|
||||
%(attributes)s
|
||||
%(inverse)s
|
||||
const IfcParse::entity& %(name)s::declaration() const { return *%(name)s_type; }
|
||||
Type::Enum %(name)s::Class() { return Type::%(name)s; }
|
||||
%(name)s::%(name)s(IfcAbstractEntity* e) : %(superclass)s { if (!e) return; if (!e->is(Type::%(name)s)) throw IfcException("Unable to find find keyword in schema"); entity = e; }
|
||||
%(name)s::%(name)s(%(constructor_arguments)s) : %(superclass)s { IfcWritableEntity* e = new IfcWritableEntity(Class());%(constructor_implementation)s entity = e; EntityBuffer::Add(this); }
|
||||
%(name)s::%(name)s(IfcAbstractEntity* e) : %(superclass)s { if (!e) return; if (!e->is(Type::%(name)s)) throw IfcException("Unable to find find keyword in schema"); data_ = e; }
|
||||
%(name)s::%(name)s(%(constructor_arguments)s) : %(superclass)s { IfcWritableEntity* e = new IfcWritableEntity(Class());%(constructor_implementation)s data_ = e; EntityBuffer::Add(this); }
|
||||
"""
|
||||
|
||||
optional_attribute_description = "/// Whether the optional attribute %s is defined for this %s"
|
||||
@@ -398,6 +425,7 @@ constructor_single_initlist = "%(class_name)s::%(class_name)s(%(arguments)s) : %
|
||||
cast_function = "%(class_name)s::operator %(return_type)s() const { %(body)s }"
|
||||
|
||||
array_type = "std::vector< %(instance_type)s > /*[%(lower)s:%(upper)s]*/"
|
||||
nested_array_type = "std::vector< std::vector< %(instance_type)s > >"
|
||||
list_type = "IfcTemplatedEntityList< %(instance_type)s >::ptr"
|
||||
list_list_type = "IfcTemplatedEntityListList< %(instance_type)s >::ptr"
|
||||
untyped_list = "IfcEntityList::ptr"
|
||||
@@ -406,25 +434,24 @@ inverse_attr = "IfcTemplatedEntityList< %(entity)s >::ptr %(name)s() const; // I
|
||||
enum_from_string_stmt = ' if (s == "%(value)s") return ::%(schema_name)s::%(name)s::%(short_name)s_%(value)s;'
|
||||
|
||||
schema_entity_stmt = ' case Type::%(name)s: return new %(name)s(e); break;'
|
||||
schema_simple_stmt = ' case Type::%(name)s: return new IfcUtil::IfcEntitySelect(e); break;'
|
||||
string_map_statement = ' string_map["%(uppercase_name)s"%(padding)s] = Type::%(name)s;'
|
||||
parent_type_stmt = ' if(v==%(name)s%(padding)s) { return %(parent)s; }'
|
||||
|
||||
parent_type_test = " || %s::is(v)"
|
||||
|
||||
optional_attr_stmt = "return !entity->getArgument(%(index)d)->isNull();"
|
||||
optional_attr_stmt = "return !data_->getArgument(%(index)d)->isNull();"
|
||||
|
||||
get_attr_stmt = "return *entity->getArgument(%(index)d);"
|
||||
get_attr_stmt_enum = "return %(type)s::FromString(*entity->getArgument(%(index)d));"
|
||||
get_attr_stmt_entity = "return (%(type)s)((IfcUtil::IfcBaseClass*)(*entity->getArgument(%(index)d)));"
|
||||
get_attr_stmt_array = "IfcEntityList::ptr es = *entity->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
|
||||
get_attr_stmt_nested_array = "IfcEntityListList::ptr es = *entity->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
|
||||
get_attr_stmt = "return *data_->getArgument(%(index)d);"
|
||||
get_attr_stmt_enum = "return %(type)s::FromString(*data_->getArgument(%(index)d));"
|
||||
get_attr_stmt_entity = "return (%(type)s)((IfcUtil::IfcBaseClass*)(*data_->getArgument(%(index)d)));"
|
||||
get_attr_stmt_array = "IfcEntityList::ptr es = *data_->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
|
||||
get_attr_stmt_nested_array = "IfcEntityListList::ptr es = *data_->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
|
||||
|
||||
get_inverse = "return entity->getInverse(Type::%(type)s, %(index)d)->as<%(type)s>();"
|
||||
get_inverse = "return data_->getInverse(Type::%(type)s, %(index)d)->as<%(type)s>();"
|
||||
|
||||
set_attr_stmt = "if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%(index)d,v);"
|
||||
set_attr_stmt_enum = "if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%(index)d,v,%(type)s::ToString(v));"
|
||||
set_attr_stmt_array = "if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%(index)d,v->generalize());"
|
||||
set_attr_stmt = "if ( ! data_->isWritable() ) { data_ = new IfcWritableEntity(data_); } ((IfcWritableEntity*)data_)->setArgument(%(index)d,v);"
|
||||
set_attr_stmt_enum = "if ( ! data_->isWritable() ) { data_ = new IfcWritableEntity(data_); } ((IfcWritableEntity*)data_)->setArgument(%(index)d,v,%(type)s::ToString(v));"
|
||||
set_attr_stmt_array = "if ( ! data_->isWritable() ) { data_ = new IfcWritableEntity(data_); } ((IfcWritableEntity*)data_)->setArgument(%(index)d,v->generalize());"
|
||||
|
||||
constructor_stmt = " e->setArgument(%(index)d,(%(name)s));"
|
||||
constructor_stmt_enum = " e->setArgument(%(index)d,%(name)s,%(type)s::ToString(%(name)s));"
|
||||
|
||||
+22
-14
@@ -44,10 +44,11 @@
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
#include "../ifcgeom/IfcGeomRepresentation.h"
|
||||
#include "../ifcgeom/IfcRepresentationShapeItem.h"
|
||||
#include "../ifcgeom/IfcGeomShapeType.h"
|
||||
|
||||
#define IN_CACHE(T,E,t,e) std::map<int,t>::const_iterator it = cache.T.find(E->entity->id());\
|
||||
#define IN_CACHE(T,E,t,e) std::map<int,t>::const_iterator it = cache.T.find(E->data().id());\
|
||||
if ( it != cache.T.end() ) { e = it->second; return true; }
|
||||
#define CACHE(T,E,e) cache.T[E->entity->id()] = e;
|
||||
#define CACHE(T,E,e) cache.T[E->data().id()] = e;
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
@@ -80,9 +81,6 @@ public:
|
||||
// that consist of many faces is really detrimental for the performance.
|
||||
// Default: 1000
|
||||
GV_MAX_FACES_TO_SEW,
|
||||
// By default singular faces have no explicitly defined orientation, to
|
||||
// force faces to be defined CounterClockWise, set this value greater than zero.
|
||||
GV_FORCE_CCW_FACE_ORIENTATION,
|
||||
// The length unit used the creation of TopoDS_Shapes, primarily affects the
|
||||
// interpretation of IfcCartesianPoints and IfcVector magnitudes
|
||||
// DefaultL 1.0
|
||||
@@ -94,13 +92,15 @@ public:
|
||||
// The precision used in boolean operations, setting this value too low results
|
||||
// in artefacts and potentially modelling failures
|
||||
// Default: 0.00001 (obtained from IfcGeometricRepresentationContext if available)
|
||||
GV_PRECISION
|
||||
GV_PRECISION,
|
||||
// Whether to process shapes of type Face or higher (1) Wire or lower (-1) or all (0)
|
||||
GV_DIMENSIONALITY
|
||||
};
|
||||
|
||||
bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face);
|
||||
bool convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire);
|
||||
bool convert_shapes(const IfcUtil::IfcBaseClass* L, IfcRepresentationShapeItems& result);
|
||||
bool is_shape_collection(const IfcUtil::IfcBaseClass* L);
|
||||
IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseClass* L);
|
||||
bool convert_shape(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
|
||||
bool flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse);
|
||||
bool convert_wire(const IfcUtil::IfcBaseClass* L, TopoDS_Wire& result);
|
||||
@@ -109,6 +109,7 @@ public:
|
||||
bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
|
||||
bool convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
|
||||
IfcSchema::IfcSurfaceStyleShading* get_surface_style(IfcSchema::IfcRepresentationItem* item);
|
||||
const IfcSchema::IfcRepresentationItem* find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item);
|
||||
bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid);
|
||||
bool is_compound(const TopoDS_Shape& shape);
|
||||
bool is_convex(const TopoDS_Wire& wire);
|
||||
@@ -121,9 +122,12 @@ public:
|
||||
double face_area(const TopoDS_Face& f);
|
||||
void apply_tolerance(TopoDS_Shape& s, double t);
|
||||
void setValue(GeomValue var, double value);
|
||||
double getValue(GeomValue var);
|
||||
double getValue(GeomValue var) const;
|
||||
bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape);
|
||||
void remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
|
||||
void remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
|
||||
void remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
|
||||
bool wire_to_sequence_of_point(const TopoDS_Wire&, TColgp_SequenceOfPnt&);
|
||||
void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed);
|
||||
|
||||
std::pair<std::string, double> initializeUnits(IfcSchema::IfcUnitAssignment*);
|
||||
|
||||
@@ -135,12 +139,16 @@ public:
|
||||
const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem* representation_item);
|
||||
|
||||
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) {
|
||||
// For certain representation items, most notably boolean operands,
|
||||
// a style definition might reside on one of its operands.
|
||||
representation_item = find_item_carrying_style(representation_item);
|
||||
|
||||
IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem();
|
||||
for (IfcSchema::IfcStyledItem::list::it jt = styled_items->begin(); jt != styled_items->end(); ++jt) {
|
||||
#ifdef USE_IFC4
|
||||
IfcUtil::IfcAbstractSelect::list::ptr style_assignments = (*jt)->Styles();
|
||||
for (IfcUtil::IfcAbstractSelect::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
if (!(*kt)->is(IfcSchema::Type::IfcPresentationStyleAssignment)) {
|
||||
IfcEntityList::ptr style_assignments = (*jt)->Styles();
|
||||
for (IfcEntityList::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
if (!(*kt)->declaration().is(IfcSchema::Type::IfcPresentationStyleAssignment)) {
|
||||
continue;
|
||||
}
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt;
|
||||
@@ -152,12 +160,12 @@ public:
|
||||
IfcEntityList::ptr styles = style_assignment->Styles();
|
||||
for (IfcEntityList::it lt = styles->begin(); lt != styles->end(); ++lt) {
|
||||
IfcUtil::IfcBaseClass* style = *lt;
|
||||
if (style->is(IfcSchema::Type::IfcSurfaceStyle)) {
|
||||
if (style->declaration().is(IfcSchema::Type::IfcSurfaceStyle)) {
|
||||
IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style;
|
||||
if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) {
|
||||
IfcEntityList::ptr styles_elements = surface_style->Styles();
|
||||
for (IfcEntityList::it mt = styles_elements->begin(); mt != styles_elements->end(); ++mt) {
|
||||
if ((*mt)->is(T::Class())) {
|
||||
if ((*mt)->declaration().is(T::Class())) {
|
||||
return std::make_pair(surface_style, (T*) *mt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,17 +77,21 @@
|
||||
|
||||
#include <TopLoc_Location.hxx>
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include <Geom_BSplineCurve.hxx>
|
||||
#endif
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircle* l, Handle(Geom_Curve)& curve) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
if ( r < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l);
|
||||
return false;
|
||||
}
|
||||
gp_Trsf trsf;
|
||||
IfcSchema::IfcAxis2Placement* placement = l->Position();
|
||||
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
if (placement->declaration().is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
} else {
|
||||
gp_Trsf2d trsf2d;
|
||||
@@ -102,7 +106,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipse* l, Handle(Geom_Curve)
|
||||
double x = l->SemiAxis1() * getValue(GV_LENGTH_UNIT);
|
||||
double y = l->SemiAxis2() * getValue(GV_LENGTH_UNIT);
|
||||
if (x < ALMOST_ZERO || y < ALMOST_ZERO) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l);
|
||||
return false;
|
||||
}
|
||||
// Open Cascade does not allow ellipses of which the minor radius
|
||||
@@ -112,7 +116,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipse* l, Handle(Geom_Curve)
|
||||
const bool rotated = y > x;
|
||||
gp_Trsf trsf;
|
||||
IfcSchema::IfcAxis2Placement* placement = l->Position();
|
||||
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
if (placement->declaration().is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
} else {
|
||||
gp_Trsf2d trsf2d;
|
||||
@@ -135,4 +139,39 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLine* l, Handle(Geom_Curve)& c
|
||||
// See note at IfcGeomWires.cpp:237
|
||||
curve = new Geom_Line(pnt,vec);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_IFC4
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineCurveWithKnots* l, Handle(Geom_Curve)& curve) {
|
||||
|
||||
const IfcSchema::IfcCartesianPoint::list::ptr cps = l->ControlPointsList();
|
||||
const std::vector<int> mults = l->KnotMultiplicities();
|
||||
const std::vector<double> knots = l->Knots();
|
||||
|
||||
TColgp_Array1OfPnt Poles(0, cps->size() - 1);
|
||||
TColStd_Array1OfReal Knots(0, (int)knots.size() - 1);
|
||||
TColStd_Array1OfInteger Mults(0, (int)mults.size() - 1);
|
||||
Standard_Integer Degree = l->Degree();
|
||||
Standard_Boolean Periodic = l->ClosedCurve();
|
||||
|
||||
int i = 0;
|
||||
for (IfcSchema::IfcCartesianPoint::list::it it = cps->begin(); it != cps->end(); ++it, ++i) {
|
||||
gp_Pnt pnt;
|
||||
if (!convert(*it, pnt)) return false;
|
||||
Poles(i) = pnt;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (std::vector<int>::const_iterator it = mults.begin(); it != mults.end(); ++it, ++i) {
|
||||
Mults(i) = *it;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (std::vector<double>::const_iterator it = knots.begin(); it != knots.end(); ++it, ++i) {
|
||||
Knots(i) = *it;
|
||||
}
|
||||
|
||||
curve = new Geom_BSplineCurve(Poles, Knots, Mults, Degree, Periodic);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -20,10 +20,14 @@
|
||||
#ifndef IFCGEOMELEMENT_H
|
||||
#define IFCGEOMELEMENT_H
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../ifcparse/IfcGlobalId.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeomRepresentation.h"
|
||||
#include "../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
template <typename P>
|
||||
@@ -72,6 +76,8 @@ namespace IfcGeom {
|
||||
std::string _name;
|
||||
std::string _type;
|
||||
std::string _guid;
|
||||
std::string _context;
|
||||
std::string _unique_id;
|
||||
Transformation<P> _transformation;
|
||||
public:
|
||||
int id() const { return _id; }
|
||||
@@ -79,10 +85,22 @@ namespace IfcGeom {
|
||||
const std::string& name() const { return _name; }
|
||||
const std::string& type() const { return _type; }
|
||||
const std::string& guid() const { return _guid; }
|
||||
const std::string& context() const { return _context; }
|
||||
const std::string& unique_id() const { return _unique_id; }
|
||||
const Transformation<P>& transformation() const { return _transformation; }
|
||||
Element(const ElementSettings& settings, int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf)
|
||||
: _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _transformation(settings, trsf)
|
||||
{}
|
||||
Element(const ElementSettings& settings, int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const std::string& context, const gp_Trsf& trsf)
|
||||
: _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _context(context), _transformation(settings, trsf)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "product-" << IfcParse::IfcGlobalId(guid).formatted();
|
||||
if (!_context.empty()) {
|
||||
std::string ctx = _context;
|
||||
std::transform(ctx.begin(), ctx.end(), ctx.begin(), ::tolower);
|
||||
std::replace(ctx.begin(), ctx.end(), ' ', '-');
|
||||
oss << "-" << ctx;
|
||||
}
|
||||
_unique_id = oss.str();
|
||||
}
|
||||
virtual ~Element() {}
|
||||
};
|
||||
|
||||
@@ -92,8 +110,8 @@ namespace IfcGeom {
|
||||
Representation::BRep* _geometry;
|
||||
public:
|
||||
const Representation::BRep& geometry() const { return *_geometry; }
|
||||
BRepElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf, Representation::BRep* geometry)
|
||||
: Element<P>(geometry->settings(),id,parent_id,name,type,guid,trsf)
|
||||
BRepElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const std::string& context, const gp_Trsf& trsf, Representation::BRep* geometry)
|
||||
: Element<P>(geometry->settings(),id,parent_id,name,type,guid,context,trsf)
|
||||
, _geometry(geometry)
|
||||
{}
|
||||
virtual ~BRepElement() {
|
||||
|
||||
+238
-171
@@ -47,6 +47,7 @@
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
#include <Geom_Line.hxx>
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include <Geom_TrimmedCurve.hxx>
|
||||
@@ -70,6 +71,7 @@
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopoDS_Iterator.hxx>
|
||||
|
||||
#include <BRepAlgoAPI_Cut.hxx>
|
||||
|
||||
@@ -83,127 +85,218 @@
|
||||
#include <Standard_Failure.hxx>
|
||||
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepCheck_Face.hxx>
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
|
||||
#include <Standard_Version.hxx>
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include <Geom_BSplineSurface.hxx>
|
||||
#include <TColgp_Array2OfPnt.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <BRepCheck_Face.hxx>
|
||||
#endif
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
|
||||
IfcSchema::IfcFaceBound::list::it it = bounds->begin();
|
||||
IfcSchema::IfcLoop* loop = (*it)->Bound();
|
||||
TopoDS_Wire outer_wire;
|
||||
if ( ! convert_wire(loop,outer_wire) ) return false;
|
||||
BRepBuilderAPI_MakeFace mf (outer_wire);
|
||||
BRepBuilderAPI_FaceError er = mf.Error();
|
||||
if ( er == BRepBuilderAPI_NotPlanar ) {
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
FTol.SetTolerance(outer_wire, 0.01, TopAbs_WIRE);
|
||||
mf.~BRepBuilderAPI_MakeFace();
|
||||
new (&mf) BRepBuilderAPI_MakeFace(outer_wire);
|
||||
er = mf.Error();
|
||||
}
|
||||
if ( er != BRepBuilderAPI_FaceDone ) return false;
|
||||
if ( bounds->size() == 1 ) {
|
||||
face = mf.Face();
|
||||
} else {
|
||||
for( ++it; it != bounds->end(); ++ it) {
|
||||
IfcSchema::IfcLoop* loop = (*it)->Bound();
|
||||
TopoDS_Wire wire;
|
||||
if ( ! convert_wire(loop,wire) ) return false;
|
||||
mf.Add(wire);
|
||||
}
|
||||
if ( mf.IsDone() ) {
|
||||
ShapeFix_Shape sfs(mf.Face());
|
||||
sfs.Perform();
|
||||
TopoDS_Shape sfs_shape = sfs.Shape();
|
||||
bool is_face = sfs_shape.ShapeType() == TopAbs_FACE;
|
||||
if ( is_face ) {
|
||||
face = TopoDS::Face(sfs_shape);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( getValue(GV_FORCE_CCW_FACE_ORIENTATION)>0 ) {
|
||||
// Check the orientation of the face by comparing the
|
||||
// normal of the topological surface to the Newell's Method's
|
||||
// normal. Newell's Method is used for the normal calculation
|
||||
// as a simple edge cross product can give opposite results
|
||||
// for a concave face boundary.
|
||||
// Reference: Graphics Gems III p. 231
|
||||
BRepGProp_Face prop(TopoDS::Face(face));
|
||||
gp_Vec normal_direction;
|
||||
gp_Pnt center;
|
||||
double u1,u2,v1,v2;
|
||||
prop.Bounds(u1,u2,v1,v2);
|
||||
prop.Normal((u1+u2)/2.0,(v1+v2)/2.0,center,normal_direction);
|
||||
gp_Dir face_normal1 = gp_Dir(normal_direction.XYZ());
|
||||
Handle(Geom_Surface) face_surface;
|
||||
const bool is_face_surface = l->declaration().is(IfcSchema::Type::IfcFaceSurface);
|
||||
|
||||
double x = 0, y = 0, z = 0;
|
||||
gp_Pnt current, previous, first;
|
||||
int n = 0;
|
||||
// Iterate over the vertices of the outer wire (discarding
|
||||
// any potential holes)
|
||||
for ( TopExp_Explorer exp(outer_wire,TopAbs_VERTEX);; exp.Next()) {
|
||||
unsigned has_more = exp.More();
|
||||
if ( has_more ) {
|
||||
const TopoDS_Vertex& v = TopoDS::Vertex(exp.Current());
|
||||
current = BRep_Tool::Pnt(v);
|
||||
} else {
|
||||
current = first;
|
||||
}
|
||||
if ( n ) {
|
||||
const double& xn = previous.X();
|
||||
const double& yn = previous.Y();
|
||||
const double& zn = previous.Z();
|
||||
const double& xn1 = current.X();
|
||||
const double& yn1 = current.Y();
|
||||
const double& zn1 = current.Z();
|
||||
x += (yn-yn1)*(zn+zn1);
|
||||
y += (xn+xn1)*(zn-zn1);
|
||||
z += (xn-xn1)*(yn+yn1);
|
||||
} else {
|
||||
first = current;
|
||||
}
|
||||
if ( !has_more ) {
|
||||
break;
|
||||
}
|
||||
previous = current;
|
||||
++n;
|
||||
}
|
||||
if (is_face_surface) {
|
||||
IfcSchema::IfcFaceSurface* fs = (IfcSchema::IfcFaceSurface*) l;
|
||||
fs->FaceSurface();
|
||||
// FIXME: Surfaces are interpreted as a TopoDS_Shape
|
||||
TopoDS_Shape surface_shape;
|
||||
if (!convert_shape(fs->FaceSurface(), surface_shape)) return false;
|
||||
|
||||
// If Newell's normal does not point in the same direction
|
||||
// as the topological face normal the face orientation is
|
||||
// reversed
|
||||
gp_Vec face_normal2(x,y,z);
|
||||
// FIXME: Assert this obtaines the only face
|
||||
TopExp_Explorer exp(surface_shape, TopAbs_FACE);
|
||||
if (!exp.More()) return false;
|
||||
|
||||
if (face_normal2.Magnitude() > ALMOST_ZERO) {
|
||||
if ( face_normal1.Dot(face_normal2) < 0 ) {
|
||||
TopAbs_Orientation o = face.Orientation();
|
||||
face.Orientation(o == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD);
|
||||
}
|
||||
}
|
||||
TopoDS_Face surface = TopoDS::Face(exp.Current());
|
||||
face_surface = BRep_Tool::Surface(surface);
|
||||
}
|
||||
|
||||
// It might be a good idea to globally discard faces
|
||||
// smaller than a certain treshold value. But for now
|
||||
// only when processing IfcConnectedFacesets the small
|
||||
// faces are skipped.
|
||||
// return face_area(face) > 0.0001;
|
||||
return true;
|
||||
const int num_bounds = bounds->size();
|
||||
int num_outer_bounds = 0;
|
||||
|
||||
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
|
||||
IfcSchema::IfcFaceBound* bound = *it;
|
||||
if (bound->declaration().is(IfcSchema::Type::IfcFaceOuterBound)) num_outer_bounds ++;
|
||||
}
|
||||
|
||||
// The number of outer bounds should be one according to the schema. Also Open Cascade
|
||||
// expects this, but it is not strictly checked. Regardless, if the number is greater,
|
||||
// the face will still be processed as long as there are no holes. A compound of faces
|
||||
// is returned in that case.
|
||||
if (num_bounds > 1 && num_outer_bounds > 1 && num_bounds != num_outer_bounds) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
if (num_outer_bounds > 1) {
|
||||
builder.MakeCompound(compound);
|
||||
}
|
||||
|
||||
// The builder is initialized on the heap because of the various different moments
|
||||
// of initialization depending on the configuration of surfaces and boundaries.
|
||||
BRepBuilderAPI_MakeFace* mf = 0;
|
||||
|
||||
bool success = false;
|
||||
int processed = 0;
|
||||
|
||||
for (int process_interior = 0; process_interior <= 1; ++process_interior) {
|
||||
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
|
||||
IfcSchema::IfcFaceBound* bound = *it;
|
||||
IfcSchema::IfcLoop* loop = bound->Bound();
|
||||
|
||||
bool same_sense = bound->Orientation();
|
||||
const bool is_interior =
|
||||
!bound->declaration().is(IfcSchema::Type::IfcFaceOuterBound) &&
|
||||
(num_bounds > 1) &&
|
||||
(num_outer_bounds < num_bounds);
|
||||
|
||||
// The exterior face boundary is processed first
|
||||
if (is_interior == !process_interior) continue;
|
||||
|
||||
TopoDS_Wire wire;
|
||||
if (!convert_wire(loop, wire)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop);
|
||||
delete mf;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
The approach below does not result in a significant speed-up
|
||||
if (loop->declaration().is(IfcSchema::Type::IfcPolyLoop) && processed == 0 && face_surface.IsNull()) {
|
||||
IfcSchema::IfcPolyLoop* polyloop = (IfcSchema::IfcPolyLoop*) loop;
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points = polyloop->Polygon();
|
||||
|
||||
if (points->size() == 3) {
|
||||
// Help Open Cascade by finding the plane more efficiently
|
||||
IfcSchema::IfcCartesianPoint::list::it point_iterator = points->begin();
|
||||
gp_Pnt a, b, c;
|
||||
convert(*point_iterator++, a);
|
||||
convert(*point_iterator++, b);
|
||||
convert(*point_iterator++, c);
|
||||
const gp_XYZ ab = (b.XYZ() - a.XYZ());
|
||||
const gp_XYZ ac = (c.XYZ() - a.XYZ());
|
||||
const gp_Vec cross = ab.Crossed(ac);
|
||||
if (cross.SquareMagnitude() > ALMOST_ZERO) {
|
||||
const gp_Dir n = cross;
|
||||
face_surface = new Geom_Plane(a, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (!same_sense) {
|
||||
wire.Reverse();
|
||||
}
|
||||
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
FTol.SetTolerance(wire, getValue(GV_PRECISION), TopAbs_WIRE);
|
||||
|
||||
if (!mf) {
|
||||
if (face_surface.IsNull()) {
|
||||
mf = new BRepBuilderAPI_MakeFace(wire);
|
||||
} else {
|
||||
mf = new BRepBuilderAPI_MakeFace(face_surface, wire);
|
||||
}
|
||||
|
||||
/* BRepBuilderAPI_FaceError er = mf->Error();
|
||||
if (er == BRepBuilderAPI_NotPlanar) {
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
FTol.SetTolerance(wire, getValue(GV_PRECISION), TopAbs_WIRE);
|
||||
delete mf;
|
||||
mf = new BRepBuilderAPI_MakeFace(wire);
|
||||
} */
|
||||
|
||||
if (mf->IsDone()) {
|
||||
TopoDS_Face outer_face_bound = mf->Face();
|
||||
|
||||
if (BRepCheck_Face(outer_face_bound).OrientationOfWires() == BRepCheck_BadOrientationOfSubshape) {
|
||||
wire.Reverse();
|
||||
same_sense = !same_sense;
|
||||
delete mf;
|
||||
if (face_surface.IsNull()) {
|
||||
mf = new BRepBuilderAPI_MakeFace(wire);
|
||||
} else {
|
||||
mf = new BRepBuilderAPI_MakeFace(face_surface, wire);
|
||||
}
|
||||
ShapeFix_Face fix(mf->Face());
|
||||
fix.FixOrientation();
|
||||
fix.Perform();
|
||||
outer_face_bound = fix.Face();
|
||||
}
|
||||
|
||||
// If the wires are reversed the face needs to be reversed as well in order
|
||||
// to maintain the counter-clock-wise ordering of the bounding wire's vertices.
|
||||
bool all_reversed = true;
|
||||
TopoDS_Iterator jt(outer_face_bound, false);
|
||||
for (; jt.More(); jt.Next()) {
|
||||
const TopoDS_Wire& w = TopoDS::Wire(jt.Value());
|
||||
if ((w.Orientation() != TopAbs_REVERSED) == same_sense) {
|
||||
all_reversed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_reversed) {
|
||||
outer_face_bound.Reverse();
|
||||
}
|
||||
|
||||
if (num_outer_bounds > 1) {
|
||||
builder.Add(compound, outer_face_bound);
|
||||
delete mf; mf = 0;
|
||||
} else if (num_bounds > 1) {
|
||||
// Reinitialize the builder to the outer face
|
||||
// bound in order to add holes more robustly.
|
||||
delete mf;
|
||||
// TODO: What about the face_surface?
|
||||
mf = new BRepBuilderAPI_MakeFace(outer_face_bound);
|
||||
} else {
|
||||
face = outer_face_bound;
|
||||
success = true;
|
||||
}
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary", bound);
|
||||
delete mf;
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
mf->Add(wire);
|
||||
}
|
||||
processed ++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
success = processed == num_bounds;
|
||||
if (success) {
|
||||
if (num_outer_bounds > 1) {
|
||||
face = compound;
|
||||
} else {
|
||||
success = success && mf->IsDone();
|
||||
if (success) {
|
||||
face = mf->Face();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
FTol.SetTolerance(face, getValue(GV_PRECISION), TopAbs_FACE);
|
||||
}
|
||||
|
||||
delete mf;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, TopoDS_Shape& face) {
|
||||
@@ -235,10 +328,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids*
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleProfileDef* l, TopoDS_Shape& face) {
|
||||
const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -254,7 +347,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef* l,
|
||||
const double r = l->RoundingRadius() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || r < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -278,7 +371,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l,
|
||||
const double r2 = fr2 ? l->InnerFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.;
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -320,7 +413,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrapeziumProfileDef* l, TopoDS
|
||||
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( x1 < ALMOST_ZERO || w < ALMOST_ZERO || y < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -345,7 +438,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcIShapeProfileDef* l, TopoDS_Sh
|
||||
bool doFillet2 = doFillet1;
|
||||
double x2 = x1, dy2 = dy1, f2 = f1;
|
||||
|
||||
if (l->is(IfcSchema::Type::IfcAsymmetricIShapeProfileDef)) {
|
||||
if (l->declaration().is(IfcSchema::Type::IfcAsymmetricIShapeProfileDef)) {
|
||||
IfcSchema::IfcAsymmetricIShapeProfileDef* assym = (IfcSchema::IfcAsymmetricIShapeProfileDef*) l;
|
||||
x2 = assym->TopFlangeWidth() / 2. * getValue(GV_LENGTH_UNIT);
|
||||
doFillet2 = assym->hasTopFlangeFilletRadius();
|
||||
@@ -358,7 +451,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcIShapeProfileDef* l, TopoDS_Sh
|
||||
}
|
||||
|
||||
if ( x1 < ALMOST_ZERO || x2 < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || dy1 < ALMOST_ZERO || dy2 < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -391,7 +484,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcZShapeProfileDef* l, TopoDS_Sh
|
||||
}
|
||||
|
||||
if ( x == 0.0f || y == 0.0f || dx == 0.0f || dy == 0.0f ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -418,7 +511,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCShapeProfileDef* l, TopoDS_Sh
|
||||
}
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -451,7 +544,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Sh
|
||||
}
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -483,7 +576,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Sh
|
||||
const double det = a1*b2 - a2*b1;
|
||||
|
||||
if (ALMOST_THE_SAME(det, 0.)) {
|
||||
Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -529,7 +622,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcUShapeProfileDef* l, TopoDS_Sh
|
||||
}
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -557,7 +650,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
|
||||
const double webSlope = hasWebSlope ? (l->WebSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -605,7 +698,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
|
||||
const double det = a1*b2 - a2*b1;
|
||||
|
||||
if (ALMOST_THE_SAME(det, 0.)) {
|
||||
Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -628,7 +721,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleProfileDef* l, TopoDS_Shape& face) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
if ( r == 0.0f ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -652,7 +745,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, Top
|
||||
const double t = l->WallThickness() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( r == 0.0f || t == 0.0f ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -681,7 +774,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipseProfileDef* l, TopoDS_S
|
||||
double ry = l->SemiAxis2() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( rx < ALMOST_ZERO || ry < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -764,7 +857,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeProfileDef* l, TopoDS
|
||||
builder.MakeCompound(compound);
|
||||
|
||||
IfcSchema::IfcProfileDef::list::ptr profiles = l->Profiles();
|
||||
bool first = true;
|
||||
//bool first = true;
|
||||
for (IfcSchema::IfcProfileDef::list::it it = profiles->begin(); it != profiles->end(); ++it) {
|
||||
TopoDS_Face f;
|
||||
if (convert_face(*it, f)) {
|
||||
@@ -798,20 +891,32 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcDerivedProfileDef* l, TopoDS_S
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPlane* l, TopoDS_Shape& face) {
|
||||
gp_Pln pln;
|
||||
convert(l, pln);
|
||||
Handle_Geom_Surface surf = new Geom_Plane(pln);
|
||||
#if OCC_VERSION_HEX < 0x60502
|
||||
face = BRepBuilderAPI_MakeFace(surf);
|
||||
#else
|
||||
face = BRepBuilderAPI_MakeFace(surf, getValue(GV_PRECISION));
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef USE_IFC4
|
||||
|
||||
bool convert_surf(IfcSchema::IfcBSplineSurfaceWithKnots* l, Handle_Geom_Surface& surf) {
|
||||
SHARED_PTR< IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint> > cps = l->ControlPointsList();
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineSurfaceWithKnots* l, TopoDS_Shape& face) {
|
||||
boost::shared_ptr< IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint> > cps = l->ControlPointsList();
|
||||
std::vector<double> uknots = l->UKnots();
|
||||
std::vector<double> vknots = l->VKnots();
|
||||
std::vector<int> umults = l->UMultiplicities();
|
||||
std::vector<int> vmults = l->VMultiplicities();
|
||||
|
||||
TColgp_Array2OfPnt Poles (0, cps->size() - 1, 0, (*cps->begin()).size() - 1);
|
||||
TColStd_Array1OfReal UKnots(0, uknots.size() - 1);
|
||||
TColStd_Array1OfReal VKnots(0, vknots.size() - 1);
|
||||
TColStd_Array1OfInteger UMults(0, umults.size() - 1);
|
||||
TColStd_Array1OfInteger VMults(0, vmults.size() - 1);
|
||||
TColgp_Array2OfPnt Poles (0, (int)cps->size() - 1, 0, (int)(*cps->begin()).size() - 1);
|
||||
TColStd_Array1OfReal UKnots(0, (int)uknots.size() - 1);
|
||||
TColStd_Array1OfReal VKnots(0, (int)vknots.size() - 1);
|
||||
TColStd_Array1OfInteger UMults(0, (int)umults.size() - 1);
|
||||
TColStd_Array1OfInteger VMults(0, (int)vmults.size() - 1);
|
||||
Standard_Integer UDegree = l->UDegree();
|
||||
Standard_Integer VDegree = l->VDegree();
|
||||
|
||||
@@ -841,51 +946,13 @@ bool convert_surf(IfcSchema::IfcBSplineSurfaceWithKnots* l, Handle_Geom_Surface&
|
||||
for (std::vector<int>::const_iterator it = vmults.begin(); it != vmults.end(); ++it, ++i) {
|
||||
VMults(i) = *it;
|
||||
}
|
||||
surf = new Geom_BSplineSurface(Poles, UKnots, VKnots, UMults, VMults, UDegree, VDegree);
|
||||
return true;
|
||||
}
|
||||
Handle_Geom_Surface surf = new Geom_BSplineSurface(Poles, UKnots, VKnots, UMults, VMults, UDegree, VDegree);
|
||||
|
||||
bool convert_surf(IfcSchema::IfcPlane* l, Handle_Geom_Surface& surf) {
|
||||
gp_Pln pln;
|
||||
convert(l, pln);
|
||||
surf = new Geom_Plane(pln);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAdvancedFace* l, TopoDS_Shape& face) {
|
||||
IfcSchema::IfcSurface* s = l->FaceSurface();
|
||||
Handle_Geom_Surface surf(0);
|
||||
if (s->is(IfcSchema::Type::IfcBSplineSurfaceWithKnots)) {
|
||||
convert_surf((IfcSchema::IfcBSplineSurfaceWithKnots*)s, surf);
|
||||
} else if (s->is(IfcSchema::Type::IfcPlane)) {
|
||||
convert_surf((IfcSchema::IfcPlane*)s, surf);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeFace mf(surf, Precision::Confusion());
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
|
||||
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
|
||||
IfcSchema::IfcLoop* loop = (*it)->Bound();
|
||||
TopoDS_Wire outer_wire;
|
||||
if (!convert_wire(loop, outer_wire)) return false;
|
||||
|
||||
TopoDS_Face temp = BRepBuilderAPI_MakeFace(surf, outer_wire);
|
||||
|
||||
if (BRepCheck_Face(temp).OrientationOfWires() == BRepCheck_BadOrientationOfSubshape) {
|
||||
outer_wire.Reverse();
|
||||
ShapeFix_Face fix(BRepBuilderAPI_MakeFace(surf, outer_wire).Face());
|
||||
fix.FixOrientation();
|
||||
fix.Perform();
|
||||
TopoDS_Face temp = fix.Face();
|
||||
TopExp_Explorer exp(temp, TopAbs_WIRE);
|
||||
outer_wire = TopoDS::Wire(exp.Current());
|
||||
}
|
||||
|
||||
mf.Add(outer_wire);
|
||||
}
|
||||
|
||||
face = mf.Face();
|
||||
#if OCC_VERSION_HEX < 0x60502
|
||||
face = BRepBuilderAPI_MakeFace(surf);
|
||||
#else
|
||||
face = BRepBuilderAPI_MakeFace(surf, getValue(GV_PRECISION));
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -63,6 +63,9 @@
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopoDS_CompSolid.hxx>
|
||||
|
||||
#include <TopExp.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
|
||||
#include <BRepPrimAPI_MakePrism.hxx>
|
||||
@@ -95,14 +98,23 @@
|
||||
#include <Poly_Triangulation.hxx>
|
||||
#include <Poly_Array1OfTriangle.hxx>
|
||||
|
||||
#include <TopExp.hxx>
|
||||
#include <TopTools_IndexedMapOfShape.hxx>
|
||||
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
|
||||
#include <TopTools_ListIteratorOfListOfShape.hxx>
|
||||
|
||||
#include <Standard_Version.hxx>
|
||||
|
||||
#include "../ifcparse/IfcSIPrefix.h"
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
#if OCC_VERSION_HEX < 0x60900
|
||||
#ifdef _MSC_VER
|
||||
#pragma message("warning: You are linking against Open CASCADE version " OCC_VERSION_COMPLETE ". Version 6.9.0 introduces various improvements with relation to boolean operations. You are advised to upgrade.")
|
||||
#else
|
||||
#warning "You are linking against linking against an older version of Open CASCADE. Version 6.9.0 introduces various improvements with relation to boolean operations. You are advised to upgrade."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
bool IfcGeom::Kernel::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape) {
|
||||
BRepOffsetAPI_Sewing builder;
|
||||
builder.SetTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
|
||||
@@ -134,7 +146,9 @@ bool IfcGeom::Kernel::is_compound(const TopoDS_Shape& shape) {
|
||||
|
||||
const TopoDS_Shape& IfcGeom::Kernel::ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid) {
|
||||
const bool is_comp = is_compound(shape);
|
||||
if ( ! is_comp ) return shape;
|
||||
if (!is_comp) {
|
||||
return solid = shape;
|
||||
}
|
||||
create_solid_from_compound(shape, solid);
|
||||
|
||||
// If the SEW_SHELLS option had been set this precision had been applied
|
||||
@@ -147,17 +161,26 @@ const TopoDS_Shape& IfcGeom::Kernel::ensure_fit_for_subtraction(const TopoDS_Sha
|
||||
|
||||
bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings,
|
||||
const IfcGeom::IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::IfcRepresentationShapeItems& cut_shapes) {
|
||||
|
||||
// TODO: Refactor convert_openings() convert_openings_fast() and convert(IfcBooleanResult) to use
|
||||
// the same code base and conform to the same checks and logging messages.
|
||||
|
||||
// Iterate over IfcOpeningElements
|
||||
IfcGeom::IfcRepresentationShapeItems opening_shapes;
|
||||
unsigned int last_size = 0;
|
||||
for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) {
|
||||
IfcSchema::IfcRelVoidsElement* v = *it;
|
||||
IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement();
|
||||
if ( fes->is(IfcSchema::Type::IfcOpeningElement) ) {
|
||||
if ( fes->declaration().is(IfcSchema::Type::IfcOpeningElement) ) {
|
||||
if (!fes->hasRepresentation()) continue;
|
||||
|
||||
// Convert the IfcRepresentation of the IfcOpeningElement
|
||||
gp_Trsf opening_trsf;
|
||||
IfcGeom::Kernel::convert(fes->ObjectPlacement(),opening_trsf);
|
||||
if (fes->hasObjectPlacement()) {
|
||||
try {
|
||||
convert(fes->ObjectPlacement(),opening_trsf);
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
// Move the opening into the coordinate system of the IfcProduct
|
||||
opening_trsf.PreMultiply(entity_trsf.Inverted());
|
||||
@@ -184,7 +207,7 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons
|
||||
const gp_GTrsf& entity_shape_gtrsf = it3->Placement();
|
||||
TopoDS_Shape entity_shape;
|
||||
if ( entity_shape_gtrsf.Form() == gp_Other ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to:",entity->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Applying non uniform transformation to:", entity);
|
||||
entity_shape = BRepBuilderAPI_GTransform(entity_shape_unlocated,entity_shape_gtrsf,true).Shape();
|
||||
} else {
|
||||
entity_shape = entity_shape_unlocated.Moved(entity_shape_gtrsf.Trsf());
|
||||
@@ -196,18 +219,17 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons
|
||||
const TopoDS_Shape& opening_shape_unlocated = ensure_fit_for_subtraction(it4->Shape(),opening_shape_solid);
|
||||
const gp_GTrsf& opening_shape_gtrsf = it4->Placement();
|
||||
if ( opening_shape_gtrsf.Form() == gp_Other ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to opening of:",entity->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Applying non uniform transformation to opening of:", entity);
|
||||
}
|
||||
const TopoDS_Shape& opening_shape = opening_shape_gtrsf.Form() == gp_Other
|
||||
? BRepBuilderAPI_GTransform(opening_shape_unlocated,opening_shape_gtrsf,true).Shape()
|
||||
: opening_shape_unlocated.Moved(opening_shape_gtrsf.Trsf());
|
||||
|
||||
double opening_volume, original_shape_volume;
|
||||
double opening_volume;
|
||||
if ( Logger::Verbosity() >= Logger::LOG_WARNING ) {
|
||||
opening_volume = shape_volume(opening_shape);
|
||||
if ( opening_volume <= ALMOST_ZERO )
|
||||
Logger::Message(Logger::LOG_WARNING,"Empty opening for:",entity->entity);
|
||||
original_shape_volume = shape_volume(entity_shape);
|
||||
Logger::Message(Logger::LOG_WARNING, "Empty opening for:", entity);
|
||||
}
|
||||
|
||||
if (entity_shape.ShapeType() == TopAbs_COMPSOLID) {
|
||||
@@ -222,16 +244,30 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons
|
||||
TopExp_Explorer exp(entity_shape, TopAbs_SOLID);
|
||||
|
||||
for (; exp.More(); exp.Next()) {
|
||||
|
||||
#if OCC_VERSION_HEX < 0x60900
|
||||
BRepAlgoAPI_Cut brep_cut(exp.Current(), opening_shape);
|
||||
#else
|
||||
BRepAlgoAPI_Cut brep_cut;
|
||||
TopTools_ListOfShape s1s;
|
||||
s1s.Append(exp.Current());
|
||||
TopTools_ListOfShape s2s;
|
||||
s2s.Append(opening_shape);
|
||||
brep_cut.SetFuzzyValue(getValue(GV_PRECISION));
|
||||
brep_cut.SetArguments(s1s);
|
||||
brep_cut.SetTools(s2s);
|
||||
brep_cut.Build();
|
||||
#endif
|
||||
|
||||
bool added = false;
|
||||
if ( brep_cut.IsDone() ) {
|
||||
TopoDS_Shape brep_cut_result = brep_cut;
|
||||
BRepCheck_Analyzer analyser(brep_cut_result);
|
||||
bool is_valid = analyser.IsValid() != 0;
|
||||
if (is_valid) {
|
||||
TopExp_Explorer exp(brep_cut_result, TopAbs_SOLID);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
builder.Add(compound, exp.Current());
|
||||
TopExp_Explorer exp2(brep_cut_result, TopAbs_SOLID);
|
||||
for (; exp2.More(); exp2.Next()) {
|
||||
builder.Add(compound, exp2.Current());
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
@@ -240,33 +276,53 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons
|
||||
// Add the original in case subtraction fails
|
||||
builder.Add(compound, exp.Current());
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",entity->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to process subtraction:", entity);
|
||||
}
|
||||
}
|
||||
|
||||
entity_shape = compound;
|
||||
|
||||
} else {
|
||||
#if OCC_VERSION_HEX < 0x60900
|
||||
BRepAlgoAPI_Cut brep_cut(entity_shape,opening_shape);
|
||||
#else
|
||||
BRepAlgoAPI_Cut brep_cut;
|
||||
TopTools_ListOfShape s1s;
|
||||
s1s.Append(entity_shape);
|
||||
TopTools_ListOfShape s2s;
|
||||
s2s.Append(opening_shape);
|
||||
brep_cut.SetFuzzyValue(getValue(GV_PRECISION));
|
||||
brep_cut.SetArguments(s1s);
|
||||
brep_cut.SetTools(s2s);
|
||||
brep_cut.Build();
|
||||
#endif
|
||||
|
||||
if ( brep_cut.IsDone() ) {
|
||||
TopoDS_Shape brep_cut_result = brep_cut;
|
||||
|
||||
|
||||
ShapeFix_Shape fix(brep_cut_result);
|
||||
try {
|
||||
fix.Perform();
|
||||
brep_cut_result = fix.Shape();
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Shape healing failed on opening subtraction result", entity);
|
||||
}
|
||||
|
||||
BRepCheck_Analyzer analyser(brep_cut_result);
|
||||
bool is_valid = analyser.IsValid() != 0;
|
||||
if ( is_valid ) {
|
||||
entity_shape = brep_cut;
|
||||
entity_shape = brep_cut_result;
|
||||
if ( Logger::Verbosity() >= Logger::LOG_WARNING ) {
|
||||
const double volume_after_subtraction = shape_volume(entity_shape);
|
||||
|
||||
double original_shape_volume = shape_volume(entity_shape);
|
||||
if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) )
|
||||
Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",entity->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Subtraction yields unchanged volume:", entity);
|
||||
}
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR,"Invalid result from subtraction:",entity->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid result from subtraction:", entity);
|
||||
}
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",entity->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to process subtraction:", entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,6 +333,7 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons
|
||||
return true;
|
||||
}
|
||||
|
||||
#if OCC_VERSION_HEX < 0x60900
|
||||
bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings,
|
||||
const IfcGeom::IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::IfcRepresentationShapeItems& cut_shapes) {
|
||||
|
||||
@@ -288,11 +345,16 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity,
|
||||
for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) {
|
||||
IfcSchema::IfcRelVoidsElement* v = *it;
|
||||
IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement();
|
||||
if ( fes->is(IfcSchema::Type::IfcOpeningElement) ) {
|
||||
if ( fes->declaration().is(IfcSchema::Type::IfcOpeningElement) ) {
|
||||
if (!fes->hasRepresentation()) continue;
|
||||
|
||||
// Convert the IfcRepresentation of the IfcOpeningElement
|
||||
gp_Trsf opening_trsf;
|
||||
IfcGeom::Kernel::convert(fes->ObjectPlacement(),opening_trsf);
|
||||
if (fes->hasObjectPlacement()) {
|
||||
try {
|
||||
convert(fes->ObjectPlacement(),opening_trsf);
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
// Move the opening into the coordinate system of the IfcProduct
|
||||
opening_trsf.PreMultiply(entity_trsf.Inverted());
|
||||
@@ -325,13 +387,14 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity,
|
||||
const gp_GTrsf& entity_shape_gtrsf = it3->Placement();
|
||||
TopoDS_Shape entity_shape;
|
||||
if ( entity_shape_gtrsf.Form() == gp_Other ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to:",entity->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Applying non uniform transformation to:", entity);
|
||||
entity_shape = BRepBuilderAPI_GTransform(entity_shape_unlocated,entity_shape_gtrsf,true).Shape();
|
||||
} else {
|
||||
entity_shape = entity_shape_unlocated.Moved(entity_shape_gtrsf.Trsf());
|
||||
}
|
||||
|
||||
BRepAlgoAPI_Cut brep_cut(entity_shape,opening_compound);
|
||||
|
||||
bool is_valid = false;
|
||||
if ( brep_cut.IsDone() ) {
|
||||
TopoDS_Shape brep_cut_result = brep_cut;
|
||||
@@ -346,13 +409,100 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity,
|
||||
// Apparently processing the boolean operation failed or resulted in an invalid result
|
||||
// in which case the original shape without the subtractions is returned instead
|
||||
// we try convert the openings in the original way, one by one.
|
||||
Logger::Message(Logger::LOG_WARNING,"Subtracting combined openings compound failed:",entity->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Subtracting combined openings compound failed:", entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings,
|
||||
const IfcGeom::IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::IfcRepresentationShapeItems& cut_shapes) {
|
||||
|
||||
TopTools_ListOfShape opening_shapelist;
|
||||
|
||||
for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) {
|
||||
IfcSchema::IfcRelVoidsElement* v = *it;
|
||||
IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement();
|
||||
if ( fes->is(IfcSchema::Type::IfcOpeningElement) ) {
|
||||
if (!fes->hasRepresentation()) continue;
|
||||
|
||||
// Convert the IfcRepresentation of the IfcOpeningElement
|
||||
gp_Trsf opening_trsf;
|
||||
if (fes->hasObjectPlacement()) {
|
||||
try {
|
||||
convert(fes->ObjectPlacement(),opening_trsf);
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
// Move the opening into the coordinate system of the IfcProduct
|
||||
opening_trsf.PreMultiply(entity_trsf.Inverted());
|
||||
|
||||
IfcSchema::IfcProductRepresentation* prodrep = fes->Representation();
|
||||
IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations();
|
||||
|
||||
IfcGeom::IfcRepresentationShapeItems opening_shapes;
|
||||
|
||||
for ( IfcSchema::IfcRepresentation::list::it it2 = reps->begin(); it2 != reps->end(); ++ it2 ) {
|
||||
convert_shapes(*it2,opening_shapes);
|
||||
}
|
||||
|
||||
for ( unsigned int i = 0; i < opening_shapes.size(); ++ i ) {
|
||||
gp_GTrsf gtrsf = opening_shapes[i].Placement();
|
||||
gtrsf.PreMultiply(opening_trsf);
|
||||
const TopoDS_Shape& opening_shape = gtrsf.Form() == gp_Other
|
||||
? BRepBuilderAPI_GTransform(opening_shapes[i].Shape(),gtrsf,true).Shape()
|
||||
: (opening_shapes[i].Shape()).Moved(gtrsf.Trsf());
|
||||
opening_shapelist.Append(opening_shape);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over the shapes of the IfcProduct
|
||||
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) {
|
||||
TopoDS_Shape entity_shape_solid;
|
||||
const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(it3->Shape(),entity_shape_solid);
|
||||
const gp_GTrsf& entity_shape_gtrsf = it3->Placement();
|
||||
TopoDS_Shape entity_shape;
|
||||
if ( entity_shape_gtrsf.Form() == gp_Other ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to:",entity->entity);
|
||||
entity_shape = BRepBuilderAPI_GTransform(entity_shape_unlocated,entity_shape_gtrsf,true).Shape();
|
||||
} else {
|
||||
entity_shape = entity_shape_unlocated.Moved(entity_shape_gtrsf.Trsf());
|
||||
}
|
||||
|
||||
BRepAlgoAPI_Cut brep_cut;
|
||||
TopTools_ListOfShape s1s;
|
||||
s1s.Append(entity_shape);
|
||||
brep_cut.SetFuzzyValue(getValue(GV_PRECISION));
|
||||
brep_cut.SetArguments(s1s);
|
||||
brep_cut.SetTools(opening_shapelist);
|
||||
brep_cut.Build();
|
||||
|
||||
bool is_valid = false;
|
||||
if ( brep_cut.IsDone() ) {
|
||||
TopoDS_Shape brep_cut_result = brep_cut;
|
||||
|
||||
BRepCheck_Analyzer analyser(brep_cut_result);
|
||||
is_valid = analyser.IsValid() != 0;
|
||||
if ( is_valid ) {
|
||||
cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(brep_cut_result, &it3->Style()));
|
||||
}
|
||||
}
|
||||
if ( !is_valid ) {
|
||||
// Apparently processing the boolean operation failed or resulted in an invalid result
|
||||
// in which case the original shape without the subtractions is returned instead
|
||||
// we try convert the openings in the original way, one by one.
|
||||
Logger::Message(Logger::LOG_WARNING, "Subtracting combined openings compound failed:", entity->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool IfcGeom::Kernel::convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face) {
|
||||
BRepBuilderAPI_MakeFace mf(wire, false);
|
||||
@@ -370,7 +520,9 @@ bool IfcGeom::Kernel::convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face&
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire) {
|
||||
wire = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(curve));
|
||||
try {
|
||||
wire = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(curve));
|
||||
} catch(...) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -501,8 +653,8 @@ static double point_equality_tolerance = 0.00001;
|
||||
static double max_faces_to_sew = -1.0;
|
||||
static double ifc_length_unit = 1.0;
|
||||
static double ifc_planeangle_unit = -1.0;
|
||||
static double force_ccw_face_orientation = -1.0;
|
||||
static double modelling_precision = 0.00001;
|
||||
static double dimensionality = 1;
|
||||
|
||||
void IfcGeom::Kernel::setValue(GeomValue var, double value) {
|
||||
switch (var) {
|
||||
@@ -527,18 +679,18 @@ void IfcGeom::Kernel::setValue(GeomValue var, double value) {
|
||||
case GV_PLANEANGLE_UNIT:
|
||||
ifc_planeangle_unit = value;
|
||||
break;
|
||||
case GV_FORCE_CCW_FACE_ORIENTATION:
|
||||
force_ccw_face_orientation = value;
|
||||
break;
|
||||
case GV_PRECISION:
|
||||
modelling_precision = value;
|
||||
break;
|
||||
case GV_DIMENSIONALITY:
|
||||
dimensionality = value;
|
||||
break;
|
||||
default:
|
||||
assert(!"never reach here");
|
||||
}
|
||||
}
|
||||
|
||||
double IfcGeom::Kernel::getValue(GeomValue var) {
|
||||
double IfcGeom::Kernel::getValue(GeomValue var) const {
|
||||
switch (var) {
|
||||
case GV_DEFLECTION_TOLERANCE:
|
||||
return deflection_tolerance;
|
||||
@@ -556,12 +708,12 @@ double IfcGeom::Kernel::getValue(GeomValue var) {
|
||||
case GV_PLANEANGLE_UNIT:
|
||||
return ifc_planeangle_unit;
|
||||
break;
|
||||
case GV_FORCE_CCW_FACE_ORIENTATION:
|
||||
return force_ccw_face_orientation;
|
||||
break;
|
||||
case GV_PRECISION:
|
||||
return modelling_precision;
|
||||
break;
|
||||
case GV_DIMENSIONALITY:
|
||||
return dimensionality;
|
||||
break;
|
||||
}
|
||||
assert(!"never reach here");
|
||||
return 0;
|
||||
@@ -599,11 +751,11 @@ IfcSchema::IfcProductDefinitionShape* IfcGeom::tesselate(TopoDS_Shape& shape, do
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, face.Orientation() != TopAbs_REVERSED);
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
IfcSchema::IfcFace* face2 = new IfcSchema::IfcFace(bounds);
|
||||
es->push(loop);
|
||||
es->push(bound);
|
||||
es->push(face);
|
||||
faces->push(face);
|
||||
es->push(face2);
|
||||
faces->push(face2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -621,7 +773,7 @@ IfcSchema::IfcProductDefinitionShape* IfcGeom::tesselate(TopoDS_Shape& shape, do
|
||||
0, std::string("Facetation"), std::string("SurfaceModel"), items);
|
||||
|
||||
reps->push(rep);
|
||||
IfcSchema::IfcProductDefinitionShape* shapedef = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
IfcSchema::IfcProductDefinitionShape* shapedef = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
|
||||
es->push(shell);
|
||||
es->push(surface_model);
|
||||
@@ -687,7 +839,6 @@ bool IfcGeom::Kernel::fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& sha
|
||||
// Now loop over all the vertices that are part of the wire(s) to be filled
|
||||
for (int i = 1; i <= num_verts; ++i) {
|
||||
first = current = TopoDS::Vertex(vertex_to_edges.FindKey(i));
|
||||
const bool isSame = first.IsSame(current);
|
||||
// We keep track of the vertices we already used
|
||||
if (visited.find(vertex_to_edges.FindIndex(current)) != visited.end()) {
|
||||
continue;
|
||||
@@ -695,7 +846,7 @@ bool IfcGeom::Kernel::fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& sha
|
||||
// Given these vertices, try to find closed loops and create new
|
||||
// wires out of them.
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
while (true) {
|
||||
for (;;) {
|
||||
visited.insert(vertex_to_edges.FindIndex(current));
|
||||
// Find the edge that the current vertex is part of and points
|
||||
// away from the previous vertex (null for the first vertex).
|
||||
@@ -760,8 +911,14 @@ bool IfcGeom::Kernel::flatten_shape_list(const IfcGeom::IfcRepresentationShapeIt
|
||||
_trsf = trsf.Trsf();
|
||||
trsf_valid = true;
|
||||
} catch (...) {}
|
||||
const TopoDS_Shape moved_shape = trsf_valid ? merged.Moved(_trsf) :
|
||||
BRepBuilderAPI_GTransform(merged,trsf,true).Shape();
|
||||
|
||||
const TopoDS_Shape moved_shape = trsf.Form() == gp_Identity
|
||||
? merged
|
||||
: (
|
||||
trsf_valid
|
||||
? merged.Moved(_trsf)
|
||||
: BRepBuilderAPI_GTransform(merged,trsf,true).Shape()
|
||||
);
|
||||
|
||||
if (shapes.size() == 1) {
|
||||
result = moved_shape;
|
||||
@@ -793,6 +950,10 @@ bool IfcGeom::Kernel::flatten_shape_list(const IfcGeom::IfcRepresentationShapeIt
|
||||
}
|
||||
}
|
||||
|
||||
if (!fuse) {
|
||||
result = compound;
|
||||
}
|
||||
|
||||
const bool success = !result.IsNull();
|
||||
if (success) {
|
||||
const double precision = getValue(GV_PRECISION);
|
||||
@@ -802,11 +963,11 @@ bool IfcGeom::Kernel::flatten_shape_list(const IfcGeom::IfcRepresentationShapeIt
|
||||
return success;
|
||||
}
|
||||
|
||||
void IfcGeom::Kernel::remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) {
|
||||
void IfcGeom::Kernel::remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) {
|
||||
if (tol <= 0.) tol = getValue(GV_POINT_EQUALITY_TOLERANCE);
|
||||
tol *= tol;
|
||||
|
||||
while (true) {
|
||||
for (;;) {
|
||||
bool removed = false;
|
||||
int n = polygon.Length() - (closed ? 0 : 1);
|
||||
for (int i = 1; i <= n; ++i) {
|
||||
@@ -826,6 +987,69 @@ void IfcGeom::Kernel::remove_redundant_points_from_loop(TColgp_SequenceOfPnt& po
|
||||
}
|
||||
}
|
||||
|
||||
void IfcGeom::Kernel::remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) {
|
||||
if (tol <= 0.) tol = getValue(GV_POINT_EQUALITY_TOLERANCE);
|
||||
const int start = closed ? 1 : 2;
|
||||
const int end = polygon.Length() - (closed ? 0 : 1);
|
||||
std::vector<bool> to_remove(polygon.Length(), false);
|
||||
for (int i = start; i <= end; ++i) {
|
||||
const gp_Pnt& a = polygon.Value(((i - 2 + polygon.Length()) % polygon.Length()) + 1);
|
||||
const gp_Pnt& b = polygon.Value(i);
|
||||
const gp_Pnt& c = polygon.Value((i % polygon.Length()) + 1);
|
||||
const gp_Vec d1 = c.XYZ() - a.XYZ();
|
||||
const gp_Vec d2 = b.XYZ() - a.XYZ();
|
||||
const double dt = d2.Dot(d1) / d1.Dot(d1);
|
||||
const gp_Vec d3 = d1.Scaled(dt);
|
||||
const gp_Pnt b2 = a.XYZ() + d3.XYZ();
|
||||
if (b.Distance(b2) < tol) {
|
||||
to_remove[i-1] = true;
|
||||
}
|
||||
}
|
||||
for (int i = (int) to_remove.size() - 1; i >= 0; --i) {
|
||||
if (to_remove[i]) {
|
||||
polygon.Remove(i+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::wire_to_sequence_of_point(const TopoDS_Wire& w, TColgp_SequenceOfPnt& p) {
|
||||
TopExp_Explorer exp(w, TopAbs_EDGE);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
double a, b;
|
||||
Handle_Geom_Curve crv = BRep_Tool::Curve(TopoDS::Edge(exp.Current()), a, b);
|
||||
if (crv->DynamicType() != STANDARD_TYPE(Geom_Line)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
exp.ReInit();
|
||||
|
||||
int i = 0;
|
||||
for (; exp.More(); exp.Next(), ++i) {
|
||||
TopoDS_Vertex v1, v2;
|
||||
TopExp::Vertices(TopoDS::Edge(exp.Current()), v1, v2, true);
|
||||
if (exp.More()) {
|
||||
if (i == 0) {
|
||||
p.Append(BRep_Tool::Pnt(v1));
|
||||
}
|
||||
p.Append(BRep_Tool::Pnt(v2));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IfcGeom::Kernel::sequence_of_point_to_wire(const TColgp_SequenceOfPnt& p, TopoDS_Wire& w, bool close) {
|
||||
BRepBuilderAPI_MakePolygon builder;
|
||||
for (int i = 1; i <= p.Length(); ++i) {
|
||||
builder.Add(p.Value(i));
|
||||
}
|
||||
if (close) {
|
||||
builder.Close();
|
||||
}
|
||||
w = builder.Wire();
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
IfcGeom::BRepElement<P>* IfcGeom::Kernel::create_brep_for_representation_and_product(const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product) {
|
||||
IfcGeom::Representation::BRep* shape;
|
||||
@@ -839,7 +1063,7 @@ IfcGeom::BRepElement<P>* IfcGeom::Kernel::create_brep_for_representation_and_pro
|
||||
try {
|
||||
IfcSchema::IfcObjectDefinition* parent_object = get_decomposing_entity(product);
|
||||
if (parent_object) {
|
||||
parent_id = parent_object->entity->id();
|
||||
parent_id = parent_object->data().id();
|
||||
}
|
||||
} catch (...) {}
|
||||
|
||||
@@ -854,12 +1078,12 @@ IfcGeom::BRepElement<P>* IfcGeom::Kernel::create_brep_for_representation_and_pro
|
||||
// Does the IfcElement have any IfcOpenings?
|
||||
// Note that openings for IfcOpeningElements are not processed
|
||||
IfcSchema::IfcRelVoidsElement::list::ptr openings;
|
||||
if ( product->is(IfcSchema::Type::IfcElement) && !product->is(IfcSchema::Type::IfcOpeningElement) ) {
|
||||
if ( product->declaration().is(IfcSchema::Type::IfcElement) && !product->declaration().is(IfcSchema::Type::IfcOpeningElement) ) {
|
||||
IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product;
|
||||
openings = element->HasOpenings();
|
||||
}
|
||||
// Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements?
|
||||
if ( product->is(IfcSchema::Type::IfcBuildingElementPart ) ) {
|
||||
if ( product->declaration().is(IfcSchema::Type::IfcBuildingElementPart ) ) {
|
||||
IfcSchema::IfcBuildingElementPart* part = (IfcSchema::IfcBuildingElementPart*)product;
|
||||
#ifdef USE_IFC4
|
||||
IfcSchema::IfcRelAggregates::list::ptr decomposes = part->Decomposes();
|
||||
@@ -869,20 +1093,25 @@ IfcGeom::BRepElement<P>* IfcGeom::Kernel::create_brep_for_representation_and_pro
|
||||
for ( IfcSchema::IfcRelDecomposes::list::it it = decomposes->begin(); it != decomposes->end(); ++ it ) {
|
||||
#endif
|
||||
IfcSchema::IfcObjectDefinition* obdef = (*it)->RelatingObject();
|
||||
if ( obdef->is(IfcSchema::Type::IfcElement) ) {
|
||||
if ( obdef->declaration().is(IfcSchema::Type::IfcElement) ) {
|
||||
IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)obdef;
|
||||
openings->push(element->HasOpenings());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::string product_type = IfcSchema::Type::ToString(product->type());
|
||||
const std::string product_type = IfcSchema::Type::ToString(product->declaration().type());
|
||||
ElementSettings element_settings(settings, getValue(GV_LENGTH_UNIT), product_type);
|
||||
|
||||
if ( !settings.disable_opening_subtractions() && openings && openings->size() ) {
|
||||
IfcGeom::IfcRepresentationShapeItems opened_shapes;
|
||||
try {
|
||||
if ( settings.faster_booleans() ) {
|
||||
#if OCC_VERSION_HEX < 0x60900
|
||||
const bool faster_booleans = settings.faster_booleans();
|
||||
#else
|
||||
const bool faster_booleans = true;
|
||||
#endif
|
||||
if (faster_booleans) {
|
||||
bool succes = convert_openings_fast(product,openings,shapes,trsf,opened_shapes);
|
||||
if ( ! succes ) {
|
||||
opened_shapes.clear();
|
||||
@@ -892,7 +1121,7 @@ IfcGeom::BRepElement<P>* IfcGeom::Kernel::create_brep_for_representation_and_pro
|
||||
convert_openings(product,openings,shapes,trsf,opened_shapes);
|
||||
}
|
||||
} catch(...) {
|
||||
Logger::Message(Logger::LOG_ERROR,"Error processing openings for:",product->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Error processing openings for:", product);
|
||||
}
|
||||
if ( settings.use_world_coords() ) {
|
||||
for ( IfcGeom::IfcRepresentationShapeItems::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) {
|
||||
@@ -900,23 +1129,31 @@ IfcGeom::BRepElement<P>* IfcGeom::Kernel::create_brep_for_representation_and_pro
|
||||
}
|
||||
trsf = gp_Trsf();
|
||||
}
|
||||
shape = new IfcGeom::Representation::BRep(element_settings, representation->entity->id(), opened_shapes);
|
||||
shape = new IfcGeom::Representation::BRep(element_settings, representation->data().id(), opened_shapes);
|
||||
} else if ( settings.use_world_coords() ) {
|
||||
for ( IfcGeom::IfcRepresentationShapeItems::iterator it = shapes.begin(); it != shapes.end(); ++ it ) {
|
||||
it->prepend(trsf);
|
||||
}
|
||||
trsf = gp_Trsf();
|
||||
shape = new IfcGeom::Representation::BRep(element_settings, representation->entity->id(), shapes);
|
||||
shape = new IfcGeom::Representation::BRep(element_settings, representation->data().id(), shapes);
|
||||
} else {
|
||||
shape = new IfcGeom::Representation::BRep(element_settings, representation->entity->id(), shapes);
|
||||
shape = new IfcGeom::Representation::BRep(element_settings, representation->data().id(), shapes);
|
||||
}
|
||||
|
||||
std::string context_string = "";
|
||||
if (representation->hasRepresentationIdentifier()) {
|
||||
context_string = representation->RepresentationIdentifier();
|
||||
} else if (representation->ContextOfItems()->hasContextType()) {
|
||||
context_string = representation->ContextOfItems()->ContextType();
|
||||
}
|
||||
|
||||
return new BRepElement<P>(
|
||||
product->entity->id(),
|
||||
product->data().id(),
|
||||
parent_id,
|
||||
name,
|
||||
product_type,
|
||||
guid,
|
||||
context_string,
|
||||
trsf,
|
||||
shape
|
||||
);
|
||||
@@ -926,14 +1163,14 @@ IfcSchema::IfcObjectDefinition* IfcGeom::Kernel::get_decomposing_entity(IfcSchem
|
||||
IfcSchema::IfcObjectDefinition* parent = 0;
|
||||
|
||||
// In case of an opening element, parent to the RelatingBuildingElement
|
||||
if ( product->is(IfcSchema::Type::IfcOpeningElement ) ) {
|
||||
if ( product->declaration().is(IfcSchema::Type::IfcOpeningElement ) ) {
|
||||
IfcSchema::IfcOpeningElement* opening = (IfcSchema::IfcOpeningElement*)product;
|
||||
IfcSchema::IfcRelVoidsElement::list::ptr voids = opening->VoidsElements();
|
||||
if ( voids->size() ) {
|
||||
IfcSchema::IfcRelVoidsElement* ifc_void = *voids->begin();
|
||||
parent = ifc_void->RelatingBuildingElement();
|
||||
}
|
||||
} else if ( product->is(IfcSchema::Type::IfcElement ) ) {
|
||||
} else if ( product->declaration().is(IfcSchema::Type::IfcElement ) ) {
|
||||
IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product;
|
||||
IfcSchema::IfcRelFillsElement::list::ptr fills = element->FillsVoids();
|
||||
// Incase of a RelatedBuildingElement parent to the opening element
|
||||
@@ -956,13 +1193,13 @@ IfcSchema::IfcObjectDefinition* IfcGeom::Kernel::get_decomposing_entity(IfcSchem
|
||||
}
|
||||
// Parent decompositions to the RelatingObject
|
||||
if (!parent) {
|
||||
IfcEntityList::ptr parents = product->entity->getInverse(IfcSchema::Type::IfcRelAggregates, -1);
|
||||
parents->push(product->entity->getInverse(IfcSchema::Type::IfcRelNests, -1));
|
||||
IfcEntityList::ptr parents = product->data().getInverse(IfcSchema::Type::IfcRelAggregates, -1);
|
||||
parents->push(product->data().getInverse(IfcSchema::Type::IfcRelNests, -1));
|
||||
for ( IfcEntityList::it it = parents->begin(); it != parents->end(); ++ it ) {
|
||||
IfcSchema::IfcRelDecomposes* decompose = (IfcSchema::IfcRelDecomposes*)*it;
|
||||
IfcSchema::IfcObjectDefinition* ifc_objectdef;
|
||||
#ifdef USE_IFC4
|
||||
if (decompose->is(IfcSchema::Type::IfcRelAggregates)) {
|
||||
if (decompose->declaration().is(IfcSchema::Type::IfcRelAggregates)) {
|
||||
ifc_objectdef = ((IfcSchema::IfcRelAggregates*)decompose)->RelatingObject();
|
||||
} else {
|
||||
continue;
|
||||
@@ -998,19 +1235,19 @@ std::pair<std::string, double> IfcGeom::Kernel::initializeUnits(IfcSchema::IfcUn
|
||||
IfcUtil::IfcBaseClass* base = *it;
|
||||
IfcSchema::IfcSIUnit* unit = 0;
|
||||
double value = 1.f;
|
||||
if ( base->is(IfcSchema::Type::IfcConversionBasedUnit) ) {
|
||||
if ( base->declaration().is(IfcSchema::Type::IfcConversionBasedUnit) ) {
|
||||
IfcSchema::IfcConversionBasedUnit* u = (IfcSchema::IfcConversionBasedUnit*)base;
|
||||
current_unit_name = u->Name();
|
||||
IfcSchema::IfcMeasureWithUnit* u2 = u->ConversionFactor();
|
||||
IfcSchema::IfcUnit* u3 = u2->UnitComponent();
|
||||
if ( u3->is(IfcSchema::Type::IfcSIUnit) ) {
|
||||
if ( u3->declaration().is(IfcSchema::Type::IfcSIUnit) ) {
|
||||
unit = (IfcSchema::IfcSIUnit*) u3;
|
||||
}
|
||||
IfcSchema::IfcValue* v = u2->ValueComponent();
|
||||
// Quick hack to get the numeric value from an IfcValue:
|
||||
const double f = *v->entity->getArgument(0);
|
||||
const double f = *v->data().getArgument(0);
|
||||
value *= f;
|
||||
} else if ( base->is(IfcSchema::Type::IfcSIUnit) ) {
|
||||
} else if ( base->declaration().is(IfcSchema::Type::IfcSIUnit) ) {
|
||||
unit = (IfcSchema::IfcSIUnit*)base;
|
||||
}
|
||||
if ( unit ) {
|
||||
@@ -1041,4 +1278,26 @@ std::pair<std::string, double> IfcGeom::Kernel::initializeUnits(IfcSchema::IfcUn
|
||||
}
|
||||
|
||||
return std::pair<std::string, double>(unit_name, unit_magnitude);
|
||||
}
|
||||
}
|
||||
|
||||
const IfcSchema::IfcRepresentationItem* IfcGeom::Kernel::find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item) {
|
||||
if (item->StyledByItem()->size()) {
|
||||
return item;
|
||||
}
|
||||
|
||||
while (item->declaration().is(IfcSchema::Type::IfcBooleanClippingResult)) {
|
||||
// All instantiations of IfcBooleanOperand (type of FirstOperand) are subtypes of
|
||||
// IfcGeometricRepresentationItem
|
||||
item = (IfcSchema::IfcGeometricRepresentationItem*) ((IfcSchema::IfcBooleanClippingResult*) item)->FirstOperand();
|
||||
if (item->StyledByItem()->size()) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Ideally this would be done for other entities (such as IfcCsgSolid) as well.
|
||||
// But neither are these very prevalent, nor does the current IfcOpenShell style
|
||||
// mechanism enable to conveniently style subshapes, which would be necessary for
|
||||
// distinctly styled union operands.
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
@@ -282,21 +282,21 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf) {
|
||||
IN_CACHE(IfcObjectPlacement,l,gp_Trsf,trsf)
|
||||
if ( ! l->is(IfcSchema::Type::IfcLocalPlacement) ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity);
|
||||
if ( ! l->declaration().is(IfcSchema::Type::IfcLocalPlacement) ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l);
|
||||
return false;
|
||||
}
|
||||
IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l;
|
||||
while (1) {
|
||||
for (;;) {
|
||||
gp_Trsf trsf2;
|
||||
IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement();
|
||||
if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) {
|
||||
if ( relplacement->declaration().is(IfcSchema::Type::IfcAxis2Placement3D) ) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2);
|
||||
trsf.PreMultiply(trsf2);
|
||||
}
|
||||
if ( current->hasPlacementRelTo() ) {
|
||||
IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo();
|
||||
if ( relto->is(IfcSchema::Type::IfcLocalPlacement) )
|
||||
if ( relto->declaration().is(IfcSchema::Type::IfcLocalPlacement) )
|
||||
current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo();
|
||||
else break;
|
||||
} else break;
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
* IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the *
|
||||
* orientation and translation of the mesh in relation to the world origin *
|
||||
* *
|
||||
* IfcGeom::Iterator::findContext() *
|
||||
* IfcGeom::Iterator::initialize() *
|
||||
* finds the most suitable representation contexts. Returns true iff *
|
||||
* at least a single representation will process successfully *
|
||||
* *
|
||||
@@ -64,6 +64,8 @@
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <gp_Mat.hxx>
|
||||
#include <gp_Mat2d.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
@@ -125,10 +127,7 @@ namespace IfcGeom {
|
||||
void populate_set(const std::set<std::string>& include_or_ignore) {
|
||||
entities_to_include_or_exclude.clear();
|
||||
for (std::set<std::string>::const_iterator it = include_or_ignore.begin(); it != include_or_ignore.end(); ++it) {
|
||||
std::string uppercase_type = *it;
|
||||
for (std::string::iterator c = uppercase_type.begin(); c != uppercase_type.end(); ++c) {
|
||||
*c = toupper(*c);
|
||||
}
|
||||
const std::string uppercase_type = boost::to_upper_copy(*it);
|
||||
IfcSchema::Type::Enum ty;
|
||||
try {
|
||||
ty = IfcSchema::Type::FromString(uppercase_type);
|
||||
@@ -143,19 +142,24 @@ namespace IfcGeom {
|
||||
}
|
||||
|
||||
public:
|
||||
bool findContext() {
|
||||
bool initialize() {
|
||||
try {
|
||||
initUnits();
|
||||
} catch (...) {}
|
||||
|
||||
// Really this should only be 'Model', as per
|
||||
// the standard 'Design' is deprecated. So,
|
||||
// just for backwards compatibility:
|
||||
std::set<std::string> context_types;
|
||||
context_types.insert("model");
|
||||
context_types.insert("design");
|
||||
// DDS likes to output 'model view'
|
||||
context_types.insert("model view");
|
||||
if (!settings.exclude_solids_and_surfaces()) {
|
||||
// Really this should only be 'Model', as per
|
||||
// the standard 'Design' is deprecated. So,
|
||||
// just for backwards compatibility:
|
||||
context_types.insert("model");
|
||||
context_types.insert("design");
|
||||
// DDS likes to output 'model view'
|
||||
context_types.insert("model view");
|
||||
}
|
||||
if (settings.include_curves()) {
|
||||
context_types.insert("plan");
|
||||
}
|
||||
|
||||
double lowest_precision_encountered = std::numeric_limits<double>::infinity();
|
||||
bool any_precision_encountered = false;
|
||||
@@ -171,34 +175,43 @@ namespace IfcGeom {
|
||||
|
||||
for (it = contexts->begin(); it != contexts->end(); ++it) {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
if (context->is(IfcSchema::Type::IfcGeometricRepresentationSubContext)) {
|
||||
if (context->declaration().is(IfcSchema::Type::IfcGeometricRepresentationSubContext)) {
|
||||
// Continue, as the list of subcontexts will be considered
|
||||
// by the parent's context inverse attributes.
|
||||
continue;
|
||||
}
|
||||
if (context->hasContextType()) {
|
||||
std::string context_type_lc = context->ContextType();
|
||||
for (std::string::iterator c = context_type_lc.begin(); c != context_type_lc.end(); ++c) {
|
||||
*c = tolower(*c);
|
||||
try {
|
||||
if (context->hasContextType()) {
|
||||
std::string context_type = context->ContextType();
|
||||
boost::to_lower(context_type);
|
||||
if (context_types.find(context_type) != context_types.end()) {
|
||||
filtered_contexts->push(context);
|
||||
}
|
||||
}
|
||||
if (context_types.find(context_type_lc) != context_types.end()) {
|
||||
} catch (const IfcParse::IfcException&) {}
|
||||
}
|
||||
|
||||
// In case no contexts are identified based on their ContextType, all contexts are
|
||||
// considered. Note that sub contexts are excluded as they are considered later on.
|
||||
if (filtered_contexts->size() == 0) {
|
||||
for (it = contexts->begin(); it != contexts->end(); ++it) {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
if (!context->declaration().is(IfcSchema::Type::IfcGeometricRepresentationSubContext)) {
|
||||
filtered_contexts->push(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (filtered_contexts->size() == 0) {
|
||||
filtered_contexts = contexts;
|
||||
}
|
||||
|
||||
for (it = filtered_contexts->begin(); it != filtered_contexts->end(); ++it) {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
|
||||
representations->push(context->RepresentationsInContext());
|
||||
if (context->hasPrecision() && context->Precision() < lowest_precision_encountered) {
|
||||
lowest_precision_encountered = context->Precision();
|
||||
any_precision_encountered = true;
|
||||
}
|
||||
try {
|
||||
if (context->hasPrecision() && context->Precision() < lowest_precision_encountered) {
|
||||
lowest_precision_encountered = context->Precision();
|
||||
any_precision_encountered = true;
|
||||
}
|
||||
} catch (const IfcParse::IfcException&) {}
|
||||
IfcSchema::IfcGeometricRepresentationSubContext::list::ptr sub_contexts = context->HasSubContexts();
|
||||
for (jt = sub_contexts->begin(); jt != sub_contexts->end(); ++jt) {
|
||||
representations->push((*jt)->RepresentationsInContext());
|
||||
@@ -276,7 +289,7 @@ namespace IfcGeom {
|
||||
}
|
||||
|
||||
BRepElement<P>* create_shape_model_for_next_entity() {
|
||||
while ( true ) {
|
||||
for (;;) {
|
||||
IfcSchema::IfcRepresentation* representation;
|
||||
|
||||
// Have we reached the end of our list of representations?
|
||||
@@ -294,7 +307,7 @@ namespace IfcGeom {
|
||||
IfcSchema::IfcProduct::list::ptr unfiltered_products(new IfcSchema::IfcProduct::list);
|
||||
|
||||
for ( IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it ) {
|
||||
if ( (*it)->is(IfcSchema::Type::IfcProductDefinitionShape) ) {
|
||||
if ( (*it)->declaration().is(IfcSchema::Type::IfcProductDefinitionShape) ) {
|
||||
IfcSchema::IfcProductDefinitionShape* pds = (IfcSchema::IfcProductDefinitionShape*)*it;
|
||||
unfiltered_products->push(pds->ShapeOfProduct());
|
||||
} else {
|
||||
@@ -304,21 +317,21 @@ namespace IfcGeom {
|
||||
|
||||
// IfcProductRepresentation also lacks the INVERSE relation to IfcProduct
|
||||
// Let's find the IfcProducts that reference the IfcProductRepresentation anyway
|
||||
unfiltered_products->push((*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>());
|
||||
unfiltered_products->push((*it)->data().getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>());
|
||||
}
|
||||
|
||||
// Filter the products based on the set of entities being included or excluded for
|
||||
// processing. The set is iterated over te able to filter on subtypes.
|
||||
for ( IfcSchema::IfcProduct::list::it it = unfiltered_products->begin(); it != unfiltered_products->end(); ++it ) {
|
||||
for ( IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin(); jt != unfiltered_products->end(); ++jt ) {
|
||||
bool found = false;
|
||||
for (std::set<IfcSchema::Type::Enum>::const_iterator jt = entities_to_include_or_exclude.begin(); jt != entities_to_include_or_exclude.end(); ++jt) {
|
||||
if ((*it)->is(*jt)) {
|
||||
for (std::set<IfcSchema::Type::Enum>::const_iterator kt = entities_to_include_or_exclude.begin(); kt != entities_to_include_or_exclude.end(); ++kt) {
|
||||
if ((*jt)->declaration().is(*kt)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found == include_entities_in_processing) {
|
||||
ifcproducts->push(*it);
|
||||
ifcproducts->push(*jt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,8 +398,8 @@ namespace IfcGeom {
|
||||
|
||||
try {
|
||||
const IfcUtil::IfcBaseClass* ifc_entity = ifc_file->entityById(id);
|
||||
instance_type = IfcSchema::Type::ToString(ifc_entity->type());
|
||||
if ( ifc_entity->is(IfcSchema::Type::IfcProduct) ) {
|
||||
instance_type = IfcSchema::Type::ToString(ifc_entity->declaration().type());
|
||||
if ( ifc_entity->declaration().is(IfcSchema::Type::IfcProduct) ) {
|
||||
IfcSchema::IfcProduct* ifc_product = (IfcSchema::IfcProduct*)ifc_entity;
|
||||
|
||||
product_guid = ifc_product->GlobalId();
|
||||
@@ -396,7 +409,7 @@ namespace IfcGeom {
|
||||
try {
|
||||
IfcSchema::IfcObjectDefinition* parent_object = kernel.get_decomposing_entity(ifc_product);
|
||||
if (parent_object) {
|
||||
parent_id = parent_object->entity->id();
|
||||
parent_id = parent_object->data().id();
|
||||
}
|
||||
} catch (...) {}
|
||||
|
||||
@@ -407,7 +420,7 @@ namespace IfcGeom {
|
||||
} catch(...) {}
|
||||
|
||||
ElementSettings element_settings(settings, unit_magnitude, instance_type);
|
||||
Element<P>* ifc_object = new Element<P>(element_settings, id, parent_id, product_name, instance_type, product_guid, trsf);
|
||||
Element<P>* ifc_object = new Element<P>(element_settings, id, parent_id, product_name, instance_type, product_guid, "", trsf);
|
||||
|
||||
return ifc_object;
|
||||
}
|
||||
@@ -432,7 +445,7 @@ namespace IfcGeom {
|
||||
}
|
||||
}
|
||||
private:
|
||||
void initialize() {
|
||||
void _initialize() {
|
||||
current_triangulation = 0;
|
||||
current_shape_model = 0;
|
||||
current_serialization = 0;
|
||||
@@ -445,40 +458,47 @@ namespace IfcGeom {
|
||||
unit_magnitude = 1.f;
|
||||
|
||||
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.sew_shells() ? 1000 : -1);
|
||||
kernel.setValue(IfcGeom::Kernel::GV_FORCE_CCW_FACE_ORIENTATION, settings.force_ccw_face_orientation() ? 1 : -1);
|
||||
kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.include_curves() ? (settings.exclude_solids_and_surfaces() ? -1. : 0.) : +1.));
|
||||
}
|
||||
|
||||
bool owns_ifc_file;
|
||||
public:
|
||||
Iterator(const IteratorSettings& settings, IfcParse::IfcFile* file)
|
||||
: settings(settings)
|
||||
, ifc_file(file)
|
||||
, owns_ifc_file(false)
|
||||
{
|
||||
initialize();
|
||||
_initialize();
|
||||
}
|
||||
Iterator(const IteratorSettings& settings, const std::string& filename)
|
||||
: settings(settings)
|
||||
, ifc_file(new IfcParse::IfcFile)
|
||||
, owns_ifc_file(true)
|
||||
{
|
||||
ifc_file->Init(filename);
|
||||
initialize();
|
||||
_initialize();
|
||||
}
|
||||
Iterator(const IteratorSettings& settings, void* data, int length)
|
||||
: settings(settings)
|
||||
, ifc_file(new IfcParse::IfcFile)
|
||||
, owns_ifc_file(true)
|
||||
{
|
||||
ifc_file->Init(data, length);
|
||||
initialize();
|
||||
_initialize();
|
||||
}
|
||||
Iterator(const IteratorSettings& settings, std::istream& filestream, int length)
|
||||
: settings(settings)
|
||||
, ifc_file(new IfcParse::IfcFile)
|
||||
, owns_ifc_file(true)
|
||||
{
|
||||
ifc_file->Init(filestream, length);
|
||||
initialize();
|
||||
_initialize();
|
||||
}
|
||||
|
||||
~Iterator() {
|
||||
// TODO: Correctly implement destructor for IfcFile
|
||||
delete ifc_file;
|
||||
if (owns_ifc_file) {
|
||||
delete ifc_file;
|
||||
}
|
||||
|
||||
delete current_triangulation;
|
||||
current_triangulation = 0;
|
||||
|
||||
@@ -55,9 +55,6 @@ namespace IfcGeom {
|
||||
// Specifies whether to compose IfcOpeningElements into a single compound
|
||||
// in order to speed up the processing of opening subtractions.
|
||||
static const int FASTER_BOOLEANS = 6;
|
||||
// By default singular faces have no explicitly defined orientation, to
|
||||
// force faces to be defined CounterClockWise set this to true.
|
||||
static const int FORCE_CCW_FACE_ORIENTATION = 7;
|
||||
// Disables the subtraction of IfcOpeningElement representations from
|
||||
// the related building element representations.
|
||||
static const int DISABLE_OPENING_SUBTRACTIONS = 8;
|
||||
@@ -66,11 +63,15 @@ namespace IfcGeom {
|
||||
static const int DISABLE_TRIANGULATION = 9;
|
||||
// Applies default materials to entity instances without a surface style.
|
||||
static const int APPLY_DEFAULT_MATERIALS = 10;
|
||||
// Specifies whether to include subtypes of IfcCurve.
|
||||
static const int INCLUDE_CURVES = 11;
|
||||
// Specifies whether to exclude subtypes of IfcSolidModel and IfcSurface.
|
||||
static const int EXCLUDE_SOLIDS_AND_SURFACES = 12;
|
||||
|
||||
// End of settings enumeration.
|
||||
|
||||
private:
|
||||
bool _weld_vertices, _use_world_coords, _convert_back_units, _use_brep_data, _sew_shells, _faster_booleans, _force_ccw_face_orientation, _disable_opening_subtractions, _disable_triangulation, _apply_default_materials;
|
||||
bool _weld_vertices, _use_world_coords, _convert_back_units, _use_brep_data, _sew_shells, _faster_booleans, _disable_opening_subtractions, _disable_triangulation, _apply_default_materials, _include_curves, _exclude_solids_and_surfaces;
|
||||
double _deflection_tolerance;
|
||||
public:
|
||||
IteratorSettings()
|
||||
@@ -80,10 +81,11 @@ namespace IfcGeom {
|
||||
, _use_brep_data(false)
|
||||
, _sew_shells(false)
|
||||
, _faster_booleans(false)
|
||||
, _force_ccw_face_orientation(false)
|
||||
, _disable_opening_subtractions(false)
|
||||
, _disable_triangulation(false)
|
||||
, _apply_default_materials(false)
|
||||
, _include_curves(false)
|
||||
, _exclude_solids_and_surfaces(false)
|
||||
// TODO: Make deflection tolerance into a command line argument
|
||||
// For now, stick to one millimeter. Note that this is independent of the IFC length unit.
|
||||
, _deflection_tolerance(1.e-3)
|
||||
@@ -101,14 +103,16 @@ namespace IfcGeom {
|
||||
bool& sew_shells() { return _sew_shells; }
|
||||
const bool& faster_booleans() const { return _faster_booleans; }
|
||||
bool& faster_booleans() { return _faster_booleans; }
|
||||
const bool& force_ccw_face_orientation() const { return _force_ccw_face_orientation; }
|
||||
bool& force_ccw_face_orientation() { return _force_ccw_face_orientation; }
|
||||
const bool& disable_opening_subtractions() const { return _disable_opening_subtractions; }
|
||||
bool& disable_opening_subtractions() { return _disable_opening_subtractions; }
|
||||
const bool& disable_triangulation() const { return _disable_triangulation; }
|
||||
bool& disable_triangulation() { return _disable_triangulation; }
|
||||
const bool& apply_default_materials() const { return _apply_default_materials; }
|
||||
bool& apply_default_materials() { return _apply_default_materials; }
|
||||
const bool& include_curves() const { return _include_curves; }
|
||||
bool& include_curves() { return _include_curves; }
|
||||
const bool& exclude_solids_and_surfaces() const { return _exclude_solids_and_surfaces; }
|
||||
bool& exclude_solids_and_surfaces() { return _exclude_solids_and_surfaces; }
|
||||
|
||||
const double& deflection_tolerance() const { return _deflection_tolerance; }
|
||||
double& deflection_tolerance() { return _deflection_tolerance; }
|
||||
@@ -133,9 +137,6 @@ namespace IfcGeom {
|
||||
case SEW_SHELLS:
|
||||
_sew_shells = value;
|
||||
break;
|
||||
case FORCE_CCW_FACE_ORIENTATION:
|
||||
_force_ccw_face_orientation = value;
|
||||
break;
|
||||
case DISABLE_OPENING_SUBTRACTIONS:
|
||||
_disable_opening_subtractions = value;
|
||||
break;
|
||||
@@ -145,6 +146,12 @@ namespace IfcGeom {
|
||||
case APPLY_DEFAULT_MATERIALS:
|
||||
_apply_default_materials = value;
|
||||
break;
|
||||
case INCLUDE_CURVES:
|
||||
_include_curves = value;
|
||||
break;
|
||||
case EXCLUDE_SOLIDS_AND_SURFACES:
|
||||
_exclude_solids_and_surfaces = value;
|
||||
break;
|
||||
default: throw IfcParse::IfcException("Invalid IteratorSetting");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include "IfcGeom.h"
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourRgb* colour, std::tr1::array<double, 3>& rgb) {
|
||||
bool process_colour(IfcSchema::IfcColourRgb* colour, double* rgb) {
|
||||
if (colour != 0) {
|
||||
rgb[0] = colour->Red();
|
||||
rgb[1] = colour->Green();
|
||||
@@ -30,7 +30,7 @@ bool process_colour(IfcSchema::IfcColourRgb* colour, std::tr1::array<double, 3>&
|
||||
return colour != 0;
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, std::tr1::array<double, 3>& rgb) {
|
||||
bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, double* rgb) {
|
||||
if (factor != 0) {
|
||||
const double f = *factor;
|
||||
rgb[0] = rgb[1] = rgb[2] = f;
|
||||
@@ -38,12 +38,12 @@ bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, std::tr1::arra
|
||||
return factor != 0;
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, std::tr1::array<double, 3>& rgb) {
|
||||
bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, double* rgb) {
|
||||
if (colour_or_factor == 0) {
|
||||
return false;
|
||||
} else if (colour_or_factor->is(IfcSchema::Type::IfcColourRgb)) {
|
||||
} else if (colour_or_factor->declaration().is(IfcSchema::Type::IfcColourRgb)) {
|
||||
return process_colour(static_cast<IfcSchema::IfcColourRgb*>(colour_or_factor), rgb);
|
||||
} else if (colour_or_factor->is(IfcSchema::Type::IfcNormalisedRatioMeasure)) {
|
||||
} else if (colour_or_factor->declaration().is(IfcSchema::Type::IfcNormalisedRatioMeasure)) {
|
||||
return process_colour(static_cast<IfcSchema::IfcNormalisedRatioMeasure*>(colour_or_factor), rgb);
|
||||
} else {
|
||||
return false;
|
||||
@@ -55,7 +55,7 @@ const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepr
|
||||
if (shading_styles.second == 0) {
|
||||
return 0;
|
||||
}
|
||||
int surface_style_id = shading_styles.first->entity->id();
|
||||
int surface_style_id = shading_styles.first->data().id();
|
||||
std::map<int,SurfaceStyle>::const_iterator it = cache.Style.find(surface_style_id);
|
||||
if (it != cache.Style.end()) {
|
||||
return &(it->second);
|
||||
@@ -66,11 +66,11 @@ const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepr
|
||||
} else {
|
||||
surface_style = SurfaceStyle(surface_style_id);
|
||||
}
|
||||
std::tr1::array<double, 3> rgb;
|
||||
double rgb[3];
|
||||
if (process_colour(shading_styles.second->SurfaceColour(), rgb)) {
|
||||
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
|
||||
}
|
||||
if (shading_styles.second->is(IfcSchema::Type::IfcSurfaceStyleRendering)) {
|
||||
if (shading_styles.second->declaration().is(IfcSchema::Type::IfcSurfaceStyleRendering)) {
|
||||
IfcSchema::IfcSurfaceStyleRendering* rendering_style = static_cast<IfcSchema::IfcSurfaceStyleRendering*>(shading_styles.second);
|
||||
if (rendering_style->hasDiffuseColour() && process_colour(rendering_style->DiffuseColour(), rgb)) {
|
||||
SurfaceStyle::ColorComponent diffuse = surface_style.Diffuse().get_value_or(SurfaceStyle::ColorComponent(1,1,1));
|
||||
@@ -87,12 +87,12 @@ const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepr
|
||||
}
|
||||
if (rendering_style->hasSpecularHighlight()) {
|
||||
IfcSchema::IfcSpecularHighlightSelect* highlight = rendering_style->SpecularHighlight();
|
||||
if (highlight->is(IfcSchema::Type::IfcSpecularRoughness)) {
|
||||
if (highlight->declaration().is(IfcSchema::Type::IfcSpecularRoughness)) {
|
||||
double roughness = *((IfcSchema::IfcSpecularRoughness*)highlight);
|
||||
if (roughness >= 1e-9) {
|
||||
surface_style.Specularity().reset(1.0 / roughness);
|
||||
}
|
||||
} else if (highlight->is(IfcSchema::Type::IfcSpecularExponent)) {
|
||||
} else if (highlight->declaration().is(IfcSchema::Type::IfcSpecularExponent)) {
|
||||
surface_style.Specularity().reset(*((IfcSchema::IfcSpecularExponent*)highlight));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,12 +20,6 @@
|
||||
#ifndef IFCGEOMRENDERSTYLES_H
|
||||
#define IFCGEOMRENDERSTYLES_H
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <tr1/array>
|
||||
#else
|
||||
#include <array>
|
||||
#endif
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include "../ifcparse/Ifc4.h"
|
||||
#else
|
||||
@@ -37,7 +31,7 @@ namespace IfcGeom {
|
||||
public:
|
||||
class ColorComponent {
|
||||
private:
|
||||
std::tr1::array<double, 3> data;
|
||||
double data[3];
|
||||
public:
|
||||
ColorComponent(double r, double g, double b) {
|
||||
data[0] = r; data[1] = g; data[2] = b;
|
||||
@@ -57,17 +51,20 @@ namespace IfcGeom {
|
||||
boost::optional<double> specularity;
|
||||
public:
|
||||
SurfaceStyle() {
|
||||
this->name = "IfcSurfaceStyleShading";
|
||||
this->name = "surface-style";
|
||||
}
|
||||
SurfaceStyle(int id) : id(id) {
|
||||
std::stringstream sstr;
|
||||
sstr << "IfcSurfaceStyleShading_" << id;
|
||||
sstr << "surface-style-" << id;
|
||||
this->name = sstr.str();
|
||||
}
|
||||
SurfaceStyle(const std::string& name) : name(name) {}
|
||||
SurfaceStyle(int id, const std::string& name) : id(id) {
|
||||
std::stringstream sstr;
|
||||
sstr << id << "_" << name;
|
||||
std::string sanitized = name;
|
||||
std::transform(sanitized.begin(), sanitized.end(), sanitized.begin(), ::tolower);
|
||||
std::replace(sanitized.begin(), sanitized.end(), ' ', '-');
|
||||
sstr << "surface-style-" << id << "-" << sanitized;
|
||||
this->name = sstr.str();
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
|
||||
#include <TopExp_Explorer.hxx>
|
||||
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <GCPnts_QuasiUniformDeflection.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
#include "../ifcgeom/IfcGeomMaterial.h"
|
||||
#include "../ifcgeom/IfcRepresentationShapeItem.h"
|
||||
@@ -38,6 +41,8 @@ namespace IfcGeom {
|
||||
namespace Representation {
|
||||
|
||||
class Representation {
|
||||
Representation(const Representation&); //N/A
|
||||
Representation& operator =(const Representation&); //N/A
|
||||
protected:
|
||||
const ElementSettings _settings;
|
||||
public:
|
||||
@@ -51,18 +56,19 @@ namespace IfcGeom {
|
||||
class BRep : public Representation {
|
||||
private:
|
||||
unsigned int id;
|
||||
const IfcGeom::IfcRepresentationShapeItems shapes;
|
||||
const IfcGeom::IfcRepresentationShapeItems _shapes;
|
||||
BRep(const BRep& other);
|
||||
BRep& operator=(const BRep& other);
|
||||
public:
|
||||
BRep(const ElementSettings& settings, unsigned int id, const IfcGeom::IfcRepresentationShapeItems& shapes)
|
||||
: Representation(settings)
|
||||
, id(id)
|
||||
, shapes(shapes)
|
||||
, _shapes(shapes)
|
||||
{}
|
||||
virtual ~BRep() {}
|
||||
IfcGeom::IfcRepresentationShapeItems::const_iterator begin() const { return shapes.begin(); }
|
||||
IfcGeom::IfcRepresentationShapeItems::const_iterator end() const { return shapes.end(); }
|
||||
IfcGeom::IfcRepresentationShapeItems::const_iterator begin() const { return _shapes.begin(); }
|
||||
IfcGeom::IfcRepresentationShapeItems::const_iterator end() const { return _shapes.end(); }
|
||||
const IfcGeom::IfcRepresentationShapeItems& shapes() const { return _shapes; }
|
||||
const unsigned int& getId() const { return id; }
|
||||
};
|
||||
|
||||
@@ -112,48 +118,47 @@ namespace IfcGeom {
|
||||
: Representation(shape_model.settings())
|
||||
, _id(shape_model.getId())
|
||||
{
|
||||
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it = shape_model.begin(); it != shape_model.end(); ++ it ) {
|
||||
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++ iit ) {
|
||||
|
||||
int surface_style_id = -1;
|
||||
if (it->hasStyle()) {
|
||||
Material adapter(&it->Style());
|
||||
if (iit->hasStyle()) {
|
||||
Material adapter(&iit->Style());
|
||||
std::vector<Material>::const_iterator jt = std::find(_materials.begin(), _materials.end(), adapter);
|
||||
if (jt == _materials.end()) {
|
||||
surface_style_id = _materials.size();
|
||||
surface_style_id = (int)_materials.size();
|
||||
_materials.push_back(adapter);
|
||||
} else {
|
||||
surface_style_id = jt - _materials.begin();
|
||||
surface_style_id = (int)(jt - _materials.begin());
|
||||
}
|
||||
}
|
||||
|
||||
if (settings().apply_default_materials() && surface_style_id == -1) {
|
||||
Material material(IfcGeom::get_default_style(settings().element_type()));
|
||||
std::vector<Material>::const_iterator it = std::find(_materials.begin(), _materials.end(), material);
|
||||
if (it == _materials.end()) {
|
||||
surface_style_id = _materials.size();
|
||||
std::vector<Material>::const_iterator mit = std::find(_materials.begin(), _materials.end(), material);
|
||||
if (mit == _materials.end()) {
|
||||
surface_style_id = (int)_materials.size();
|
||||
_materials.push_back(material);
|
||||
} else {
|
||||
surface_style_id = it - _materials.begin();
|
||||
surface_style_id = (int)(mit - _materials.begin());
|
||||
}
|
||||
}
|
||||
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
const gp_GTrsf& trsf = it->Placement();
|
||||
const TopoDS_Shape& s = iit->Shape();
|
||||
const gp_GTrsf& trsf = iit->Placement();
|
||||
|
||||
// Triangulate the shape
|
||||
try {
|
||||
BRepMesh_IncrementalMesh(s, settings().deflection_tolerance());
|
||||
} catch(...) {
|
||||
|
||||
// TODO: Catch outside
|
||||
// Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape:",ifc_file->entityById(_id)->entity);
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape");
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape");
|
||||
continue;
|
||||
}
|
||||
TopExp_Explorer exp;
|
||||
|
||||
// Iterates over the faces of the shape
|
||||
for ( exp.Init(s,TopAbs_FACE); exp.More(); exp.Next() ) {
|
||||
int num_faces = 0;
|
||||
TopExp_Explorer exp;
|
||||
for ( exp.Init(s,TopAbs_FACE); exp.More(); exp.Next(), ++num_faces ) {
|
||||
TopoDS_Face face = TopoDS::Face(exp.Current());
|
||||
TopLoc_Location loc;
|
||||
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face,loc);
|
||||
@@ -191,9 +196,9 @@ namespace IfcGeom {
|
||||
if (normal_direction.Magnitude() > ALMOST_ZERO) {
|
||||
normal = gp_Dir(normal_direction.XYZ() * rotation_matrix);
|
||||
}
|
||||
_normals.push_back((float)normal.X());
|
||||
_normals.push_back((float)normal.Y());
|
||||
_normals.push_back((float)normal.Z());
|
||||
_normals.push_back(static_cast<P>(normal.X()));
|
||||
_normals.push_back(static_cast<P>(normal.Y()));
|
||||
_normals.push_back(static_cast<P>(normal.Z()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,15 +229,47 @@ namespace IfcGeom {
|
||||
|
||||
_material_ids.push_back(surface_style_id);
|
||||
|
||||
addEdge(n1,n2,edgecount,edges_temp);
|
||||
addEdge(n2,n3,edgecount,edges_temp);
|
||||
addEdge(n3,n1,edgecount,edges_temp);
|
||||
addEdge(dict[n1], dict[n2], edgecount, edges_temp);
|
||||
addEdge(dict[n2], dict[n3], edgecount, edges_temp);
|
||||
addEdge(dict[n3], dict[n1], edgecount, edges_temp);
|
||||
}
|
||||
for ( std::vector<std::pair<int,int> >::const_iterator it = edges_temp.begin(); it != edges_temp.end(); ++it ) {
|
||||
_edges.push_back(edgecount[*it]==1);
|
||||
for ( std::vector<std::pair<int,int> >::const_iterator jt = edges_temp.begin(); jt != edges_temp.end(); ++jt ) {
|
||||
if (edgecount[*jt] == 1) {
|
||||
// non manifold edge, face boundary
|
||||
_edges.push_back(jt->first);
|
||||
_edges.push_back(jt->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (num_faces == 0) {
|
||||
// Edges are only emitted if there are no faces. A mixed representation of faces
|
||||
// and loose edges is discouraged by the standard. An alternative would be to use
|
||||
// TopExp::MapShapesAndAncestors() to find edges that do not belong to any face.
|
||||
for (TopExp_Explorer texp(s, TopAbs_EDGE); texp.More(); texp.Next()) {
|
||||
BRepAdaptor_Curve crv(TopoDS::Edge(texp.Current()));
|
||||
GCPnts_QuasiUniformDeflection tessellater(crv, settings().deflection_tolerance());
|
||||
int n = tessellater.NbPoints();
|
||||
int start = (int)_verts.size() / 3;
|
||||
for (int i = 1; i <= n; ++i) {
|
||||
gp_XYZ p = tessellater.Value(i).XYZ();
|
||||
trsf.Transforms(p);
|
||||
|
||||
_material_ids.push_back(surface_style_id);
|
||||
|
||||
_verts.push_back(static_cast<P>(p.X()));
|
||||
_verts.push_back(static_cast<P>(p.Y()));
|
||||
_verts.push_back(static_cast<P>(p.Z()));
|
||||
|
||||
if (i > 1) {
|
||||
_edges.push_back(start + i - 2);
|
||||
_edges.push_back(start + i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
virtual ~Triangulation() {}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 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 *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMSHAPETYPE_H
|
||||
#define IFCGEOMSHAPETYPE_H
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
enum ShapeType {
|
||||
ST_SHAPELIST,
|
||||
ST_SHAPE,
|
||||
ST_FACE,
|
||||
ST_WIRE,
|
||||
ST_CURVE,
|
||||
ST_EDGE,
|
||||
ST_VERTEX,
|
||||
ST_OTHER
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+226
-49
@@ -65,6 +65,8 @@
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopoDS_CompSolid.hxx>
|
||||
|
||||
#include <TopExp_Explorer.hxx>
|
||||
|
||||
#include <BRepPrimAPI_MakePrism.hxx>
|
||||
@@ -74,6 +76,7 @@
|
||||
#include <BRepPrimAPI_MakeCylinder.hxx>
|
||||
#include <BRepPrimAPI_MakeSphere.hxx>
|
||||
#include <BRepPrimAPI_MakeWedge.hxx>
|
||||
#include <BRepBuilderAPI_MakePolygon.hxx>
|
||||
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
#include <BRepBuilderAPI_MakeShell.hxx>
|
||||
@@ -98,10 +101,15 @@
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_Shape& shape) {
|
||||
const double height = l->Depth() * getValue(GV_LENGTH_UNIT);
|
||||
if (height < getValue(GV_PRECISION)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
TopoDS_Shape face;
|
||||
if ( !convert_face(l->SweptArea(),face) ) return false;
|
||||
|
||||
const double height = l->Depth() * getValue(GV_LENGTH_UNIT);
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
|
||||
@@ -229,8 +237,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFaceBasedSurfaceModel* l, IfcR
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, TopoDS_Shape& shape) {
|
||||
IfcSchema::IfcSurface* surface = l->BaseSurface();
|
||||
if ( ! surface->is(IfcSchema::Type::IfcPlane) ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface->entity);
|
||||
if ( ! surface->declaration().is(IfcSchema::Type::IfcPlane) ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface);
|
||||
return false;
|
||||
}
|
||||
gp_Pln pln;
|
||||
@@ -243,10 +251,20 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, TopoDS_Shap
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l, TopoDS_Shape& shape) {
|
||||
TopoDS_Shape halfspace;
|
||||
if ( ! IfcGeom::Kernel::convert((IfcSchema::IfcHalfSpaceSolid*)l,halfspace) ) return false;
|
||||
|
||||
TopoDS_Wire wire;
|
||||
if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false;
|
||||
if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false;
|
||||
|
||||
gp_Trsf trsf;
|
||||
convert(l->Position(),trsf);
|
||||
if ( ! convert(l->Position(),trsf) ) return false;
|
||||
|
||||
TColgp_SequenceOfPnt points;
|
||||
if (wire_to_sequence_of_point(wire, points)) {
|
||||
remove_duplicate_points_from_loop(points, wire.Closed()); // Note: wire always closed, as per if statement above
|
||||
remove_collinear_points_from_loop(points, wire.Closed());
|
||||
sequence_of_point_to_wire(points, wire, wire.Closed());
|
||||
}
|
||||
|
||||
TopoDS_Shape prism = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,200));
|
||||
gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-100.0));
|
||||
prism.Move(trsf*down);
|
||||
@@ -260,7 +278,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, Ifc
|
||||
for( IfcEntityList::it it = shells->begin(); it != shells->end(); ++ it ) {
|
||||
TopoDS_Shape s;
|
||||
const SurfaceStyle* shell_style = 0;
|
||||
if ((*it)->is(IfcSchema::Type::IfcRepresentationItem)) {
|
||||
if ((*it)->declaration().is(IfcSchema::Type::IfcRepresentationItem)) {
|
||||
shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it);
|
||||
}
|
||||
if (convert_shape(*it,s)) {
|
||||
@@ -271,58 +289,90 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, Ifc
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) {
|
||||
|
||||
TopoDS_Shape s1, s2;
|
||||
IfcRepresentationShapeItems items1, items2;
|
||||
TopoDS_Wire boundary_wire;
|
||||
IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand();
|
||||
IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand();
|
||||
bool is_halfspace = operand2->is(IfcSchema::Type::IfcHalfSpaceSolid);
|
||||
bool is_halfspace = operand2->declaration().is(IfcSchema::Type::IfcHalfSpaceSolid);
|
||||
|
||||
if ( is_shape_collection(operand1) ) {
|
||||
if ( shape_type(operand1) == ST_SHAPELIST ) {
|
||||
if (!(convert_shapes(operand1, items1) && flatten_shape_list(items1, s1, true))) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
} else if ( shape_type(operand1) == ST_SHAPE ) {
|
||||
if ( ! convert_shape(operand1, s1) ) {
|
||||
return false;
|
||||
}
|
||||
{ TopoDS_Solid temp_solid;
|
||||
s1 = ensure_fit_for_subtraction(s1, temp_solid); }
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", operand1);
|
||||
return false;
|
||||
}
|
||||
|
||||
const double first_operand_volume = shape_volume(s1);
|
||||
if ( first_operand_volume <= ALMOST_ZERO )
|
||||
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand()->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Empty solid for:", l->FirstOperand());
|
||||
|
||||
bool shape2_processed = false;
|
||||
if ( is_shape_collection(operand2) ) {
|
||||
if ( shape_type(operand2) == ST_SHAPELIST ) {
|
||||
shape2_processed = convert_shapes(operand2, items2) && flatten_shape_list(items2, s2, true);
|
||||
} else {
|
||||
} else if ( shape_type(operand2) == ST_SHAPE ) {
|
||||
shape2_processed = convert_shape(operand2,s2);
|
||||
if (shape2_processed && !is_halfspace) {
|
||||
TopoDS_Solid temp_solid;
|
||||
s2 = ensure_fit_for_subtraction(s2, temp_solid);
|
||||
}
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", operand2);
|
||||
}
|
||||
|
||||
if (!shape2_processed) {
|
||||
shape = s1;
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to convert SecondOperand of:", l);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!is_halfspace) {
|
||||
const double second_operand_volume = shape_volume(s2);
|
||||
if ( second_operand_volume <= ALMOST_ZERO )
|
||||
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Empty solid for:", operand2);
|
||||
}
|
||||
|
||||
const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator();
|
||||
|
||||
/*
|
||||
// TK: A little debugging trick to output both operands for visual inspection
|
||||
|
||||
BRep_Builder builder;
|
||||
TopoDS_Compound compound;
|
||||
builder.MakeCompound(compound);
|
||||
builder.Add(compound, s1);
|
||||
builder.Add(compound, s2);
|
||||
shape = compound;
|
||||
return true;
|
||||
*/
|
||||
|
||||
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
|
||||
|
||||
bool valid_cut = false;
|
||||
BRepAlgoAPI_Cut brep_cut(s1,s2);
|
||||
|
||||
#if OCC_VERSION_HEX < 0x60900
|
||||
BRepAlgoAPI_Cut brep_cut(s1, s2);
|
||||
#else
|
||||
BRepAlgoAPI_Cut brep_cut;
|
||||
TopTools_ListOfShape s1s;
|
||||
s1s.Append(s1);
|
||||
TopTools_ListOfShape s2s;
|
||||
s2s.Append(s2);
|
||||
brep_cut.SetFuzzyValue(getValue(GV_PRECISION));
|
||||
brep_cut.SetArguments(s1s);
|
||||
brep_cut.SetTools(s2s);
|
||||
brep_cut.Build();
|
||||
#endif
|
||||
|
||||
if ( brep_cut.IsDone() ) {
|
||||
TopoDS_Shape result = brep_cut;
|
||||
|
||||
@@ -331,7 +381,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
|
||||
fix.Perform();
|
||||
result = fix.Shape();
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Shape healing failed on boolean result", l->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Shape healing failed on boolean result", l);
|
||||
}
|
||||
|
||||
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
|
||||
@@ -344,9 +394,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
|
||||
if ( valid_cut ) {
|
||||
const double volume_after_subtraction = shape_volume(shape);
|
||||
if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) )
|
||||
Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",l->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Subtraction yields unchanged volume:", l);
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to process subtraction:", l);
|
||||
shape = s1;
|
||||
}
|
||||
|
||||
@@ -393,7 +443,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Shape& shape) {
|
||||
IfcSchema::IfcFace::list::ptr faces = l->CfsFaces();
|
||||
bool facesAdded = false;
|
||||
const unsigned int num_faces = faces->size();
|
||||
const unsigned int num_faces = (unsigned)faces->size();
|
||||
bool valid_shell = false;
|
||||
if ( num_faces < getValue(GV_MAX_FACES_TO_SEW) ) {
|
||||
BRepOffsetAPI_Sewing builder;
|
||||
@@ -410,7 +460,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Sh
|
||||
builder.Add(face);
|
||||
facesAdded = true;
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Invalid face:", *it);
|
||||
}
|
||||
}
|
||||
if ( ! facesAdded ) return false;
|
||||
@@ -432,7 +482,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Sh
|
||||
}
|
||||
} catch(...) {}
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_WARNING,"Failed to sew faceset:",l->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Failed to sew faceset:", l);
|
||||
}
|
||||
}
|
||||
if (!valid_shell) {
|
||||
@@ -449,7 +499,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Sh
|
||||
builder.Add(compound,face);
|
||||
facesAdded = true;
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Invalid face:", *it);
|
||||
}
|
||||
}
|
||||
if ( ! facesAdded ) return false;
|
||||
@@ -461,16 +511,16 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Sh
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentationShapeItems& shapes) {
|
||||
gp_GTrsf gtrsf;
|
||||
IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget();
|
||||
if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) {
|
||||
if ( transform->declaration().is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf);
|
||||
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity);
|
||||
} else if ( transform->declaration().is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform);
|
||||
return false;
|
||||
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) {
|
||||
} else if ( transform->declaration().is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) {
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf);
|
||||
gtrsf = trsf;
|
||||
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) {
|
||||
} else if ( transform->declaration().is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) {
|
||||
gp_Trsf2d trsf_2d;
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,trsf_2d);
|
||||
gtrsf = (gp_Trsf) trsf_2d;
|
||||
@@ -478,7 +528,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentati
|
||||
IfcSchema::IfcRepresentationMap* map = l->MappingSource();
|
||||
IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin();
|
||||
gp_Trsf trsf;
|
||||
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
if (placement->declaration().is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
} else {
|
||||
gp_Trsf2d trsf_2d;
|
||||
@@ -486,21 +536,32 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentati
|
||||
trsf = trsf_2d;
|
||||
}
|
||||
gtrsf.Multiply(trsf);
|
||||
|
||||
const IfcGeom::SurfaceStyle* mapped_item_style = get_style(l);
|
||||
|
||||
const unsigned int previous_size = (const unsigned int) shapes.size();
|
||||
bool b = convert_shapes(map->MappedRepresentation(),shapes);
|
||||
bool b = convert_shapes(map->MappedRepresentation(), shapes);
|
||||
|
||||
for ( unsigned int i = previous_size; i < shapes.size(); ++ i ) {
|
||||
shapes[i].append(gtrsf);
|
||||
|
||||
// Apply styles assigned to the mapped item only if on
|
||||
// a more granular level no styles have been applied
|
||||
if (!shapes[i].hasStyle()) {
|
||||
shapes[i].setStyle(mapped_item_style);
|
||||
}
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcShapeRepresentation* l, IfcRepresentationShapeItems& shapes) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRepresentation* l, IfcRepresentationShapeItems& shapes) {
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items = l->Items();
|
||||
bool part_succes = false;
|
||||
if ( items->size() ) {
|
||||
for ( IfcSchema::IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++ it ) {
|
||||
IfcSchema::IfcRepresentationItem* representation_item = *it;
|
||||
if ( is_shape_collection(representation_item) ) {
|
||||
if ( shape_type(representation_item) == ST_SHAPELIST ) {
|
||||
part_succes |= convert_shapes(*it, shapes);
|
||||
} else {
|
||||
TopoDS_Shape s;
|
||||
@@ -521,14 +582,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcGeometricSet* l, IfcRepresenta
|
||||
const IfcGeom::SurfaceStyle* parent_style = get_style(l);
|
||||
for ( IfcEntityList::it it = elements->begin(); it != elements->end(); ++ it ) {
|
||||
IfcSchema::IfcGeometricSetSelect* element = *it;
|
||||
if (element->is(IfcSchema::Type::IfcSurface)) {
|
||||
IfcSchema::IfcSurface* surface = (IfcSchema::IfcSurface*) element;
|
||||
TopoDS_Shape s;
|
||||
if (convert_shape(surface, s)) {
|
||||
part_succes = true;
|
||||
const IfcGeom::SurfaceStyle* style = get_style(surface);
|
||||
shapes.push_back(IfcRepresentationShapeItem(s, style ? style : parent_style));
|
||||
TopoDS_Shape s;
|
||||
if (convert_shape(element, s)) {
|
||||
part_succes = true;
|
||||
const IfcGeom::SurfaceStyle* style = 0;
|
||||
if (element->declaration().is(IfcSchema::Type::IfcPoint)) {
|
||||
style = get_style((IfcSchema::IfcPoint*) element);
|
||||
} else if (element->declaration().is(IfcSchema::Type::IfcCurve)) {
|
||||
style = get_style((IfcSchema::IfcCurve*) element);
|
||||
} else if (element->declaration().is(IfcSchema::Type::IfcSurface)) {
|
||||
style = get_style((IfcSchema::IfcSurface*) element);
|
||||
}
|
||||
shapes.push_back(IfcRepresentationShapeItem(s, style ? style : parent_style));
|
||||
}
|
||||
}
|
||||
return part_succes;
|
||||
@@ -609,7 +674,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_S
|
||||
IfcGeom::Kernel::convert(l->BasisSurface(), pln);
|
||||
|
||||
gp_Trsf trsf;
|
||||
trsf.SetTransformation(pln.Position());
|
||||
trsf.SetTransformation(pln.Position(), gp::XOY());
|
||||
|
||||
TopoDS_Wire outer;
|
||||
convert_wire(l->OuterBoundary(), outer);
|
||||
@@ -617,9 +682,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_S
|
||||
BRepBuilderAPI_MakeFace mf (outer);
|
||||
mf.Add(outer);
|
||||
|
||||
IfcSchema::IfcCurve::list::ptr inner = l->InnerBoundaries();
|
||||
IfcSchema::IfcCurve::list::ptr boundaries = l->InnerBoundaries();
|
||||
|
||||
for (IfcSchema::IfcCurve::list::it it = inner->begin(); it != inner->end(); ++it) {
|
||||
for (IfcSchema::IfcCurve::list::it it = boundaries->begin(); it != boundaries->end(); ++it) {
|
||||
TopoDS_Wire inner;
|
||||
convert_wire(*it, inner);
|
||||
|
||||
@@ -634,8 +699,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_S
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularTrimmedSurface* l, TopoDS_Shape& face) {
|
||||
if (!l->BasisSurface()->is(IfcSchema::Type::IfcPlane)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported BasisSurface:", l->BasisSurface()->entity);
|
||||
if (!l->BasisSurface()->declaration().is(IfcSchema::Type::IfcPlane)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported BasisSurface:", l->BasisSurface());
|
||||
return false;
|
||||
}
|
||||
gp_Pln pln;
|
||||
@@ -653,8 +718,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l,
|
||||
TopoDS_Shape face;
|
||||
TopoDS_Wire wire, section;
|
||||
|
||||
if (!l->ReferenceSurface()->is(IfcSchema::Type::IfcPlane)) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Reference surface not supported", l->ReferenceSurface()->entity);
|
||||
if (!l->ReferenceSurface()->declaration().is(IfcSchema::Type::IfcPlane)) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Reference surface not supported", l->ReferenceSurface());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -679,7 +744,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l,
|
||||
for (TopExp_Explorer exp(wire, TopAbs_VERTEX); exp.More(); exp.Next()) {
|
||||
if (pln.Distance(BRep_Tool::Pnt(TopoDS::Vertex(exp.Current()))) > ALMOST_ZERO) {
|
||||
directrix_on_plane = false;
|
||||
Logger::Message(Logger::LOG_WARNING, "The Directrix does not lie on the ReferenceSurface", l->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "The Directrix does not lie on the ReferenceSurface", l);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -752,8 +817,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shap
|
||||
// Subtraction of pipes with small radii is unstable.
|
||||
hasInnerRadius = false;
|
||||
} else {
|
||||
Handle(Geom_Circle) circle = new Geom_Circle(directrix, r2);
|
||||
section2 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle));
|
||||
Handle(Geom_Circle) circle2 = new Geom_Circle(directrix, r2);
|
||||
section2 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -794,7 +859,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shap
|
||||
}
|
||||
|
||||
if (!is_valid) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Failed to subtract inner radius void for:", l->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Failed to subtract inner radius void for:", l);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -807,7 +872,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCylindricalSurface* l, TopoDS_
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
|
||||
#if OCC_VERSION_HEX < 0x60502
|
||||
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius())).Face().Moved(trsf);
|
||||
#else
|
||||
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius()), getValue(GV_PRECISION)).Face().Moved(trsf);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -815,4 +884,112 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAdvancedBrep* l, TopoDS_Shape&
|
||||
return convert(l->Outer(), shape);
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, TopoDS_Shape& shape) {
|
||||
IfcSchema::IfcCartesianPointList3D* point_list = l->Coordinates();
|
||||
const std::vector< std::vector<double> > coordinates = point_list->CoordList();
|
||||
std::vector<gp_Pnt> points;
|
||||
points.reserve(coordinates.size());
|
||||
for (std::vector< std::vector<double> >::const_iterator it = coordinates.begin(); it != coordinates.end(); ++it) {
|
||||
const std::vector<double>& coords = *it;
|
||||
if (coords.size() != 3) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on Coordinates", l);
|
||||
return false;
|
||||
}
|
||||
points.push_back(gp_Pnt(coords[0] * getValue(GV_LENGTH_UNIT),
|
||||
coords[1] * getValue(GV_LENGTH_UNIT),
|
||||
coords[2] * getValue(GV_LENGTH_UNIT)));
|
||||
}
|
||||
|
||||
std::vector< std::vector<int> > indices = l->CoordIndex();
|
||||
|
||||
std::vector<TopoDS_Face> faces;
|
||||
faces.reserve(indices.size());
|
||||
|
||||
for(std::vector< std::vector<int> >::const_iterator it = indices.begin(); it != indices.end(); ++ it) {
|
||||
const std::vector<int>& tri = *it;
|
||||
if (tri.size() != 3) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on CoordIndex", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
const int min_index = *std::min_element(tri.begin(), tri.end());
|
||||
const int max_index = *std::max_element(tri.begin(), tri.end());
|
||||
|
||||
if (min_index < 1 || max_index > points.size()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Contents of CoordIndex out of bounds", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
const gp_Pnt& a = points[tri[0] - 1]; // account for zero- vs
|
||||
const gp_Pnt& b = points[tri[1] - 1]; // one-based indices in
|
||||
const gp_Pnt& c = points[tri[2] - 1]; // c++ and express
|
||||
|
||||
TopoDS_Wire wire = BRepBuilderAPI_MakePolygon(a, b, c, true).Wire();
|
||||
TopoDS_Face face = BRepBuilderAPI_MakeFace(wire).Face();
|
||||
|
||||
TopoDS_Iterator face_it(face, false);
|
||||
const TopoDS_Wire& w = TopoDS::Wire(face_it.Value());
|
||||
const bool reversed = w.Orientation() == TopAbs_REVERSED;
|
||||
if (reversed) {
|
||||
face.Reverse();
|
||||
}
|
||||
|
||||
if (face_area(face) > getValue(GV_MINIMAL_FACE_AREA)) {
|
||||
faces.push_back(face);
|
||||
}
|
||||
}
|
||||
|
||||
if (faces.empty()) return false;
|
||||
|
||||
const unsigned int num_faces = (unsigned)indices.size();
|
||||
bool valid_shell = false;
|
||||
|
||||
if (faces.size() < getValue(GV_MAX_FACES_TO_SEW)) {
|
||||
BRepOffsetAPI_Sewing builder;
|
||||
builder.SetTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
|
||||
builder.SetMaxTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
|
||||
builder.SetMinTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
|
||||
|
||||
for (std::vector<TopoDS_Face>::const_iterator it = faces.begin(); it != faces.end(); ++it) {
|
||||
builder.Add(*it);
|
||||
}
|
||||
|
||||
try {
|
||||
builder.Perform();
|
||||
shape = builder.SewedShape();
|
||||
valid_shell = BRepCheck_Analyzer(shape).IsValid();
|
||||
} catch(...) {}
|
||||
|
||||
if (valid_shell) {
|
||||
try {
|
||||
ShapeFix_Solid solid;
|
||||
solid.LimitTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
|
||||
TopoDS_Solid solid_shape = solid.SolidFromShell(TopoDS::Shell(shape));
|
||||
if (!solid_shape.IsNull()) {
|
||||
try {
|
||||
BRepClass3d_SolidClassifier classifier(solid_shape);
|
||||
shape = solid_shape;
|
||||
} catch (...) {}
|
||||
}
|
||||
} catch(...) {}
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_WARNING, "Failed to sew faceset:", l);
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid_shell) {
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
|
||||
for (std::vector<TopoDS_Face>::const_iterator it = faces.begin(); it != faces.end(); ++it) {
|
||||
builder.Add(compound, *it);
|
||||
}
|
||||
|
||||
shape = compound;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+111
-46
@@ -65,6 +65,8 @@
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
|
||||
#include <TopExp.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopLoc_Location.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
@@ -85,7 +87,7 @@
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire& wire) {
|
||||
if ( getValue(GV_PLANEANGLE_UNIT)<0 ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Creating a composite curve without unit information:", l);
|
||||
|
||||
// Temporarily pretend we do have unit information
|
||||
setValue(GV_PLANEANGLE_UNIT,1.0);
|
||||
@@ -146,7 +148,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
|
||||
IfcSchema::IfcCurve* curve = (*it)->ParentCurve();
|
||||
TopoDS_Wire wire2;
|
||||
if ( !convert_wire(curve,wire2) ) {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to convert curve:", curve);
|
||||
continue;
|
||||
}
|
||||
if ( ! (*it)->SameSense() ) wire2.Reverse();
|
||||
@@ -165,7 +167,26 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
|
||||
w.Add(wire2);
|
||||
//last_vertex = w.Vertex();
|
||||
if ( w.Error() != BRepBuilderAPI_WireDone ) {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to join curve segments:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to join curve segments:", l);
|
||||
|
||||
TopoDS_Vertex v1, v2, last;
|
||||
last = w.Vertex();
|
||||
|
||||
if (!last.IsNull()) {
|
||||
std::stringstream ss;
|
||||
gp_Pnt p = BRep_Tool::Pnt(last);
|
||||
ss << std::setprecision(4) << "Last vertex at (" << p.X() << " " << p.Y() << " " << p.Z() << ")";
|
||||
Logger::Message(Logger::LOG_NOTICE, ss.str());
|
||||
}
|
||||
|
||||
TopExp::Vertices(wire2, v1, v2);
|
||||
if (!v1.IsNull()) {
|
||||
std::stringstream ss;
|
||||
gp_Pnt p = BRep_Tool::Pnt(v1);
|
||||
ss << std::setprecision(4) << "Segment starts at (" << p.X() << " " << p.Y() << " " << p.Z() << ") for:";
|
||||
Logger::Message(Logger::LOG_NOTICE, ss.str(), *it);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -175,15 +196,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& wire) {
|
||||
IfcSchema::IfcCurve* basis_curve = l->BasisCurve();
|
||||
bool isConic = basis_curve->is(IfcSchema::Type::IfcConic);
|
||||
bool isConic = basis_curve->declaration().is(IfcSchema::Type::IfcConic);
|
||||
double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT);
|
||||
Handle(Geom_Curve) curve;
|
||||
if ( !convert_curve(basis_curve,curve) ) return false;
|
||||
bool trim_cartesian = l->MasterRepresentation() == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN;
|
||||
IfcEntityList::ptr trims1 = l->Trim1();
|
||||
IfcEntityList::ptr trims2 = l->Trim2();
|
||||
bool trimmed1 = false;
|
||||
bool trimmed2 = false;
|
||||
unsigned sense_agreement = l->SenseAgreement() ? 0 : 1;
|
||||
double flts[2];
|
||||
gp_Pnt pnts[2];
|
||||
@@ -192,10 +211,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) {
|
||||
IfcUtil::IfcBaseClass* i = *it;
|
||||
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
|
||||
if ( i->declaration().is(IfcSchema::Type::IfcCartesianPoint) ) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] );
|
||||
has_pnts[sense_agreement] = true;
|
||||
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
|
||||
} else if ( i->declaration().is(IfcSchema::Type::IfcParameterValue) ) {
|
||||
const double value = *((IfcSchema::IfcParameterValue*)i);
|
||||
flts[sense_agreement] = value * parameterFactor;
|
||||
has_flts[sense_agreement] = true;
|
||||
@@ -203,10 +222,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
|
||||
}
|
||||
for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) {
|
||||
IfcUtil::IfcBaseClass* i = *it;
|
||||
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
|
||||
if ( i->declaration().is(IfcSchema::Type::IfcCartesianPoint) ) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] );
|
||||
has_pnts[1-sense_agreement] = true;
|
||||
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
|
||||
} else if ( i->declaration().is(IfcSchema::Type::IfcParameterValue) ) {
|
||||
const double value = *((IfcSchema::IfcParameterValue*)i);
|
||||
flts[1-sense_agreement] = value * parameterFactor;
|
||||
has_flts[1-sense_agreement] = true;
|
||||
@@ -216,7 +235,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
|
||||
bool trim_cartesian_failed = !trim_cartesian;
|
||||
if ( trim_cartesian ) {
|
||||
if ( pnts[0].Distance(pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE) ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Skipping segment with length below tolerance level:", l);
|
||||
return false;
|
||||
}
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
@@ -228,7 +247,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
|
||||
if ( ! e.IsDone() ) {
|
||||
BRepBuilderAPI_EdgeError err = e.Error();
|
||||
if ( err == BRepBuilderAPI_PointProjectionFailed ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Point projection failed for:",l->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Point projection failed for:", l);
|
||||
trim_cartesian_failed = true;
|
||||
}
|
||||
} else {
|
||||
@@ -240,12 +259,12 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
|
||||
// is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because
|
||||
// the vector is normalised when passed to Geom_Line constructor the magnitude
|
||||
// needs to be factored in with the IfcParameterValue here.
|
||||
if ( basis_curve->is(IfcSchema::Type::IfcLine) ) {
|
||||
if ( basis_curve->declaration().is(IfcSchema::Type::IfcLine) ) {
|
||||
IfcSchema::IfcLine* line = static_cast<IfcSchema::IfcLine*>(basis_curve);
|
||||
const double magnitude = line->Dir()->Magnitude();
|
||||
flts[0] *= magnitude; flts[1] *= magnitude;
|
||||
}
|
||||
if ( basis_curve->is(IfcSchema::Type::IfcEllipse) ) {
|
||||
if ( basis_curve->declaration().is(IfcSchema::Type::IfcEllipse) ) {
|
||||
IfcSchema::IfcEllipse* ellipse = static_cast<IfcSchema::IfcEllipse*>(basis_curve);
|
||||
double x = ellipse->SemiAxis1() * getValue(GV_LENGTH_UNIT);
|
||||
double y = ellipse->SemiAxis2() * getValue(GV_LENGTH_UNIT);
|
||||
@@ -255,7 +274,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
|
||||
flts[1] -= M_PI / 2.;
|
||||
}
|
||||
}
|
||||
if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],(double)(M_PI*2.0)),0.0f) ) {
|
||||
if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],M_PI*2.),0.) ) {
|
||||
w.Add(BRepBuilderAPI_MakeEdge(curve));
|
||||
} else {
|
||||
BRepBuilderAPI_MakeEdge e (curve,flts[0],flts[1]);
|
||||
@@ -284,7 +303,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& resu
|
||||
}
|
||||
|
||||
// Remove points that are too close to one another
|
||||
remove_redundant_points_from_loop(polygon, false);
|
||||
remove_duplicate_points_from_loop(polygon, false);
|
||||
|
||||
BRepBuilderAPI_MakePolygon w;
|
||||
for (int i = 1; i <= polygon.Length(); ++i) {
|
||||
@@ -309,21 +328,21 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& resu
|
||||
// A loop should consist of at least three vertices
|
||||
int original_count = polygon.Length();
|
||||
if (original_count < 3) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove points that are too close to one another
|
||||
remove_redundant_points_from_loop(polygon, true);
|
||||
remove_duplicate_points_from_loop(polygon, true);
|
||||
|
||||
int count = polygon.Length();
|
||||
if (original_count - count != 0) {
|
||||
std::stringstream ss; ss << (original_count - count) << " edges removed for:";
|
||||
Logger::Message(Logger::LOG_WARNING, ss.str(), l->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, ss.str(), l);
|
||||
}
|
||||
|
||||
if (count < 3) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -344,8 +363,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryOpenProfileDef* l, To
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeCurve* l, TopoDS_Wire& result) {
|
||||
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry();
|
||||
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry();
|
||||
if (!pnt1->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l->entity);
|
||||
if (!pnt1->declaration().is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->declaration().is(IfcSchema::Type::IfcCartesianPoint)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -364,7 +383,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeCurve* l, TopoDS_Wire& res
|
||||
// assumed that a topological wire can be crafted from it. After which an
|
||||
// attempt is made to reconstruct it from the individual curves and the vertices
|
||||
// of the IfcEdgeCurve.
|
||||
const bool is_bounded = l->EdgeGeometry()->is(IfcSchema::Type::IfcBoundedCurve);
|
||||
const bool is_bounded = l->EdgeGeometry()->declaration().is(IfcSchema::Type::IfcBoundedCurve);
|
||||
|
||||
if (!is_bounded && convert_curve(l->EdgeGeometry(), crv)) {
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(crv, p1, p2));
|
||||
@@ -406,32 +425,78 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeLoop* l, TopoDS_Wire& resu
|
||||
IfcSchema::IfcOrientedEdge::list::ptr li = l->EdgeList();
|
||||
BRepBuilderAPI_MakeWire mw;
|
||||
for (IfcSchema::IfcOrientedEdge::list::it it = li->begin(); it != li->end(); ++it) {
|
||||
IfcSchema::IfcOrientedEdge* e = *it;
|
||||
|
||||
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) e->EdgeStart())->VertexGeometry();
|
||||
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) e->EdgeEnd())->VertexGeometry();
|
||||
if (!pnt1->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Pnt p1, p2;
|
||||
if (!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
|
||||
!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(p1, p2));
|
||||
continue;
|
||||
|
||||
IfcSchema::IfcEdge* base = e->EdgeElement();
|
||||
TopoDS_Wire w;
|
||||
if (convert_wire(e->EdgeElement(), w)) {
|
||||
if (!e->Orientation()) w.Reverse();
|
||||
mw.Add(w);
|
||||
if (convert_wire(*it, w)) {
|
||||
if (!(*it)->Orientation()) w.Reverse();
|
||||
TopoDS_Iterator topoit(w, false);
|
||||
for (; topoit.More(); topoit.Next()) {
|
||||
const TopoDS_Edge& e = TopoDS::Edge(topoit.Value());
|
||||
mw.Add(e);
|
||||
}
|
||||
// mw.Add(w);
|
||||
}
|
||||
}
|
||||
result = mw;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdge* l, TopoDS_Wire& result) {
|
||||
if (!l->EdgeStart()->declaration().is(IfcSchema::Type::IfcVertexPoint) || !l->EdgeEnd()->declaration().is(IfcSchema::Type::IfcVertexPoint)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcVertexPoints are supported for EdgeStart and -End", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry();
|
||||
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry();
|
||||
if (!pnt1->declaration().is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->declaration().is(IfcSchema::Type::IfcCartesianPoint)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Pnt p1, p2;
|
||||
if (!convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
|
||||
!convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeWire mw;
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(p1, p2));
|
||||
|
||||
result = mw.Wire();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcOrientedEdge* l, TopoDS_Wire& result) {
|
||||
if (convert_wire(l->EdgeElement(), result)) {
|
||||
if (!l->Orientation()) {
|
||||
result.Reverse();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSubedge* l, TopoDS_Wire& result) {
|
||||
TopoDS_Wire temp;
|
||||
if (convert_wire(l->ParentEdge(), result) && convert((IfcSchema::IfcEdge*) l, temp)) {
|
||||
TopExp_Explorer exp(result, TopAbs_EDGE);
|
||||
TopoDS_Edge edge = TopoDS::Edge(exp.Current());
|
||||
Standard_Real u1, u2;
|
||||
Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u1, u2);
|
||||
TopoDS_Vertex v1, v2;
|
||||
TopExp::Vertices(temp, v1, v2);
|
||||
BRepBuilderAPI_MakeWire mw;
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(crv, v1, v2));
|
||||
result = mw.Wire();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+56
-11
@@ -18,34 +18,79 @@
|
||||
********************************************************************************/
|
||||
|
||||
#include "IfcGeom.h"
|
||||
#include "IfcGeomShapeType.h"
|
||||
|
||||
using namespace IfcSchema;
|
||||
using namespace IfcUtil;
|
||||
|
||||
bool IfcGeom::Kernel::convert_shapes(const IfcBaseClass* l, IfcRepresentationShapeItems& r) {
|
||||
if (shape_type(l) != ST_SHAPELIST) {
|
||||
TopoDS_Shape shp;
|
||||
if (convert_shape(l, shp)) {
|
||||
r.push_back(IfcGeom::IfcRepresentationShapeItem(shp, get_style(l->as<IfcSchema::IfcRepresentationItem>())));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "IfcRegisterConvertShapes.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::is_shape_collection(const IfcBaseClass* l) {
|
||||
#include "IfcRegisterIsShapeCollection.h"
|
||||
return false;
|
||||
IfcGeom::ShapeType IfcGeom::Kernel::shape_type(const IfcBaseClass* l) {
|
||||
#include "IfcRegisterShapeType.h"
|
||||
return ST_OTHER;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) {
|
||||
const unsigned int id = l->entity->id();
|
||||
const unsigned int id = l->data().id();
|
||||
bool success = false;
|
||||
bool processed = false;
|
||||
bool ignored = false;
|
||||
|
||||
std::map<int,TopoDS_Shape>::const_iterator it = cache.Shape.find(id);
|
||||
if ( it != cache.Shape.end() ) { r = it->second; return true; }
|
||||
const bool include_curves = getValue(GV_DIMENSIONALITY) != +1;
|
||||
const bool include_solids_and_surfaces = getValue(GV_DIMENSIONALITY) != -1;
|
||||
|
||||
IfcGeom::ShapeType st = shape_type(l);
|
||||
ignored = (!include_solids_and_surfaces && (st == ST_SHAPE || st == ST_FACE)) || (!include_curves && (st == ST_WIRE || st == ST_CURVE));
|
||||
if (st == ST_SHAPELIST) {
|
||||
processed = true;
|
||||
IfcRepresentationShapeItems items;
|
||||
success = convert_shapes(l, items) && flatten_shape_list(items, r, false);
|
||||
} else if (st == ST_SHAPE && include_solids_and_surfaces) {
|
||||
#include "IfcRegisterConvertShape.h"
|
||||
if ( processed ) {
|
||||
} else if (st == ST_FACE && include_solids_and_surfaces) {
|
||||
processed = true;
|
||||
success = convert_face(l, r);
|
||||
} else if (st == ST_WIRE && include_curves) {
|
||||
processed = true;
|
||||
TopoDS_Wire w;
|
||||
success = convert_wire(l, w);
|
||||
if (success) {
|
||||
r = w;
|
||||
}
|
||||
} else if (st == ST_CURVE && include_curves) {
|
||||
processed = true;
|
||||
Handle(Geom_Curve) crv;
|
||||
TopoDS_Wire w;
|
||||
success = convert_curve(l, crv) && convert_curve_to_wire(crv, w);
|
||||
if (success) {
|
||||
r = w;
|
||||
}
|
||||
}
|
||||
|
||||
if ( processed && success ) {
|
||||
const double precision = getValue(GV_PRECISION);
|
||||
apply_tolerance(r, precision);
|
||||
cache.Shape[id] = r;
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
} else if (!ignored) {
|
||||
const char* const msg = processed
|
||||
? "Failed to convert:"
|
||||
: "No operation defined for:";
|
||||
Logger::Message(Logger::LOG_ERROR, msg, l);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@@ -56,18 +101,18 @@ bool IfcGeom::Kernel::convert_wire(const IfcBaseClass* l, TopoDS_Wire& r) {
|
||||
if (IfcGeom::Kernel::convert_curve(l, curve)) {
|
||||
return IfcGeom::Kernel::convert_curve_to_wire(curve, r);
|
||||
}
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert_face(const IfcBaseClass* l, TopoDS_Shape& r) {
|
||||
#include "IfcRegisterConvertFace.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert_curve(const IfcBaseClass* l, Handle(Geom_Curve)& r) {
|
||||
#include "IfcRegisterConvertCurve.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l);
|
||||
return false;
|
||||
}
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
SHAPES(IfcShellBasedSurfaceModel);
|
||||
SHAPES(IfcFaceBasedSurfaceModel);
|
||||
SHAPES(IfcShapeRepresentation);
|
||||
SHAPES(IfcRepresentation);
|
||||
SHAPES(IfcMappedItem);
|
||||
SHAPES(IfcFacetedBrep);
|
||||
SHAPES(IfcGeometricSet);
|
||||
@@ -51,13 +51,18 @@ SHAPES(IfcGeometricSet);
|
||||
#ifdef USE_IFC4
|
||||
SHAPE(IfcCylindricalSurface);
|
||||
SHAPE(IfcAdvancedBrep);
|
||||
// FIXME: Surfaces should have a shape type of their own
|
||||
SHAPE(IfcBSplineSurfaceWithKnots);
|
||||
SHAPE(IfcTriangulatedFaceSet);
|
||||
#endif
|
||||
SHAPE(IfcPlane);
|
||||
SHAPE(IfcExtrudedAreaSolid);
|
||||
SHAPE(IfcRevolvedAreaSolid);
|
||||
SHAPE(IfcConnectedFaceSet);
|
||||
SHAPE(IfcBooleanResult);
|
||||
SHAPE(IfcPolygonalBoundedHalfSpace);
|
||||
SHAPE(IfcHalfSpaceSolid);
|
||||
// FIXME: Surfaces should have a shape type of their own
|
||||
SHAPE(IfcSurfaceOfLinearExtrusion);
|
||||
SHAPE(IfcSurfaceOfRevolution);
|
||||
SHAPE(IfcBlock);
|
||||
@@ -71,9 +76,6 @@ SHAPE(IfcRectangularTrimmedSurface);
|
||||
SHAPE(IfcSurfaceCurveSweptAreaSolid);
|
||||
SHAPE(IfcSweptDiskSolid);
|
||||
|
||||
#ifdef USE_IFC4
|
||||
FACE(IfcAdvancedFace);
|
||||
#endif
|
||||
FACE(IfcArbitraryProfileDefWithVoids);
|
||||
FACE(IfcArbitraryClosedProfileDef);
|
||||
FACE(IfcRoundedRectangleProfileDef);
|
||||
@@ -93,9 +95,14 @@ FACE(IfcEllipseProfileDef);
|
||||
FACE(IfcCenterLineProfileDef);
|
||||
FACE(IfcCompositeProfileDef);
|
||||
FACE(IfcDerivedProfileDef);
|
||||
// IfcFaceSurface included
|
||||
// IfcAdvancedFace included in case of IFC4
|
||||
FACE(IfcFace);
|
||||
|
||||
WIRE(IfcEdgeCurve);
|
||||
WIRE(IfcSubedge);
|
||||
WIRE(IfcOrientedEdge);
|
||||
WIRE(IfcEdge);
|
||||
WIRE(IfcEdgeLoop);
|
||||
WIRE(IfcPolyline);
|
||||
WIRE(IfcPolyLoop);
|
||||
@@ -106,6 +113,9 @@ WIRE(IfcArbitraryOpenProfileDef);
|
||||
CURVE(IfcCircle);
|
||||
CURVE(IfcEllipse);
|
||||
CURVE(IfcLine);
|
||||
#ifdef USE_IFC4
|
||||
CURVE(IfcBSplineCurveWithKnots);
|
||||
#endif
|
||||
|
||||
CLASS(IfcCartesianPoint,gp_Pnt);
|
||||
CLASS(IfcDirection,gp_Dir);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define CURVE(T) \
|
||||
if ( l->is(T::Class()) ) return convert((T*)l,r);
|
||||
if ( l->declaration().is(T::Class()) ) return convert(l->as<T>(), r);
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
#include "IfcRegister.h"
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define FACE(T) \
|
||||
if ( l->is(T::Class()) ) return convert((T*)l,r);
|
||||
if ( l->declaration().is(T::Class()) ) return convert(l->as<T>(), r);
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
#include "IfcRegister.h"
|
||||
@@ -1,14 +1,14 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define SHAPE(T) \
|
||||
if ( !processed && l->is(T::Class()) ) { \
|
||||
if ( !processed && l->declaration().is(T::Class()) ) { \
|
||||
processed = true; \
|
||||
try { \
|
||||
if ( convert((T*)l,r) ) { \
|
||||
if ( convert(l->as<T>(), r) ) { \
|
||||
success = true; \
|
||||
} \
|
||||
} catch(...) { } \
|
||||
if ( !success) { \
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to convert:", l); \
|
||||
return false; \
|
||||
} \
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define SHAPES(T) \
|
||||
if ( l->is(T::Class()) ) { \
|
||||
if ( l->declaration().is(T::Class()) ) { \
|
||||
try { \
|
||||
return convert((T*)l,r); \
|
||||
return convert(l->as<T>(), r); \
|
||||
} catch (...) { } \
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to convert:", l); \
|
||||
return false; \
|
||||
}
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define WIRE(T) \
|
||||
if ( l->is(T::Class()) ) return convert((T*)l,r);
|
||||
if ( l->declaration().is(T::Class()) ) return convert((T*)l,r);
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
#include "IfcRegister.h"
|
||||
@@ -1,6 +0,0 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define SHAPES(T) \
|
||||
if ( l->is(T::Class()) ) return true;
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
#include "IfcRegister.h"
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define SHAPES(T) \
|
||||
if ( l->declaration().is(T::Class()) ) return ST_SHAPELIST;
|
||||
#define SHAPE(T) \
|
||||
if ( l->declaration().is(T::Class()) ) return ST_SHAPE;
|
||||
#define WIRE(T) \
|
||||
if ( l->declaration().is(T::Class()) ) return ST_WIRE;
|
||||
#define FACE(T) \
|
||||
if ( l->declaration().is(T::Class()) ) return ST_FACE;
|
||||
#define CURVE(T) \
|
||||
if ( l->declaration().is(T::Class()) ) return ST_CURVE;
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
#include "IfcRegister.h"
|
||||
@@ -46,6 +46,7 @@ namespace IfcGeom {
|
||||
const gp_GTrsf& Placement() const { return placement; }
|
||||
bool hasStyle() const { return style != 0; }
|
||||
const SurfaceStyle& Style() const { return *style; }
|
||||
void setStyle(const SurfaceStyle* style) { this->style = style; }
|
||||
};
|
||||
typedef std::vector<IfcRepresentationShapeItem> IfcRepresentationShapeItems;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
#endif
|
||||
|
||||
using namespace boost;
|
||||
|
||||
template <typename T>
|
||||
@@ -69,7 +73,7 @@ void swrite(std::ostream& s, T t) {
|
||||
|
||||
template <>
|
||||
void swrite(std::ostream& s, std::string t) {
|
||||
int32_t len = t.size();
|
||||
int32_t len = (int32_t)t.size();
|
||||
swrite(s, len);
|
||||
s.write(t.c_str(), len);
|
||||
while (len++ % 4) s.put(0);
|
||||
@@ -156,16 +160,16 @@ public:
|
||||
|
||||
class Get : public Command {
|
||||
protected:
|
||||
void read_content(std::istream& s) {}
|
||||
void write_content(std::ostream& s) {}
|
||||
void read_content(std::istream& /*s*/) {}
|
||||
void write_content(std::ostream& /*s*/) {}
|
||||
public:
|
||||
Get() : Command(GET) {};
|
||||
};
|
||||
|
||||
class GetLog : public Command {
|
||||
protected:
|
||||
void read_content(std::istream& s) {}
|
||||
void write_content(std::ostream& s) {}
|
||||
void read_content(std::istream& /*s*/) {}
|
||||
void write_content(std::ostream& /*s*/) {}
|
||||
public:
|
||||
GetLog() : Command(GET_LOG) {};
|
||||
};
|
||||
@@ -187,8 +191,9 @@ public:
|
||||
class Entity : public Command {
|
||||
private:
|
||||
const IfcGeom::TriangulationElement<float>* geom;
|
||||
bool append_line_data;
|
||||
protected:
|
||||
void read_content(std::istream& s) {}
|
||||
void read_content(std::istream& /*s*/) {}
|
||||
void write_content(std::ostream& s) {
|
||||
swrite<int32_t>(s, geom->id());
|
||||
swrite(s, geom->guid());
|
||||
@@ -206,16 +211,40 @@ protected:
|
||||
swrite<int32_t>(s, geom->geometry().id());
|
||||
swrite(s, std::string((char*)geom->geometry().verts().data(), geom->geometry().verts().size() * sizeof(float)));
|
||||
swrite(s, std::string((char*)geom->geometry().normals().data(), geom->geometry().normals().size() * sizeof(float)));
|
||||
{ std::vector<int32_t> indices;
|
||||
for (std::vector<int>::const_iterator it = geom->geometry().faces().begin(); it != geom->geometry().faces().end(); ++it) {
|
||||
indices.push_back(*it);
|
||||
}
|
||||
swrite(s, std::string((char*) indices.data(), indices.size() * sizeof(int32_t))); }
|
||||
{
|
||||
std::vector<int32_t> indices;
|
||||
const std::vector<int>& faces = geom->geometry().faces();
|
||||
indices.reserve(faces.size());
|
||||
for (std::vector<int>::const_iterator it = indices.begin(); it != indices.end(); ++it) {
|
||||
indices.push_back(*it);
|
||||
}
|
||||
swrite(s, std::string((char*) indices.data(), indices.size() * sizeof(int32_t)));
|
||||
|
||||
if (append_line_data) {
|
||||
std::vector<int32_t> lines;
|
||||
std::set<int32_t> faces_set (indices.begin(), indices.end());
|
||||
|
||||
const std::vector<int>& edges = geom->geometry().edges();
|
||||
for ( std::vector<int>::const_iterator it = edges.begin(); it != edges.end(); ) {
|
||||
const int32_t i1 = *(it++);
|
||||
const int32_t i2 = *(it++);
|
||||
|
||||
if (faces_set.find(i1) != faces_set.end() || faces_set.find(i2) != faces_set.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lines.push_back(i1);
|
||||
lines.push_back(i2);
|
||||
}
|
||||
|
||||
swrite(s, std::string((char*) lines.data(), lines.size() * sizeof(int32_t)));
|
||||
}
|
||||
}
|
||||
{ std::vector<float> diffuse_color_array;
|
||||
for (std::vector<IfcGeom::Material>::const_iterator it = geom->geometry().materials().begin(); it != geom->geometry().materials().end(); ++it) {
|
||||
const IfcGeom::Material& m = *it;
|
||||
if (m.hasDiffuse()) {
|
||||
const double* color = m.diffuse();
|
||||
const IfcGeom::Material& mat = *it;
|
||||
if (mat.hasDiffuse()) {
|
||||
const double* color = mat.diffuse();
|
||||
diffuse_color_array.push_back(static_cast<float>(color[0]));
|
||||
diffuse_color_array.push_back(static_cast<float>(color[1]));
|
||||
diffuse_color_array.push_back(static_cast<float>(color[2]));
|
||||
@@ -224,8 +253,8 @@ protected:
|
||||
diffuse_color_array.push_back(0.f);
|
||||
diffuse_color_array.push_back(0.f);
|
||||
}
|
||||
if (m.hasTransparency()) {
|
||||
diffuse_color_array.push_back(static_cast<float>(1. - m.transparency()));
|
||||
if (mat.hasTransparency()) {
|
||||
diffuse_color_array.push_back(static_cast<float>(1. - mat.transparency()));
|
||||
} else {
|
||||
diffuse_color_array.push_back(1.f);
|
||||
}
|
||||
@@ -238,30 +267,26 @@ protected:
|
||||
swrite(s, std::string((char*) material_indices.data(), material_indices.size() * sizeof(int32_t))); }
|
||||
}
|
||||
public:
|
||||
Entity(const IfcGeom::TriangulationElement<float>* geom) : Command(ENTITY), geom(geom) {};
|
||||
Entity(const IfcGeom::TriangulationElement<float>* geom) : Command(ENTITY), geom(geom), append_line_data(true) {};
|
||||
};
|
||||
|
||||
class Next : public Command {
|
||||
protected:
|
||||
void read_content(std::istream& s) {}
|
||||
void write_content(std::ostream& s) {}
|
||||
void read_content(std::istream& /*s*/) {}
|
||||
void write_content(std::ostream& /*s*/) {}
|
||||
public:
|
||||
Next() : Command(NEXT) {};
|
||||
};
|
||||
|
||||
class Bye : public Command {
|
||||
protected:
|
||||
void read_content(std::istream& s) {}
|
||||
void write_content(std::ostream& s) {}
|
||||
void read_content(std::istream& /*s*/) {}
|
||||
void write_content(std::ostream& /*s*/) {}
|
||||
public:
|
||||
Bye() : Command(BYE) {};
|
||||
};
|
||||
|
||||
int main (int argc, char** argv) {
|
||||
if (sizeof(float) != 4 || sizeof(int32_t) != 4) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main () {
|
||||
// Redirect stdout to this stream, so that involuntary
|
||||
// writes to stdout do not interfere with our protocol.
|
||||
std::ostringstream oss;
|
||||
@@ -283,7 +308,7 @@ int main (int argc, char** argv) {
|
||||
Hello().write(std::cout);
|
||||
|
||||
int exit_code = 0;
|
||||
while (1) {
|
||||
for (;;) {
|
||||
const int32_t msg_type = sread<int32_t>(std::cin);
|
||||
switch (msg_type) {
|
||||
case IFC_MODEL: {
|
||||
@@ -296,10 +321,10 @@ int main (int argc, char** argv) {
|
||||
settings.use_world_coords() = false;
|
||||
settings.weld_vertices() = false;
|
||||
settings.convert_back_units() = true;
|
||||
settings.force_ccw_face_orientation() = true;
|
||||
settings.include_curves() = true;
|
||||
|
||||
iterator = new IfcGeom::Iterator<float>(settings, data, len);
|
||||
has_more = iterator->findContext();
|
||||
iterator = new IfcGeom::Iterator<float>(settings, data, (int)len);
|
||||
has_more = iterator->initialize();
|
||||
|
||||
More(has_more).write(std::cout);
|
||||
continue;
|
||||
|
||||
+33
-4
@@ -17,6 +17,9 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include <Max.h>
|
||||
#include <stdmat.h>
|
||||
#include <istdplug.h>
|
||||
@@ -215,7 +218,7 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
|
||||
|
||||
IfcGeom::Iterator<float> iterator(settings, fn_mb);
|
||||
|
||||
if (!iterator.findContext()) return false;
|
||||
if (!iterator.initialize()) return false;
|
||||
|
||||
itfc->ProgressStart(_T("Importing file..."), TRUE, fn, NULL);
|
||||
|
||||
@@ -244,11 +247,37 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
|
||||
|
||||
bool needs_default = std::find(o->geometry().material_ids().begin(), o->geometry().material_ids().end(), -1) != o->geometry().material_ids().end();
|
||||
|
||||
typedef std::pair<int, int> edge_t;
|
||||
|
||||
std::set<edge_t> face_boundaries;
|
||||
for(std::vector<int>::const_iterator it = o->geometry().edges().begin(); it != o->geometry().edges().end();) {
|
||||
const int v1 = *it++;
|
||||
const int v2 = *it++;
|
||||
|
||||
const edge_t e((std::min)(v1, v2), (std::max)(v1, v2));
|
||||
face_boundaries.insert(e);
|
||||
}
|
||||
|
||||
for( int i = 0; i < numFaces; i ++ ) {
|
||||
tri->mesh.faces[i].setVerts(o->geometry().faces()[3*i+0],o->geometry().faces()[3*i+1],o->geometry().faces()[3*i+2]);
|
||||
tri->mesh.faces[i].setEdgeVisFlags(o->geometry().edges()[3*i+0],o->geometry().edges()[3*i+1],o->geometry().edges()[3*i+2]);
|
||||
const int v1 = o->geometry().faces()[3*i+0];
|
||||
const int v2 = o->geometry().faces()[3*i+1];
|
||||
const int v3 = o->geometry().faces()[3*i+2];
|
||||
|
||||
const edge_t e1((std::min)(v1, v2), (std::max)(v1, v2));
|
||||
const edge_t e2((std::min)(v2, v3), (std::max)(v2, v3));
|
||||
const edge_t e3((std::min)(v3, v1), (std::max)(v3, v1));
|
||||
|
||||
const bool b1 = face_boundaries.find(e1) != face_boundaries.end();
|
||||
const bool b2 = face_boundaries.find(e2) != face_boundaries.end();
|
||||
const bool b3 = face_boundaries.find(e3) != face_boundaries.end();
|
||||
|
||||
tri->mesh.faces[i].setVerts(v1, v2, v3);
|
||||
tri->mesh.faces[i].setEdgeVisFlags(b1, b2, b3);
|
||||
|
||||
MtlID mtlid = o->geometry().material_ids()[i];
|
||||
if (needs_default) mtlid ++;
|
||||
if (needs_default) {
|
||||
mtlid ++;
|
||||
}
|
||||
tri->mesh.faces[i].setMatID(mtlid);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
import numbers
|
||||
import platform
|
||||
import functools
|
||||
import itertools
|
||||
@@ -43,30 +44,30 @@ class entity_instance(object):
|
||||
def __init__(self, e):
|
||||
super(entity_instance, self).__setattr__('wrapped_data', e)
|
||||
def __getattr__(self, name):
|
||||
try: return entity_instance.wrap_value(self.wrapped_data.get_argument(self.wrapped_data.get_argument_index(name)))
|
||||
except:
|
||||
try: return entity_instance.wrap_value(self.wrapped_data.get_inverse(name))
|
||||
except: raise AttributeError("entity instance of type '%s' has no attribute '%s'"%(self.wrapped_data.is_a(), name))
|
||||
INVALID, FORWARD, INVERSE = range(3)
|
||||
attr_cat = self.wrapped_data.get_attribute_category(name)
|
||||
if attr_cat == FORWARD:
|
||||
return entity_instance.wrap_value(self.wrapped_data.get_argument(self.wrapped_data.get_argument_index(name)))
|
||||
elif attr_cat == INVERSE:
|
||||
return entity_instance.wrap_value(self.wrapped_data.get_inverse(name))
|
||||
else: raise AttributeError("entity instance of type '%s' has no attribute '%s'"%(self.wrapped_data.is_a(), name))
|
||||
@staticmethod
|
||||
def map_value(v):
|
||||
if isinstance(v, entity_instance): return v.wrapped_data
|
||||
elif isinstance(v, (tuple, list)) and len(v):
|
||||
classes = list(map(type, v))
|
||||
if float in classes: return ifcopenshell_wrapper.double_vector(v)
|
||||
elif int in classes: return ifcopenshell_wrapper.int_vector(v)
|
||||
elif str in classes: return ifcopenshell_wrapper.string_vector(v)
|
||||
elif entity_instance in classes: return list(map(lambda e: e.wrapped_data, v))
|
||||
return v
|
||||
def walk(f, g, value):
|
||||
if isinstance(value, (tuple, list)): return tuple(map(functools.partial(entity_instance.walk, f, g), value))
|
||||
elif f(value): return g(value)
|
||||
else: return value
|
||||
@staticmethod
|
||||
def wrap_value(v):
|
||||
wrap = lambda e: entity_instance(e)
|
||||
if isinstance(v, ifcopenshell_wrapper.entity_instance): return wrap(v)
|
||||
elif isinstance(v, (tuple, list)) and len(v):
|
||||
classes = list(map(type, v))
|
||||
if ifcopenshell_wrapper.entity_instance in classes: return list(map(wrap, v))
|
||||
return v
|
||||
is_instance = lambda e: isinstance(e, ifcopenshell_wrapper.entity_instance)
|
||||
return entity_instance.walk(is_instance, wrap, v)
|
||||
@staticmethod
|
||||
def unwrap_value(v):
|
||||
unwrap = lambda e: e.wrapped_data
|
||||
is_instance = lambda e: isinstance(e, entity_instance)
|
||||
return entity_instance.walk(is_instance, unwrap, v)
|
||||
def attribute_type(self, attr):
|
||||
attr_idx = attr if isinstance(attr, int) else self.wrapped_data.get_argument_index(attr)
|
||||
attr_idx = attr if isinstance(attr, numbers.Integral) else self.wrapped_data.get_argument_index(attr)
|
||||
return self.wrapped_data.get_argument_type(attr_idx)
|
||||
def attribute_name(self, attr_idx):
|
||||
return self.wrapped_data.get_argument_name(attr_idx)
|
||||
@@ -75,7 +76,17 @@ class entity_instance(object):
|
||||
def __getitem__(self, key):
|
||||
return entity_instance.wrap_value(self.wrapped_data.get_argument(key))
|
||||
def __setitem__(self, idx, value):
|
||||
self.wrapped_data.set_argument(idx, entity_instance.map_value(value))
|
||||
if value is None:
|
||||
self.wrapped_data.setArgumentAsNull(idx)
|
||||
else:
|
||||
attr_type = self.attribute_type(idx).title().replace(' ', '')
|
||||
attr_type = attr_type.replace('Binary', 'String')
|
||||
attr_type = attr_type.replace('Enumeration', 'String')
|
||||
try:
|
||||
if isinstance(value, unicode): value = value.encode("utf-8")
|
||||
except: pass
|
||||
getattr(self.wrapped_data, "setArgumentAs%s" % attr_type)(idx, entity_instance.unwrap_value(value))
|
||||
return value
|
||||
def __len__(self): return len(self.wrapped_data)
|
||||
def __repr__(self): return repr(self.wrapped_data)
|
||||
def is_a(self, *args): return self.wrapped_data.is_a(*args)
|
||||
@@ -103,10 +114,12 @@ class file(object):
|
||||
if attr[0:6] == 'create': return functools.partial(self.create_entity,attr[6:])
|
||||
else: return getattr(self.wrapped_data, attr)
|
||||
def __getitem__(self, key):
|
||||
if isinstance(key, int):
|
||||
if isinstance(key, numbers.Integral):
|
||||
return entity_instance(self.wrapped_data.by_id(key))
|
||||
elif isinstance(key, str):
|
||||
return entity_instance(self.wrapped_data.by_guid(key))
|
||||
def by_id(self, id): return self[id]
|
||||
def by_guid(self, guid): return self[guid]
|
||||
def add(self, inst):
|
||||
inst.wrapped_data.this.disown()
|
||||
return entity_instance(self.wrapped_data.add(inst.wrapped_data))
|
||||
@@ -131,3 +144,6 @@ def create_entity(type,*args,**kwargs):
|
||||
for idx, arg in attrs: e[idx] = arg
|
||||
return e
|
||||
|
||||
|
||||
version = ifcopenshell_wrapper.version()
|
||||
schema_identifier = ifcopenshell_wrapper.schema_identifier()
|
||||
|
||||
@@ -31,7 +31,7 @@ def has_occ():
|
||||
has_occ = has_occ()
|
||||
wrap_shape_creation = lambda settings, shape: shape
|
||||
if has_occ:
|
||||
import occ_utils as utils
|
||||
from . import occ_utils as utils
|
||||
wrap_shape_creation = lambda settings, shape: utils.create_shape_from_serialization(shape) if getattr(settings, 'use_python_opencascade', False) else shape
|
||||
|
||||
|
||||
@@ -68,13 +68,19 @@ class iterator(_iterator):
|
||||
return wrap_shape_creation(self.settings, _iterator.get(self))
|
||||
|
||||
|
||||
def create_shape(settings, inst):
|
||||
return wrap_shape_creation(settings, ifcopenshell_wrapper.create_shape(settings, inst.wrapped_data))
|
||||
def create_shape(settings, inst, repr=None):
|
||||
return wrap_shape_creation(
|
||||
settings,
|
||||
ifcopenshell_wrapper.create_shape(
|
||||
settings,
|
||||
inst.wrapped_data,
|
||||
repr.wrapped_data if repr is not None else None
|
||||
))
|
||||
|
||||
|
||||
def iterate(settings, filename):
|
||||
it = iterator(settings, filename)
|
||||
if it.findContext():
|
||||
if it.initialize():
|
||||
while True:
|
||||
yield it.get()
|
||||
if not it.next(): break
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 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 #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import random
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -52,8 +71,14 @@ def get_bounding_box_center(bbox):
|
||||
def create_shape_from_serialization(brep_object):
|
||||
brep_data, occ_shape = None, None
|
||||
|
||||
try: brep_data = brep_object.geometry.brep_data
|
||||
except: pass
|
||||
is_product_shape = True
|
||||
try:
|
||||
brep_data = brep_object.geometry.brep_data
|
||||
except:
|
||||
try:
|
||||
brep_data = brep_object.brep_data
|
||||
is_product_shape = False
|
||||
except: pass
|
||||
if not brep_data: return tuple(brep_object, None)
|
||||
|
||||
try:
|
||||
@@ -62,5 +87,8 @@ def create_shape_from_serialization(brep_object):
|
||||
occ_shape = ss.Shape(ss.NbShapes())
|
||||
except: pass
|
||||
|
||||
return tuple(brep_object, occ_shape)
|
||||
if is_product_shape:
|
||||
return tuple(brep_object, occ_shape)
|
||||
else:
|
||||
return occ_shape
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 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 *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef HDF5SETTINGS_H
|
||||
#define HDF5SETTINGS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace IfcParse {
|
||||
|
||||
struct Hdf5Settings {
|
||||
private:
|
||||
bool compress_, fix_cartesian_point_, fix_global_id_, instantiate_select_, instantiate_inverse_;
|
||||
unsigned int chunk_size_;
|
||||
std::vector<std::string> ref_attributes_;
|
||||
|
||||
public:
|
||||
enum Profile {
|
||||
standard,
|
||||
padded,
|
||||
standard_referenced,
|
||||
padded_referenced
|
||||
};
|
||||
|
||||
static Profile ProfileFromString(const std::string& s) {
|
||||
if (s == "standard") return standard;
|
||||
if (s == "padded") return padded;
|
||||
if (s == "referenced") return standard_referenced;
|
||||
if (s == "padded-referenced") return padded_referenced;
|
||||
throw std::runtime_error("Unrecognized profile");
|
||||
}
|
||||
|
||||
private:
|
||||
Profile profile_;
|
||||
|
||||
public:
|
||||
Hdf5Settings()
|
||||
: compress_(false)
|
||||
, fix_cartesian_point_(false)
|
||||
, fix_global_id_(false)
|
||||
, instantiate_select_(false)
|
||||
, instantiate_inverse_(false)
|
||||
, chunk_size_(false)
|
||||
, profile_(standard)
|
||||
{}
|
||||
|
||||
bool compress() const { return compress_; }
|
||||
bool fix_cartesian_point() const { return fix_cartesian_point_; }
|
||||
bool fix_global_id() const { return fix_global_id_; }
|
||||
bool instantiate_select() const { return instantiate_select_; }
|
||||
bool instantiate_inverse() const { return instantiate_inverse_; }
|
||||
|
||||
bool& compress() { return compress_; }
|
||||
bool& fix_cartesian_point() { return fix_cartesian_point_; }
|
||||
bool& fix_global_id() { return fix_global_id_; }
|
||||
bool& instantiate_select() { return instantiate_select_; }
|
||||
bool& instantiate_inverse() { return instantiate_inverse_; }
|
||||
|
||||
unsigned int chunk_size() const { return chunk_size_; }
|
||||
unsigned int& chunk_size() { return chunk_size_; }
|
||||
|
||||
Profile profile() const { return profile_; }
|
||||
Profile& profile() { return profile_; }
|
||||
|
||||
const std::vector<std::string>& ref_attributes() const { return ref_attributes_; }
|
||||
std::vector<std::string>& ref_attributes() { return ref_attributes_; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+540
-525
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,8 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef USE_IFC4
|
||||
|
||||
#ifndef IFC2X3RT_H
|
||||
#define IFC2X3RT_H
|
||||
|
||||
@@ -49,3 +51,4 @@ namespace Type {
|
||||
}}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+7901
-6822
File diff suppressed because one or more lines are too long
+2157
-6449
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
+654
-583
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,8 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifdef USE_IFC4
|
||||
|
||||
#ifndef IFC4RT_H
|
||||
#define IFC4RT_H
|
||||
|
||||
@@ -49,3 +51,4 @@ namespace Type {
|
||||
}}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+9424
-7881
File diff suppressed because one or more lines are too long
+1719
-6526
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -47,6 +47,7 @@
|
||||
#define ENDEXTENDED_0 (1 << 20)
|
||||
#define FOURTH_SOLIDUS (1 << 21)
|
||||
#define IGNORED_DIRECTIVE (1 << 22)
|
||||
#define ENCOUNTERED_HEX (1 << 23)
|
||||
|
||||
// FIXME: These probably need to be less forgiving in terms of wrongly defined sequences
|
||||
#define EXPECTS_ALPHABET(S) (S & FIRST_SOLIDUS)
|
||||
@@ -64,7 +65,7 @@
|
||||
#define IS_VALID_ALPHABET_DEFINITION(C) (C >= 0x40 && C <= 0x4A)
|
||||
#define IS_HEXADECIMAL(C) ((C >= 0x30 && C <= 0x39 ) || (C >= 0x41 && C <= 0x46 ))
|
||||
#define HEX_TO_INT(C) ((C >= 0x30 && C <= 0x39 ) ? C - 0x30 : (C+10) - 0x41)
|
||||
#define CLEAR_HEX(C) (C &= ~(HEX(1)&HEX(2)&HEX(3)&HEX(4)&HEX(5)&HEX(6)&HEX(7)&HEX(8)))
|
||||
#define CLEAR_HEX(C) (C &= ~(HEX(1)|HEX(2)|HEX(3)|HEX(4)|HEX(5)|HEX(6)|HEX(7)|HEX(8)))
|
||||
|
||||
using namespace IfcParse;
|
||||
using namespace IfcWrite;
|
||||
@@ -117,6 +118,7 @@ IfcCharacterDecoder::~IfcCharacterDecoder() {
|
||||
destination = 0;
|
||||
converter = 0;
|
||||
compatibility_converter = 0;
|
||||
ucnv_flushCache();
|
||||
#endif
|
||||
}
|
||||
IfcCharacterDecoder::operator std::string() {
|
||||
@@ -130,12 +132,12 @@ IfcCharacterDecoder::operator std::string() {
|
||||
#ifdef HAVE_ICU
|
||||
unsigned int old_hex = 0; // for compatibility_mode
|
||||
#endif
|
||||
while ( current_char = file->Peek() ) {
|
||||
while ( (current_char = file->Peek()) != 0 ) {
|
||||
if ( EXPECTS_CHARACTER(parse_state) ) {
|
||||
#ifdef HAVE_ICU
|
||||
if ( previous_codepage != codepage ) {
|
||||
if ( converter ) ucnv_close(converter);
|
||||
char encoder[11] = {'i','s','o','-','8','8','5','9','-',codepage + 0x30};
|
||||
char encoder[11] = {'i','s','o','-','8','8','5','9','-', (char)codepage + 0x30};
|
||||
converter = ucnv_open(encoder, &status);
|
||||
}
|
||||
const char characters[2] = { current_char + 0x80 };
|
||||
@@ -155,7 +157,10 @@ IfcCharacterDecoder::operator std::string() {
|
||||
if ( parse_state & ALPHABET_DEFINITION ||
|
||||
parse_state & IGNORED_DIRECTIVE ||
|
||||
parse_state & ENDEXTENDED_0 ) parse_state = hex = hex_count = 0;
|
||||
else if ( parse_state & HEX(3) ) parse_state += THIRD_SOLIDUS;
|
||||
else if ( parse_state & ENCOUNTERED_HEX ) {
|
||||
parse_state += THIRD_SOLIDUS;
|
||||
parse_state -= ENCOUNTERED_HEX;
|
||||
}
|
||||
else parse_state += SECOND_SOLIDUS;
|
||||
} else if ( current_char == 'X' && EXPECTS_ENDEXTENDED_X(parse_state) ) {
|
||||
parse_state += ENDEXTENDED_X;
|
||||
@@ -188,7 +193,7 @@ IfcCharacterDecoder::operator std::string() {
|
||||
if (old_hex == 0) {
|
||||
old_hex = hex;
|
||||
} else {
|
||||
char characters[3] = { old_hex, hex };
|
||||
char characters[3] = { (char)old_hex, (char)hex };
|
||||
const char* char_array = &characters[0];
|
||||
UChar32 ch = ucnv_getNextUChar(compatibility_converter,&char_array,char_array+2,&status);
|
||||
addChar(s,ch);
|
||||
@@ -202,7 +207,10 @@ IfcCharacterDecoder::operator std::string() {
|
||||
}
|
||||
#endif
|
||||
if ( hex_count == 2 ) parse_state = 0;
|
||||
else CLEAR_HEX(parse_state);
|
||||
else {
|
||||
CLEAR_HEX(parse_state);
|
||||
parse_state |= ENCOUNTERED_HEX;
|
||||
}
|
||||
hex = hex_count = 0;
|
||||
}
|
||||
} else if ( parse_state && !(
|
||||
@@ -227,7 +235,7 @@ void IfcCharacterDecoder::dryRun() {
|
||||
unsigned int parse_state = 0;
|
||||
char current_char;
|
||||
unsigned int hex_count = 0;
|
||||
while ( current_char = file->Peek() ) {
|
||||
while ((current_char = file->Peek()) != 0) {
|
||||
if ( EXPECTS_CHARACTER(parse_state) ) {
|
||||
parse_state = 0;
|
||||
} else if ( current_char == '\'' && ! parse_state ) {
|
||||
@@ -238,7 +246,10 @@ void IfcCharacterDecoder::dryRun() {
|
||||
if ( parse_state & ALPHABET_DEFINITION ||
|
||||
parse_state & IGNORED_DIRECTIVE ||
|
||||
parse_state & ENDEXTENDED_0 ) parse_state = hex_count = 0;
|
||||
else if ( parse_state & HEX(3) ) parse_state += THIRD_SOLIDUS;
|
||||
else if ( parse_state & ENCOUNTERED_HEX ) {
|
||||
parse_state += THIRD_SOLIDUS;
|
||||
parse_state -= ENCOUNTERED_HEX;
|
||||
}
|
||||
else parse_state += SECOND_SOLIDUS;
|
||||
} else if ( current_char == 'X' && EXPECTS_ENDEXTENDED_X(parse_state) ) {
|
||||
parse_state += ENDEXTENDED_X;
|
||||
@@ -264,7 +275,10 @@ void IfcCharacterDecoder::dryRun() {
|
||||
(hex_count == 4 && !(parse_state & EXTENDED4)) ||
|
||||
(hex_count == 8) ) {
|
||||
if ( hex_count == 2 ) parse_state = 0;
|
||||
else CLEAR_HEX(parse_state);
|
||||
else {
|
||||
CLEAR_HEX(parse_state);
|
||||
parse_state |= ENCOUNTERED_HEX;
|
||||
}
|
||||
hex_count = 0;
|
||||
}
|
||||
} else if ( parse_state && !(
|
||||
@@ -288,7 +302,7 @@ UErrorCode IfcCharacterDecoder::status = U_ZERO_ERROR;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ICU
|
||||
IfcCharacterDecoder::ConversionMode IfcCharacterDecoder::mode = IfcCharacterDecoder::JSON;
|
||||
IfcCharacterDecoder::ConversionMode IfcCharacterDecoder::mode = IfcCharacterDecoder::UTF8;
|
||||
|
||||
// Many BIM software (eg. Revit, ArchiCAD, ...) has wrong behavior
|
||||
bool IfcCharacterDecoder::compatibility_mode = false;
|
||||
@@ -340,8 +354,8 @@ IfcCharacterEncoder::operator std::string() {
|
||||
oss << "\\X" << num_bytes_str << "\\";
|
||||
}
|
||||
if ( within_spf_range ) {
|
||||
oss.put(ch);
|
||||
if ( ch == '\\' || ch == '\'' ) oss.put(ch);
|
||||
oss.put((char)ch);
|
||||
if ( ch == '\\' || ch == '\'' ) oss.put((char)ch);
|
||||
} else {
|
||||
oss << std::hex << std::setw(num_bytes*2) << std::uppercase << std::setfill('0') << (int) ch;
|
||||
}
|
||||
@@ -352,8 +366,15 @@ IfcCharacterEncoder::operator std::string() {
|
||||
#else
|
||||
for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) {
|
||||
char ch = *i;
|
||||
if ( ch == '\\' || ch == '\'' ) oss.put(ch);
|
||||
oss.put(ch);
|
||||
const bool within_spf_range = ch >= 0x20 && ch <= 0x7e;
|
||||
if (within_spf_range) {
|
||||
if ( ch == '\\' || ch == '\'' ) {
|
||||
oss.put(ch);
|
||||
}
|
||||
oss.put(ch);
|
||||
} else {
|
||||
oss.put('_');
|
||||
}
|
||||
}
|
||||
#endif
|
||||
oss.put('\'');
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../ifcparse/SharedPointer.h"
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
|
||||
@@ -48,7 +49,7 @@ namespace IfcUtil {
|
||||
std::pair<const char*, int> getIndex(const std::string& value) const {
|
||||
std::vector<std::string>::const_iterator it = std::find(values.begin(), values.end(), value);
|
||||
if (it != values.end()) {
|
||||
return std::make_pair(it->c_str(), std::distance(it, values.begin()));
|
||||
return std::make_pair(it->c_str(), (int)std::distance(it, values.begin()));
|
||||
} else {
|
||||
throw IfcParse::IfcException("Invalid enumeration value");
|
||||
}
|
||||
@@ -82,7 +83,7 @@ namespace IfcUtil {
|
||||
}
|
||||
const IfcArgumentDescriptor& get_argument(unsigned i) const {
|
||||
if (i < arguments.size()) return arguments[i];
|
||||
else throw IfcParse::IfcException("Argument out of range");
|
||||
else throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range");
|
||||
}
|
||||
public:
|
||||
IfcEntityDescriptor(IfcSchema::Type::Enum type, IfcEntityDescriptor* parent)
|
||||
@@ -91,7 +92,7 @@ namespace IfcUtil {
|
||||
arguments.push_back(IfcArgumentDescriptor(name, optional, argument_type, data_type));
|
||||
}
|
||||
unsigned getArgumentCount() const {
|
||||
return (parent ? parent->getArgumentCount() : 0) + arguments.size();
|
||||
return (parent ? parent->getArgumentCount() : 0) + (unsigned)arguments.size();
|
||||
}
|
||||
const std::string& getArgumentName(unsigned i) const {
|
||||
const unsigned a = argument_start();
|
||||
|
||||
@@ -26,11 +26,21 @@
|
||||
namespace IfcParse {
|
||||
class IfcException : public std::exception {
|
||||
private:
|
||||
std::string error;
|
||||
std::string message;
|
||||
public:
|
||||
IfcException(std::string e);
|
||||
~IfcException () throw ();
|
||||
const char* what() const throw();
|
||||
IfcException(const std::string& m)
|
||||
: message(m) {}
|
||||
~IfcException () throw () {}
|
||||
const char* what() const throw() {
|
||||
return message.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class IfcAttributeOutOfRangeException : public IfcException {
|
||||
public:
|
||||
IfcAttributeOutOfRangeException(const std::string& e)
|
||||
: IfcException(e) {}
|
||||
~IfcAttributeOutOfRangeException () throw () {}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include "../ifcparse/Hdf5Settings.h"
|
||||
#include "../ifcparse/IfcParse.h"
|
||||
#include "../ifcparse/IfcSpfHeader.h"
|
||||
|
||||
@@ -36,18 +37,18 @@ public:
|
||||
typedef std::map<unsigned int, IfcUtil::IfcBaseClass*> entity_by_id_t;
|
||||
typedef std::map<std::string, IfcSchema::IfcRoot*> entity_by_guid_t;
|
||||
typedef std::map<unsigned int, IfcEntityList::ptr> entities_by_ref_t;
|
||||
typedef std::map<unsigned int, unsigned int> offset_by_id_t;
|
||||
typedef entity_by_id_t::const_iterator const_iterator;
|
||||
private:
|
||||
typedef std::map<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*> entity_entity_map_t;
|
||||
|
||||
const schema_definition* schema_;
|
||||
|
||||
bool _create_latebound_entities;
|
||||
|
||||
entity_by_id_t byid;
|
||||
entities_by_type_t bytype;
|
||||
entities_by_ref_t byref;
|
||||
entity_by_guid_t byguid;
|
||||
offset_by_id_t offsets;
|
||||
|
||||
entity_entity_map_t entity_file_map;
|
||||
|
||||
@@ -126,11 +127,13 @@ public:
|
||||
const IfcSpfHeader& header() const { return _header; }
|
||||
IfcSpfHeader& header() { return _header; }
|
||||
|
||||
std::string createTimestamp() const;
|
||||
|
||||
bool create_latebound_entities() const { return _create_latebound_entities; }
|
||||
|
||||
std::pair<IfcSchema::IfcNamedUnit*, double> getUnit(IfcSchema::IfcUnitEnum::IfcUnitEnum);
|
||||
|
||||
const IfcParse::schema_definition* schema() const { return schema_; }
|
||||
|
||||
void write_hdf5(const std::string&, const IfcParse::Hdf5Settings&);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 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 *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include "../ifcparse/IfcGlobalId.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
|
||||
static const char* chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$";
|
||||
|
||||
// Converts an unsigned integer into a base64 string of length l
|
||||
std::string base64(unsigned v, int l) {
|
||||
std::string r;
|
||||
r.reserve(l);
|
||||
while ( v ) {
|
||||
r.push_back(chars[v%64]);
|
||||
v /= 64;
|
||||
}
|
||||
while ( (int)r.size() != l ) r.push_back('0');
|
||||
std::reverse(r.begin(),r.end());
|
||||
return r;
|
||||
}
|
||||
|
||||
// Converts a base64 string into an unsigned integer
|
||||
unsigned from_base64(const std::string& s) {
|
||||
std::string::size_type zeros = s.find_first_not_of('0');
|
||||
unsigned r = 0;
|
||||
if ( zeros != std::string::npos )
|
||||
for ( std::string::const_iterator i = s.begin()+zeros; i != s.end(); ++ i ) {
|
||||
r *= 64;
|
||||
const char* c = strchr(chars,*i);
|
||||
if ( !c ) throw IfcParse::IfcException("Failed to decode GlobalId");
|
||||
r += (unsigned)(c-chars);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Compresses the UUID byte array into a base64 representation
|
||||
std::string compress(unsigned char* v) {
|
||||
std::string r;
|
||||
r.reserve(22);
|
||||
r += base64(v[0],2);
|
||||
for ( unsigned i = 1; i < 16; i += 3 ) {
|
||||
r += base64((v[i]<<16) + (v[i+1]<<8) + v[i+2],4);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Expands the base64 representation into a UUID byte array
|
||||
void expand(const std::string& s, std::vector<unsigned char>& v) {
|
||||
v.push_back((unsigned char)from_base64(s.substr(0,2)));
|
||||
for( unsigned i = 0; i < 5; ++i ) {
|
||||
unsigned d = from_base64(s.substr(2+4*i,4));
|
||||
for ( unsigned j = 0; j < 3; ++ j ) {
|
||||
v.push_back((d>>(8*(2-j))) % 256);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A random number generator for the UUID
|
||||
static boost::uuids::basic_random_generator<boost::mt19937> gen;
|
||||
|
||||
IfcParse::IfcGlobalId::IfcGlobalId() {
|
||||
uuid_data = gen();
|
||||
std::vector<unsigned char> v(uuid_data.size());
|
||||
std::copy(uuid_data.begin(), uuid_data.end(), v.begin());
|
||||
string_data = compress(&v[0]);
|
||||
#if BOOST_VERSION < 104400
|
||||
formatted_string = boost::lexical_cast<std::string>(uuid_data);
|
||||
#else
|
||||
formatted_string = boost::uuids::to_string(uuid_data);
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::vector<unsigned char> test_vector;
|
||||
expand(string_data, test_vector);
|
||||
boost::uuids::uuid test_uuid;
|
||||
std::copy(test_vector.begin(), test_vector.end(), test_uuid.begin());
|
||||
if (uuid_data != test_uuid) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Internal error generating GlobalId");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
IfcParse::IfcGlobalId::IfcGlobalId(const std::string& s)
|
||||
: string_data(s)
|
||||
{
|
||||
std::vector<unsigned char> v;
|
||||
expand(string_data, v);
|
||||
std::copy(v.begin(), v.end(), uuid_data.begin());
|
||||
#if BOOST_VERSION < 104400
|
||||
formatted_string = boost::lexical_cast<std::string>(uuid_data);
|
||||
#else
|
||||
formatted_string = boost::uuids::to_string(uuid_data);
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
const std::string test_string = compress(&uuid_data.data[0]);
|
||||
if (string_data != test_string) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Internal error generating GlobalId");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
IfcParse::IfcGlobalId::operator const std::string&() const {
|
||||
return string_data;
|
||||
}
|
||||
|
||||
IfcParse::IfcGlobalId::operator const boost::uuids::uuid&() const {
|
||||
return uuid_data;
|
||||
}
|
||||
|
||||
const std::string& IfcParse::IfcGlobalId::formatted() const {
|
||||
return formatted_string;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -17,22 +17,28 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file defines the shared pointer implementation to use, shared pointers *
|
||||
* are used extensively in IfcOpenShell *
|
||||
* *
|
||||
********************************************************************************/
|
||||
#ifndef IFCGLOBALID_H
|
||||
#define IFCGLOBALID_H
|
||||
|
||||
#include <string>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
|
||||
namespace IfcParse {
|
||||
|
||||
/// A helper class for the creation of IFC GlobalIds.
|
||||
class IfcGlobalId {
|
||||
private:
|
||||
std::string string_data, formatted_string;
|
||||
boost::uuids::uuid uuid_data;
|
||||
public:
|
||||
static const unsigned int length = 22;
|
||||
IfcGlobalId();
|
||||
IfcGlobalId(const std::string&);
|
||||
operator const std::string&() const;
|
||||
operator const boost::uuids::uuid&() const;
|
||||
const std::string& formatted() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <tr1/memory>
|
||||
#define SHARED_PTR std::tr1::shared_ptr
|
||||
#else
|
||||
#ifdef _MSC_VER
|
||||
#include <memory>
|
||||
#define SHARED_PTR std::tr1::shared_ptr
|
||||
#else
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#define SHARED_PTR boost::shared_ptr
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,107 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 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 *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Please consider this a placeholder for an actual GlobalId generation *
|
||||
* algorithm. A real implementation could for example be based on Boost::uuid *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
|
||||
#include "../ifcparse/IfcWrite.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
|
||||
static const char* chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$";
|
||||
|
||||
// Converts an unsigned integer into a base64 string of length l
|
||||
std::string base64(unsigned v, int l) {
|
||||
std::string r;
|
||||
r.reserve(l);
|
||||
while ( v ) {
|
||||
r.push_back(chars[v%64]);
|
||||
v /= 64;
|
||||
}
|
||||
while ( r.size() != l ) r.push_back('0');
|
||||
std::reverse(r.begin(),r.end());
|
||||
return r;
|
||||
}
|
||||
|
||||
// Converts a base64 string into an unsigned integer
|
||||
unsigned from_base64(const std::string& s) {
|
||||
std::string::size_type zeros = s.find_first_not_of('0');
|
||||
unsigned r = 0;
|
||||
if ( zeros != std::string::npos )
|
||||
for ( std::string::const_iterator i = s.begin()+zeros; i != s.end(); ++ i ) {
|
||||
r *= 64;
|
||||
const char* c = strchr(chars,*i);
|
||||
if ( !c ) throw IfcParse::IfcException("Failed to decode GlobalId");
|
||||
r += (c-chars);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Compresses the UUID byte array into a base64 representation
|
||||
std::string compress(unsigned char* v) {
|
||||
std::string r;
|
||||
r.reserve(22);
|
||||
r += base64(v[0],2);
|
||||
for ( unsigned i = 1; i < 16; i += 3 ) {
|
||||
r += base64((v[i]<<16) + (v[i+1]<<8) + v[i+2],4);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Expands the base64 representation into a UUID byte array
|
||||
void expand(const std::string& s, std::vector<unsigned char>& v) {
|
||||
v.push_back(from_base64(s.substr(0,2)));
|
||||
for( unsigned i = 0; i < 5; ++i ) {
|
||||
unsigned d = from_base64(s.substr(2+4*i,4));
|
||||
for ( unsigned j = 0; j < 3; ++ j ) {
|
||||
v.push_back((d>>(8*(2-j))) % 256);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A random number generator for the UUID
|
||||
static boost::uuids::basic_random_generator<boost::mt19937> gen;
|
||||
|
||||
IfcWrite::IfcGuidHelper::IfcGuidHelper() {
|
||||
boost::uuids::uuid u = gen();
|
||||
std::vector<unsigned char> v(u.size());
|
||||
std::copy(u.begin(), u.end(), v.begin());
|
||||
data = compress(&v[0]);
|
||||
|
||||
std::vector<unsigned char> v2;
|
||||
expand(data,v2);
|
||||
boost::uuids::uuid u2;
|
||||
std::copy(v2.begin(), v2.end(), u2.begin());
|
||||
}
|
||||
IfcWrite::IfcGuidHelper::operator std::string() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
bool IfcWrite::IfcGuidHelper::seeded = false;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,286 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 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 *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCHDF5FILE_H
|
||||
#define IFCHDF5FILE_H
|
||||
|
||||
#define SORT_ON_NAME
|
||||
|
||||
#include <H5Cpp.h>
|
||||
|
||||
#include "../ifcparse/Hdf5Settings.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
|
||||
namespace IfcParse {
|
||||
|
||||
class abstract_instance_locator {
|
||||
public:
|
||||
typedef std::vector< IfcSchema::Type::Enum >::const_iterator const_iterator;
|
||||
|
||||
virtual const_iterator begin() const = 0;
|
||||
virtual const_iterator end() const = 0;
|
||||
|
||||
virtual const std::vector<IfcUtil::IfcBaseEntity*>& instances(IfcSchema::Type::Enum) = 0;
|
||||
virtual std::pair<int, int> operator()(IfcUtil::IfcBaseClass* v) = 0;
|
||||
virtual void make_reference(IfcUtil::IfcBaseClass*, void*&) = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class vector_vector_iterator {
|
||||
private:
|
||||
const std::vector<std::vector<T> >& container_;
|
||||
const typename std::vector<std::vector<T> >::const_iterator a_;
|
||||
boost::optional<typename std::vector<T>::const_iterator> b_;
|
||||
|
||||
public:
|
||||
vector_vector_iterator(const std::vector<std::vector<T> >& container)
|
||||
: container_(container)
|
||||
, a_(container_.begin())
|
||||
{
|
||||
if (a_ != container_.end()) {
|
||||
b_ = a_->begin();
|
||||
}
|
||||
}
|
||||
|
||||
vector_vector_iterator(const std::vector<std::vector<T> >& container, typename std::vector<std::vector<T> >::const_iterator x)
|
||||
: container_(container)
|
||||
, a_(x)
|
||||
{
|
||||
if (a_ != container_.end()) {
|
||||
b_ = a_->begin();
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const vector_vector_iterator<T>& other) const {
|
||||
if (a_ != container_.end()) {
|
||||
return a_ == other.a_ && b_ == other.b_;
|
||||
} else {
|
||||
return other.a_ == container_.end();
|
||||
}
|
||||
}
|
||||
|
||||
bool operator!=(const vector_vector_iterator<T>& other) const {
|
||||
return !((*this) == other);
|
||||
}
|
||||
|
||||
T& operator*() { return *b_; }
|
||||
const T& operator*() const { return *b_; }
|
||||
T* operator->() { return b_.operator->(); }
|
||||
|
||||
vector_vector_iterator<T>& operator++() {
|
||||
if (!b_) {
|
||||
throw std::runtime_error("");
|
||||
}
|
||||
++(*b_);
|
||||
if ((*b_) == a_->end()) {
|
||||
do {
|
||||
++a_;
|
||||
} while (a_ != container_.end() && a_->size() == 0);
|
||||
if (a_ != container_.end()) {
|
||||
b_ = a_->begin();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class instance_categorizer {
|
||||
private:
|
||||
std::vector< IfcSchema::Type::Enum > dataset_names_;
|
||||
std::vector< std::vector<IfcUtil::IfcBaseEntity*> > instances_;
|
||||
std::vector<IfcUtil::IfcBaseEntity*> empty_;
|
||||
|
||||
public:
|
||||
|
||||
typedef vector_vector_iterator<IfcUtil::IfcBaseEntity*> const_iterator;
|
||||
|
||||
template <typename ForwardIt>
|
||||
instance_categorizer(ForwardIt begin, ForwardIt end) {
|
||||
std::set<IfcSchema::Type::Enum> dataset_names_set;
|
||||
std::map<IfcSchema::Type::Enum, std::vector<IfcUtil::IfcBaseEntity*> > instances_map;
|
||||
|
||||
std::for_each(begin, end, [&dataset_names_set, &instances_map](IfcUtil::IfcBaseClass* inst) {
|
||||
if (inst->declaration().as_entity()) {
|
||||
dataset_names_set.insert(inst->declaration().type());
|
||||
instances_map[inst->declaration().type()].push_back((IfcUtil::IfcBaseEntity*) inst);
|
||||
}
|
||||
});
|
||||
|
||||
dataset_names_.assign(dataset_names_set.begin(), dataset_names_set.end());
|
||||
for (IfcSchema::Type::Enum ty : dataset_names_) {
|
||||
auto&& insts = instances_map[ty];
|
||||
std::sort(insts.begin(), insts.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
|
||||
return i1->data().id() < i2->data().id();
|
||||
});
|
||||
instances_.emplace_back(insts);
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<IfcUtil::IfcBaseEntity*>& instances(IfcSchema::Type::Enum t) {
|
||||
auto it = std::lower_bound(dataset_names_.begin(), dataset_names_.end(), t);
|
||||
if (it == dataset_names_.end() || (*it) != t) return empty_;
|
||||
return instances_[std::distance(dataset_names_.begin(), it)];
|
||||
}
|
||||
|
||||
const std::vector<IfcSchema::Type::Enum>& dataset_names() const { return dataset_names_; };
|
||||
|
||||
const_iterator begin() const { return const_iterator(instances_); }
|
||||
const_iterator end() const { return const_iterator(instances_, instances_.end()); }
|
||||
};
|
||||
|
||||
class instance_enumerator {
|
||||
private:
|
||||
const IfcSpfHeader* header_;
|
||||
instance_categorizer* categories_;
|
||||
public:
|
||||
typedef instance_categorizer::const_iterator const_iterator;
|
||||
|
||||
instance_enumerator()
|
||||
: header_(nullptr)
|
||||
, categories_(nullptr)
|
||||
{}
|
||||
|
||||
explicit instance_enumerator(IfcFile* file)
|
||||
: header_(&file->header())
|
||||
{
|
||||
std::vector<IfcUtil::IfcBaseClass*> temp;
|
||||
std::transform(file->begin(), file->end(), std::back_inserter(temp), [](auto& pair) {
|
||||
return pair.second;
|
||||
});
|
||||
categories_ = new instance_categorizer(temp.begin(), temp.end());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
instance_enumerator(IfcSpfHeader* header, T begin, T end)
|
||||
: header_(header)
|
||||
, categories_(new instance_categorizer(begin, end))
|
||||
{}
|
||||
|
||||
const IfcSpfHeader& header() const {
|
||||
return *header_;
|
||||
}
|
||||
|
||||
const std::vector<IfcUtil::IfcBaseEntity*>& by_type(IfcSchema::Type::Enum t) {
|
||||
return categories_->instances(t);
|
||||
}
|
||||
|
||||
const_iterator begin() const { return categories_->begin(); }
|
||||
const_iterator end() const { return categories_->end(); }
|
||||
|
||||
const std::vector<IfcSchema::Type::Enum>& dataset_names() const { return categories_->dataset_names(); }
|
||||
instance_categorizer* categorizer() const { return categories_; }
|
||||
};
|
||||
|
||||
class IfcHdf5File {
|
||||
private:
|
||||
class allocator_t {
|
||||
private:
|
||||
// TODO: Change this?
|
||||
mutable std::vector<uint8_t*> buffers;
|
||||
public:
|
||||
void* allocate(size_t n) const {
|
||||
return new uint8_t[n];
|
||||
}
|
||||
void free() {
|
||||
std::vector<uint8_t*>::const_iterator it;
|
||||
for (it = buffers.begin(); it != buffers.end(); ++it) {
|
||||
delete[] *it;
|
||||
}
|
||||
buffers.clear();
|
||||
}
|
||||
~allocator_t() {
|
||||
free();
|
||||
}
|
||||
};
|
||||
|
||||
allocator_t allocator;
|
||||
Hdf5Settings settings_;
|
||||
|
||||
boost::optional<std::string> name_;
|
||||
const schema_definition* schema_;
|
||||
instance_enumerator ifcfile_;
|
||||
|
||||
H5::H5File* file_;
|
||||
H5::Group schema_group;
|
||||
// H5::Group population_group;
|
||||
|
||||
// TODO: const
|
||||
H5::CompType* instance_reference;
|
||||
const H5::DataType* object_reference_type;
|
||||
|
||||
std::map<IfcSchema::Type::Enum, H5::DataType*> declared_types;
|
||||
|
||||
#ifdef SORT_ON_NAME
|
||||
std::map<IfcSchema::Type::Enum, std::vector<uint32_t> > sorted_entities;
|
||||
#else
|
||||
std::map<IfcSchema::Type::Enum, std::vector<IfcUtil::IfcBaseClass*> > sorted_entities;
|
||||
#endif
|
||||
std::vector<IfcSchema::Type::Enum> dataset_names;
|
||||
|
||||
H5::DataType* map_type(const IfcParse::parameter_type* pt);
|
||||
H5::CompType* map_entity(const IfcParse::entity* e);
|
||||
H5::DataType* map_select(const IfcParse::select_type* pt);
|
||||
H5::DataType* commit(H5::DataType* dt, const std::string& name);
|
||||
|
||||
void init_default_types();
|
||||
void visit_select(const IfcParse::select_type* pt, std::set<const IfcParse::declaration*>& leafs);
|
||||
std::string flatten_aggregate_name(const IfcParse::parameter_type* at) const;
|
||||
std::pair<size_t, size_t> make_instance_reference(const IfcUtil::IfcBaseClass* instance) const;
|
||||
// void write_select(void*& ptr, IfcUtil::IfcBaseClass* instance, const H5::CompType* datatype) const;
|
||||
|
||||
H5::DataSet create_dataset(H5::Group* population_group, const std::string& path, H5::DataType datatype, int rank, hsize_t* dimensions);
|
||||
|
||||
void write_header(H5::Group& group, const IfcSpfHeader& header);
|
||||
|
||||
template <typename T>
|
||||
void write_instance(void*& ptr, T& visitor, H5::DataType& datatype, IfcUtil::IfcBaseEntity* v);
|
||||
|
||||
// TODO: Obviously change this;
|
||||
void* mapper_;
|
||||
public:
|
||||
typedef std::pair<std::string, const H5::DataType*> compound_member;
|
||||
|
||||
void write_schema(IfcParse::instance_categorizer* ifc_file = nullptr);
|
||||
void write_population(H5::Group&, instance_enumerator&, IfcParse::abstract_instance_locator* locator = nullptr);
|
||||
|
||||
IfcHdf5File(IfcFile* f, const std::string& name, const Hdf5Settings& settings)
|
||||
: name_(name)
|
||||
, file_(nullptr)
|
||||
, schema_(f->schema())
|
||||
, ifcfile_(f)
|
||||
, settings_(settings)
|
||||
{
|
||||
write_schema(ifcfile_.categorizer());
|
||||
H5::Group population_group = file_->createGroup("population");
|
||||
write_population(population_group, ifcfile_);
|
||||
};
|
||||
|
||||
IfcHdf5File(H5::H5File& file, const IfcParse::schema_definition& schema, const Hdf5Settings& settings)
|
||||
: file_(&file)
|
||||
, schema_(&schema)
|
||||
, settings_(settings)
|
||||
{
|
||||
};
|
||||
|
||||
static void convert_to_spf(const std::string& name, std::ostream& output, const boost::optional< std::vector<std::string> >& mount_points = boost::none);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user