mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-08 00:41:36 +00:00
Compare commits
76 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ba00526e1b | |||
| e744ba404e | |||
| eb39eeb30b | |||
| 286e9d183a | |||
| d4e4ca3a2a | |||
| f7adeb9cc1 | |||
| 607f7bd015 | |||
| bd00d3287e | |||
| f674493843 | |||
| dbc60bedd6 | |||
| f7f949b37b | |||
| 31ca1ac1b5 | |||
| 99d83fce42 | |||
| 4158424c25 | |||
| 1d8616883c | |||
| 8851641d94 | |||
| 0a7b1dd7f4 | |||
| bb2a983a00 | |||
| 604358b48e | |||
| 68e60f0586 | |||
| e4f141b107 | |||
| fe172672e9 | |||
| 69a27e3591 | |||
| d91e5d31f6 | |||
| a4c3fdfd18 | |||
| b235320d8c | |||
| e9a3464c26 | |||
| e08db74706 | |||
| 3a971d63f8 | |||
| 9a75a1f12d | |||
| 64f88cbf25 | |||
| ca66aac1c1 | |||
| 9262ea1890 | |||
| 81537bee95 | |||
| f9e94f5e01 | |||
| 691e5766c4 | |||
| 0770d91a3c | |||
| f3531276c8 | |||
| ffe1eddb00 | |||
| ba0ba1973a | |||
| b4e1b15da5 | |||
| a2b2add58f | |||
| c70517f3ba | |||
| d79e28157f | |||
| 4a36816f8f | |||
| 83ac741b59 | |||
| 2fb4be2edc | |||
| 868bd6efc8 | |||
| 27e18386d2 | |||
| 562210b862 | |||
| 39b3e03fc5 | |||
| ba7eec2c0b | |||
| 357357ad78 | |||
| b3bf86e697 | |||
| 6b65402611 | |||
| c7355f03e7 | |||
| 5274d73fd0 | |||
| 88f6242804 | |||
| e936ba8391 | |||
| 9136b83223 | |||
| 4987753a47 | |||
| 871ee13e05 | |||
| 9c4040345a | |||
| aa4f6c0a7b | |||
| 5471f345d8 | |||
| 9679d450fc | |||
| d8d221dce3 | |||
| ed5f879b9f | |||
| 3bc3331983 | |||
| 10657416ea | |||
| e5abdb7de8 | |||
| 7b57c8b5b3 | |||
| 22563f7283 | |||
| d35e775407 | |||
| a5684f0996 | |||
| 509c34d66a |
-11
@@ -1,11 +0,0 @@
|
||||
# Dependency and build folders created by the build scripts
|
||||
/deps*/
|
||||
/build*/
|
||||
/install*/
|
||||
/win/BuildDepsCache*.txt
|
||||
# IfcExpressParser residue
|
||||
/src/ifcexpressparser/express_parser.py
|
||||
# General Python residue
|
||||
__pycache__
|
||||
# Visual Studio Code files
|
||||
.vscode
|
||||
-58
@@ -1,58 +0,0 @@
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
|
||||
|
||||
install:
|
||||
- sudo apt-get install -qq gcc-4.8 g++-4.8
|
||||
|
||||
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 90
|
||||
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 90
|
||||
|
||||
- sudo apt-get install -y libboost1.55-dev
|
||||
- sudo apt-get install -y libboost-regex1.55-dev
|
||||
- sudo apt-get install -y libboost-system1.55-dev
|
||||
- sudo apt-get install -y libboost-thread1.55-dev
|
||||
- sudo apt-get install -y libboost-program-options1.55-dev
|
||||
- sudo apt-get install -y cmake
|
||||
- sudo apt-get install -y libicu-dev
|
||||
- sudo apt-get install -y python-all-dev
|
||||
- sudo apt-get install -y swig
|
||||
- sudo apt-get install -y liboce-foundation-dev
|
||||
- sudo apt-get install -y liboce-modeling-dev
|
||||
- sudo apt-get install -y liboce-ocaf-dev
|
||||
- sudo apt-get install -y liboce-visualization-dev
|
||||
- sudo apt-get install -y liboce-ocaf-lite-dev
|
||||
|
||||
- sudo apt-get install -y libpcre3-dev
|
||||
|
||||
script:
|
||||
- pwd
|
||||
- cd ..
|
||||
- git clone https://github.com/KhronosGroup/OpenCOLLADA.git
|
||||
- cd OpenCOLLADA
|
||||
- git checkout 064a60b65c2c31b94f013820856bc84fb1937cc6
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake ..
|
||||
- make
|
||||
- sudo make install
|
||||
- cd ..
|
||||
- cd ..
|
||||
- pwd
|
||||
- cd IfcOpenShell
|
||||
- pwd
|
||||
- cd cmake
|
||||
- mkdir build-ifc2x3 build-ifc4
|
||||
- cd build-ifc2x3
|
||||
- cmake -DCOLLADA_SUPPORT=True -DOPENCOLLADA_INCLUDE_DIR=/usr/local/include/opencollada -DOPENCOLLADA_LIBRARY_DIR=/usr/local/lib/opencollada -DPCRE_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu -DUSE_IFC4=False -DBUILD_IFCPYTHON=True -DUNICODE_SUPPORT=True -DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu ..
|
||||
- make -j
|
||||
- cd ../build-ifc4
|
||||
- cmake -DCOLLADA_SUPPORT=True -DOPENCOLLADA_INCLUDE_DIR=/usr/local/include/opencollada -DOPENCOLLADA_LIBRARY_DIR=/usr/local/lib/opencollada -DPCRE_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu -DUSE_IFC4=True -DBUILD_IFCPYTHON=True -DUNICODE_SUPPORT=True -DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu ..
|
||||
- make -j
|
||||
-165
@@ -1,165 +0,0 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
@@ -1,167 +1,26 @@
|
||||
IfcOpenShell
|
||||
============
|
||||
IfcOpenShell is an open source ([LGPL]) software library for working with the Industry Foundation Classes ([IFC])
|
||||
file format. Currently supported IFC releases are [IFC2x3 TC1] and [IFC4 Add1].
|
||||
open source (LGPL) software library for working with the IFC file format
|
||||
|
||||
For more information, see
|
||||
* [http://ifcopenshell.org](http://ifcopenshell.org)
|
||||
* [http://academy.ifcopenshell.org](http://academy.ifcopenshell.org)
|
||||
|
||||
[](https://api.travis-ci.org/IfcOpenShell/IfcOpenShell)
|
||||
http://IfcOpenShell.org
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
* Git
|
||||
* CMake (2.6 or newer)
|
||||
* Windows: [Visual Studio] 2008 or newer (2017 not yet officially supported) with C++ toolset (or [Visual C++ Build Tools]) or [MSYS2] + MinGW
|
||||
* *nix: GCC 4.7 or newer, or Clang (any version)
|
||||
About this repository
|
||||
=====================
|
||||
|
||||
Dependencies
|
||||
-------------
|
||||
* [Boost](http://www.boost.org/)
|
||||
* [Open Cascade](http://opencascade.org) - *optional*, but required for building IfcGeom
|
||||
([official](http://www.opencascade.org/getocc/download/loadocc/), "OCCT", or [community edition](https://github.com/tpaviot/oce), "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/) and [Python](https://www.python.org/) - *optional*
|
||||
For building the IfcOpenShell Python interface and the Blender add-on
|
||||
* [3ds Max SDK](http://www.autodesk.com/products/3ds-max/free-trial) - *optional*
|
||||
For building the 3ds Max plug-in.
|
||||
All recent versions of 3ds Max (2014 and newer) are 64-bit only, so a 64-bit installation is assumed.
|
||||
This is an initiative to expose the functionality of IfcOpenShell for parsing and writing IFC files to a Python interface. The creation of a topological representation for building elements using Open Cascade is also wrapped by returning a string serialization of the Open Cascade TopoDS_Shape. Using SWIG, a wrapper is obtained for a C++ Class which evaluates its Express attribute names at runtime. The functions created by the SWIG wrapper closely resemble the C++ structure. An additional Python wrapper around these functions is created that is more idiomatic to Python.
|
||||
|
||||
Building IfcOpenShell
|
||||
---------------------
|
||||
The following interactive session illustrates its use:
|
||||
|
||||
**Note:** The path where the source code is cloned to can contain spaces but non-ASCII characters are very likely to cause problems with the build.
|
||||
|
||||
### Compiling on Windows
|
||||
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**.
|
||||
|
||||
#### Using Visual Studio
|
||||
Instructions in a nutshell (**assuming Visual Studio 2015 x64 environment variables set**):
|
||||
|
||||
> 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 file(s) to build and install the project easily from the command-line
|
||||
(installing a project will build it also, if required):
|
||||
|
||||
> install-ifcopenshell.bat
|
||||
|
||||
#### Using MSYS2 + MinGW
|
||||
|
||||
Start the MSYS2 Shell and then:
|
||||
|
||||
$ cd IfcOpenShell/win
|
||||
$ ./build-deps.sh
|
||||
$ ./run-cmake.sh
|
||||
$ ./install-ifcopenshell.sh
|
||||
|
||||
#### Using Bash on Ubuntu on Windows
|
||||
|
||||
Start Bash on Ubuntu on Windows and follow the instructions below. Compiling on Ubuntu 14.04.4 LTS using GCC 4.8.4
|
||||
or Clang 3.5 has been confirmed to work.
|
||||
|
||||
### Compiling on *nix
|
||||
|
||||
The following instructions are for Ubuntu, modify as required for other operating systems. [nix/build-all.sh] script
|
||||
can be experimented with and studied for pointers for other operating systems, but note that this script is not currently
|
||||
meant to be used for a typical IfcOpenShell workspace setup.
|
||||
|
||||
**1)** Install most of the prerequisites and dependencies:
|
||||
|
||||
$ sudo apt-get install git cmake gcc g++ libboost-all-dev libicu-dev
|
||||
|
||||
**2a)** Either use an OCE package from your operating system's software repository
|
||||
|
||||
$ sudo apt-get install liboce-foundation-dev liboce-modeling-dev liboce-ocaf-dev liboce-visualization-dev liboce-ocaf-lite-dev
|
||||
|
||||
**2b)** or (if not available, or the latest code is wanted) compile OCE yourself (note that the build takes a long time):
|
||||
|
||||
$ sudo apt-get install libftgl-dev libtbb2 libtbb-dev libgl1-mesa-dev libfreetype6-dev
|
||||
$ git clone https://github.com/tpaviot/oce.git
|
||||
$ cd oce
|
||||
$ mkdir build && cd build
|
||||
$ cmake ..
|
||||
$ make -j
|
||||
$ sudo make install
|
||||
|
||||
**2c)** or obtain and compile OCCT from http://www.opencascade.org/getocc/download/loadocc/
|
||||
|
||||
**3)** For building IfcConvert with COLLADA (.dae) support (on by default), OpenCOLLADA is needed:
|
||||
|
||||
$ sudo apt-get install libpcre3-dev
|
||||
$ git clone https://github.com/KhronosGroup/OpenCOLLADA.git
|
||||
$ cd OpenCOLLADA
|
||||
Using a known good revision, but HEAD should work too:
|
||||
$ git checkout 064a60b65c2c31b94f013820856bc84fb1937cc6
|
||||
$ mkdir build && cd build
|
||||
$ cmake ..
|
||||
$ make -j
|
||||
$ sudo make install
|
||||
|
||||
**4)** For building the IfcPython wrapper (on by default), SWIG and Python development are needed, if not already available:
|
||||
|
||||
$ sudo apt-get install python-all-dev swig
|
||||
|
||||
**5)** To build IfcOpenShell please take the following steps. Alternatively use environment variables for setting the
|
||||
dependencies' paths. `OCC_INCLUDE_DIR` might be needed to set also. `OPENCOLLADA_INCLUDE_DIR` and `OPENCOLLADA_LIBRARY_DIR`
|
||||
(and potentially `PCRE_LIBRARY_DIR`) are needed if building with COLLADA support. (`-DCOLLADA_SUPPORT=0` disables it).
|
||||
|
||||
$ cd /path/to/IfcOpenShell
|
||||
$ mkdir build && cd build
|
||||
$ cmake ../cmake -DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu/ \
|
||||
-DOPENCOLLADA_INCLUDE_DIR="/usr/local/include/opencollada" \
|
||||
-DOPENCOLLADA_LIBRARY_DIR="/usr/local/lib/opencollada" \
|
||||
-DPCRE_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu/
|
||||
$ make -j
|
||||
|
||||
If all worked out correctly you can now use IfcOpenShell. See the examples below.
|
||||
|
||||
**6)** Install the project if wanted:
|
||||
|
||||
$ sudo make install
|
||||
|
||||
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]
|
||||
>>> brep_data = ifcopenshell.create_shape(wall, ifcopenshell.SEW_SHELLS)
|
||||
>>> len(wall) # number of EXPRESS attributes
|
||||
8
|
||||
>>>
|
||||
>>> # Accessing EXPRESS attributes by name:
|
||||
>>> wall.GlobalId
|
||||
>>> wall.GlobalId
|
||||
'2O2Fr$t4X7Zf8NOew3FL9r'
|
||||
>>> wall.Name = "My wall"
|
||||
>>> wall.NonExistingAttr
|
||||
@@ -183,11 +42,8 @@ Usage examples
|
||||
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'
|
||||
@@ -196,22 +52,81 @@ Usage examples
|
||||
>>> 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")
|
||||
|
||||
[LGPL]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/COPYING "LGPL"
|
||||
[IFC]: http://www.buildingsmart-tech.org/specifications/ifc-overview "IFC"
|
||||
[IFC2x3 TC1]: http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc2x3-tc1-release "IFC2x3 TC1"
|
||||
[IFC4 Add1]: http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc4-add1-release "IFC4 Add1"
|
||||
[Visual Studio]: https://www.visualstudio.com/ "Visual Studio"
|
||||
[Visual C++ Build Tools]: http://landinghub.visualstudio.com/visual-cpp-build-tools "Visual C++ Build Tools"
|
||||
[MSYS2]: https://msys2.github.io/ "MSYS2"
|
||||
[win/readme.md]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/win/readme.md "win/readme.md"
|
||||
[nix/build-all.sh]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/nix/build-all.sh "nix/build-all.sh"
|
||||
|
||||
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
|
||||
|
||||
|
||||
Ubuntu Notes
|
||||
============
|
||||
|
||||
The following sequence of commands has been tested successfully on Ubuntu 14.04.
|
||||
|
||||
OCE installation. This step worked OK with cmake 2.8.12.2, gcc 4.8.2, g++ 4.8.2. Also, it might take up to an hour to complete.
|
||||
|
||||
apt-get install git cmake gcc g++ libftgl-dev libtbb2 libtbb-dev libboost-all-dev
|
||||
cd /
|
||||
mkdir git && cd git
|
||||
git clone https://github.com/tpaviot/oce.git
|
||||
mkdir oceBuild && cd oceBuild
|
||||
cmake ../oce
|
||||
make -j4
|
||||
sudo make install
|
||||
|
||||
IfcOpenShell installation. This step worked OK with cmake 2.8.12.2, gcc 4.8.2, g++ 4.8.2.
|
||||
|
||||
apt-get install swig
|
||||
cd /git/
|
||||
git clone https://github.com/aothms/IfcOpenShell.git
|
||||
cd IfcOpenShell/cmake
|
||||
mkdir build && cd build
|
||||
cmake ../
|
||||
make -j4
|
||||
|
||||
Once done, IfcConvert is to be found in the build folder.
|
||||
|
||||
|
||||
+176
-551
@@ -1,605 +1,230 @@
|
||||
################################################################################
|
||||
# #
|
||||
# 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)
|
||||
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
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(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF)
|
||||
OPTION(IFCCONVERT_DOUBLE_PRECISION "IfcConvert: Use double precision floating-point numbers." ON)
|
||||
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)
|
||||
OPTION(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." OFF)
|
||||
OPTION(BUILD_SHARED_LIBS "Build IfcParse and IfcGeom as shared libs (SO/DLL)." 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)
|
||||
|
||||
|
||||
# Specify where to install files
|
||||
IF(NOT BINDIR)
|
||||
set(BINDIR bin)
|
||||
ENDIF()
|
||||
IF(NOT IS_ABSOLUTE ${BINDIR})
|
||||
set(BINDIR ${CMAKE_INSTALL_PREFIX}/${BINDIR})
|
||||
ENDIF()
|
||||
MESSAGE(STATUS "BINDIR: ${BINDIR}")
|
||||
|
||||
IF(NOT INCLUDEDIR)
|
||||
set(INCLUDEDIR include)
|
||||
ENDIF()
|
||||
IF(NOT IS_ABSOLUTE ${INCLUDEDIR})
|
||||
set(INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/${INCLUDEDIR})
|
||||
ENDIF()
|
||||
MESSAGE(STATUS "INCLUDEDIR: ${INCLUDEDIR}")
|
||||
|
||||
IF(NOT LIBDIR)
|
||||
set(LIBDIR lib)
|
||||
ENDIF()
|
||||
IF(NOT IS_ABSOLUTE ${LIBDIR})
|
||||
set(LIBDIR ${CMAKE_INSTALL_PREFIX}/${LIBDIR})
|
||||
ENDIF()
|
||||
MESSAGE(STATUS "LIBDIR: ${LIBDIR}")
|
||||
|
||||
set(IFCOPENSHELL_LIBARY_DIR "") # for *nix rpaths
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
add_definitions(-DIFC_SHARED_BUILD)
|
||||
if (MSVC)
|
||||
message(WARNING "Building DLLs against the static VC run-time. This is not recommended if the DLLs are to be redistributed.")
|
||||
# C4521: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
|
||||
# There will be couple hundreds of these so suppress them away, https://msdn.microsoft.com/en-us/library/esew7y1w.aspx
|
||||
add_definitions(-wd4251)
|
||||
endif()
|
||||
set(IFCOPENSHELL_LIBARY_DIR "${LIBDIR}")
|
||||
endif()
|
||||
|
||||
# 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(PCRE_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE)
|
||||
IF(WIN32)
|
||||
UNIFY_ENVVARS_AND_CACHE(THREEDS_MAX_SDK_HOME)
|
||||
ENDIF()
|
||||
|
||||
|
||||
# Set INSTALL_RPATH for target
|
||||
MACRO(SET_INSTALL_RPATHS _target _paths)
|
||||
SET(${_target}_rpaths "")
|
||||
FOREACH(_path ${_paths})
|
||||
LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${_path}" isSystemDir)
|
||||
IF("${isSystemDir}" STREQUAL "-1")
|
||||
LIST(APPEND ${_target}_rpaths ${_path})
|
||||
ENDIF()
|
||||
ENDFOREACH()
|
||||
MESSAGE(STATUS "Set INSTALL_RPATH for ${_target}: ${${_target}_rpaths}")
|
||||
SET_TARGET_PROPERTIES(${_target} PROPERTIES INSTALL_RPATH "${${_target}_rpaths}")
|
||||
ENDMACRO()
|
||||
|
||||
# Find Boost
|
||||
IF(WIN32)
|
||||
SET(Boost_USE_STATIC_LIBS ON)
|
||||
SET(Boost_USE_STATIC_RUNTIME ON)
|
||||
SET(Boost_USE_MULTITHREADED ON)
|
||||
ENDIF()
|
||||
FIND_PACKAGE(Boost REQUIRED COMPONENTS system program_options regex thread date_time)
|
||||
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}")
|
||||
|
||||
# Usage:
|
||||
# set(SOME_LIRARIES foo bar)
|
||||
# add_debug_variants(SOME_LIRARIES "${SOME_LIRARIES}" d)
|
||||
# "foo bar" -> "optimized foo debug food optimized bar debug bard"
|
||||
# or
|
||||
# set(SOME_LIRARIES path/foo.lib)
|
||||
# add_debug_variants(SOME_LIRARIES "${SOME_LIRARIES}" "d")
|
||||
# "path/foo.lib" -> "optimized path/foo.lib debug path/food.lib"
|
||||
# TODO Could be refined: take the library file extension as a parameter and
|
||||
# make sure the lib variable ends with not just contains it.
|
||||
function(add_debug_variants NAME LIBRARIES POSTFIX)
|
||||
set(LIBRARIES_STR "${LIBRARIES}")
|
||||
# the result, "optimized <lib> debug <lib>", needs to be a list instead of a string
|
||||
foreach(lib ${LIBRARIES_STR})
|
||||
list(APPEND LIBRARIES optimized)
|
||||
if ("${lib}" MATCHES ".lib")
|
||||
string(REPLACE ".lib" "" lib ${lib})
|
||||
list(APPEND LIBRARIES ${lib}.lib)
|
||||
else()
|
||||
list(APPEND LIBRARIES ${lib})
|
||||
endif()
|
||||
|
||||
list(APPEND LIBRARIES debug)
|
||||
if ("${lib}" MATCHES ".lib")
|
||||
string(REPLACE ".lib" "" lib ${lib})
|
||||
list(APPEND LIBRARIES ${lib}${POSTFIX}.lib)
|
||||
else()
|
||||
list(APPEND LIBRARIES ${lib}${POSTFIX})
|
||||
endif()
|
||||
endforeach()
|
||||
set(${NAME} ${LIBRARIES} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Find Open CASCADE
|
||||
IF("${OCC_INCLUDE_DIR}" STREQUAL "")
|
||||
SET(OCC_INCLUDE_DIR "/usr/include/oce/" CACHE FILEPATH "Open CASCADE header files")
|
||||
MESSAGE(STATUS "Looking for Open CASCADE include files in: ${OCC_INCLUDE_DIR}")
|
||||
# Find Open CASCADE header files
|
||||
IF("$ENV{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 ${OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files")
|
||||
MESSAGE(STATUS "Looking for Open CASCADE include files in: ${OCC_INCLUDE_DIR}")
|
||||
SET(OCC_INCLUDE_DIR $ENV{OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files")
|
||||
MESSAGE(STATUS "Looking for opencascade include files in: ${OCC_INCLUDE_DIR}")
|
||||
ENDIF()
|
||||
|
||||
FIND_FILE(gp_Pnt_hxx "gp_Pnt.hxx" ${OCC_INCLUDE_DIR})
|
||||
FIND_FILE(gp_Pnt_hxx "gp_Pnt.hxx" ${OCC_INCLUDE_DIR} /usr/inc /usr/local/inc /usr/local/include/oce)
|
||||
IF(gp_Pnt_hxx)
|
||||
MESSAGE(STATUS "Header files found")
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "Unable to find header files, aborting")
|
||||
ENDIF()
|
||||
|
||||
SET(OPENCASCADE_LIBRARY_NAMES
|
||||
TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO
|
||||
TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset
|
||||
)
|
||||
|
||||
IF("${OCC_LIBRARY_DIR}" STREQUAL "")
|
||||
# Find Open CASCADE library files
|
||||
IF("$ENV{OCC_LIBRARY_DIR}" STREQUAL "")
|
||||
SET(OCC_LIBRARY_DIR "/usr/lib/" CACHE FILEPATH "Open CASCADE library files")
|
||||
MESSAGE(STATUS "Looking for Open CASCADE library files in: ${OCC_LIBRARY_DIR}")
|
||||
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 ${OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files")
|
||||
MESSAGE(STATUS "Looking for Open CASCADE library files in: ${OCC_LIBRARY_DIR}")
|
||||
SET(OCC_LIBRARY_DIR $ENV{OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files")
|
||||
MESSAGE(STATUS "Looking for opencascade library files in: ${OCC_LIBRARY_DIR}")
|
||||
ENDIF()
|
||||
|
||||
FIND_LIBRARY(libTKernel NAMES TKernel TKerneld PATHS ${OCC_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
FIND_LIBRARY(libTKernel "TKernel" ${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()
|
||||
|
||||
# Use the found libTKernel as a template for all other OCC libraries
|
||||
foreach(lib ${OPENCASCADE_LIBRARY_NAMES})
|
||||
string(REPLACE TKernel "${lib}" lib_path "${libTKernel}")
|
||||
list(APPEND OPENCASCADE_LIBRARIES "${lib_path}")
|
||||
endforeach()
|
||||
|
||||
if(MSVC)
|
||||
add_definitions(-DHAVE_NO_DLL)
|
||||
add_debug_variants(OPENCASCADE_LIBRARIES "${OPENCASCADE_LIBRARIES}" d)
|
||||
endif()
|
||||
|
||||
IF(UNICODE_SUPPORT)
|
||||
# Find ICU
|
||||
IF("${ICU_INCLUDE_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No ICU include directory specified")
|
||||
ENDIF()
|
||||
|
||||
IF("${ICU_LIBRARY_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No ICU library directory specified")
|
||||
FIND_LIBRARY(icu NAMES icuuc icuucd PATHS ${ICU_LIBRARY_DIR})
|
||||
ELSE()
|
||||
FIND_LIBRARY(icu NAMES icuuc icuucd PATHS ${ICU_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
ENDIF()
|
||||
|
||||
IF(icu)
|
||||
GET_FILENAME_COMPONENT(ICU_LIBRARY_DIR ${icu} PATH)
|
||||
|
||||
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(WIN32)
|
||||
FIND_LIBRARY(icudt NAMES icudt PATHS ${ICU_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
SET(ICU_LIBRARIES ${icu} ${icudt})
|
||||
add_debug_variants(ICU_LIBRARIES "${ICU_LIBRARIES}" d)
|
||||
# TODO MinGW build would appear to be using dynamic ICU regardless of this definition.
|
||||
ADD_DEFINITIONS(-DU_STATIC_IMPLEMENTATION) # required for static ICU
|
||||
ELSE()
|
||||
FIND_LIBRARY(icudt NAMES icudata PATHS ${ICU_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
FIND_LIBRARY(dl NAMES dl)
|
||||
SET(ICU_LIBRARIES ${icu} ${icudt} ${dl})
|
||||
ENDIF()
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "UNICODE_SUPPORT enabled, but unable to find ICU. Disable UNICODE_SUPPORT or fix ICU paths to proceed.")
|
||||
ENDIF()
|
||||
IF("$ENV{ICU_INCLUDE_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No ICU include directory specified")
|
||||
ElSE()
|
||||
SET(ICU_INCLUDE_DIR CACHE FILEPATH "ICU header files")
|
||||
ENDIF()
|
||||
|
||||
IF(COLLADA_SUPPORT)
|
||||
# Find OpenCOLLADA
|
||||
IF("${OPENCOLLADA_INCLUDE_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No OpenCOLLADA include directory specified")
|
||||
SET(OPENCOLLADA_INCLUDE_DIR "/usr/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")
|
||||
FIND_LIBRARY(OPENCOLLADA_FRAMEWORK_LIB NAMES OpenCOLLADAFramework
|
||||
PATHS /usr/lib64/opencollada /usr/lib/opencollada /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib)
|
||||
GET_FILENAME_COMPONENT(OPENCOLLADA_LIBRARY_DIR ${OPENCOLLADA_FRAMEWORK_LIB} PATH)
|
||||
ENDIF()
|
||||
|
||||
FIND_LIBRARY(OpenCOLLADAFramework NAMES OpenCOLLADAFramework PATHS ${OPENCOLLADA_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
|
||||
SET(OPENCOLLADA_LIBRARY_DIR "${OPENCOLLADA_LIBRARY_DIR}" CACHE FILEPATH "OpenCOLLADA library files")
|
||||
|
||||
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_LIBRARY_NAMES
|
||||
GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader
|
||||
OpenCOLLADAStreamWriter UTF buffer ftoa
|
||||
)
|
||||
|
||||
# Use the found OpenCOLLADAFramework as a template for all other OpenCOLLADA libraries
|
||||
foreach(lib ${OPENCOLLADA_LIBRARY_NAMES})
|
||||
string(REPLACE OpenCOLLADAFramework "${lib}" lib_path "${OpenCOLLADAFramework}")
|
||||
list(APPEND OPENCOLLADA_LIBRARIES "${lib_path}")
|
||||
endforeach()
|
||||
|
||||
if("${PCRE_LIBRARY_DIR}" STREQUAL "")
|
||||
if(WIN32)
|
||||
find_library(pcre_library NAMES pcre PATHS ${OPENCOLLADA_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
else()
|
||||
find_library(pcre_library NAMES pcre PATHS ${OPENCOLLADA_LIBRARY_DIR})
|
||||
endif()
|
||||
GET_FILENAME_COMPONENT(PCRE_LIBRARY_DIR ${pcre_library} PATH)
|
||||
else()
|
||||
find_library(pcre_library NAMES pcre PATHS ${PCRE_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
if (pcre_library)
|
||||
SET(OPENCOLLADA_LIBRARY_DIR ${OPENCOLLADA_LIBRARY_DIR} ${PCRE_LIBRARY_DIR})
|
||||
list(APPEND OPENCOLLADA_LIBRARIES "${pcre_library}")
|
||||
else()
|
||||
message(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find PCRE. "
|
||||
"Disable COLLADA_SUPPORT or fix PCRE_LIBRARY_DIR path to proceed.")
|
||||
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()
|
||||
IF("$ENV{ICU_LIBRARY_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No ICU library directory specified")
|
||||
ElSE()
|
||||
SET(ICU_LIBRARY_DIR CACHE FILEPATH "ICU library files")
|
||||
ENDIF()
|
||||
|
||||
# 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)
|
||||
# OPENCASCADE_LIBRARIES repeated three times below in order to fix cyclic dependencies - use --start-group ... --end-group instead?
|
||||
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
if (NOT APPLE AND NOT WIN32)
|
||||
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} "rt")
|
||||
endif()
|
||||
if (NOT WIN32)
|
||||
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} "dl")
|
||||
endif()
|
||||
endif()
|
||||
FIND_LIBRARY(icu "icuuc" /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR})
|
||||
|
||||
IF(icu)
|
||||
MESSAGE(STATUS "ICU libraries found")
|
||||
ADD_DEFINITIONS(-DHAVE_ICU)
|
||||
ELSE()
|
||||
MESSAGE(STATUS "Unable to find ICU library files, continuing")
|
||||
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()
|
||||
|
||||
if(ENABLE_BUILD_OPTIMIZATIONS)
|
||||
if(MSVC)
|
||||
# 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)
|
||||
# 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()
|
||||
# GCC-like: Release should use O3 but RelWithDebInfo 02 so enforce 03. Anything other useful that could be added here?
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
||||
endif()
|
||||
endif()
|
||||
SET(CMAKE_BUILD_TYPE "Release")
|
||||
ENDIF(NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
IF(MSVC)
|
||||
# Enable solution folders (free VS versions prior to 2012 don't support solution folders)
|
||||
if (MSVC_VERSION GREATER 1600)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
endif()
|
||||
ADD_DEFINITIONS(-D_UNICODE)
|
||||
ElSE(MSVC)
|
||||
ADD_DEFINITIONS(-fPIC -Wno-non-virtual-dtor)
|
||||
ENDIF(MSVC)
|
||||
|
||||
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
|
||||
# TODO Make this configurable
|
||||
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(-Wall -Wextra)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_definitions(-Wno-tautological-constant-out-of-range-compare)
|
||||
endif()
|
||||
# -fPIC is not relevant on Windows and creates pointless warnings
|
||||
if (UNIX)
|
||||
add_definitions(-fPIC)
|
||||
endif()
|
||||
ENDIF()
|
||||
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})
|
||||
|
||||
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS}
|
||||
${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS}
|
||||
ADD_LIBRARY(IfcParse STATIC
|
||||
../src/ifcparse/Ifc2x3.cpp
|
||||
../src/ifcparse/Ifc4.cpp
|
||||
../src/ifcparse/IfcUtil.cpp
|
||||
../src/ifcparse/IfcParse.cpp
|
||||
../src/ifcparse/IfcCharacterDecoder.cpp
|
||||
|
||||
../src/ifcparse/IfcWrite.cpp
|
||||
../src/ifcparse/IfcGuidHelper.cpp
|
||||
|
||||
../src/ifcparse/IfcHierarchyHelper.cpp
|
||||
|
||||
../src/ifcparse/Ifc2x3-rt.cpp
|
||||
../src/ifcparse/Ifc4-rt.cpp
|
||||
../src/ifcparse/IfcUntypedEntity.cpp
|
||||
)
|
||||
|
||||
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
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endfunction()
|
||||
ADD_LIBRARY(IfcGeom STATIC
|
||||
../src/ifcgeom/IfcGeomCurves.cpp
|
||||
../src/ifcgeom/IfcGeomFaces.cpp
|
||||
../src/ifcgeom/IfcGeomFunctions.cpp
|
||||
../src/ifcgeom/IfcGeomHelpers.cpp
|
||||
../src/ifcgeom/IfcGeomObjects.cpp
|
||||
../src/ifcgeom/IfcGeomRenderStyles.cpp
|
||||
../src/ifcgeom/IfcGeomShapes.cpp
|
||||
../src/ifcgeom/IfcGeomWires.cpp
|
||||
../src/ifcgeom/IfcRegister.cpp
|
||||
)
|
||||
|
||||
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()
|
||||
|
||||
# Boost >= 1.58 requires BOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE to build on some Linux distros.
|
||||
if(NOT Boost_VERSION LESS 105800)
|
||||
add_definitions(-DBOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE)
|
||||
endif()
|
||||
|
||||
# Detect OCC version on gcc/clang/mingw as
|
||||
# -std=c++11 is needed for OCCT >= 7.0.0
|
||||
if(NOT MSVC)
|
||||
FIND_FILE(Standard_Version "Standard_Version.hxx" ${OCC_INCLUDE_DIR})
|
||||
|
||||
set(CMAKE_CONFIGURABLE_FILE_CONTENT "
|
||||
#include <Standard_Version.hxx>
|
||||
#include <iostream>
|
||||
int main(int argc, char** argv) {
|
||||
std::cout << OCC_VERSION_COMPLETE;
|
||||
}")
|
||||
configure_file(
|
||||
"${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
|
||||
"${CMAKE_BINARY_DIR}/version.cxx" @ONLY)
|
||||
|
||||
try_compile(VERSION_CHECK
|
||||
${CMAKE_BINARY_DIR}
|
||||
"${CMAKE_BINARY_DIR}/version.cxx"
|
||||
CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${OCC_INCLUDE_DIR}"
|
||||
COPY_FILE "${CMAKE_BINARY_DIR}/version"
|
||||
OUTPUT_VARIABLE OUT
|
||||
COPY_FILE_ERROR ERR
|
||||
)
|
||||
|
||||
if(${VERSION_CHECK})
|
||||
EXECUTE_PROCESS(COMMAND ${CMAKE_BINARY_DIR}/version OUTPUT_VARIABLE OCC_VERSION)
|
||||
else()
|
||||
message(FATAL_ERROR "Failed to compile OCC version test:
|
||||
${OUT}
|
||||
------
|
||||
${ERR}")
|
||||
endif()
|
||||
|
||||
MESSAGE(STATUS "OCC version is ${OCC_VERSION}. Detected from: ${Standard_Version}")
|
||||
|
||||
if(NOT ("${OCC_VERSION}" LESS "7.0.0"))
|
||||
include(CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
||||
if(COMPILER_SUPPORTS_CXX11)
|
||||
add_definitions(-std=c++11)
|
||||
else()
|
||||
message(FATAL_ERROR "OCCT7 requires a compiler with C++11 support")
|
||||
endif()
|
||||
else()
|
||||
add_definitions(-std=c++03)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(IFCOPENSHELL_LIBRARIES IfcParse IfcGeom)
|
||||
|
||||
# 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 ${IFCPARSE_FILES})
|
||||
set_target_properties(IfcParse PROPERTIES COMPILE_FLAGS -DIFC_PARSE_EXPORTS)
|
||||
|
||||
IF(UNICODE_SUPPORT)
|
||||
TARGET_LINK_LIBRARIES(IfcParse ${ICU_LIBRARIES} ${Boost_LIBRARIES})
|
||||
IF(icu)
|
||||
TARGET_LINK_LIBRARIES(IfcParse icuuc)
|
||||
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})
|
||||
TARGET_LINK_LIBRARIES(IfcGeom IfcParse)
|
||||
|
||||
add_library(IfcGeom ${IFCGEOM_FILES})
|
||||
set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS)
|
||||
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})
|
||||
|
||||
TARGET_LINK_LIBRARIES(IfcGeom IfcParse ${OPENCASCADE_LIBRARIES})
|
||||
ADD_EXECUTABLE(IfcConvert
|
||||
../src/ifcconvert/ColladaSerializer.cpp
|
||||
../src/ifcconvert/IfcConvert.cpp
|
||||
../src/ifcconvert/OpenCascadeBasedSerializer.cpp
|
||||
../src/ifcconvert/WavefrontObjSerializer.cpp
|
||||
)
|
||||
|
||||
# IfcConvert
|
||||
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})
|
||||
if (IFCCONVERT_DOUBLE_PRECISION)
|
||||
set_target_properties(IfcConvert PROPERTIES COMPILE_FLAGS -DIFCCONVERT_DOUBLE_PRECISION)
|
||||
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})
|
||||
|
||||
TARGET_LINK_LIBRARIES(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${ICU_LIBRARIES})
|
||||
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
|
||||
# Only set RPATHs when building shared libraries (i.e. IfcParse and
|
||||
# IfcGeom are dynamically linked). Not necessarily a perfect solution
|
||||
# but probably a good indication of whether RPATHs are necessary.
|
||||
SET_INSTALL_RPATHS(IfcConvert "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS};${OPENCOLLADA_LIBRARY_DIR};${ICU_LIBRARY_DIR}")
|
||||
endif()
|
||||
ADD_EXECUTABLE(IfcGeomServer
|
||||
../src/ifcgeomserver/IfcGeomServer.cpp
|
||||
)
|
||||
|
||||
# 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})
|
||||
TARGET_LINK_LIBRARIES(IfcGeomServer ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBRARIES})
|
||||
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
|
||||
SET_INSTALL_RPATHS(IfcGeomServer "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS};${ICU_LIBRARY_DIR}")
|
||||
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)
|
||||
|
||||
IF(BUILD_IFCPYTHON)
|
||||
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
|
||||
ENDIF()
|
||||
# Build python wrapper using separate CMakeLists.txt
|
||||
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
|
||||
|
||||
IF(BUILD_EXAMPLES)
|
||||
ADD_SUBDIRECTORY(../src/examples examples)
|
||||
ENDIF()
|
||||
# Build IfcParseExamples using separate CMakeLists.txt
|
||||
ADD_SUBDIRECTORY(../src/examples examples)
|
||||
|
||||
IF(BUILD_IFCMAX)
|
||||
ADD_SUBDIRECTORY(../src/ifcmax ifcmax)
|
||||
ENDIF()
|
||||
# ADD_SUBDIRECTORY(../src/qtviewer qtviewer)
|
||||
|
||||
# CMake installation targets
|
||||
INSTALL(FILES ${IFCPARSE_H_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/ifcparse
|
||||
SET(include_files_geom
|
||||
../src/ifcgeom/IfcGeom.h
|
||||
../src/ifcgeom/IfcGeomObjects.h
|
||||
../src/ifcgeom/IfcGeomRenderStyles.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/IfcGeomRenderStyles.h
|
||||
../src/ifcgeom/IfcRepresentationShapeItem.h
|
||||
)
|
||||
SET(include_files_parse
|
||||
../src/ifcparse/Ifc2x3.h
|
||||
../src/ifcparse/Ifc2x3enum.h
|
||||
../src/ifcparse/Ifc4.h
|
||||
../src/ifcparse/Ifc4enum.h
|
||||
../src/ifcparse/IfcCharacterDecoder.h
|
||||
../src/ifcparse/IfcException.h
|
||||
../src/ifcparse/IfcFile.h
|
||||
../src/ifcparse/IfcHierarchyHelper.h
|
||||
../src/ifcparse/IfcParse.h
|
||||
../src/ifcparse/IfcUtil.h
|
||||
../src/ifcparse/SharedPointer.h
|
||||
|
||||
../src/ifcparse/IfcWrite.h
|
||||
../src/ifcparse/IfcWritableEntity.h
|
||||
|
||||
INSTALL(FILES ${IFCGEOM_H_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/ifcgeom
|
||||
)
|
||||
|
||||
INSTALL(TARGETS IfcParse IfcGeom IfcConvert IfcGeomServer
|
||||
ARCHIVE DESTINATION ${LIBDIR}
|
||||
LIBRARY DESTINATION ${LIBDIR}
|
||||
RUNTIME DESTINATION ${BINDIR}
|
||||
../src/ifcparse/Ifc2x3-rt.h
|
||||
../src/ifcparse/Ifc4-rt.h
|
||||
../src/ifcparse/IfcUntypedEntity.h
|
||||
../src/ifcparse/IfcEntityDescriptor.h
|
||||
)
|
||||
INSTALL(FILES ${include_files_geom} DESTINATION include/ifcgeom)
|
||||
INSTALL(FILES ${include_files_parse} DESTINATION include/ifcparse)
|
||||
INSTALL(TARGETS IfcConvert DESTINATION bin)
|
||||
INSTALL(TARGETS IfcParse IfcGeom DESTINATION lib)
|
||||
|
||||
@@ -1,529 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
###############################################################################
|
||||
# #
|
||||
# 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 gcc g++ autoconf bison bzip2 #
|
||||
# on ubuntu 14.04: #
|
||||
# $ apt-get install git gcc g++ autoconf bison make #
|
||||
# on OS X El Capitan with homebrew: #
|
||||
# $ brew install git bison autoconf automake #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import subprocess as sp
|
||||
import shutil
|
||||
import time
|
||||
import tarfile
|
||||
import multiprocessing
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.INFO)
|
||||
ch = logging.StreamHandler()
|
||||
ch.setLevel(logging.INFO)
|
||||
logger.addHandler(ch)
|
||||
|
||||
PROJECT_NAME="IfcOpenShell"
|
||||
OCE_VERSION="0.18"
|
||||
PYTHON_VERSIONS=["2.7.12", "3.2.6", "3.3.6", "3.4.6", "3.5.3"]
|
||||
BOOST_VERSION="1.59.0"
|
||||
PCRE_VERSION="8.39"
|
||||
LIBXML_VERSION="2.9.3"
|
||||
CMAKE_VERSION="3.4.1"
|
||||
ICU_VERSION="56.1"
|
||||
|
||||
# binaries
|
||||
cp="cp"
|
||||
bash="bash"
|
||||
uname="uname"
|
||||
git="git"
|
||||
bunzip2="bunzip2"
|
||||
tar="tar"
|
||||
cc="cc"
|
||||
cplusplus="c++"
|
||||
autoconf="autoconf"
|
||||
automake="automake"
|
||||
yacc="yacc"
|
||||
make="make"
|
||||
date = "date"
|
||||
curl="curl"
|
||||
wget="wget"
|
||||
strip="strip"
|
||||
|
||||
# Helper function for coloured printing
|
||||
|
||||
NO_COLOR="\033[0m" # <ref>http://stackoverflow.com/questions/5947742/how-to-change-the-output-color-of-echo-in-linux</ref>
|
||||
BLACK_ON_WHITE="\033[0;30;107m"
|
||||
RED="\033[31m"
|
||||
GREEN="\033[32m"
|
||||
YELLOW="\033[33m"
|
||||
MAGENTA="\033[35m"
|
||||
|
||||
def cecho(message, color=NO_COLOR):
|
||||
"""Logs message `message` in color `color`."""
|
||||
logger.info("%s%s\033[0m\n" % (color, message))
|
||||
|
||||
def fullpath(arg):
|
||||
return os.path.realpath(os.path.dirname(sys.argv[1]))
|
||||
|
||||
def which(cmd):
|
||||
for path in os.environ["PATH"].split(":"):
|
||||
if os.path.exists(path) and cmd in os.listdir(path):
|
||||
return cmd
|
||||
return None
|
||||
|
||||
def get_os():
|
||||
ret_value = sp.check_output([uname, "-s"]).strip()
|
||||
return ret_value
|
||||
|
||||
# Set defaults for missing empty environment variables
|
||||
|
||||
try:
|
||||
IFCOS_NUM_BUILD_PROCS = os.environ["IFCOS_NUM_BUILD_PROCS"]
|
||||
except KeyError:
|
||||
IFCOS_NUM_BUILD_PROCS=multiprocessing.cpu_count() + 1
|
||||
os.environ["IFCOS_NUM_BUILD_PROCS"]=str(IFCOS_NUM_BUILD_PROCS)
|
||||
|
||||
try:
|
||||
TARGET_ARCH = os.environ["TARGET_ARCH"]
|
||||
del os.environ["TARGET_ARCH"]
|
||||
except KeyError:
|
||||
TARGET_ARCH = sp.check_output([uname, "-m"]).strip()
|
||||
|
||||
CMAKE_DIR=os.path.realpath(os.path.join("..", "cmake"))
|
||||
|
||||
try:
|
||||
DEPS_DIR = os.environ["DEPS_DIR"]
|
||||
except KeyError:
|
||||
DEPS_DIR = os.path.realpath(os.path.join("..", "build", sp.check_output(uname).strip(), TARGET_ARCH))
|
||||
os.environ["DEPS_DIR"] = DEPS_DIR
|
||||
if not os.path.exists(DEPS_DIR):
|
||||
os.makedirs(DEPS_DIR)
|
||||
|
||||
try:
|
||||
BUILD_CFG=os.environ["BUILD_CFG"]
|
||||
except KeyError:
|
||||
BUILD_CFG="RelWithDebInfo"
|
||||
os.environ["BUILD_CFG"]=BUILD_CFG
|
||||
|
||||
try:
|
||||
BUILD_TYPE=os.environ["BUILD_TYPE"]
|
||||
except KeyError:
|
||||
BUILD_TYPE="Build"
|
||||
os.environ["BUILD_TYPE"] = BUILD_TYPE
|
||||
|
||||
# Print build configuration information
|
||||
|
||||
cecho ("""This script fetches and builds %s and its dependencies
|
||||
""" % (PROJECT_NAME,), BLACK_ON_WHITE)
|
||||
cecho("""Script configuration:
|
||||
|
||||
""", GREEN)
|
||||
cecho("""* Target Architecture = %s""" % (TARGET_ARCH,), MAGENTA)
|
||||
cecho(" - Whether 32-bit (i686) or 64-bit (x86_64) will be built.")
|
||||
cecho("* Dependency Directory = %s" % (DEPS_DIR,), MAGENTA)
|
||||
cecho(" - The directory where %s dependencies are installed." % (PROJECT_NAME,))
|
||||
cecho("* Build Config Type = %s" % (BUILD_CFG,), MAGENTA)
|
||||
cecho(""" - The used build configuration type for the dependencies.
|
||||
Defaults to RelWithDebInfo if not specified.""")
|
||||
|
||||
if BUILD_CFG == "MinSizeRel":
|
||||
cecho(" WARNING: MinSizeRel build can suffer from a significant performance loss.", RED)
|
||||
|
||||
cecho("* IFCOS_NUM_BUILD_PROCS = %s" % (IFCOS_NUM_BUILD_PROCS,), MAGENTA)
|
||||
cecho(""" - How many compiler processes may be run in parallel.
|
||||
""")
|
||||
|
||||
# Check that required tools are in PATH
|
||||
|
||||
for cmd in [git, bunzip2, tar, cc, cplusplus, autoconf, automake, yacc, make]:
|
||||
if which(cmd) is None:
|
||||
raise ValueError("Required tool '%s' not installed or not added to PATH" % (cmd,))
|
||||
|
||||
# identifiers for the download tool (could be less memory consuming as ints, but are more verbose as strings)
|
||||
download_tool_curl="curl"
|
||||
download_tool_wget="wget"
|
||||
download_tool_git = "git"
|
||||
# curl randomly has trouble and fails with return code 6 without further feedback -> prefer wget
|
||||
if which(wget) != None:
|
||||
download_tool_default = download_tool_wget
|
||||
elif which(curl) != None:
|
||||
download_tool_default = download_tool_curl
|
||||
else:
|
||||
raise ValueError("No download application found, tried: curl, wget")
|
||||
CURL = ["curl", "-sLO"]
|
||||
WGET= ["wget", "-q", "--no-check-certificate"]
|
||||
|
||||
# Create log directory and file
|
||||
|
||||
log_dir = os.path.join(DEPS_DIR, "logs")
|
||||
if not os.path.exists(log_dir):
|
||||
os.makedirs(log_dir)
|
||||
LOG_FILE="%s.log" % (os.path.join(log_dir, sp.check_output([date, "+%Y%m%d"]).strip()),)
|
||||
if not os.path.exists(LOG_FILE):
|
||||
open(LOG_FILE, "w").close()
|
||||
logger.info("using command log file '%s'" % (LOG_FILE,))
|
||||
|
||||
def __check_call__(cmds, cwd=None):
|
||||
logger.debug("running command %r in directory %r" % (" ".join(cmds), cwd))
|
||||
log_file_handle = open(LOG_FILE, "a")
|
||||
proc = sp.Popen(cmds, cwd=cwd, stdout=log_file_handle, stderr=sp.PIPE)
|
||||
_, stderr = proc.communicate()
|
||||
log_file_handle.write(stderr)
|
||||
log_file_handle.close()
|
||||
|
||||
if proc.returncode != 0:
|
||||
print "-" * 70
|
||||
print stderr
|
||||
print "-" * 70
|
||||
raise Exception("Command `%s` returned exit code %d" % (" ".join(cmds), proc.returncode))
|
||||
|
||||
def __check_output__(cmds, cwd=None):
|
||||
"""Wraps `subprocess.check_output` and logs the command being executed,
|
||||
sets up logging `stderr` to `LOG_FILE` (in append mode) and strips the
|
||||
return value because it's unlikely that the newline at the end of output is
|
||||
useful and it often causes errors"""
|
||||
logger.debug("running command '%s' in directory %r" % (" ".join(cmds), cwd))
|
||||
log_file_handle = open(LOG_FILE, "a")
|
||||
ret_value = sp.check_output(cmds, cwd=cwd, stderr=log_file_handle).strip()
|
||||
logger.debug("command returned %r" % ret_value)
|
||||
log_file_handle.close()
|
||||
return ret_value
|
||||
|
||||
BOOST_VERSION_UNDERSCORE=BOOST_VERSION.replace(".", "_")
|
||||
ICU_VERSION_UNDERSCORE=ICU_VERSION.replace(".", "_")
|
||||
CMAKE_VERSION_2=CMAKE_VERSION[0:3]
|
||||
|
||||
OCE_LOCATION="https://github.com/tpaviot/oce/archive/OCE-%s.tar.gz" % (OCE_VERSION,)
|
||||
BOOST_LOCATION="http://downloads.sourceforge.net/project/boost/boost/%s/boost_%s.tar.bz2" % (BOOST_VERSION, BOOST_VERSION_UNDERSCORE)
|
||||
OPENCOLLADA_LOCATION="https://github.com/KhronosGroup/OpenCOLLADA.git"
|
||||
OPENCOLLADA_COMMIT="f99d59e73e565a41715eaebc00c7664e1ee5e628"
|
||||
|
||||
# Helper functions
|
||||
|
||||
def run_autoconf(arg1, configure_args, cwd):
|
||||
configure_path = os.path.realpath(os.path.join(cwd, "..", "configure"))
|
||||
if not os.path.exists(configure_path):
|
||||
__check_call__([bash, "./autogen.sh"], cwd=os.path.realpath(os.path.join(cwd, ".."))) # only run autogen.sh in the directory it is located and use cwd to achieve that in order to not mess up things
|
||||
# Using `sh` over `bash` fixes issues with building swig
|
||||
__check_call__(["/bin/sh", "../configure"]+configure_args+["--prefix=%s" % (os.path.realpath("%s/install/%s" % (DEPS_DIR, arg1)),)], cwd=cwd)
|
||||
|
||||
def run_cmake(arg1, cmake_args, cmake_dir=None, cwd=None):
|
||||
if cmake_dir is None:
|
||||
P=".."
|
||||
else:
|
||||
P=cmake_dir
|
||||
cmake_path= os.path.join(DEPS_DIR, "install", "cmake-%s" % (CMAKE_VERSION,), "bin", "cmake")
|
||||
__check_call__([cmake_path, P]+cmake_args+["-DCMAKE_BUILD_TYPE=%s" % (BUILD_TYPE,)], cwd=cwd)
|
||||
|
||||
def run_icu(arg1, icu_args, cwd):
|
||||
PLATFORM=get_os()
|
||||
if PLATFORM == "Darwin":
|
||||
PLATFORM="MacOSX"
|
||||
__check_call__([bash, "../source/runConfigureICU", PLATFORM]+icu_args+["--prefix=%s/install/%s" % (DEPS_DIR, arg1)], cwd=cwd)
|
||||
|
||||
def git_clone(clone_url, target_dir, revision=None):
|
||||
"""Lazily clones the `git` repository denoted by `clone_url` into
|
||||
`target_dir`, i.e. skips cloning if `target_dir` exists (naively assumes
|
||||
that a working clone exists there) and optionally checks out a revision
|
||||
`revision` after cloning or in the existing clone if `revision` is not
|
||||
`None`."""
|
||||
if not os.path.exists(target_dir):
|
||||
logger.info("cloning '%s' into '%s'" % (clone_url, target_dir))
|
||||
__check_call__([git, "clone", clone_url, target_dir])
|
||||
else:
|
||||
logger.info("directory '%s' exists, skipping cloning" % (target_dir,))
|
||||
if revision != None:
|
||||
__check_call__([git, "checkout", revision], cwd=target_dir)
|
||||
|
||||
def build_dependency(name, mode, build_tool_args, download_url, download_name, download_tool=download_tool_default, revision=None):
|
||||
"""Handles building of dependencies with different tools (which are
|
||||
distinguished with the `mode` argument. `build_tool_args` is expected to be
|
||||
a list which is necessary in order to not mess up quoting of compiler and
|
||||
linker flags."""
|
||||
check_dir = os.path.join(DEPS_DIR, "install", name)
|
||||
if os.path.exists(check_dir):
|
||||
logger.info( "Found existing %s, skipping" % (name,))
|
||||
return
|
||||
build_dir = os.path.join(DEPS_DIR, "build")
|
||||
if not os.path.exists(build_dir):
|
||||
os.makedirs(build_dir)
|
||||
|
||||
logger.info("\rFetching %s... " % (name,))
|
||||
if download_tool == download_tool_curl:
|
||||
download_path = os.path.join(build_dir, download_name)
|
||||
if not os.path.exists(download_path):
|
||||
__check_call__(CURL+[download_url, download_name], cwd=build_dir)
|
||||
else:
|
||||
logger.info("Download '%s' already exists, assuming it's an undamaged download and that it has been extracted if possible, skipping" % (download_path,))
|
||||
elif download_tool == download_tool_wget:
|
||||
download_path = os.path.join(build_dir, download_name)
|
||||
if not os.path.exists(download_path):
|
||||
__check_call__(WGET+[os.path.join(download_url, download_name)], cwd=build_dir)
|
||||
else:
|
||||
logger.info("Download '%s' already exists, assuming it's an undamaged download and that it has been extracted if possible, skipping" % (download_path,))
|
||||
elif download_tool == download_tool_git:
|
||||
git_clone(download_url, target_dir=os.path.join(build_dir, download_name), revision=revision)
|
||||
else:
|
||||
raise ValueError("download tool '%s' is not supported" % (download_tool,))
|
||||
download_dir = os.path.join(build_dir, download_name)
|
||||
if os.path.isdir(download_dir):
|
||||
extract_dir_name=download_name
|
||||
extract_dir = os.path.join(build_dir, extract_dir_name)
|
||||
else:
|
||||
download_tarfile_path = os.path.join(build_dir, download_name)
|
||||
if download_name.endswith(".tar.gz") or download_name.endswith(".tgz"):
|
||||
compr = "gz"
|
||||
elif download_name.endswith(".tar.bz2"):
|
||||
compr = "bz2"
|
||||
else:
|
||||
raise RuntimeError("fix source for new download type")
|
||||
download_tarfile = tarfile.open(name=download_tarfile_path, mode="r:%s" % (compr,))
|
||||
extract_dir_name= os.path.commonprefix(download_tarfile.getnames()) # tarfile seriously doesn't have a function to retrieve the root directory more easily
|
||||
#__check_output__([tar, "--exclude=\"*/*\"", "-tf", download_name], cwd=build_dir).strip() no longer works
|
||||
if extract_dir_name is None:
|
||||
extract_dir_name= __check_output__([bash, "-c", "tar -tf %s 2> /dev/null | head -n 1 | cut -f1 -d /" % (download_name,)], cwd=build_dir)
|
||||
extract_dir = os.path.join(build_dir, extract_dir_name)
|
||||
if not os.path.exists(extract_dir):
|
||||
__check_call__([tar, "-xf", download_name], cwd=build_dir)
|
||||
|
||||
if mode != "bjam":
|
||||
extract_build_dir = os.path.join(extract_dir, "build")
|
||||
if os.path.exists(extract_build_dir):
|
||||
shutil.rmtree(extract_build_dir)
|
||||
os.makedirs(extract_build_dir)
|
||||
|
||||
logger.info("\rConfiguring %s..." % (name,))
|
||||
if mode == "icu":
|
||||
run_icu(name, build_tool_args, cwd=extract_build_dir)
|
||||
elif mode == "autoconf":
|
||||
run_autoconf(name, build_tool_args, cwd=extract_build_dir)
|
||||
elif mode == "cmake":
|
||||
run_cmake(name, build_tool_args, cwd=extract_build_dir)
|
||||
else:
|
||||
raise ValueError()
|
||||
logger.info("\rBuilding %s... " % (name,))
|
||||
__check_call__([make, "-j%s" % (IFCOS_NUM_BUILD_PROCS,)], cwd=extract_build_dir)
|
||||
logger.info( "\rInstalling %s... " % (name,))
|
||||
__check_call__([make, "install"], cwd=extract_build_dir)
|
||||
logger.info( "\rInstalled %s \n" % (name,))
|
||||
else:
|
||||
logger.info( "\rConfiguring %s..." % (name,))
|
||||
__check_call__([bash, "./bootstrap.sh"], cwd=extract_dir)
|
||||
logger.info("\rBuilding %s... " % (name,))
|
||||
__check_call__(["./b2", "-j%s" % (IFCOS_NUM_BUILD_PROCS,)]+build_tool_args, cwd=extract_dir)
|
||||
logger.info("\rInstalling %s... " % (name,))
|
||||
shutil.copytree(os.path.join(extract_dir, "boost"), os.path.join(DEPS_DIR, "install", "boost-%s" % BOOST_VERSION, "boost"))
|
||||
logger.info("\rInstalled %s \n" % (name,))
|
||||
|
||||
cecho("Collecting dependencies:", GREEN)
|
||||
|
||||
# Set compiler flags for 32bit builds on 64bit system
|
||||
# TODO: This is untested
|
||||
|
||||
ADDITIONAL_ARGS=[]
|
||||
BOOST_ADDRESS_MODEL=[]
|
||||
if TARGET_ARCH == "i686" and __check_output__([uname, "-m"]).strip() == "x86_64":
|
||||
ADDITIONAL_ARGS=["-m32", "-arch i386"]
|
||||
BOOST_ADDRESS_MODEL=["architecture=x86", "address-model=32"]
|
||||
|
||||
if get_os() == "Darwin":
|
||||
ADDITIONAL_ARGS=["-mmacosx-version-min=10.6"]+ADDITIONAL_ARGS
|
||||
|
||||
# If the linker supports GC sections, set it up to reduce binary file size
|
||||
# -fPIC is required for the shared libraries to work
|
||||
|
||||
try:
|
||||
CXXFLAGS=os.environ["CXXFLAGS"]
|
||||
except KeyError:
|
||||
CXXFLAGS=""
|
||||
try:
|
||||
CFLAGS=os.environ["CFLAGS"]
|
||||
except KeyError:
|
||||
CFLAGS=""
|
||||
try:
|
||||
LDFLAGS=os.environ["LDFLAGS"]
|
||||
except KeyError:
|
||||
LDFLAGS=""
|
||||
if sp.call([bash, "-c", "man ld 2> /dev/null | grep gc-sections &> /dev/null"]) == 0:
|
||||
CXXFLAGS_MINIMAL="%s -fPIC %s" % (CXXFLAGS, str.join(" ", ADDITIONAL_ARGS))
|
||||
os.environ["CXXFLAGS_MINIMAL"]=CXXFLAGS_MINIMAL
|
||||
CFLAGS_MINIMAL="%s -fPIC %s" % (CFLAGS, str.join(" ", ADDITIONAL_ARGS))
|
||||
os.environ["CFLAGS_MINIMAL"]=CFLAGS_MINIMAL
|
||||
CXXFLAGS="%s -fPIC -fdata-sections -ffunction-sections -fvisibility=hidden -fvisibility-inlines-hidden %s" % (CXXFLAGS, str.join(" ", ADDITIONAL_ARGS))
|
||||
os.environ["CXXFLAGS"]=CXXFLAGS
|
||||
CFLAGS="%s -fPIC -fdata-sections -ffunction-sections -fvisibility=hidden %s"% (CFLAGS, str.join(" ", ADDITIONAL_ARGS))
|
||||
os.environ["CFLAGS"]=CFLAGS
|
||||
LDFLAGS="%s -Wl,--gc-sections %s" % (LDFLAGS, str.join(" ", ADDITIONAL_ARGS))
|
||||
os.environ["LDFLAGS"]=LDFLAGS
|
||||
else:
|
||||
CXXFLAGS_MINIMAL="%s -fPIC %s" % (CXXFLAGS, str.join(" ", ADDITIONAL_ARGS))
|
||||
os.environ["CXXFLAGS_MINIMAL"]=CXXFLAGS_MINIMAL
|
||||
CFLAGS_MINIMAL="%s -fPIC %s" % (CFLAGS, str.join(" ", ADDITIONAL_ARGS))
|
||||
os.environ["CFLAGS_MINIMAL"]=CFLAGS_MINIMAL
|
||||
CXXFLAGS="%s -fPIC -fvisibility=hidden -fvisibility-inlines-hidden %s" % (CXXFLAGS, str.join(" ", ADDITIONAL_ARGS))
|
||||
os.environ["CXXFLAGS"]=CXXFLAGS
|
||||
CFLAGS="%s -fPIC -fvisibility=hidden -fvisibility-inlines-hidden %s" % (CFLAGS, str.join(" ", ADDITIONAL_ARGS))
|
||||
os.environ["CFLAGS"]=CFLAGS
|
||||
LDFLAGS="%s %s" % (LDFLAGS, str.join(" ", ADDITIONAL_ARGS))
|
||||
os.environ["LDFLAGS"]=LDFLAGS
|
||||
|
||||
# Some dependencies need a more recent CMake version than most distros provide
|
||||
build_dependency(name="cmake-%s" % (CMAKE_VERSION,), mode="autoconf", build_tool_args=[], download_url="https://cmake.org/files/v%s" % (CMAKE_VERSION_2,), download_name="cmake-%s.tar.gz" % (CMAKE_VERSION,))
|
||||
|
||||
# Extract compiler flags from CMake to harmonize settings with other autoconf dependencies
|
||||
CMAKE_FLAG_EXTRACT_DIR="ifcopenshell_cmake_test_%s" % (time.time(),)
|
||||
# was sp.check_output([bash, "-c", "cat /dev/urandom | env LC_CTYPE=C tr -dc 'a-zA-Z0-9' | head -c 32"]), in bash script, unclear what the exact required format is and whether it's needed
|
||||
if os.path.exists(CMAKE_FLAG_EXTRACT_DIR):
|
||||
shutil.rmtree(CMAKE_FLAG_EXTRACT_DIR)
|
||||
os.makedirs(CMAKE_FLAG_EXTRACT_DIR)
|
||||
BUILD_CFG_UPPER=BUILD_CFG.upper()
|
||||
for FL in ["C", "CXX"]:
|
||||
__check_call__([bash, "-c", """echo "
|
||||
message(\"\${CMAKE_%s_FLAGS_%s}\")
|
||||
" > CMakeLists.txt""" % (FL, BUILD_CFG_UPPER)], cwd=CMAKE_FLAG_EXTRACT_DIR)
|
||||
FL="%sFLAGS" % (FL,)
|
||||
FLM="%sFLAGS_MINIMAL" % (FL,)
|
||||
# @TODO: bash code unclear
|
||||
# exec("%sFLAGS=%s" % (FL, sp.check_output([os.path.join(DEPS_DIR, "install", "cmake-%s" % (CMAKE_VERSION,), "bin", "cmake"), "."
|
||||
# declare ${FL}FLAGS_MINIMAL="`$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake . 2>&1 >/dev/null` ${!FLM}"
|
||||
shutil.rmtree(CMAKE_FLAG_EXTRACT_DIR)
|
||||
|
||||
build_dependency(name="pcre-%s" % (PCRE_VERSION,), mode="autoconf", build_tool_args=["--disable-shared"], download_url="https://downloads.sourceforge.net/project/pcre/pcre/%s/" % (PCRE_VERSION,), download_name="pcre-%s.tar.bz2" % (PCRE_VERSION,))
|
||||
|
||||
# An issue exists with swig-1.3 and python >= 3.2
|
||||
# Therefore, build a recent copy from source
|
||||
build_dependency(name="swig", mode="autoconf", build_tool_args=["--with-pcre-prefix=%s/install/pcre-%s" % (DEPS_DIR, PCRE_VERSION)], download_url="https://github.com/swig/swig.git", download_name="swig", download_tool=download_tool_git, revision="rel-3.0.8")
|
||||
|
||||
build_dependency(name="oce-%s" % (OCE_VERSION,), mode="cmake", build_tool_args=["-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=%s/install/oce-%s" % (DEPS_DIR, OCE_VERSION)], download_url="https://github.com/tpaviot/oce/archive/", download_name="OCE-%s.tar.gz" % (OCE_VERSION,))
|
||||
build_dependency("libxml2-%s" % (LIBXML_VERSION,), "autoconf", build_tool_args=["--without-python", "--disable-shared", "--without-zlib", "--without-iconv", "--without-lzma"], download_url="ftp://xmlsoft.org/libxml2/", download_name="libxml2-%s.tar.gz" % (LIBXML_VERSION,))
|
||||
build_dependency("OpenCOLLADA", "cmake", build_tool_args=["-DLIBXML2_INCLUDE_DIR=%s/install/libxml2-%s/include/libxml2" % (DEPS_DIR, LIBXML_VERSION), "-DLIBXML2_LIBRARIES=%s/install/libxml2-%s/lib/libxml2.a" % (DEPS_DIR, LIBXML_VERSION), "-DPCRE_INCLUDE_DIR=%s/install/pcre-%s/include" % (DEPS_DIR, PCRE_VERSION), "-DPCRE_PCREPOSIX_LIBRARY=%s/install/pcre-%s/lib/libpcreposix.a" % (DEPS_DIR, PCRE_VERSION), "-DPCRE_PCRE_LIBRARY=%s/install/pcre-%s/lib/libpcre.a" % (DEPS_DIR, PCRE_VERSION), "-DCMAKE_INSTALL_PREFIX=%s/install/OpenCOLLADA/" % (DEPS_DIR,)], download_url="https://github.com/KhronosGroup/OpenCOLLADA.git", download_name="OpenCOLLADA", download_tool=download_tool_git, revision=OPENCOLLADA_COMMIT)
|
||||
|
||||
# Python should not be built with -fvisibility=hidden, from experience that introduces segfaults
|
||||
|
||||
OLD_CXX_FLAGS=os.environ["CXXFLAGS"]
|
||||
OLD_C_FLAGS=os.environ["CFLAGS"]
|
||||
os.environ["CXXFLAGS"]=CXXFLAGS_MINIMAL
|
||||
os.environ["CFLAGS"]=CFLAGS_MINIMAL
|
||||
|
||||
# On OSX a dynamic python library is built or it would not be compatible
|
||||
# with the system python because of some threading initialization
|
||||
PYTHON_CONFIGURE_ARGS=[]
|
||||
if get_os() == "Darwin":
|
||||
PYTHON_CONFIGURE_ARGS=["--disable-static", "--enable-shared"]
|
||||
|
||||
for PYTHON_VERSION in PYTHON_VERSIONS:
|
||||
build_dependency("python-%s" % (PYTHON_VERSION,), "autoconf", PYTHON_CONFIGURE_ARGS, "http://www.python.org/ftp/python/%s/" % (PYTHON_VERSION,), "Python-%s.tgz" % (PYTHON_VERSION,))
|
||||
|
||||
os.environ["CXXFLAGS"]=OLD_CXX_FLAGS
|
||||
os.environ["CFLAGS"]=OLD_C_FLAGS
|
||||
|
||||
str_concat = lambda prefix: lambda postfix: "=".join((prefix, postfix.strip()))
|
||||
build_dependency("boost-%s" % (BOOST_VERSION,), mode="bjam", build_tool_args=["--stagedir=%s/install/boost-%s" % (DEPS_DIR, BOOST_VERSION), "--with-system", "--with-program_options", "--with-regex", "--with-thread", "--with-date_time", "link=static"]+BOOST_ADDRESS_MODEL+list(map(str_concat("cxxflags"), CXXFLAGS.strip().split(' '))) + list(map(str_concat("linkflags"), LDFLAGS.strip().split(' '))) + ["stage"], download_url="http://downloads.sourceforge.net/project/boost/boost/%s/" % (BOOST_VERSION,), download_name="boost_%s.tar.bz2" % (BOOST_VERSION_UNDERSCORE,))
|
||||
|
||||
build_dependency(name="icu-%s" % (ICU_VERSION,), mode="icu", build_tool_args=["--enable-static", "--disable-shared"], download_url="http://download.icu-project.org/files/icu4c/%s/" % (ICU_VERSION,), download_name="icu4c-%s-src.tgz" % (ICU_VERSION_UNDERSCORE,))
|
||||
|
||||
cecho("Building IfcOpenShell:", GREEN)
|
||||
|
||||
IFCOS_DIR=os.path.join(DEPS_DIR, "build", "ifcopenshell")
|
||||
if os.path.exists(IFCOS_DIR):
|
||||
shutil.rmtree(IFCOS_DIR)
|
||||
os.makedirs(IFCOS_DIR)
|
||||
|
||||
executables_dir = os.path.join(IFCOS_DIR, "executables")
|
||||
if not os.path.exists(executables_dir):
|
||||
os.makedirs(executables_dir)
|
||||
|
||||
logger.info("\rConfiguring executables...")
|
||||
|
||||
run_cmake("", cmake_args=[
|
||||
"-DBOOST_ROOT=" "%s/install/boost-%s" % (DEPS_DIR, BOOST_VERSION),
|
||||
"-DOCC_INCLUDE_DIR=" "%s/install/oce-%s/include/oce" % (DEPS_DIR, OCE_VERSION),
|
||||
"-DOCC_LIBRARY_DIR=" "%s/install/oce-%s/lib" % (DEPS_DIR, OCE_VERSION),
|
||||
"-DOPENCOLLADA_INCLUDE_DIR=" "%s/install/OpenCOLLADA/include/opencollada" % (DEPS_DIR,),
|
||||
"-DOPENCOLLADA_LIBRARY_DIR=" "%s/install/OpenCOLLADA/lib/opencollada" % (DEPS_DIR,),
|
||||
"-DICU_INCLUDE_DIR=" "%s/install/icu-%s/include" % (DEPS_DIR, ICU_VERSION),
|
||||
"-DICU_LIBRARY_DIR=" "%s/install/icu-%s/lib" % (DEPS_DIR, ICU_VERSION),
|
||||
"-DPCRE_LIBRARY_DIR=" "%s/install/pcre-%s/lib" % (DEPS_DIR, PCRE_VERSION),
|
||||
"-DBUILD_IFCPYTHON=" "OFF",
|
||||
"-DCMAKE_INSTALL_PREFIX=" "%s/install/ifcopenshell" % (DEPS_DIR,)], cmake_dir=CMAKE_DIR, cwd=executables_dir)
|
||||
|
||||
logger.info("\rBuilding executables... ")
|
||||
|
||||
__check_call__([make, "-j%s" % (IFCOS_NUM_BUILD_PROCS,)], cwd=executables_dir)
|
||||
__check_call__([make, "install/strip"], cwd=executables_dir)
|
||||
|
||||
# On OSX the actual Python library is not linked against.
|
||||
ADDITIONAL_ARGS=""
|
||||
if get_os() == "Darwin":
|
||||
ADDITIONAL_ARGS="-Wl,-flat_namespace,-undefined,suppress"
|
||||
|
||||
os.environ["CXXFLAGS"]="%s %s" % (CXXFLAGS_MINIMAL, ADDITIONAL_ARGS)
|
||||
os.environ["CFLAGS"]="%s %s" % (CFLAGS_MINIMAL, ADDITIONAL_ARGS)
|
||||
os.environ["LDFLAGS"]="%s %s" % (LDFLAGS, ADDITIONAL_ARGS)
|
||||
|
||||
for PYTHON_VERSION in PYTHON_VERSIONS:
|
||||
logger.info("\rConfiguring python %s wrapper..." % (PYTHON_VERSION,))
|
||||
|
||||
python_dir = os.path.join(IFCOS_DIR, "python-%s" % (PYTHON_VERSION,))
|
||||
if not os.path.exists(python_dir):
|
||||
os.makedirs(python_dir)
|
||||
|
||||
PYTHON_LIBRARY=__check_output__([bash, "-c", "ls %s/install/python-%s/lib/libpython*.*" % (DEPS_DIR, PYTHON_VERSION)], cwd=None).strip()
|
||||
PYTHON_INCLUDE=__check_output__([bash, "-c", "ls -d %s/install/python-%s/include/python*" % (DEPS_DIR, PYTHON_VERSION)], cwd=None).strip()
|
||||
PYTHON_EXECUTABLE=os.path.join(DEPS_DIR, "install", "python-%s" % (PYTHON_VERSION,), "bin", "python%s" % (PYTHON_VERSION[0],))
|
||||
os.environ["PYTHON_LIBRARY_BASENAME"]=os.path.basename(PYTHON_LIBRARY)
|
||||
|
||||
run_cmake("", cmake_args=["-DBOOST_ROOT=%s/install/boost-%s" % (DEPS_DIR, BOOST_VERSION),
|
||||
"-DOCC_INCLUDE_DIR=%s/install/oce-%s/include/oce" % (DEPS_DIR, OCE_VERSION),
|
||||
"-DOCC_LIBRARY_DIR=%s/install/oce-%s/lib" % (DEPS_DIR, OCE_VERSION),
|
||||
"-DOPENCOLLADA_INCLUDE_DIR=%s/install/OpenCOLLADA/include/opencollada" % (DEPS_DIR,),
|
||||
"-DOPENCOLLADA_LIBRARY_DIR=%s/install/OpenCOLLADA/lib/opencollada" % (DEPS_DIR,),
|
||||
"-DICU_INCLUDE_DIR=%s/install/icu-%s/include" % (DEPS_DIR, ICU_VERSION),
|
||||
"-DICU_LIBRARY_DIR=%s/install/icu-%s/lib" % (DEPS_DIR, ICU_VERSION),
|
||||
"-DPYTHON_LIBRARY=%s" % (PYTHON_LIBRARY,),
|
||||
"-DPYTHON_EXECUTABLE=%s" % (PYTHON_EXECUTABLE,),
|
||||
"-DPYTHON_INCLUDE_DIR=%s" % (PYTHON_INCLUDE,),
|
||||
"-DSWIG_EXECUTABLE=%s/install/swig/bin/swig" % (DEPS_DIR,),
|
||||
"-DCMAKE_INSTALL_PREFIX=%s/install/ifcopenshell/tmp" % (DEPS_DIR,),
|
||||
"-DCOLLADA_SUPPORT=OFF"], cmake_dir=CMAKE_DIR, cwd=python_dir)
|
||||
|
||||
logger.info("\rBuilding python %s wrapper... " % (PYTHON_VERSION,))
|
||||
|
||||
__check_call__([make, "-j%s" % (IFCOS_NUM_BUILD_PROCS,), "_ifcopenshell_wrapper"], cwd=python_dir)
|
||||
__check_call__([make, "install/local"], cwd=os.path.join(python_dir, "ifcwrap"))
|
||||
|
||||
module_dir = os.path.dirname(__check_output__([PYTHON_EXECUTABLE, "-c", "from __future__ import print_function; import inspect, ifcopenshell; print(inspect.getfile(ifcopenshell))"]))
|
||||
|
||||
if get_os() != "Darwin":
|
||||
# TODO: This symbol name depends on the Python version?
|
||||
__check_call__([strip, "-s", "-K", "PyInit__ifcopenshell_wrapper", "_ifcopenshell_wrapper.so"], cwd=module_dir)
|
||||
|
||||
__check_call__([cp, "-R", module_dir, os.path.join(DEPS_DIR, "install", "ifcopenshell", "python-%s" % (PYTHON_VERSION,))])
|
||||
|
||||
logger.info("\rBuilt IfcOpenShell...\n\n")
|
||||
@@ -1,30 +1,5 @@
|
||||
################################################################################
|
||||
# #
|
||||
# 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)
|
||||
set_target_properties(IfcParseExamples PROPERTIES FOLDER Examples)
|
||||
TARGET_LINK_LIBRARIES (IfcParseExamples IfcParse)
|
||||
|
||||
ADD_EXECUTABLE(IfcOpenHouse IfcOpenHouse.cpp)
|
||||
TARGET_LINK_LIBRARIES(IfcOpenHouse ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES})
|
||||
set_target_properties(IfcOpenHouse PROPERTIES FOLDER Examples)
|
||||
|
||||
ADD_EXECUTABLE(IfcAdvancedHouse IfcAdvancedHouse.cpp)
|
||||
TARGET_LINK_LIBRARIES(IfcAdvancedHouse ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES})
|
||||
set_target_properties(IfcAdvancedHouse PROPERTIES FOLDER Examples)
|
||||
TARGET_LINK_LIBRARIES (IfcOpenHouse IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKOffset)
|
||||
|
||||
@@ -1,179 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <TColgp_Array2OfPnt.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
|
||||
#include <Geom_BSplineSurface.hxx>
|
||||
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRepBuilderAPI_NurbsConvert.hxx>
|
||||
|
||||
#include <BRepPrimAPI_MakeBox.hxx>
|
||||
#include <BRepPrimAPI_MakeSphere.hxx>
|
||||
|
||||
#include <BRepAlgoAPI_Cut.hxx>
|
||||
|
||||
#include <Standard_Version.hxx>
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include "../ifcparse/Ifc4.h"
|
||||
#else
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#endif
|
||||
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
#endif
|
||||
|
||||
// The creation of Nurbs-surface for the IfcSite mesh, to be implemented lateron
|
||||
void createGroundShape(TopoDS_Shape& shape);
|
||||
|
||||
int main() {
|
||||
|
||||
// The IfcHierarchyHelper is a subclass of the regular IfcFile that provides several
|
||||
// convenience functions for working with geometry in IFC files.
|
||||
IfcHierarchyHelper file;
|
||||
file.header().file_name().name("IfcAdvancedHouse.ifc");
|
||||
|
||||
IfcSchema::IfcBuilding* building = file.addBuilding();
|
||||
// By adding a building, a hierarchy has been automatically created that consists of the following
|
||||
// structure: IfcProject > IfcSite > IfcBuilding
|
||||
|
||||
// Lateron changing the name of the IfcProject can be done by obtaining a reference to the
|
||||
// project, which has been created automatically.
|
||||
file.getSingle<IfcSchema::IfcProject>()->setName("IfcOpenHouse");
|
||||
|
||||
// To demonstrate the ability to serialize arbitrary opencascade solids a building envelope is
|
||||
// constructed by applying boolean operations. Naturally, in IFC, building elements should be
|
||||
// modeled separately, with rich parametric and relational semantics. Creating geometry in this
|
||||
// way does not preserve any history and is merely a demonstration of technical capabilities.
|
||||
TopoDS_Shape outer = BRepPrimAPI_MakeBox(gp_Pnt(-5000., -180., -2000.), gp_Pnt(5000., 5180., 3000.)).Shape();
|
||||
TopoDS_Shape inner = BRepPrimAPI_MakeBox(gp_Pnt(-4640., 180., 0.), gp_Pnt(4640., 4820., 3000.)).Shape();
|
||||
TopoDS_Shape window1 = BRepPrimAPI_MakeBox(gp_Pnt(-5000., -180., 400.), gp_Pnt( 500., 1180., 2000.)).Shape();
|
||||
TopoDS_Shape window2 = BRepPrimAPI_MakeBox(gp_Pnt( 2070., -180., 400.), gp_Pnt(3930., 180., 2000.)).Shape();
|
||||
|
||||
TopoDS_Shape building_shell = BRepAlgoAPI_Cut(
|
||||
BRepAlgoAPI_Cut(
|
||||
BRepAlgoAPI_Cut(outer, inner),
|
||||
window1
|
||||
),
|
||||
window2
|
||||
);
|
||||
|
||||
// Since the solid consists only of planar faces and straight edges it can be serialized as an
|
||||
// IfcFacetedBRep. If it would not be a polyhedron, serialise() can only be successful when linked
|
||||
// to the IFC4 model and with `advanced` set to `true` which introduces IfcAdvancedFace. It would
|
||||
// return `0` otherwise.
|
||||
IfcSchema::IfcProductDefinitionShape* building_shape = IfcGeom::serialise(building_shell, false);
|
||||
|
||||
file.addEntity(building_shape);
|
||||
IfcSchema::IfcRepresentation* rep = *building_shape->Representations()->begin();
|
||||
rep->setContextOfItems(file.getRepresentationContext("model"));
|
||||
|
||||
building->setRepresentation(building_shape);
|
||||
|
||||
// A pale white colour is assigned to the building.
|
||||
file.setSurfaceColour(
|
||||
building_shape, 0.75, 0.73, 0.68);
|
||||
|
||||
// For the ground mesh of the IfcSite we will use a Nurbs surface created in Open Cascade. Only
|
||||
// in IFC4 the surface can be directly serialized. In IFC2X3 the it will have to be tesselated.
|
||||
TopoDS_Shape shape;
|
||||
createGroundShape(shape);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::serialise(shape, true);
|
||||
if (!ground_representation) {
|
||||
ground_representation = IfcGeom::tesselate(shape, 100.);
|
||||
}
|
||||
file.getSingle<IfcSchema::IfcSite>()->setRepresentation(ground_representation);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr ground_reps = file.getSingle<IfcSchema::IfcSite>()->Representation()->Representations();
|
||||
for (IfcSchema::IfcRepresentation::list::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
|
||||
(*it)->setContextOfItems(file.getRepresentationContext("Model"));
|
||||
}
|
||||
file.addEntity(ground_representation);
|
||||
file.setSurfaceColour(ground_representation, 0.15, 0.25, 0.05);
|
||||
|
||||
/*
|
||||
// Note that IFC lacks elementary surfaces that STEP does have, such as spherical_surface.
|
||||
// BRepBuilderAPI_NurbsConvert can be used to serialize such surfaces as nurbs surfaces.
|
||||
TopoDS_Shape sphere = BRepPrimAPI_MakeSphere(gp_Pnt(), 1000.).Shape();
|
||||
IfcSchema::IfcProductDefinitionShape* sphere_representation = IfcGeom::serialise(sphere, true);
|
||||
if (S(IfcSchema::Identifier) == "IFC4") {
|
||||
sphere = BRepBuilderAPI_NurbsConvert(sphere, true).Shape();
|
||||
sphere_representation = IfcGeom::serialise(sphere, true);
|
||||
}
|
||||
*/
|
||||
|
||||
// Finally create a file stream for our output and write the IFC file to it.
|
||||
std::ofstream f("IfcAdvancedHouse.ifc");
|
||||
f << file;
|
||||
}
|
||||
|
||||
void createGroundShape(TopoDS_Shape& shape) {
|
||||
TColgp_Array2OfPnt cv (0, 4, 0, 4);
|
||||
cv.SetValue(0, 0, gp_Pnt(-10000, -10000, -4130));
|
||||
cv.SetValue(0, 1, gp_Pnt(-10000, -4330, -4130));
|
||||
cv.SetValue(0, 2, gp_Pnt(-10000, 0, -5130));
|
||||
cv.SetValue(0, 3, gp_Pnt(-10000, 4330, -7130));
|
||||
cv.SetValue(0, 4, gp_Pnt(-10000, 10000, -7130));
|
||||
cv.SetValue(1, 0, gp_Pnt( -3330, -10000, -5130));
|
||||
cv.SetValue(1, 1, gp_Pnt( -7670, -3670, 5000));
|
||||
cv.SetValue(1, 2, gp_Pnt( -9000, 0, 1000));
|
||||
cv.SetValue(1, 3, gp_Pnt( -7670, 7670, 6000));
|
||||
cv.SetValue(1, 4, gp_Pnt( -3330, 10000, -4130));
|
||||
cv.SetValue(2, 0, gp_Pnt( 0, -10000, -5530));
|
||||
cv.SetValue(2, 1, gp_Pnt( 0, -3670, 3000));
|
||||
cv.SetValue(2, 2, gp_Pnt( 0, 0, -12000));
|
||||
cv.SetValue(2, 3, gp_Pnt( 0, 7670, 1500));
|
||||
cv.SetValue(2, 4, gp_Pnt( 0, 10000, -4130));
|
||||
cv.SetValue(3, 0, gp_Pnt( 3330, -10000, -6130));
|
||||
cv.SetValue(3, 1, gp_Pnt( 7670, -3670, 6000));
|
||||
cv.SetValue(3, 2, gp_Pnt( 9000, 0, 5000));
|
||||
cv.SetValue(3, 3, gp_Pnt( 7670, 9000, 7000));
|
||||
cv.SetValue(3, 4, gp_Pnt( 3330, 10000, -4130));
|
||||
cv.SetValue(4, 0, gp_Pnt( 10000, -10000, -6130));
|
||||
cv.SetValue(4, 1, gp_Pnt( 10000, -4330, -5130));
|
||||
cv.SetValue(4, 2, gp_Pnt( 10000, 0, -4130));
|
||||
cv.SetValue(4, 3, gp_Pnt( 10000, 4330, -4130));
|
||||
cv.SetValue(4, 4, gp_Pnt( 10000, 10000, -8130));
|
||||
TColStd_Array1OfReal knots(0, 1);
|
||||
knots(0) = 0;
|
||||
knots(1) = 1;
|
||||
TColStd_Array1OfInteger mult(0, 1);
|
||||
mult(0) = 5;
|
||||
mult(1) = 5;
|
||||
Handle(Geom_BSplineSurface) surf = new Geom_BSplineSurface(cv, knots, knots, mult, mult, 4, 4);
|
||||
#if OCC_VERSION_HEX < 0x60502
|
||||
shape = BRepBuilderAPI_MakeFace(surf);
|
||||
#else
|
||||
shape = BRepBuilderAPI_MakeFace(surf, Precision::Confusion());
|
||||
#endif
|
||||
}
|
||||
+100
-159
@@ -41,25 +41,21 @@
|
||||
#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 IfcParse::IfcGlobalId guid;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
typedef std::pair<double, double> XY;
|
||||
boost::none_t const null = boost::none;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
// The creation of Nurbs-surface for the IfcSite mesh, to be implemented lateron
|
||||
void createGroundShape(TopoDS_Shape& shape);
|
||||
|
||||
int main() {
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
// The IfcHierarchyHelper is a subclass of the regular IfcFile that provides several
|
||||
// convenience functions for working with geometry in IFC files.
|
||||
IfcHierarchyHelper file;
|
||||
file.header().file_name().name("IfcOpenHouse.ifc");
|
||||
file.filename("IfcOpenHouse.ifc");
|
||||
|
||||
// Start by adding a wall to the file, initially leaving most attributes blank.
|
||||
IfcSchema::IfcWallStandardCase* south_wall = new IfcSchema::IfcWallStandardCase(
|
||||
@@ -87,23 +83,17 @@ int main() {
|
||||
// An IfcOwnerHistory has been initialized as well, which should be assigned to the wall.
|
||||
south_wall->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
// The wall will be shaped as a box, with the dimensions specified in millimeters. The resulting
|
||||
// product definition will consist of both a body representation as well as an axis representation
|
||||
// that runs over the centerline of the box in the X-axis.
|
||||
IfcSchema::IfcProductDefinitionShape* south_wall_shape = file.addAxisBox(10000, 360, 3000);
|
||||
|
||||
// Obtain a reference to the placement of the IfcBuildingStorey in order to create a hierarchy
|
||||
// of placements for the products
|
||||
IfcSchema::IfcObjectPlacement* storey_placement = file.getSingle<IfcSchema::IfcBuildingStorey>()->ObjectPlacement();
|
||||
// The wall will be shaped as a box, with the dimensions specified in millimeters.
|
||||
IfcSchema::IfcProductDefinitionShape* south_wall_shape = file.addBox(10000, 360, 3000);
|
||||
|
||||
// The shape has to be assigned to the representation of the wall and is placed at the origin
|
||||
// of the coordinate system.
|
||||
south_wall->setRepresentation(south_wall_shape);
|
||||
south_wall->setObjectPlacement(file.addLocalPlacement(storey_placement));
|
||||
south_wall->setObjectPlacement(file.addLocalPlacement());
|
||||
|
||||
// A pale white colour is assigned to the wall.
|
||||
IfcSchema::IfcPresentationStyleAssignment* wall_colour = file.setSurfaceColour(
|
||||
south_wall_shape, 0.75, 0.73, 0.68);
|
||||
south_wall->Representation(), 0.75, 0.73, 0.68);
|
||||
|
||||
// Now create a footing for the wall to rest on.
|
||||
IfcSchema::IfcFooting* footing = new IfcSchema::IfcFooting(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
@@ -114,125 +104,90 @@ int main() {
|
||||
// The footing will span the entire floor plan of our building. The IfcRepresentationContext is
|
||||
// something that has been created automatically as well, but representations could have been
|
||||
// assigned to a specific context, for example to add a two dimensional plan representation as well.
|
||||
footing->setRepresentation(file.addBox(10100, 5460, 2000));
|
||||
footing->setObjectPlacement(file.addLocalPlacement(storey_placement, 0, 2500, -2000));
|
||||
footing->setRepresentation(file.addBox(10100, 5460, 2000, 0, 0, 0, file.getSingle<IfcSchema::IfcRepresentationContext>()));
|
||||
footing->setObjectPlacement(file.addLocalPlacement(0, 2500, -2000));
|
||||
// The footing will have a dark gray colour
|
||||
IfcSchema::IfcPresentationStyleAssignment* footing_colour = file.setSurfaceColour(footing->Representation(), 0.26, 0.22, 0.18);
|
||||
|
||||
// IFC has two ways to apply boolean operations to geometry. IfcBooleanResults are commonly used
|
||||
// to clip geometry to a surface, for example to a slanted roof. For openings that are filled
|
||||
// with another element, for example a door or a window, an IfcOpeningElement is used instead.
|
||||
|
||||
// An opening element is created with rectangular geometry:
|
||||
// An opening element is created with rectangular geometry
|
||||
IfcSchema::IfcOpeningElement* west_opening = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, file.addLocalPlacement(south_wall->ObjectPlacement(), -2500, 0, 400),
|
||||
file.addBox(6000, 3630, 1600), null
|
||||
null, null, null, file.addLocalPlacement(-2500, 0, 400),
|
||||
file.addBox(6000, 3630, 1600, 0, 0, 0, file.getSingle<IfcSchema::IfcRepresentationContext>()), null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING
|
||||
#endif
|
||||
);
|
||||
file.addEntity(west_opening);
|
||||
file.AddEntity(west_opening);
|
||||
|
||||
// Relate the opening element to the wall.
|
||||
IfcSchema::IfcRelVoidsElement* void_element = new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, south_wall, west_opening);
|
||||
file.addEntity(void_element);
|
||||
file.AddEntity(void_element);
|
||||
|
||||
// Now create an additional opening
|
||||
IfcSchema::IfcOpeningElement* south_opening = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, file.addLocalPlacement(storey_placement, 3000, 0, 400),
|
||||
file.addBox(1860, 3000, 1600), null
|
||||
null, null, null, file.addLocalPlacement(3000, 0, 400),
|
||||
file.addBox(1860, 3000, 1600, 0, 0, 0, file.getSingle<IfcSchema::IfcRepresentationContext>()), null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING
|
||||
#endif
|
||||
);
|
||||
file.addEntity(south_opening);
|
||||
file.addEntity(new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, south_wall, south_opening));
|
||||
file.AddEntity(south_opening);
|
||||
file.AddEntity(new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, south_wall, south_opening));
|
||||
|
||||
// Create a roof element
|
||||
IfcSchema::IfcRoof* south_roof = new IfcSchema::IfcRoof(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("South roof"), null, null,
|
||||
0, 0, null, IfcSchema::IfcRoofTypeEnum::IfcRoofType_GABLE_ROOF);
|
||||
|
||||
// Create a roof element that will consist of two slabs:
|
||||
IfcSchema::IfcRoof* roof = new IfcSchema::IfcRoof(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("Roof"), null, null,
|
||||
file.addLocalPlacement(storey_placement), 0, null, IfcSchema::IfcRoofTypeEnum::IfcRoofType_GABLE_ROOF);
|
||||
|
||||
// The roof geometry is slanted 45 degrees by specifying a direction for the box extrusion
|
||||
IfcSchema::IfcShapeRepresentation* roof_rep = file.addEmptyRepresentation();
|
||||
file.addBox(roof_rep, 10200, 360, sqrt(2.0*2900*2900), 0, file.addPlacement3d(0, 0, 0, 0, 1, 0),
|
||||
file.addTriplet<IfcSchema::IfcDirection>(0, -sqrt(0.5), sqrt(0.5)));
|
||||
south_roof->setRepresentation(file.addBox(10200, 360, sqrt(2.0*2900*2900), 0, file.addPlacement3d(0, 0, 0, 0, 1, 0),
|
||||
file.addTriplet<IfcSchema::IfcDirection>(0, -sqrt(0.5), sqrt(0.5)), file.getSingle<IfcSchema::IfcRepresentationContext>()));
|
||||
south_roof->setObjectPlacement(file.addLocalPlacement(0, -400, 2700));
|
||||
file.addBuildingProduct(south_roof);
|
||||
|
||||
// CV-2x3-144: Roofs are aggregates and shall have at least one contained element and no own geometry
|
||||
IfcSchema::IfcSlab* south_roof_part = new IfcSchema::IfcSlab(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("South roof"),
|
||||
null, null, 0, 0, null, IfcSchema::IfcSlabTypeEnum::IfcSlabType_ROOF);
|
||||
|
||||
// The geometry is instantiated by using IfcMappedItems. This way geometry definitions can
|
||||
// be reused while maintaining the cardinality constraint that the ShapeOfProduct relation
|
||||
// imposes on the IfcProductDefinitionShape. Note that this constrained is lifted in IFC4.
|
||||
south_roof_part->setRepresentation(file.addMappedItem(roof_rep));
|
||||
south_roof_part->setObjectPlacement(file.addLocalPlacement(roof->ObjectPlacement(), 0, -400, 2700));
|
||||
|
||||
// The same roof geometry is re-used on the north side of the roof, by inverting the X-axis of
|
||||
// the local placement the roof is rotated 180 degrees around the Z-axis
|
||||
IfcSchema::IfcSlab* north_roof_part = new IfcSchema::IfcSlab(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("North roof"),
|
||||
null, null, 0, 0, null, IfcSchema::IfcSlabTypeEnum::IfcSlabType_ROOF);
|
||||
north_roof_part->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
north_roof_part->setRepresentation(file.addMappedItem(roof_rep));
|
||||
north_roof_part->setObjectPlacement(file.addLocalPlacement(roof->ObjectPlacement(), 0, 5400, 2700, 0, 0, 1, -1, 0, 0));
|
||||
|
||||
IfcSchema::IfcObjectDefinition::list::ptr roof_parts(new IfcSchema::IfcObjectDefinition::list);
|
||||
roof_parts->push(south_roof_part);
|
||||
roof_parts->push(north_roof_part);
|
||||
IfcSchema::IfcRelDecomposes* roof_decomposition = new IfcSchema::IfcRelAggregates(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, roof, roof_parts);
|
||||
file.addEntity(roof_decomposition);
|
||||
IfcSchema::IfcRoof* north_roof = new IfcSchema::IfcRoof(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("North roof"),
|
||||
null, null, 0, 0, null, IfcSchema::IfcRoofTypeEnum::IfcRoofType_GABLE_ROOF);
|
||||
north_roof->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
north_roof->setRepresentation(south_roof->Representation());
|
||||
north_roof->setObjectPlacement(file.addLocalPlacement(0, 5400, 2700, 0, 0, 1, -1, 0, 0));
|
||||
file.addBuildingProduct(north_roof);
|
||||
|
||||
file.addBuildingProduct(south_roof_part);
|
||||
file.addBuildingProduct(north_roof_part);
|
||||
file.addBuildingProduct(roof);
|
||||
|
||||
file.setSurfaceColour(roof_rep, 0.24, 0.08, 0.04);
|
||||
// By specifying a surface style for the south part of the roof, it gets assigned to the other
|
||||
// roof part as well, because they share the same representation.
|
||||
file.setSurfaceColour(south_roof->Representation(), 0.24, 0.08, 0.04);
|
||||
|
||||
// Copy the south wall to the north
|
||||
IfcSchema::IfcWallStandardCase* north_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("North wall"),
|
||||
null, null, file.addLocalPlacement(storey_placement, 0, 5000, 0), file.addAxisBox(10000, 360, 3000), null
|
||||
file.addBuildingProduct(new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("North wall"),
|
||||
null, null, file.addLocalPlacement(0, 5000, 0), south_wall->Representation(), null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
|
||||
#endif
|
||||
);
|
||||
file.addBuildingProduct(north_wall);
|
||||
file.setSurfaceColour(north_wall->Representation(), wall_colour);
|
||||
|
||||
// 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), clipped_wall_body_reps[0], null
|
||||
S("East wall"), null, null, file.addLocalPlacement(4820, 2500, 0, 0, 0, 1, 0, 1, 0), file.addBox(5000, 360, 6000), null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
|
||||
#endif
|
||||
);
|
||||
file.addBuildingProduct(east_wall);
|
||||
|
||||
// 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(east_wall->Representation(), file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false);
|
||||
file.clipRepresentation(east_wall->Representation(), file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false);
|
||||
|
||||
file.setSurfaceColour(east_wall->Representation(), 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), clipped_wall_body_reps[1], null
|
||||
S("West wall"), null, null, file.addLocalPlacement(-4820, 2500, 0, 0, 0, 1, 0, -1, 0), east_wall->Representation(), null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
|
||||
#endif
|
||||
@@ -244,30 +199,27 @@ int main() {
|
||||
// wall will not feature this opening.
|
||||
// NB: an Opening Element can only be used to create a single void within a single Element, as per:
|
||||
// http://www.buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcproductextension/lexical/ifcfeatureelementsubtraction.htm
|
||||
|
||||
// Not all viewers support opening elements with mapped representations, hence an exact copy of the
|
||||
// same subtraction box is instantiated for the otherwise identical opening element.
|
||||
IfcSchema::IfcOpeningElement* west_opening_copy = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, file.addLocalPlacement(west_wall->ObjectPlacement(), 2500, -2500+4820, 400, 0, 0, 1, 0, 1, 0),
|
||||
file.addBox(6000, 3630, 1600), null
|
||||
null, null, null, west_opening->ObjectPlacement(), west_opening->Representation(), null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING
|
||||
#endif
|
||||
);
|
||||
file.addEntity(west_opening_copy);
|
||||
file.addEntity(new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, west_wall, west_opening_copy));
|
||||
file.AddEntity(west_opening_copy);
|
||||
file.AddEntity(new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, west_wall, west_opening_copy));
|
||||
|
||||
// Up until now we have only used simple extrusions for the creation of the geometry. For the
|
||||
// ground mesh of the IfcSite we will use a Nurbs surface created in Open Cascade. The surface
|
||||
// will be tesselated using the deflection specified.
|
||||
TopoDS_Shape shape;
|
||||
createGroundShape(shape);
|
||||
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::tesselate(shape, 100.);
|
||||
IfcEntities geometrical_entities(new IfcEntityList());
|
||||
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::tesselate(shape, 100., geometrical_entities);
|
||||
file.getSingle<IfcSchema::IfcSite>()->setRepresentation(ground_representation);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr ground_reps = file.getSingle<IfcSchema::IfcSite>()->Representation()->Representations();
|
||||
for (IfcSchema::IfcRepresentation::list::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
|
||||
(*it)->setContextOfItems(file.getRepresentationContext("Model"));
|
||||
file.AddEntities(geometrical_entities);
|
||||
IfcSchema::IfcShapeRepresentation::list ground_reps = geometrical_entities->as<IfcSchema::IfcShapeRepresentation>();
|
||||
for (IfcSchema::IfcShapeRepresentation::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
|
||||
(*it)->setContextOfItems(file.getSingle<IfcSchema::IfcRepresentationContext>());
|
||||
}
|
||||
file.setSurfaceColour(ground_representation, 0.15, 0.25, 0.05);
|
||||
|
||||
@@ -294,7 +246,7 @@ int main() {
|
||||
, null
|
||||
#endif
|
||||
);
|
||||
IfcSchema::IfcMaterialLayer::list::ptr layers (new IfcTemplatedEntityList<IfcSchema::IfcMaterialLayer>());
|
||||
IfcSchema::IfcMaterialLayer::list layers (new IfcTemplatedEntityList<IfcSchema::IfcMaterialLayer>());
|
||||
layers->push(layer);
|
||||
IfcSchema::IfcMaterialLayerSet* layer_set = new IfcSchema::IfcMaterialLayerSet(
|
||||
layers,
|
||||
@@ -319,17 +271,17 @@ int main() {
|
||||
null,
|
||||
null,
|
||||
#ifdef USE_IFC4
|
||||
file.entitiesByType<IfcSchema::IfcWallStandardCase>()->generalize(),
|
||||
file.EntitiesByType<IfcSchema::IfcWallStandardCase>()->generalize(),
|
||||
#else
|
||||
file.entitiesByType<IfcSchema::IfcWallStandardCase>()->as<IfcSchema::IfcRoot>(),
|
||||
file.EntitiesByType<IfcSchema::IfcWallStandardCase>()->as<IfcSchema::IfcRoot>(),
|
||||
#endif
|
||||
layer_usage);
|
||||
|
||||
file.addEntity(material);
|
||||
file.addEntity(layer);
|
||||
file.addEntity(layer_set);
|
||||
file.addEntity(layer_usage);
|
||||
file.addEntity(associates_material);
|
||||
file.AddEntity(material);
|
||||
file.AddEntity(layer);
|
||||
file.AddEntity(layer_set);
|
||||
file.AddEntity(layer_usage);
|
||||
file.AddEntity(associates_material);
|
||||
|
||||
// In addition, another common way to represent geometry in IFC files is to use extrusions of
|
||||
// planar areas bounded by a polygon.
|
||||
@@ -341,7 +293,7 @@ int main() {
|
||||
stair_points.push_back(XY(500, 400));
|
||||
stair_points.push_back(XY( 0, 400));
|
||||
IfcSchema::IfcStairFlight* stair = new IfcSchema::IfcStairFlight(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, file.addLocalPlacement(storey_placement, 5050, 1000, 0, 0, 1, 0, 1, 0, 0),
|
||||
null, null, null, file.addLocalPlacement(5050, 1000, 0, 0, 1, 0, 1, 0, 0),
|
||||
file.addExtrudedPolyline(stair_points, 1200), null, 2, 2, 0.2, 0.25
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcStairFlightTypeEnum::IfcStairFlightType_STRAIGHT
|
||||
@@ -352,19 +304,19 @@ int main() {
|
||||
file.setSurfaceColour(stair->Representation(), footing_colour);
|
||||
|
||||
IfcSchema::IfcOpeningElement* door_opening = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, file.addLocalPlacement(storey_placement, 5000-180, 2500-900, 0), file.addBox(1000, 1000, 2200), null
|
||||
null, null, null, file.addLocalPlacement(5000-180, 2500-900, 0), file.addBox(1000, 1000, 2200), null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING
|
||||
#endif
|
||||
);
|
||||
file.addEntity(door_opening);
|
||||
file.addEntity(new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, east_wall, door_opening));
|
||||
file.AddEntity(door_opening);
|
||||
file.AddEntity(new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, east_wall, door_opening));
|
||||
|
||||
// A single shape representation can contain multiple representiation items. This way a product
|
||||
// can be a composition of multiple solids. The following door will be composed of four boxes
|
||||
// which constitute the door and its frame.
|
||||
IfcSchema::IfcDoor* door = new IfcSchema::IfcDoor(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, null,
|
||||
file.addLocalPlacement(storey_placement, 4800, 1600, 0, 0, 0, 1, 0, 1, 0), 0, null, 2200, 1000
|
||||
file.addLocalPlacement(4800, 1600, 0, 0, 0, 1, 0, 1, 0), 0, null, 2200, 1000
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcDoorTypeEnum::IfcDoorType_DOOR
|
||||
, IfcSchema::IfcDoorTypeOperationEnum::IfcDoorTypeOperation_SINGLE_SWING_LEFT
|
||||
@@ -372,9 +324,9 @@ int main() {
|
||||
#endif
|
||||
);
|
||||
door->setRepresentation(file.addBox(80, 80, 2120, 0, file.addPlacement3d(460, 0, 0)));
|
||||
IfcSchema::IfcRepresentation::list::ptr door_representations = door->Representation()->Representations();
|
||||
IfcSchema::IfcRepresentation::list door_representations = door->Representation()->Representations();
|
||||
IfcSchema::IfcShapeRepresentation* door_body = 0;
|
||||
for (IfcSchema::IfcRepresentation::list::it i = door_representations->begin(); i != door_representations->end(); ++i) {
|
||||
for (IfcSchema::IfcRepresentation::it i = door_representations->begin(); i != door_representations->end(); ++i) {
|
||||
IfcSchema::IfcRepresentation* rep = *i;
|
||||
if (rep->is(IfcSchema::Type::IfcShapeRepresentation) && rep->RepresentationIdentifier() == "Body") {
|
||||
door_body = (IfcSchema::IfcShapeRepresentation*) rep;
|
||||
@@ -385,11 +337,7 @@ int main() {
|
||||
file.addBox(door_body, 860, 30, 2120);
|
||||
file.addBuildingProduct(door);
|
||||
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);
|
||||
file.AddEntity(new IfcSchema::IfcRelFillsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, door_opening, 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
|
||||
@@ -402,39 +350,32 @@ int main() {
|
||||
// Therefore the OverallWidth and OverallHeight of the window attributes will need to
|
||||
// match the bounding box of the representation. Furthermore, the window placement needs
|
||||
// to align with the lowerleft corner of the constituent parts.
|
||||
IfcSchema::IfcShapeRepresentation::list::ptr frame_representations(new IfcSchema::IfcShapeRepresentation::list);
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* horizontal_bar = file.addEmptyRepresentation();
|
||||
IfcSchema::IfcShapeRepresentation* vertical_bar = file.addEmptyRepresentation();
|
||||
file.addBox(horizontal_bar, 1860, 90, 90);
|
||||
file.addBox(vertical_bar, 90, 90, 1420);
|
||||
|
||||
frame_representations->push(horizontal_bar);
|
||||
frame_representations->push(horizontal_bar); // Add another reference to the horizontal bar created above
|
||||
frame_representations->push(vertical_bar);
|
||||
frame_representations->push(vertical_bar); // Add another reference to the vertical bar created above
|
||||
IfcSchema::IfcProductDefinitionShape::list frame_representations (new IfcTemplatedEntityList<IfcSchema::IfcProductDefinitionShape>());
|
||||
frame_representations->push(file.addBox(1860, 90, 90));
|
||||
frame_representations->push(*frame_representations->begin()); // Add a reference to the shape created above
|
||||
frame_representations->push(file.addBox(90, 90, 1420));
|
||||
frame_representations->push(*(frame_representations->end()-1)); // Add a reference to the shape created above
|
||||
|
||||
// The beams all have the same surface style assigned
|
||||
IfcSchema::IfcPresentationStyleAssignment* frame_style = 0;
|
||||
for (IfcSchema::IfcShapeRepresentation::list::it i = frame_representations->begin(); i != frame_representations->end(); i += 2) {
|
||||
for (IfcSchema::IfcProductDefinitionShape::it i = frame_representations->begin(); i != frame_representations->end(); ++i) {
|
||||
if (frame_style) {
|
||||
file.setSurfaceColour(*i, frame_style);
|
||||
} else {
|
||||
frame_style = file.setSurfaceColour(*i, 0.5, 0.4, 0.3);
|
||||
}
|
||||
// Because of the duplication the iterator is incremented twice
|
||||
}
|
||||
|
||||
// This window will be placed at five locations within the building. A list of placements is
|
||||
// created and is iterated over to create all window instances.
|
||||
IfcSchema::IfcLocalPlacement::list::ptr window_placements (new IfcSchema::IfcLocalPlacement::list);
|
||||
window_placements->push(file.addLocalPlacement(storey_placement, 2*-1770-430-930, -45, 400));
|
||||
window_placements->push(file.addLocalPlacement(storey_placement, -1770-430-930, -45, 400));
|
||||
window_placements->push(file.addLocalPlacement(storey_placement, -430-930, -45, 400));
|
||||
window_placements->push(file.addLocalPlacement(storey_placement, 3000-930, -45, 400));
|
||||
window_placements->push(file.addLocalPlacement(storey_placement, -4855+45, 885-930, 400, 0, 0, 1, 0, 1, 0));
|
||||
IfcSchema::IfcLocalPlacement::list window_placements (new IfcTemplatedEntityList<IfcSchema::IfcLocalPlacement>());
|
||||
window_placements->push(file.addLocalPlacement(2*-1770-430-930, -45, 400));
|
||||
window_placements->push(file.addLocalPlacement( -1770-430-930, -45, 400));
|
||||
window_placements->push(file.addLocalPlacement( -430-930, -45, 400));
|
||||
window_placements->push(file.addLocalPlacement( 3000-930, -45, 400));
|
||||
window_placements->push(file.addLocalPlacement( -4855+45, 885-930, 400, 0, 0, 1, 0, 1, 0));
|
||||
|
||||
for (IfcSchema::IfcLocalPlacement::list::it it = window_placements->begin(); it != window_placements->end(); ++it) {
|
||||
for (IfcSchema::IfcLocalPlacement::it it = window_placements->begin(); it != window_placements->end(); ++it) {
|
||||
|
||||
// Create the window at the current location
|
||||
IfcSchema::IfcLocalPlacement* place = *it;
|
||||
@@ -449,42 +390,42 @@ int main() {
|
||||
file.addBuildingProduct(window);
|
||||
|
||||
// Initalize a list of parts for the window to be composed of
|
||||
IfcSchema::IfcObjectDefinition::list::ptr window_parts(new IfcTemplatedEntityList<IfcSchema::IfcObjectDefinition>());
|
||||
IfcSchema::IfcObjectDefinition::list window_parts(new IfcTemplatedEntityList<IfcSchema::IfcObjectDefinition>());
|
||||
|
||||
// The placements for the beams are not shared accross the different windows because every
|
||||
// beam is placed relative to its parent window entity.
|
||||
IfcSchema::IfcLocalPlacement::list::ptr frame_placements (new IfcTemplatedEntityList<IfcSchema::IfcLocalPlacement>());
|
||||
frame_placements->push(file.addLocalPlacement(storey_placement, 930,45));
|
||||
frame_placements->push(file.addLocalPlacement(storey_placement, 930, 45, 1510));
|
||||
frame_placements->push(file.addLocalPlacement(storey_placement, -885+930, 45, 90));
|
||||
frame_placements->push(file.addLocalPlacement(storey_placement, 885+930, 45, 90));
|
||||
IfcSchema::IfcLocalPlacement::list frame_placements (new IfcTemplatedEntityList<IfcSchema::IfcLocalPlacement>());
|
||||
frame_placements->push(file.addLocalPlacement( 930,45));
|
||||
frame_placements->push(file.addLocalPlacement( 930, 45, 1510));
|
||||
frame_placements->push(file.addLocalPlacement(-885+930, 45, 90));
|
||||
frame_placements->push(file.addLocalPlacement( 885+930, 45, 90));
|
||||
|
||||
// Now iterate over the placements and representations of the beam and add them to list of parts
|
||||
IfcSchema::IfcLocalPlacement::list::it frame_placement;
|
||||
IfcSchema::IfcShapeRepresentation::list::it frame_representation;
|
||||
IfcSchema::IfcLocalPlacement::it frame_placement;
|
||||
IfcSchema::IfcProductDefinitionShape::it frame_representation;
|
||||
for (frame_placement = frame_placements->begin(), frame_representation = frame_representations->begin();
|
||||
frame_placement != frame_placements->end() && frame_representation != frame_representations->end();
|
||||
++frame_placement, ++frame_representation)
|
||||
{
|
||||
IfcSchema::IfcMember* frame_part = new IfcSchema::IfcMember(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, *frame_placement, file.addMappedItem(*frame_representation), null
|
||||
null, null, null, *frame_placement, *frame_representation, null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcMemberTypeEnum::IfcMemberType_MULLION
|
||||
#endif
|
||||
);
|
||||
file.addEntity(frame_part);
|
||||
file.AddEntity(frame_part);
|
||||
window_parts->push(frame_part);
|
||||
file.relatePlacements(window, frame_part);
|
||||
}
|
||||
|
||||
// Add the glass plate to the list of parts
|
||||
IfcSchema::IfcPlate* glass_part = new IfcSchema::IfcPlate(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null,
|
||||
null, null, file.addLocalPlacement(storey_placement, 930, 45, 90), file.addBox(1680, 10, 1420), null
|
||||
null, null, file.addLocalPlacement(930, 45, 90), file.addBox(1680, 10, 1420), null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcPlateTypeEnum::IfcPlateType_SHEET
|
||||
#endif
|
||||
);
|
||||
file.addEntity(glass_part);
|
||||
file.AddEntity(glass_part);
|
||||
window_parts->push(glass_part);
|
||||
file.relatePlacements(window, glass_part);
|
||||
file.setSurfaceColour(glass_part->Representation(), 0.6, 0.7, 0.75, 0.1);
|
||||
@@ -493,7 +434,7 @@ int main() {
|
||||
// tools will consider the window a single entity that can be selected as a whole.
|
||||
IfcSchema::IfcRelDecomposes* decomposition = new IfcSchema::IfcRelAggregates(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, window, window_parts);
|
||||
file.addEntity(decomposition);
|
||||
file.AddEntity(decomposition);
|
||||
}
|
||||
|
||||
// Finally create a file stream for our output and write the IFC file to it.
|
||||
@@ -538,6 +479,6 @@ void createGroundShape(TopoDS_Shape& shape) {
|
||||
#if OCC_VERSION_HEX < 0x60502
|
||||
shape = BRepBuilderAPI_MakeFace(surf);
|
||||
#else
|
||||
shape = BRepBuilderAPI_MakeFace(surf, Precision::Confusion());
|
||||
shape = BRepBuilderAPI_MakeFace(surf, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -17,12 +17,9 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../ifcparse/IfcParse.h"
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
#endif
|
||||
|
||||
using namespace IfcSchema;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
@@ -44,7 +41,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
// Lets get a list of IfcBuildingElements, this is the parent
|
||||
// type of things like walls, windows and doors.
|
||||
// entitiesByType is a templated function and returns a
|
||||
// EntitiesByType is a templated function and returns a
|
||||
// templated class that behaves like a std::vector.
|
||||
// Note that the return types are all typedef'ed as members of
|
||||
// the generated classes, ::list for the templated vector class,
|
||||
@@ -58,17 +55,17 @@ int main(int argc, char** argv) {
|
||||
// we need to cast them to IfcWindows. Since these properties
|
||||
// are optional we need to make sure the properties are
|
||||
// defined for the window in question before accessing them.
|
||||
IfcBuildingElement::list::ptr elements = file.entitiesByType<IfcBuildingElement>();
|
||||
IfcBuildingElement::list elements = file.EntitiesByType<IfcBuildingElement>();
|
||||
|
||||
std::cout << "Found " << elements->size() << " elements in " << argv[1] << ":" << std::endl;
|
||||
std::cout << "Found " << elements->Size() << " elements in " << argv[1] << ":" << std::endl;
|
||||
|
||||
for ( IfcBuildingElement::list::it it = elements->begin(); it != elements->end(); ++ it ) {
|
||||
for ( IfcBuildingElement::it it = elements->begin(); it != elements->end(); ++ it ) {
|
||||
|
||||
const IfcBuildingElement* element = *it;
|
||||
const IfcBuildingElement::ptr element = *it;
|
||||
std::cout << element->entity->toString() << std::endl;
|
||||
|
||||
if ( element->is(IfcWindow::Class()) ) {
|
||||
const IfcWindow* window = (IfcWindow*)element;
|
||||
const IfcWindow::ptr window = reinterpret_pointer_cast<IfcBuildingElement,IfcWindow>(element);
|
||||
|
||||
if ( window->hasOverallWidth() && window->hasOverallHeight() ) {
|
||||
const double area = window->OverallWidth()*window->OverallHeight();
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
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(0, 120 * i++));
|
||||
product->setObjectPlacement(file.addLocalPlacement(120 * i++));
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
items->push(item);
|
||||
|
||||
if (s == "GeometricSet") {
|
||||
IfcSchema::IfcGeometricSet* set = new IfcSchema::IfcGeometricSet(items->generalize());
|
||||
file.addEntity(set);
|
||||
items = IfcSchema::IfcRepresentationItem::list::ptr(new IfcSchema::IfcRepresentationItem::list());
|
||||
file.AddEntity(set);
|
||||
items = IfcSchema::IfcRepresentationItem::list(new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
items->push(set);
|
||||
}
|
||||
|
||||
@@ -60,21 +60,21 @@ 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(boost::none, boost::none, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
file.AddEntity(rep);
|
||||
file.AddEntity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
}
|
||||
|
||||
void create_surfaces_from_profile(IfcHierarchyHelper& file, IfcSchema::IfcProfileDef* profile) {
|
||||
IfcSchema::IfcSurfaceOfLinearExtrusion* extrusion = new IfcSchema::IfcSurfaceOfLinearExtrusion(profile, file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 100.);
|
||||
file.addEntity(extrusion);
|
||||
file.AddEntity(extrusion);
|
||||
|
||||
IfcSchema::IfcAxis1Placement* ax1 = new IfcSchema::IfcAxis1Placement(file.addTriplet<IfcSchema::IfcCartesianPoint>(0,100,0), file.addTriplet<IfcSchema::IfcDirection>(1,0,0));
|
||||
IfcSchema::IfcSurfaceOfRevolution* revolution = new IfcSchema::IfcSurfaceOfRevolution(profile, file.addPlacement3d(), ax1);
|
||||
file.addEntity(ax1);
|
||||
file.addEntity(revolution);
|
||||
file.AddEntity(ax1);
|
||||
file.AddEntity(revolution);
|
||||
|
||||
create_product_from_item(file, extrusion, "GeometricSet");
|
||||
create_product_from_item(file, revolution, "GeometricSet");
|
||||
@@ -82,14 +82,14 @@ void create_surfaces_from_profile(IfcHierarchyHelper& file, IfcSchema::IfcProfil
|
||||
|
||||
void create_solids_from_profile(IfcHierarchyHelper& file, IfcSchema::IfcProfileDef* profile) {
|
||||
IfcSchema::IfcExtrudedAreaSolid* extrusion = new IfcSchema::IfcExtrudedAreaSolid(profile, file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 100.);
|
||||
file.addEntity(extrusion);
|
||||
file.AddEntity(extrusion);
|
||||
|
||||
IfcSchema::IfcAxis1Placement* ax1 = new IfcSchema::IfcAxis1Placement(file.addTriplet<IfcSchema::IfcCartesianPoint>(0,100,0), file.addTriplet<IfcSchema::IfcDirection>(1,0,0));
|
||||
IfcSchema::IfcRevolvedAreaSolid* revolution1 = new IfcSchema::IfcRevolvedAreaSolid(profile, file.addPlacement3d(), ax1, 360.);
|
||||
IfcSchema::IfcRevolvedAreaSolid* revolution2 = new IfcSchema::IfcRevolvedAreaSolid(profile, file.addPlacement3d(), ax1, 90.);
|
||||
file.addEntity(ax1);
|
||||
file.addEntity(revolution1);
|
||||
file.addEntity(revolution2);
|
||||
file.AddEntity(ax1);
|
||||
file.AddEntity(revolution1);
|
||||
file.AddEntity(revolution2);
|
||||
|
||||
create_product_from_item(file, extrusion, "SweptSolid");
|
||||
create_product_from_item(file, revolution1, "SweptSolid");
|
||||
@@ -99,8 +99,8 @@ void create_solids_from_profile(IfcHierarchyHelper& file, IfcSchema::IfcProfileD
|
||||
void create_products_from_curve(IfcHierarchyHelper& file, IfcSchema::IfcBoundedCurve* curve) {
|
||||
IfcSchema::IfcArbitraryOpenProfileDef* open = new IfcSchema::IfcArbitraryOpenProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_CURVE, null, curve);
|
||||
IfcSchema::IfcCenterLineProfileDef* center_line = new IfcSchema::IfcCenterLineProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, null, curve, 10.);
|
||||
file.addEntity(open);
|
||||
file.addEntity(center_line);
|
||||
file.AddEntity(open);
|
||||
file.AddEntity(center_line);
|
||||
|
||||
create_surfaces_from_profile(file, open);
|
||||
create_solids_from_profile(file, center_line);
|
||||
@@ -109,27 +109,27 @@ void create_products_from_curve(IfcHierarchyHelper& file, IfcSchema::IfcBoundedC
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "IfcArbitraryOpenProfileDef.ifc";
|
||||
IfcHierarchyHelper file;
|
||||
file.header().file_name().name(filename);
|
||||
file.filename(filename);
|
||||
|
||||
double coords1[] = {-50.0, 0.0};
|
||||
double coords2[] = { 50.0, 0.0};
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list());
|
||||
IfcSchema::IfcCartesianPoint::list points (new IfcTemplatedEntityList<IfcSchema::IfcCartesianPoint>());
|
||||
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());
|
||||
file.AddEntities(points->generalize());
|
||||
IfcSchema::IfcPolyline* poly = new IfcSchema::IfcPolyline(points);
|
||||
file.addEntity(poly);
|
||||
file.AddEntity(poly);
|
||||
|
||||
create_products_from_curve(file, poly);
|
||||
|
||||
IfcSchema::IfcEllipse* ellipse = new IfcSchema::IfcEllipse(file.addPlacement2d(), 50., 25.);
|
||||
file.addEntity(ellipse);
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
trim1->push(new IfcSchema::IfcParameterValue( 0.));
|
||||
trim2->push(new IfcSchema::IfcParameterValue(180.));
|
||||
file.AddEntity(ellipse);
|
||||
IfcEntities trim1(new IfcEntityList());
|
||||
IfcEntities trim2(new IfcEntityList());
|
||||
trim1->push(new IfcWrite::IfcSelectHelper( 0., Ifc2x3::Type::IfcParameterValue));
|
||||
trim2->push(new IfcWrite::IfcSelectHelper(180., Ifc2x3::Type::IfcParameterValue));
|
||||
IfcSchema::IfcTrimmedCurve* trim = new IfcSchema::IfcTrimmedCurve(ellipse, trim1, trim2, true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
file.addEntity(trim);
|
||||
file.AddEntity(trim);
|
||||
|
||||
create_products_from_curve(file, trim);
|
||||
|
||||
|
||||
@@ -32,19 +32,19 @@
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "IfcCompositeProfileDef.ifc";
|
||||
IfcHierarchyHelper file;
|
||||
file.header().file_name().name(filename);
|
||||
file.filename(filename);
|
||||
|
||||
double coords1[] = {100.0, 0.0};
|
||||
double coords2[] = {200.0, 0.0};
|
||||
double coords3[] = {300.0, 0.0};
|
||||
|
||||
IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list());
|
||||
IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
|
||||
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);
|
||||
@@ -65,11 +65,11 @@ int main(int argc, char** argv) {
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, file.addPlacement2d(80.), 50.0, 25.0, 5.0, 10.0, 2.0, null);
|
||||
|
||||
file.addEntity(p2);
|
||||
file.addEntity(p3);
|
||||
file.AddEntity(p2);
|
||||
file.AddEntity(p3);
|
||||
|
||||
file.addEntity(transform1);
|
||||
file.addEntity(transform2);
|
||||
file.AddEntity(transform1);
|
||||
file.AddEntity(transform2);
|
||||
|
||||
IfcSchema::IfcDerivedProfileDef* p5 = new IfcSchema::IfcDerivedProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, null, p2, transform1, null);
|
||||
IfcSchema::IfcDerivedProfileDef* p6 = new IfcSchema::IfcDerivedProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, null, p3, transform2, null);
|
||||
@@ -79,7 +79,7 @@ int main(int argc, char** argv) {
|
||||
profiles->push(p6);
|
||||
profiles->push(p4);
|
||||
|
||||
file.addEntities(profiles->generalize());
|
||||
file.AddEntities(profiles->generalize());
|
||||
|
||||
IfcSchema::IfcCompositeProfileDef* composite = new IfcSchema::IfcCompositeProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, S("IFC"), profiles, null);
|
||||
|
||||
@@ -95,20 +95,20 @@ int main(int argc, char** argv) {
|
||||
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(composite,
|
||||
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
|
||||
|
||||
file.addEntity(composite);
|
||||
file.addEntity(solid);
|
||||
file.AddEntity(composite);
|
||||
file.AddEntity(solid);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
|
||||
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(boost::none, boost::none, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
file.AddEntity(rep);
|
||||
file.AddEntity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
class Node {
|
||||
private:
|
||||
@@ -127,7 +127,7 @@ public:
|
||||
}
|
||||
my = new IfcSchema::IfcBooleanResult(o, left->serialize(file), right->serialize(file));
|
||||
}
|
||||
file.addEntity(my);
|
||||
file.AddEntity(my);
|
||||
return my;
|
||||
}
|
||||
};
|
||||
@@ -135,7 +135,7 @@ public:
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "IfcCsgPrimitive.ifc";
|
||||
IfcHierarchyHelper file;
|
||||
file.header().file_name().name(filename);
|
||||
file.filename(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::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
|
||||
items->push(csg1);
|
||||
items->push(csg2);
|
||||
@@ -180,9 +180,9 @@ int main(int argc, char** argv) {
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("CSG"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
file.AddEntity(rep);
|
||||
file.AddEntity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
typedef struct {
|
||||
double r1;
|
||||
@@ -58,66 +58,66 @@ 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::ptr points(new Ifc2x3::IfcCartesianPoint::list());
|
||||
Ifc2x3::IfcCartesianPoint::list points(new IfcTemplatedEntityList<Ifc2x3::IfcCartesianPoint>());
|
||||
points->push(p3);
|
||||
points->push(p1);
|
||||
points->push(p2);
|
||||
file.addEntities(points->generalize());
|
||||
file.AddEntities(points->generalize());
|
||||
|
||||
|
||||
Ifc2x3::IfcEllipse* ellipse = new Ifc2x3::IfcEllipse(file.addPlacement2d(), pie.r1, pie.r2);
|
||||
file.addEntity(ellipse);
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
file.AddEntity(ellipse);
|
||||
IfcEntities trim1(new IfcEntityList());
|
||||
IfcEntities trim2(new IfcEntityList());
|
||||
if (pref == Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER) {
|
||||
trim1->push(new Ifc2x3::IfcParameterValue(pie.t1));
|
||||
trim2->push(new Ifc2x3::IfcParameterValue(pie.t2));
|
||||
trim1->push(new IfcWrite::IfcSelectHelper(pie.t1, Ifc2x3::Type::IfcParameterValue));
|
||||
trim2->push(new IfcWrite::IfcSelectHelper(pie.t2, Ifc2x3::Type::IfcParameterValue));
|
||||
} else {
|
||||
trim1->push(p2);
|
||||
trim2->push(p3);
|
||||
}
|
||||
Ifc2x3::IfcTrimmedCurve* trim = new Ifc2x3::IfcTrimmedCurve(ellipse, trim1, trim2, true, pref);
|
||||
file.addEntity(trim);
|
||||
file.AddEntity(trim);
|
||||
|
||||
Ifc2x3::IfcCompositeCurveSegment::list::ptr segments(new Ifc2x3::IfcCompositeCurveSegment::list());
|
||||
Ifc2x3::IfcCompositeCurveSegment::list segments(new IfcTemplatedEntityList<Ifc2x3::IfcCompositeCurveSegment>());
|
||||
Ifc2x3::IfcCompositeCurveSegment* s2 = new Ifc2x3::IfcCompositeCurveSegment(Ifc2x3::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, trim);
|
||||
|
||||
Ifc2x3::IfcPolyline* poly = new Ifc2x3::IfcPolyline(points);
|
||||
file.addEntity(poly);
|
||||
file.AddEntity(poly);
|
||||
Ifc2x3::IfcCompositeCurveSegment* s1 = new Ifc2x3::IfcCompositeCurveSegment(Ifc2x3::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, poly);
|
||||
segments->push(s1);
|
||||
|
||||
segments->push(s2);
|
||||
file.addEntities(segments->generalize());
|
||||
file.AddEntities(segments->generalize());
|
||||
|
||||
Ifc2x3::IfcCompositeCurve* ccurve = new Ifc2x3::IfcCompositeCurve(segments, false);
|
||||
Ifc2x3::IfcArbitraryClosedProfileDef* profile = new Ifc2x3::IfcArbitraryClosedProfileDef(Ifc2x3::IfcProfileTypeEnum::IfcProfileType_AREA, null, ccurve);
|
||||
file.addEntity(ccurve);
|
||||
file.addEntity(profile);
|
||||
file.AddEntity(ccurve);
|
||||
file.AddEntity(profile);
|
||||
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, S("profile"), null, null, 0, 0, null, null);
|
||||
file.addBuildingProduct(product);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement(0, 200 * i++));
|
||||
product->setObjectPlacement(file.addLocalPlacement(200 * i++));
|
||||
|
||||
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(profile,
|
||||
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
|
||||
|
||||
file.addEntity(solid);
|
||||
file.AddEntity(solid);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
|
||||
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(boost::none, boost::none, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
file.AddEntity(rep);
|
||||
file.AddEntity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
}
|
||||
|
||||
@@ -1,207 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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;
|
||||
}
|
||||
@@ -1,143 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Example of curve rebar. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
#include "ifcparse\Ifc2x3.h"
|
||||
#include "ifcparse\IfcUtil.h"
|
||||
#include "ifcparse\IfcHierarchyHelper.h"
|
||||
#include "ifcgeom\IfcGeom.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
void create_curve_rebar(IfcHierarchyHelper& file)
|
||||
{
|
||||
int dia = 24;
|
||||
int R = 3 * dia;
|
||||
int length = 12 * dia;
|
||||
|
||||
double crossSectionarea = M_PI * (dia / 2) * 2;
|
||||
IfcSchema::IfcReinforcingBar* rebar = new IfcSchema::IfcReinforcingBar(
|
||||
guid(), 0, S("test"), null,
|
||||
null, 0, 0,
|
||||
null, S("SR24"), //SteelGrade
|
||||
dia, //diameter
|
||||
crossSectionarea, //crossSectionarea = math.pi*(12.0/2)**2
|
||||
0,
|
||||
IfcSchema::IfcReinforcingBarRoleEnum::IfcReinforcingBarRoleEnum::IfcReinforcingBarRole_LIGATURE,
|
||||
IfcSchema::IfcReinforcingBarSurfaceEnum::IfcReinforcingBarSurfaceEnum::IfcReinforcingBarSurface_PLAIN //PLAIN or TEXTURED
|
||||
);
|
||||
|
||||
file.addBuildingProduct(rebar);
|
||||
rebar->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
IfcSchema::IfcCompositeCurveSegment::list::ptr segments(new IfcSchema::IfcCompositeCurveSegment::list());
|
||||
|
||||
IfcSchema::IfcCartesianPoint* p1 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, 0, 1000.);
|
||||
IfcSchema::IfcCartesianPoint* p2 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, 0, 0);
|
||||
IfcSchema::IfcCartesianPoint* p3 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, R, 0);
|
||||
IfcSchema::IfcCartesianPoint* p4 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, R, -R);
|
||||
IfcSchema::IfcCartesianPoint* p5 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, R + length, -R);
|
||||
|
||||
/*first segment - line */
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points1(new IfcSchema::IfcCartesianPoint::list());
|
||||
points1->push(p1);
|
||||
points1->push(p2);
|
||||
file.addEntities(points1->generalize());
|
||||
IfcSchema::IfcPolyline* poly1 = new IfcSchema::IfcPolyline(points1);
|
||||
file.addEntity(poly1);
|
||||
|
||||
IfcSchema::IfcCompositeCurveSegment* segment1 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, poly1);
|
||||
file.addEntity(segment1);
|
||||
segments->push(segment1);
|
||||
|
||||
/*second segment - arc */
|
||||
IfcSchema::IfcAxis2Placement3D* axis1 = new IfcSchema::IfcAxis2Placement3D(p3, file.addTriplet<IfcSchema::IfcDirection>(1, 0, 0), file.addTriplet<IfcSchema::IfcDirection>(0, 1, 0));
|
||||
file.addEntity(axis1);
|
||||
IfcSchema::IfcCircle* circle = new IfcSchema::IfcCircle(axis1, R);
|
||||
file.addEntity(circle);
|
||||
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
|
||||
trim1->push(new IfcSchema::IfcParameterValue(180));
|
||||
trim1->push(p2);
|
||||
|
||||
trim2->push(new IfcSchema::IfcParameterValue(270));
|
||||
trim2->push(p4);
|
||||
IfcSchema::IfcTrimmedCurve* trimmed_curve = new IfcSchema::IfcTrimmedCurve(circle, trim1, trim2, false, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
file.addEntity(trimmed_curve);
|
||||
|
||||
IfcSchema::IfcCompositeCurveSegment* segment2 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT, false, trimmed_curve);
|
||||
file.addEntity(segment2);
|
||||
segments->push(segment2);
|
||||
|
||||
/*third segment - line */
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points2(new IfcSchema::IfcCartesianPoint::list());
|
||||
points2->push(p4);
|
||||
points2->push(p5);
|
||||
file.addEntities(points2->generalize());
|
||||
IfcSchema::IfcPolyline* poly2 = new IfcSchema::IfcPolyline(points2);
|
||||
file.addEntity(poly2);
|
||||
|
||||
IfcSchema::IfcCompositeCurveSegment* segment3 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, poly2);
|
||||
file.addEntity(segment3);
|
||||
segments->push(segment3);
|
||||
|
||||
IfcSchema::IfcCompositeCurve* curve = new IfcSchema::IfcCompositeCurve(segments, false);
|
||||
file.addEntity(curve);
|
||||
|
||||
IfcSchema::IfcSweptDiskSolid* solid = new IfcSchema::IfcSweptDiskSolid(curve, dia / 2, null, 0, 1);
|
||||
|
||||
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("AdvancedSweptSolid"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
|
||||
file.addEntity(shape);
|
||||
|
||||
rebar->setRepresentation(shape);
|
||||
|
||||
IfcSchema::IfcObjectPlacement* storey_placement = file.getSingle<IfcSchema::IfcBuildingStorey>()->ObjectPlacement();
|
||||
rebar->setObjectPlacement(file.addLocalPlacement(storey_placement, 0, 0, 0));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
IfcHierarchyHelper file;
|
||||
file.header().file_name().name("ifc_curve_rebar.ifc");
|
||||
create_curve_rebar(file);
|
||||
std::ofstream f("ifc_curve_rebar.ifc");
|
||||
f << file;
|
||||
|
||||
return 0;
|
||||
}
|
||||
+19
-22
@@ -35,7 +35,7 @@ typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
void create_testcase_for(IfcSchema::IfcProfileDef::list::ptr profiles) {
|
||||
void create_testcase_for(IfcSchema::IfcProfileDef::list profiles) {
|
||||
IfcSchema::IfcProfileDef* profile = *profiles->begin();
|
||||
const std::string profile_type = IfcSchema::Type::ToString(profile->type());
|
||||
const std::string filename = profile_type + ".ifc";
|
||||
@@ -44,7 +44,7 @@ void create_testcase_for(IfcSchema::IfcProfileDef::list::ptr profiles) {
|
||||
file.filename(filename);
|
||||
|
||||
int i = 0;
|
||||
for (IfcSchema::IfcProfileDef::list::it it = profiles->begin(); it != profiles->end(); ++it, ++i) {
|
||||
for (IfcSchema::IfcProfileDef::it it = profiles->begin(); it != profiles->end(); ++it, ++i) {
|
||||
IfcSchema::IfcProfileDef* profile = *it;
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, S("profile"), null, null, 0, 0, null, null);
|
||||
@@ -52,7 +52,7 @@ void create_testcase_for(IfcSchema::IfcProfileDef::list::ptr profiles) {
|
||||
file.getSingle<IfcSchema::IfcProject>()->setName(profile_type);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement(0, 100. * i));
|
||||
product->setObjectPlacement(file.addLocalPlacement(100 * i));
|
||||
|
||||
if (profile->is(IfcSchema::Type::IfcParameterizedProfileDef)) {
|
||||
((IfcSchema::IfcParameterizedProfileDef*) profile)->setPosition(file.addPlacement2d());
|
||||
@@ -61,11 +61,11 @@ void create_testcase_for(IfcSchema::IfcProfileDef::list::ptr profiles) {
|
||||
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(profile,
|
||||
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
|
||||
|
||||
file.addEntity(profile);
|
||||
file.addEntity(solid);
|
||||
file.AddEntity(profile);
|
||||
file.AddEntity(solid);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
|
||||
items->push(solid);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
@@ -73,8 +73,8 @@ void create_testcase_for(IfcSchema::IfcProfileDef::list::ptr profiles) {
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
file.AddEntity(rep);
|
||||
file.AddEntity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
}
|
||||
@@ -84,7 +84,7 @@ void create_testcase_for(IfcSchema::IfcProfileDef::list::ptr profiles) {
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
profiles->push(new Ifc2x3::IfcUShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, null, null, null, null));
|
||||
@@ -99,7 +99,7 @@ int main(int argc, char** argv) {
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, 1.0, 3.0, 6.0, null));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
profiles->push(new Ifc2x3::IfcTShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, null, null, null, null, null, null));
|
||||
@@ -114,7 +114,7 @@ int main(int argc, char** argv) {
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, 3.0, 2.0, 1.0, 2.0, 2.0, null));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
profiles->push(new Ifc2x3::IfcZShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, null, null));
|
||||
@@ -123,7 +123,7 @@ int main(int argc, char** argv) {
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, 2.0, 2.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
profiles->push(new Ifc2x3::IfcEllipseProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0, 15.0));
|
||||
@@ -132,19 +132,16 @@ int main(int argc, char** argv) {
|
||||
null, 0, 15.0, 25.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
profiles->push(new Ifc2x3::IfcIShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0, 50.0, 5.0, 5.0, null));
|
||||
profiles->push(new Ifc2x3::IfcIShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0, 50.0, 5.0, 5.0, 2.0));
|
||||
profiles->push(new Ifc2x3::IfcAsymmetricIShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0, 50.0, 5.0, 5.0, 2.0, 20.0, 10.0, 5.0, null));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
profiles->push(new Ifc2x3::IfcLShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, null, null, null, null, null));
|
||||
@@ -159,7 +156,7 @@ int main(int argc, char** argv) {
|
||||
null, 0, 50.0, 25.0, 5.0, 1.0, 2.0, 2.0, null, null));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
profiles->push(new Ifc2x3::IfcCShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 10.0, null, null));
|
||||
@@ -168,7 +165,7 @@ int main(int argc, char** argv) {
|
||||
null, 0, 50.0, 25.0, 5.0, 10.0, 2.0, null));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
profiles->push(new Ifc2x3::IfcCircleProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0));
|
||||
@@ -177,7 +174,7 @@ int main(int argc, char** argv) {
|
||||
null, 0, 25.0, 5.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
profiles->push(new Ifc2x3::IfcRectangleProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0));
|
||||
@@ -192,7 +189,7 @@ int main(int argc, char** argv) {
|
||||
null, 0, 50.0, 25.0, 5.0, 2.0, 4.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
profiles->push(new Ifc2x3::IfcTrapeziumProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 30.0, 25.0, 0.0));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,85 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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;
|
||||
}
|
||||
@@ -30,16 +30,27 @@ bl_info = {
|
||||
"description": "Import files in the "\
|
||||
"Industry Foundation Classes (.ifc) file format",
|
||||
"author": "Thomas Krijnen, IfcOpenShell",
|
||||
"blender": (2, 73, 0),
|
||||
"blender": (2, 5, 8),
|
||||
"api": 37702,
|
||||
"location": "File > Import",
|
||||
"tracker_url": "https://sourceforge.net/p/ifcopenshell/"\
|
||||
"_list/tickets?source=navbar",
|
||||
"warning": "",
|
||||
"wiki_url": "http://sourceforge.net/apps/"\
|
||||
"mediawiki/ifcopenshell/index.php",
|
||||
"tracker_url": "http://sourceforge.net/tracker/?group_id=543113",
|
||||
"category": "Import-Export"}
|
||||
|
||||
import sys
|
||||
max_unicode = 0x110000-1 if sys.platform[0:5] == 'linux' else 0x10000-1
|
||||
wrong_unicode = max_unicode != sys.maxunicode
|
||||
if wrong_unicode:
|
||||
print("\nWarning: wrong unicode representation detected, switching to "\
|
||||
"compatibility layer for text transferral, may result in undefined "\
|
||||
"behaviour, please use offical release from http://blender.org\n")
|
||||
|
||||
if "bpy" in locals():
|
||||
import imp
|
||||
if "ifcopenshell" in locals():
|
||||
imp.reload(ifcopenshell)
|
||||
if "IfcImport" in locals():
|
||||
imp.reload(IfcImport)
|
||||
|
||||
import bpy
|
||||
import mathutils
|
||||
@@ -59,64 +70,54 @@ bpy.types.Object.ifc_type = StringProperty(name="IFC Entity Type",
|
||||
description="The STEP Datatype keyword")
|
||||
|
||||
|
||||
def import_ifc(filename, use_names, process_relations, blender_booleans):
|
||||
from . import ifcopenshell
|
||||
from .ifcopenshell import geom as ifcopenshell_geom
|
||||
def import_ifc(filename, use_names, process_relations):
|
||||
global wrong_unicode
|
||||
from . import IfcImport
|
||||
print("Reading %s..."%bpy.path.basename(filename))
|
||||
settings = ifcopenshell_geom.settings()
|
||||
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, blender_booleans)
|
||||
iterator = ifcopenshell_geom.iterator(settings, filename)
|
||||
valid_file = iterator.initialize()
|
||||
if wrong_unicode:
|
||||
valid_file = IfcImport.InitUCS2(
|
||||
''.join(['\0']+['\0%s'%s for s in filename]+['\0\0'])
|
||||
)
|
||||
else:
|
||||
valid_file = IfcImport.Init(filename)
|
||||
if not valid_file:
|
||||
IfcImport.CleanUp()
|
||||
return False
|
||||
print("Done reading file")
|
||||
id_to_object = {}
|
||||
id_to_parent = {}
|
||||
id_to_matrix = {}
|
||||
openings = []
|
||||
old_progress = -1
|
||||
print("Creating geometry...")
|
||||
while True:
|
||||
ob = iterator.get()
|
||||
|
||||
f = ob.geometry.faces
|
||||
v = ob.geometry.verts
|
||||
mats = ob.geometry.materials
|
||||
matids = ob.geometry.material_ids
|
||||
m = ob.transformation.matrix.data
|
||||
t = ob.type[0:21]
|
||||
nm = ob.name if len(ob.name) and use_names else ob.guid
|
||||
ob = IfcImport.Get()
|
||||
|
||||
if wrong_unicode:
|
||||
ob_name = ''.join([chr(c) for c in ob.name_as_intvector()])
|
||||
ob_type = ''.join([chr(c) for c in ob.type_as_intvector()])
|
||||
ob_guid = ''.join([chr(c) for c in ob.guid_as_intvector()])
|
||||
else:
|
||||
ob_name, ob_type, ob_guid = ob.name, ob.type, ob.guid
|
||||
|
||||
f = ob.mesh.faces
|
||||
v = ob.mesh.verts
|
||||
m = ob.matrix
|
||||
t = ob_type[0:21]
|
||||
nm = ob_name if len(ob_name) and use_names else ob_guid
|
||||
|
||||
verts = [[v[i], v[i + 1], v[i + 2]] \
|
||||
for i in range(0, len(v), 3)]
|
||||
faces = [[f[i], f[i + 1], f[i + 2]] \
|
||||
for i in range(0, len(f), 3)]
|
||||
|
||||
me = bpy.data.meshes.new('mesh%d' % ob.geometry.id)
|
||||
me = bpy.data.meshes.new('mesh%d' % ob.mesh.id)
|
||||
me.from_pydata(verts, [], faces)
|
||||
|
||||
def add_material(mname, props):
|
||||
if mname in bpy.data.materials:
|
||||
mat = bpy.data.materials[mname]
|
||||
mat.use_fake_user = True
|
||||
else:
|
||||
mat = bpy.data.materials.new(mname)
|
||||
for k,v in props.items():
|
||||
setattr(mat, k, v)
|
||||
me.materials.append(mat)
|
||||
|
||||
needs_default = -1 in matids
|
||||
if needs_default: add_material(t, {})
|
||||
|
||||
for mat in mats:
|
||||
props = {}
|
||||
if mat.has_diffuse: props['diffuse_color'] = mat.diffuse
|
||||
if mat.has_specular: props['specular_color'] = mat.specular
|
||||
if mat.has_transparency and mat.transparency > 0:
|
||||
props['alpha'] = 1.0 - mat.transparency
|
||||
props['use_transparency'] = True
|
||||
if mat.has_specularity: props['specular_hardness'] = mat.specularity
|
||||
add_material(mat.name, props)
|
||||
if t in bpy.data.materials:
|
||||
mat = bpy.data.materials[t]
|
||||
mat.use_fake_user = True
|
||||
else:
|
||||
mat = bpy.data.materials.new(t)
|
||||
me.materials.append(mat)
|
||||
|
||||
bob = bpy.data.objects.new(nm, me)
|
||||
mat = mathutils.Matrix(([m[0], m[1], m[2], 0],
|
||||
@@ -137,12 +138,10 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
bob.ifc_id, bob.ifc_guid, bob.ifc_name, bob.ifc_type = \
|
||||
ob.id, ob.guid, ob.name, ob.type
|
||||
ob.id, ob_guid, ob_name, ob_type
|
||||
|
||||
if ob.type == 'IfcSpace' or ob.type == 'IfcOpeningElement':
|
||||
if not (ob.type == 'IfcOpeningElement' and blender_booleans):
|
||||
bob.hide = bob.hide_render = True
|
||||
bob.draw_type = 'WIRE'
|
||||
bob.hide = ob_type == 'IfcSpace' or ob_type == 'IfcOpeningElement'
|
||||
bob.hide_render = bob.hide
|
||||
|
||||
if ob.id not in id_to_object: id_to_object[ob.id] = []
|
||||
id_to_object[ob.id].append(bob)
|
||||
@@ -150,19 +149,11 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
||||
if ob.parent_id > 0:
|
||||
id_to_parent[ob.id] = ob.parent_id
|
||||
|
||||
if blender_booleans and ob.type == 'IfcOpeningElement':
|
||||
openings.append(ob.id)
|
||||
|
||||
faces = me.polygons if hasattr(me, 'polygons') else me.faces
|
||||
if len(faces) == len(matids):
|
||||
for face, matid in zip(faces, matids):
|
||||
face.material_index = matid + (1 if needs_default else 0)
|
||||
|
||||
progress = iterator.progress() // 2
|
||||
progress = IfcImport.Progress() // 2
|
||||
if progress > old_progress:
|
||||
print("\r[" + "#" * progress + " " * (50 - progress) + "]", end="")
|
||||
old_progress = progress
|
||||
if not iterator.next():
|
||||
if not IfcImport.Next():
|
||||
break
|
||||
|
||||
print("\rDone creating geometry" + " " * 30)
|
||||
@@ -178,13 +169,24 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
||||
if parent_id in id_to_object:
|
||||
bob = id_to_object[parent_id][0]
|
||||
else:
|
||||
parent_ob = iterator.getObject(parent_id)
|
||||
parent_ob = IfcImport.GetObject(parent_id)
|
||||
if parent_ob.id == -1:
|
||||
bob = None
|
||||
else:
|
||||
m = parent_ob.transformation.matrix.data
|
||||
nm = parent_ob.name if len(parent_ob.name) and use_names \
|
||||
else parent_ob.guid
|
||||
if wrong_unicode:
|
||||
parent_ob_name = ''.join(
|
||||
[chr(c) for c in parent_ob.name_as_intvector()])
|
||||
parent_ob_type = ''.join(
|
||||
[chr(c) for c in parent_ob.type_as_intvector()])
|
||||
parent_ob_guid = ''.join(
|
||||
[chr(c) for c in parent_ob.guid_as_intvector()])
|
||||
else:
|
||||
parent_ob_name, parent_ob_type, parent_ob_guid = \
|
||||
parent_ob.name, parent_ob.type, parent_ob.guid
|
||||
|
||||
m = parent_ob.matrix
|
||||
nm = parent_ob_name if len(parent_ob_name) and use_names \
|
||||
else parent_ob_guid
|
||||
bob = bpy.data.objects.new(nm, None)
|
||||
|
||||
mat = mathutils.Matrix((
|
||||
@@ -199,7 +201,7 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
||||
|
||||
bob.ifc_id = parent_ob.id
|
||||
bob.ifc_name, bob.ifc_type, bob.ifc_guid = \
|
||||
parent_ob.name, parent_ob.type, parent_ob.guid
|
||||
parent_ob_name, parent_ob_type, parent_ob_guid
|
||||
|
||||
if parent_ob.parent_id > 0:
|
||||
id_to_parent[parent_id] = parent_ob.parent_id
|
||||
@@ -224,19 +226,13 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
||||
|
||||
if process_relations:
|
||||
print("Done processing relations")
|
||||
|
||||
for opening_id in openings:
|
||||
parent_id = id_to_parent[opening_id]
|
||||
if parent_id in id_to_object:
|
||||
parent_ob = id_to_object[parent_id][0]
|
||||
for opening_ob in id_to_object[opening_id]:
|
||||
mod = parent_ob.modifiers.new("opening", "BOOLEAN")
|
||||
mod.operation = "DIFFERENCE"
|
||||
mod.object = opening_ob
|
||||
|
||||
txt = bpy.data.texts.new("%s.log"%bpy.path.basename(filename))
|
||||
txt.from_string(iterator.getLog())
|
||||
|
||||
if not wrong_unicode:
|
||||
txt = bpy.data.texts.new("%s.log"%bpy.path.basename(filename))
|
||||
txt.from_string(IfcImport.GetLog())
|
||||
|
||||
IfcImport.CleanUp()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@@ -255,13 +251,15 @@ class ImportIFC(bpy.types.Operator, ImportHelper):
|
||||
" relations to parenting" \
|
||||
" (warning: may be slow on large files)",
|
||||
default=False)
|
||||
blender_booleans = BoolProperty(name="Use Blender booleans",
|
||||
description="Use Blender boolean modifiers for opening" \
|
||||
" elements",
|
||||
default=False)
|
||||
|
||||
def execute(self, context):
|
||||
if not import_ifc(self.filepath, self.use_names, self.process_relations, self.blender_booleans):
|
||||
global wrong_unicode
|
||||
if wrong_unicode and sys.platform[0:5] != 'linux':
|
||||
self.report({'ERROR'},
|
||||
'Your version of Blender is incompatible with IfcBlender\n' \
|
||||
'Please use the offical release from http://blender.org instead'
|
||||
)
|
||||
elif not import_ifc(self.filepath, self.use_names, self.process_relations):
|
||||
self.report({'ERROR'},
|
||||
'Unable to parse .ifc file or no geometrical entities found'
|
||||
)
|
||||
|
||||
@@ -19,65 +19,48 @@
|
||||
|
||||
#ifdef WITH_OPENCOLLADA
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ColladaSerializer.h"
|
||||
|
||||
#include <COLLADASWPrimitves.h>
|
||||
#include <COLLADASWSource.h>
|
||||
#include <COLLADASWScene.h>
|
||||
#include <COLLADASWNode.h>
|
||||
#include <COLLADASWInstanceGeometry.h>
|
||||
#include <COLLADASWBaseInputElement.h>
|
||||
#include <COLLADASWAsset.h>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
|
||||
static void collada_id(std::string &s)
|
||||
{
|
||||
IfcUtil::sanitate_material_name(s);
|
||||
IfcUtil::escape_xml(s);
|
||||
std::string collada_id(const std::string& s) {
|
||||
std::string id;
|
||||
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 == '_')) {
|
||||
id.push_back(c);
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id,
|
||||
const std::string& suffix, const std::vector<real_t>& floats, const char* coords /* = "XYZ" */)
|
||||
{
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<float>& floats, const char* coords /* = "XYZ" */) {
|
||||
COLLADASW::FloatSource source(mSW);
|
||||
source.setId(mesh_id + suffix);
|
||||
source.setArrayId(mesh_id + suffix + COLLADASW::LibraryGeometries::ARRAY_ID_SUFFIX);
|
||||
const size_t num_elems = strlen(coords);
|
||||
source.setAccessorStride(static_cast<unsigned long>(num_elems));
|
||||
source.setAccessorCount(static_cast<unsigned long>(floats.size() / num_elems));
|
||||
for (size_t i = 0; i < num_elems; ++i) {
|
||||
source.setAccessorStride(strlen(coords));
|
||||
source.setAccessorCount(floats.size() / 3);
|
||||
for (unsigned int i = 0; i < source.getAccessorStride(); ++i) {
|
||||
source.getParameterNameList().push_back(std::string(1, coords[i]));
|
||||
}
|
||||
source.prepareToAppendValues();
|
||||
for (std::vector<real_t>::const_iterator it = floats.begin(); it != floats.end(); ++it) {
|
||||
for (std::vector<float>::const_iterator it = floats.begin(); it != floats.end(); ++it) {
|
||||
source.appendValues(*it);
|
||||
}
|
||||
source.finish();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::write(
|
||||
const std::string &mesh_id, const std::string& default_material_name, const std::vector<real_t>& positions,
|
||||
const std::vector<real_t>& 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<real_t>& uvs)
|
||||
{
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::string& default_material_name, const std::vector<float>& positions, const std::vector<float>& normals, const std::vector<int>& indices, const std::vector<int> material_ids, const std::vector<IfcGeomObjects::Material>& materials) {
|
||||
openMesh(mesh_id);
|
||||
|
||||
// The normals vector can be empty for example when the WELD_VERTICES setting is used.
|
||||
// IfcOpenShell does not provide them with multiple face normals collapsed into a single vertex.
|
||||
const bool has_normals = !normals.empty();
|
||||
const bool has_uvs = !uvs.empty();
|
||||
|
||||
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX, positions);
|
||||
if (has_normals) {
|
||||
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, normals);
|
||||
if (has_uvs) {
|
||||
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::TEXCOORDS_SOURCE_ID_SUFFIX, uvs, "UV");
|
||||
}
|
||||
}
|
||||
|
||||
COLLADASW::VerticesElement vertices(mSW);
|
||||
@@ -85,40 +68,29 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(
|
||||
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 = faces.begin();
|
||||
std::vector<int>::const_iterator index_range_start = indices.begin();
|
||||
std::vector<int>::const_iterator material_it = material_ids.begin();
|
||||
int previous_material_id = -1;
|
||||
for (std::vector<int>::const_iterator it = faces.begin(); !faces.empty(); it += 3) {
|
||||
|
||||
int current_material_id = 0;
|
||||
if (material_it != material_ids.end()) {
|
||||
// In order for the last range of equal material ids to be output as well, this loop iterates
|
||||
// one element past the end of the vector. This needs to be observed when incrementing.
|
||||
current_material_id = *(material_it++);
|
||||
}
|
||||
|
||||
const size_t num_triangles = std::distance(index_range_start, it) / 3;
|
||||
if ((previous_material_id != current_material_id && num_triangles > 0) || (it == faces.end())) {
|
||||
int previous_material_id = -2;
|
||||
for (std::vector<int>::const_iterator it = indices.begin(); ; it += 3) {
|
||||
const int current_material_id = material_it == material_ids.end()
|
||||
? -3
|
||||
: *(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())) {
|
||||
COLLADASW::Triangles triangles(mSW);
|
||||
std::string material_name = (serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES)
|
||||
? materials[previous_material_id].original_name() : materials[previous_material_id].name());
|
||||
collada_id(material_name);
|
||||
triangles.setMaterial(material_name);
|
||||
triangles.setCount((unsigned long)num_triangles);
|
||||
triangles.setMaterial(collada_id(previous_material_id < 0
|
||||
? default_material_name
|
||||
: materials[previous_material_id].name()));
|
||||
triangles.setCount(num_triangles);
|
||||
int offset = 0;
|
||||
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX,"#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++));
|
||||
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX,"#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++ ) );
|
||||
if (has_normals) {
|
||||
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::NORMAL,"#" + mesh_id + COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, offset++));
|
||||
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::NORMAL,"#" + mesh_id + COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, offset++ ) );
|
||||
}
|
||||
if (has_uvs) {
|
||||
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::TEXCOORD,"#" + mesh_id + COLLADASW::LibraryGeometries::TEXCOORDS_SOURCE_ID_SUFFIX, offset++));
|
||||
}
|
||||
triangles.prepareToAppendValues();
|
||||
for (std::vector<int>::const_iterator jt = index_range_start; jt != it; ++jt) {
|
||||
const int idx = *jt;
|
||||
if (has_normals && has_uvs) {
|
||||
triangles.appendValues(idx, idx, idx);
|
||||
} else if(has_normals) {
|
||||
if (has_normals) {
|
||||
triangles.appendValues(idx, idx);
|
||||
} else {
|
||||
triangles.appendValues(idx);
|
||||
@@ -128,47 +100,11 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(
|
||||
index_range_start = it;
|
||||
}
|
||||
previous_material_id = current_material_id;
|
||||
if (it == faces.end()) {
|
||||
if (it == indices.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);
|
||||
std::string material_name = (serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES)
|
||||
? materials[it->first].original_name() : materials[it->first].name());
|
||||
collada_id(material_name);
|
||||
lines.setMaterial(material_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();
|
||||
}
|
||||
@@ -176,11 +112,8 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::close() {
|
||||
closeLibrary();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaScene::add(
|
||||
const std::string& node_id, const std::string& node_name, const std::string& geom_name,
|
||||
const std::vector<std::string>& material_ids, const std::vector<real_t>& matrix)
|
||||
{
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaScene::add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<float>& matrix) {
|
||||
if (!scene_opened) {
|
||||
openVisualScene(scene_id);
|
||||
scene_opened = true;
|
||||
@@ -194,24 +127,18 @@ void ColladaSerializer::ColladaExporter::ColladaScene::add(
|
||||
// The matrix attribute of an entity is basically a 4x3 representation of its ObjectPlacement.
|
||||
// Note that this placement is absolute, ie it is multiplied with all parent placements.
|
||||
double matrix_array[4][4] = {
|
||||
{ (double)matrix[0], (double)matrix[3], (double)matrix[6], (double)matrix[ 9] },
|
||||
{ (double)matrix[1], (double)matrix[4], (double)matrix[7], (double)matrix[10] },
|
||||
{ (double)matrix[2], (double)matrix[5], (double)matrix[8], (double)matrix[11] },
|
||||
{ 0, 0, 0, 1 }
|
||||
{matrix[0], matrix[3], matrix[6], matrix[ 9]},
|
||||
{matrix[1], matrix[4], matrix[7], matrix[10]},
|
||||
{matrix[2], matrix[5], matrix[8], matrix[11]},
|
||||
{ 0, 0, 0, 1}
|
||||
};
|
||||
|
||||
matrix_array[0][3] += serializer->settings().offset[0];
|
||||
matrix_array[1][3] += serializer->settings().offset[1];
|
||||
matrix_array[2][3] += serializer->settings().offset[2];
|
||||
|
||||
node.start();
|
||||
node.addMatrix(matrix_array);
|
||||
COLLADASW::InstanceGeometry instanceGeometry(mSW);
|
||||
instanceGeometry.setUrl ("#" + geom_name);
|
||||
foreach(std::string material_name, material_ids) {
|
||||
/// @todo This is done 6 times in this file, try to perform this once and be done with the material naming for the export.
|
||||
collada_id(material_name);
|
||||
COLLADASW::InstanceMaterial material (material_name, "#" + material_name);
|
||||
for (std::vector<std::string>::const_iterator it = material_ids.begin(); it != material_ids.end(); ++it) {
|
||||
COLLADASW::InstanceMaterial material (*it, "#" + *it);
|
||||
instanceGeometry.getBindMaterial().getInstanceMaterialList().push_back(material);
|
||||
}
|
||||
instanceGeometry.add();
|
||||
@@ -227,13 +154,9 @@ void ColladaSerializer::ColladaExporter::ColladaScene::write() {
|
||||
scene.add();
|
||||
}
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeom::Material& material)
|
||||
{
|
||||
std::string material_name = (serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES)
|
||||
? material.original_name() : material.name());
|
||||
collada_id(material_name);
|
||||
openEffect(material_name + "-fx");
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeomObjects::Material& material) {
|
||||
openEffect(collada_id(material.name()) + "-fx");
|
||||
COLLADASW::EffectProfile effect(mSW);
|
||||
effect.setShaderType(COLLADASW::EffectProfile::LAMBERT);
|
||||
if (material.hasDiffuse()) {
|
||||
@@ -262,33 +185,29 @@ void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::close() {
|
||||
closeLibrary();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const IfcGeom::Material& material) {
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const IfcGeomObjects::Material& material) {
|
||||
if (!contains(material)) {
|
||||
effects.write(material);
|
||||
materials.push_back(material);
|
||||
}
|
||||
}
|
||||
|
||||
bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeom::Material& material) {
|
||||
bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeomObjects::Material& material) {
|
||||
return std::find(materials.begin(), materials.end(), material) != materials.end();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::write() {
|
||||
effects.close();
|
||||
foreach(const IfcGeom::Material& material, materials) {
|
||||
std::string material_name = (serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES)
|
||||
? material.original_name() : material.name());
|
||||
std::string material_name_unescaped = material_name; // workaround double-escaping that would occur in addInstanceEffect()
|
||||
IfcUtil::sanitate_material_name(material_name_unescaped);
|
||||
collada_id(material_name);
|
||||
for (std::vector<IfcGeomObjects::Material>::const_iterator it = materials.begin(); it != materials.end(); ++it) {
|
||||
const std::string& material_name = collada_id((*it).name());
|
||||
openMaterial(material_name);
|
||||
addInstanceEffect("#" + material_name_unescaped + "-fx");
|
||||
addInstanceEffect("#" + material_name + "-fx");
|
||||
closeMaterial();
|
||||
}
|
||||
closeLibrary();
|
||||
}
|
||||
|
||||
|
||||
void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_name, float unit_magnitude) {
|
||||
stream.startDocument();
|
||||
|
||||
@@ -299,52 +218,53 @@ void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_n
|
||||
asset.add();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::write(const IfcGeom::TriangulationElement<real_t>* o)
|
||||
{
|
||||
const IfcGeom::Representation::Triangulation<real_t>& mesh = o->geometry();
|
||||
const std::string name = serializer->settings().get(SerializerSettings::USE_ELEMENT_GUIDS) ?
|
||||
o->guid() : (serializer->settings().get(SerializerSettings::USE_ELEMENT_NAMES) ? o->name() : o->unique_id());
|
||||
const std::string representation_id = "representation-" + boost::lexical_cast<std::string>(o->geometry().id());
|
||||
|
||||
void ColladaSerializer::ColladaExporter::writeTesselated(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<float>& matrix, const std::vector<float>& vertices, const std::vector<float>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids, const std::vector<IfcGeomObjects::Material>& _materials) {
|
||||
const IfcGeomObjects::Material default_for_type = IfcGeomObjects::Material(IfcGeom::get_default_style(type));
|
||||
std::vector<std::string> material_references;
|
||||
foreach(const IfcGeom::Material& material, mesh.materials()) {
|
||||
const bool needs_default = std::find(material_ids.begin(), material_ids.end(), -1) != material_ids.end();
|
||||
if (needs_default) {
|
||||
if (!materials.contains(default_for_type)) {
|
||||
materials.add(default_for_type);
|
||||
}
|
||||
material_references.push_back(collada_id(default_for_type.name()));
|
||||
}
|
||||
for (std::vector<IfcGeomObjects::Material>::const_iterator it = _materials.begin(); it != _materials.end(); ++it) {
|
||||
const IfcGeomObjects::Material& material = *it;
|
||||
if (!materials.contains(material)) {
|
||||
materials.add(material);
|
||||
}
|
||||
std::string material_name = (serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES)
|
||||
? material.original_name() : material.name());
|
||||
collada_id(material_name);
|
||||
material_references.push_back(material_name);
|
||||
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));
|
||||
}
|
||||
|
||||
deferreds.push_back(
|
||||
DeferredObject(name, representation_id, o->type(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(),
|
||||
mesh.faces(), mesh.edges(), mesh.material_ids(), mesh.materials(), material_references, mesh.uvs())
|
||||
);
|
||||
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());
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::endDocument() {
|
||||
// In fact due the XML based nature of Collada and its dependency on library nodes,
|
||||
// only at this point all objects are written to the stream.
|
||||
materials.write();
|
||||
std::set<std::string> geometries_written;
|
||||
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
|
||||
if (geometries_written.find(it->representation_id) != geometries_written.end()) {
|
||||
continue;
|
||||
}
|
||||
geometries_written.insert(it->representation_id);
|
||||
geometries.write(it->representation_id, it->type, it->vertices, it->normals, it->faces, it->edges, it->material_ids, it->materials, it->uvs);
|
||||
const std::string object_name = it->Name();
|
||||
geometries.write(object_name, it->type, it->vertices, it->normals, it->indices, 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->unique_id;
|
||||
/// @todo redundant information using ID as both ID and Name, maybe omit Name or allow specifying what would be used as the name
|
||||
scene.add(object_name, object_name, it->representation_id, it->material_references, it->matrix);
|
||||
const std::string object_name = it->Name();
|
||||
scene.add(object_name + "-instance", object_name, object_name, it->material_references, it->matrix);
|
||||
}
|
||||
scene.write();
|
||||
stream.endDocument();
|
||||
}
|
||||
|
||||
|
||||
bool ColladaSerializer::ready() {
|
||||
return true;
|
||||
}
|
||||
@@ -353,8 +273,9 @@ void ColladaSerializer::writeHeader() {
|
||||
exporter.startDocument(unit_name, unit_magnitude);
|
||||
}
|
||||
|
||||
void ColladaSerializer::write(const IfcGeom::TriangulationElement<real_t>* o) {
|
||||
exporter.write(o);
|
||||
void ColladaSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject* o) {
|
||||
const IfcGeomObjects::IfcRepresentationTriangulation& mesh = o->mesh();
|
||||
exporter.writeTesselated(o->guid(), o->name(), o->type(), o->id(), o->matrix(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.material_ids(), mesh.materials());
|
||||
}
|
||||
|
||||
void ColladaSerializer::finalize() {
|
||||
|
||||
@@ -22,182 +22,141 @@
|
||||
#ifndef COLLADASERIALIZER_H
|
||||
#define COLLADASERIALIZER_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4201 4512)
|
||||
#else
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
|
||||
#endif
|
||||
#include <COLLADASWStreamWriter.h>
|
||||
#include <COLLADASWPrimitves.h>
|
||||
#include <COLLADASWLibraryGeometries.h>
|
||||
#include <COLLADASWSource.h>
|
||||
#include <COLLADASWScene.h>
|
||||
#include <COLLADASWNode.h>
|
||||
#include <COLLADASWInstanceGeometry.h>
|
||||
#include <COLLADASWLibraryVisualScenes.h>
|
||||
#include <COLLADASWLibraryEffects.h>
|
||||
#include <COLLADASWLibraryMaterials.h>
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#include <COLLADASWBaseInputElement.h>
|
||||
#include <COLLADASWAsset.h>
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
|
||||
#include "../ifcconvert/GeometrySerializer.h"
|
||||
|
||||
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, ColladaSerializer *_serializer)
|
||||
explicit ColladaGeometries(COLLADASW::StreamWriter& stream)
|
||||
: COLLADASW::LibraryGeometries(&stream)
|
||||
, serializer(_serializer)
|
||||
{}
|
||||
void addFloatSource(const std::string& mesh_id, const std::string& suffix,
|
||||
const std::vector<real_t>& floats, const char* coords = "XYZ");
|
||||
void write(const std::string &mesh_id, const std::string& default_material_name,
|
||||
const std::vector<real_t>& positions, const std::vector<real_t>& 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<real_t>& uvs);
|
||||
void addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<float>& floats, const char* coords = "XYZ");
|
||||
void write(const std::string mesh_id, const std::string& default_material_name, const std::vector<float>& positions, const std::vector<float>& normals, const std::vector<int>& indices, const std::vector<int> material_ids, const std::vector<IfcGeomObjects::Material>& materials);
|
||||
void close();
|
||||
ColladaSerializer *serializer;
|
||||
};
|
||||
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:
|
||||
ColladaScene(const std::string& scene_id, COLLADASW::StreamWriter& stream, ColladaSerializer *_serializer)
|
||||
ColladaScene(const std::string& scene_id, COLLADASW::StreamWriter& stream)
|
||||
: COLLADASW::LibraryVisualScenes(&stream)
|
||||
, scene_id(scene_id)
|
||||
, scene_opened(false)
|
||||
, serializer(_serializer)
|
||||
, scene_opened(false)
|
||||
{}
|
||||
void add(const std::string& node_id, const std::string& node_name, const std::string& geom_name,
|
||||
const std::vector<std::string>& material_ids, const std::vector<real_t>& matrix);
|
||||
void add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<float>& matrix);
|
||||
void write();
|
||||
ColladaSerializer *serializer;
|
||||
};
|
||||
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)
|
||||
{}
|
||||
void write(const IfcGeom::Material& material);
|
||||
void write(const IfcGeomObjects::Material& material);
|
||||
void close();
|
||||
ColladaSerializer *serializer;
|
||||
};
|
||||
std::vector<IfcGeom::Material> materials;
|
||||
std::vector<IfcGeomObjects::Material> materials;
|
||||
ColladaEffects effects;
|
||||
public:
|
||||
explicit ColladaMaterials(COLLADASW::StreamWriter& stream, ColladaSerializer *_serializer)
|
||||
explicit ColladaMaterials(COLLADASW::StreamWriter& stream)
|
||||
: COLLADASW::LibraryMaterials(&stream)
|
||||
, serializer(_serializer)
|
||||
, effects(stream)
|
||||
, effects(stream)
|
||||
{}
|
||||
void add(const IfcGeom::Material& material);
|
||||
bool contains(const IfcGeom::Material& material);
|
||||
void add(const IfcGeomObjects::Material& material);
|
||||
bool contains(const IfcGeomObjects::Material& material);
|
||||
void write();
|
||||
ColladaSerializer *serializer;
|
||||
ColladaEffects effects;
|
||||
};
|
||||
class DeferredObject {
|
||||
public:
|
||||
std::string unique_id, representation_id, type;
|
||||
std::vector<real_t> matrix;
|
||||
std::vector<real_t> vertices;
|
||||
std::vector<real_t> normals;
|
||||
std::vector<int> faces;
|
||||
std::vector<int> edges;
|
||||
std::string guid, name, type;
|
||||
int obj_id;
|
||||
std::vector<float> matrix;
|
||||
std::vector<float> vertices;
|
||||
std::vector<float> normals;
|
||||
std::vector<int> indices;
|
||||
std::vector<int> material_ids;
|
||||
std::vector<IfcGeom::Material> materials;
|
||||
std::vector<IfcGeomObjects::Material> materials;
|
||||
std::vector<std::string> material_references;
|
||||
std::vector<real_t> uvs;
|
||||
DeferredObject(const std::string& unique_id, const std::string& representation_id, const std::string& type, const std::vector<real_t>& matrix,
|
||||
const std::vector<real_t>& vertices, const std::vector<real_t>& 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, const std::vector<real_t>& uvs)
|
||||
: unique_id(unique_id)
|
||||
, representation_id(representation_id)
|
||||
DeferredObject(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<float>& matrix, const std::vector<float>& vertices,
|
||||
const std::vector<float>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids,
|
||||
const std::vector<IfcGeomObjects::Material>& materials, const std::vector<std::string>& material_references)
|
||||
: guid(guid)
|
||||
, name(name)
|
||||
, type(type)
|
||||
, obj_id(obj_id)
|
||||
, matrix(matrix)
|
||||
, vertices(vertices)
|
||||
, normals(normals)
|
||||
, faces(faces)
|
||||
, edges(edges)
|
||||
, indices(indices)
|
||||
, material_ids(material_ids)
|
||||
, materials(materials)
|
||||
, material_references(material_references)
|
||||
, uvs(uvs)
|
||||
{}
|
||||
const std::string Name() const;
|
||||
};
|
||||
COLLADABU::NativeString filename;
|
||||
COLLADASW::StreamWriter stream;
|
||||
ColladaGeometries geometries;
|
||||
ColladaScene scene;
|
||||
ColladaMaterials materials;
|
||||
public:
|
||||
/// @param double_precision Whether to use "double precision" (up to 16 decimals) or not (6 or 7 decimals).
|
||||
ColladaExporter(const std::string& scene_name, const std::string& fn, ColladaSerializer *_serializer,
|
||||
bool double_precision)
|
||||
: filename(fn)
|
||||
, stream(filename, double_precision)
|
||||
, scene(scene_name, stream, _serializer)
|
||||
, materials(stream, _serializer)
|
||||
, geometries(stream, _serializer)
|
||||
, serializer(_serializer)
|
||||
{
|
||||
}
|
||||
ColladaMaterials materials;
|
||||
ColladaGeometries geometries;
|
||||
ColladaSerializer *serializer;
|
||||
ColladaExporter(const std::string& scene_name, const std::string& fn)
|
||||
: filename(fn.c_str())
|
||||
, stream(filename)
|
||||
, geometries(stream)
|
||||
, scene(scene_name, stream)
|
||||
, materials(stream)
|
||||
{}
|
||||
std::vector<DeferredObject> deferreds;
|
||||
virtual ~ColladaExporter() {}
|
||||
void startDocument(const std::string& unit_name, float unit_magnitude);
|
||||
void write(const IfcGeom::TriangulationElement<real_t>* o);
|
||||
void writeTesselated(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<float>& matrix, const std::vector<float>& vertices, const std::vector<float>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids, const std::vector<IfcGeomObjects::Material>& materials);
|
||||
void endDocument();
|
||||
};
|
||||
ColladaExporter exporter;
|
||||
std::string unit_name;
|
||||
float unit_magnitude;
|
||||
public:
|
||||
ColladaSerializer(const std::string& dae_filename, const SerializerSettings& settings)
|
||||
: GeometrySerializer(settings)
|
||||
, exporter("IfcOpenShell", dae_filename, this, settings.precision >= 15)
|
||||
{
|
||||
exporter.serializer = this;
|
||||
exporter.materials.serializer = this;
|
||||
exporter.materials.effects.serializer = this;
|
||||
exporter.geometries.serializer = this;
|
||||
}
|
||||
ColladaSerializer(const std::string& dae_filename)
|
||||
: GeometrySerializer()
|
||||
, exporter("IfcOpenShell", dae_filename)
|
||||
{}
|
||||
bool ready();
|
||||
void writeHeader();
|
||||
void write(const IfcGeom::TriangulationElement<real_t>* o);
|
||||
void write(const IfcGeom::BRepElement<real_t>* /*o*/) {}
|
||||
void writeTesselated(const IfcGeomObjects::IfcGeomObject* o);
|
||||
void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) {}
|
||||
void finalize();
|
||||
bool isTesselated() const { return true; }
|
||||
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
|
||||
unit_name = name;
|
||||
unit_magnitude = magnitude;
|
||||
}
|
||||
void setFile(IfcParse::IfcFile*) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,64 +20,18 @@
|
||||
#ifndef GEOMETRYSERIALIZER_H
|
||||
#define GEOMETRYSERIALIZER_H
|
||||
|
||||
#ifdef IFCCONVERT_DOUBLE_PRECISION
|
||||
typedef double real_t;
|
||||
#else
|
||||
typedef float real_t;
|
||||
#endif
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
|
||||
#include "../ifcconvert/Serializer.h"
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
class SerializerSettings : public IfcGeom::IteratorSettings
|
||||
{
|
||||
class GeometrySerializer {
|
||||
public:
|
||||
enum Setting
|
||||
{
|
||||
/// Use entity names instead of unique IDs for naming elements.
|
||||
/// Applicable for OBJ, DAE, and SVG output.
|
||||
USE_ELEMENT_NAMES = 1 << (IfcGeom::IteratorSettings::NUM_SETTINGS + 1),
|
||||
/// Use entity GUIDs instead of unique IDs for naming elements.
|
||||
/// Applicable for OBJ, DAE, and SVG output.
|
||||
USE_ELEMENT_GUIDS = 1 << (IfcGeom::IteratorSettings::NUM_SETTINGS + 2),
|
||||
/// Use material names instead of unique IDs for naming materials.
|
||||
/// Applicable for OBJ and DAE output.
|
||||
USE_MATERIAL_NAMES = 1 << (IfcGeom::IteratorSettings::NUM_SETTINGS + 3),
|
||||
/// Number of different setting flags.
|
||||
NUM_SETTINGS = 3
|
||||
};
|
||||
|
||||
SerializerSettings()
|
||||
: precision(DEFAULT_PRECISION)
|
||||
{
|
||||
memset(offset, 0, sizeof(offset));
|
||||
}
|
||||
|
||||
/// Optional offset that is applied to serialized objects, (0,0,0) by default.
|
||||
double offset[3];
|
||||
|
||||
/// Sets the precision used to format floating-point values, 15 by default.
|
||||
/// Use a negative value to use the system's default precision (should be 6 typically).
|
||||
short precision;
|
||||
|
||||
enum { DEFAULT_PRECISION = 15 };
|
||||
};
|
||||
|
||||
class GeometrySerializer : public Serializer {
|
||||
public:
|
||||
GeometrySerializer(const SerializerSettings& settings) : settings_(settings) {}
|
||||
virtual ~GeometrySerializer() {}
|
||||
|
||||
virtual bool ready() = 0;
|
||||
virtual void writeHeader() = 0;
|
||||
virtual void finalize() = 0;
|
||||
virtual bool isTesselated() const = 0;
|
||||
virtual void write(const IfcGeom::TriangulationElement<real_t>* o) = 0;
|
||||
virtual void write(const IfcGeom::BRepElement<real_t>* o) = 0;
|
||||
virtual ~GeometrySerializer() {}
|
||||
virtual void writeTesselated(const IfcGeomObjects::IfcGeomObject* o) = 0;
|
||||
virtual void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) = 0;
|
||||
virtual void setUnitNameAndMagnitude(const std::string& name, float magnitude) = 0;
|
||||
|
||||
const SerializerSettings& settings() const { return settings_; }
|
||||
SerializerSettings& settings() { return settings_; }
|
||||
|
||||
protected:
|
||||
SerializerSettings settings_;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
+168
-620
@@ -26,65 +26,38 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../ifcconvert/ColladaSerializer.h"
|
||||
#include "../ifcconvert/IgesSerializer.h"
|
||||
#include "../ifcconvert/StepSerializer.h"
|
||||
#include "../ifcconvert/WavefrontObjSerializer.h"
|
||||
#include "../ifcconvert/XmlSerializer.h"
|
||||
#include "../ifcconvert/SvgSerializer.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
#include <IGESControl_Controller.hxx>
|
||||
#include <Standard_Version.hxx>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <time.h>
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
#endif
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
const std::string DEFAULT_EXTENSION = "obj";
|
||||
const std::string TEMP_FILE_EXTENSION = ".tmp";
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
|
||||
namespace po = boost::program_options;
|
||||
#include "../ifcconvert/ColladaSerializer.h"
|
||||
#include "../ifcconvert/IgesSerializer.h"
|
||||
#include "../ifcconvert/StepSerializer.h"
|
||||
#include "../ifcconvert/WavefrontObjSerializer.h"
|
||||
|
||||
void print_version()
|
||||
{
|
||||
std::cout << "IfcOpenShell " << IfcSchema::Identifier << " IfcConvert " << IFCOPENSHELL_VERSION << std::endl;
|
||||
void printVersion() {
|
||||
std::cerr << "IfcOpenShell IfcConvert " << IFCOPENSHELL_VERSION << std::endl;
|
||||
}
|
||||
|
||||
void print_usage(bool suggest_help = true)
|
||||
{
|
||||
std::cout << "Usage: IfcConvert [options] <input.ifc> [<output>]\n"
|
||||
<< "\n"
|
||||
<< "Converts the geometry in an IFC file into one of the following formats:\n"
|
||||
<< " .obj WaveFront OBJ (a .mtl file is also created)\n"
|
||||
#ifdef WITH_OPENCOLLADA
|
||||
<< " .dae Collada Digital Assets Exchange\n"
|
||||
void printUsage(const boost::program_options::options_description& generic_options, const boost::program_options::options_description& geom_options) {
|
||||
printVersion();
|
||||
std::cerr << "Usage: IfcConvert [options] <input.ifc> [<output>]" << std::endl
|
||||
<< std::endl
|
||||
<< "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;
|
||||
#endif
|
||||
<< " .stp STEP Standard for the Exchange of Product Data\n"
|
||||
<< " .igs IGES Initial Graphics Exchange Specification\n"
|
||||
<< " .xml XML Property definitions and decomposition tree\n"
|
||||
<< " .svg SVG Scalable Vector Graphics (2D floor plan)\n"
|
||||
<< "\n"
|
||||
<< "If no output filename given, <input>." + DEFAULT_EXTENSION + " will be used as the output file.\n";
|
||||
if (suggest_help) {
|
||||
std::cout << "\nRun 'IfcConvert --help' for more information.";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/// @todo Add help for single option
|
||||
void print_options(const po::options_description& options)
|
||||
{
|
||||
std::cout << "\n" << options;
|
||||
std::cout << std::endl;
|
||||
std::cerr << " .stp STEP Standard for the Exchange of Product Data" << std::endl
|
||||
<< " .igs IGES Initial Graphics Exchange Specification" << std::endl
|
||||
<< std::endl
|
||||
<< "Command line options" << std::endl << generic_options << std::endl
|
||||
<< "Advanced options" << std::endl << geom_options << std::endl;
|
||||
}
|
||||
|
||||
std::string change_extension(const std::string& fn, const std::string& ext) {
|
||||
@@ -96,660 +69,235 @@ std::string change_extension(const std::string& fn, const std::string& ext) {
|
||||
}
|
||||
}
|
||||
|
||||
bool file_exists(const std::string& filename)
|
||||
{
|
||||
/// @todo Windows Unicode support
|
||||
std::ifstream file(filename.c_str());
|
||||
return file.good();
|
||||
}
|
||||
|
||||
bool rename_file(const std::string& old_filename, const std::string& new_filename)
|
||||
{
|
||||
// Whether or not rename() replaces an existing file is implementation-specific,
|
||||
// so remove() possible existing file always.
|
||||
/// @todo Windows Unicode support
|
||||
std::remove(new_filename.c_str());
|
||||
return std::rename(old_filename.c_str(), new_filename.c_str()) == 0;
|
||||
}
|
||||
|
||||
static std::stringstream log_stream;
|
||||
void write_log();
|
||||
|
||||
/// @todo make the filters non-global
|
||||
IfcGeom::entity_filter entity_filter; // Entity filter is used always by default.
|
||||
IfcGeom::layer_filter layer_filter;
|
||||
const std::string NAME_ARG = "Name", GUID_ARG = "GlobalId", DESC_ARG = "Description", TAG_ARG = "Tag";
|
||||
boost::array<std::string, 4> supported_args = { { NAME_ARG, GUID_ARG, DESC_ARG, TAG_ARG } };
|
||||
IfcGeom::string_arg_filter guid_filter(IfcSchema::Type::IfcRoot, 0); // IfcRoot.GlobalId
|
||||
// Note: skipping IfcRoot OwnerHistory, argument index 1
|
||||
IfcGeom::string_arg_filter name_filter(IfcSchema::Type::IfcRoot, 2); // IfcRoot.Name
|
||||
IfcGeom::string_arg_filter desc_filter(IfcSchema::Type::IfcRoot, 3); // IfcRoot.Description
|
||||
IfcGeom::string_arg_filter tag_filter(IfcSchema::Type::IfcProxy, 8, IfcSchema::Type::IfcElement, 7); // IfcProxy.Tag & IfcElement.Tag
|
||||
|
||||
struct geom_filter
|
||||
{
|
||||
geom_filter(bool include, bool traverse) : type(UNUSED), include(include), traverse(traverse) {}
|
||||
geom_filter() : type(UNUSED), include(false), traverse(false) {}
|
||||
enum filter_type { UNUSED, ENTITY_TYPE, LAYER_NAME, ENTITY_ARG };
|
||||
filter_type type;
|
||||
bool include;
|
||||
bool traverse;
|
||||
std::string arg;
|
||||
std::set<std::string> values;
|
||||
};
|
||||
// Specialized classes for knowing which type of filter we are validating within validate().
|
||||
// Could not figure out easily how else to know it if using single type for both.
|
||||
struct inclusion_filter : public geom_filter { inclusion_filter() : geom_filter(true, false) {} };
|
||||
struct inclusion_traverse_filter : public geom_filter { inclusion_traverse_filter() : geom_filter(true, true) {} };
|
||||
struct exclusion_filter : public geom_filter { exclusion_filter() : geom_filter(false, false) {} };
|
||||
struct exclusion_traverse_filter : public geom_filter { exclusion_traverse_filter() : geom_filter(false, true) {} };
|
||||
|
||||
std::vector<IfcGeom::filter_t> setup_filters(const std::vector<geom_filter>&, const std::string&);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
po::options_description generic_options("Command line options");
|
||||
int main(int argc, char** argv) {
|
||||
boost::program_options::options_description generic_options;
|
||||
generic_options.add_options()
|
||||
("help,h", "display usage information")
|
||||
("help", "display usage information")
|
||||
("version", "display version information")
|
||||
("verbose,v", "more verbose output")
|
||||
("yes,y", "answer 'yes' automatically to possible confirmation queries (e.g. overwriting an existing output file)");
|
||||
("verbose,v", "more verbose output");
|
||||
|
||||
po::options_description fileio_options;
|
||||
boost::program_options::options_description fileio_options;
|
||||
fileio_options.add_options()
|
||||
("input-file", po::value<std::string>(), "input IFC file")
|
||||
("output-file", po::value<std::string>(), "output geometry file");
|
||||
("input-file", boost::program_options::value<std::string>(), "input IFC file")
|
||||
("output-file", boost::program_options::value<std::string>(), "output geometry file");
|
||||
|
||||
double deflection_tolerance;
|
||||
inclusion_filter include_filter;
|
||||
inclusion_traverse_filter include_traverse_filter;
|
||||
exclusion_filter exclude_filter;
|
||||
exclusion_traverse_filter exclude_traverse_filter;
|
||||
|
||||
po::options_description geom_options("Geometry options");
|
||||
std::vector<std::string> ignore_types_vector;
|
||||
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 "
|
||||
"manifold mesh which is useful for modelling applications, but might "
|
||||
"result in unwanted shading artefacts in rendering applications.")
|
||||
("use-world-coords",
|
||||
"Specifies whether to apply the local placements of building elements "
|
||||
"directly to the coordinates of the representation mesh rather than "
|
||||
"to represent the local placement in the 4x3 matrix, which will in that "
|
||||
"case be the identity matrix.")
|
||||
("convert-back-units",
|
||||
"Specifies whether to convert back geometrical output back to the "
|
||||
"unit of measure in which it is defined in the IFC file. Default is "
|
||||
"to use meters.")
|
||||
("sew-shells",
|
||||
"Specifies whether to sew the faces of IfcConnectedFaceSets together. "
|
||||
"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.")
|
||||
#endif
|
||||
("disable-opening-subtractions",
|
||||
"Specifies whether to disable the boolean subtraction of "
|
||||
"IfcOpeningElement Representations from their RelatingElements.")
|
||||
("enable-layerset-slicing",
|
||||
"Specifies whether to enable the slicing of products according "
|
||||
"to their associated IfcMaterialLayerSet.")
|
||||
("include", po::value<inclusion_filter>(&include_filter)->multitoken(),
|
||||
"Specifies that the entities that match a specific filtering criteria are to be included in the geometrical output:\n"
|
||||
"1) 'entities': the following list of types should be included. SVG output defaults "
|
||||
"to IfcSpace to be included. The entity names are handled case-insensitively.\n"
|
||||
"2) 'layers': the entities that are assigned to presentation layers of which names "
|
||||
"match the given values should be included.\n"
|
||||
"3) 'arg <ArgumentName>': the following list of values for that specific argument should be included. "
|
||||
"Currently supported arguments are GlobalId, Name, Description, and Tag.\n\n"
|
||||
"The values for 'layers' and 'arg' are handled case-sensitively (wildcards supported)."
|
||||
"--include and --exclude cannot be placed right before input file argument and "
|
||||
"only single of each argument supported for now. See also --exclude.")
|
||||
("include+", po::value<inclusion_traverse_filter>(&include_traverse_filter)->multitoken(),
|
||||
"Same as --include but applies filtering also to the decomposition and/or containment (IsDecomposedBy, "
|
||||
"HasOpenings, FillsVoid, ContainedInStructure) of the filtered entity, e.g. --include+=arg Name \"Level 1\" "
|
||||
"includes entity with name \"Level 1\" and all of its children. See --include for more information. ")
|
||||
("exclude", po::value<exclusion_filter>(&exclude_filter)->multitoken(),
|
||||
"Specifies that the entities that match a specific filtering criteria are to be excluded in the geometrical output."
|
||||
"See --include for syntax and more details. The default value is '--exclude=entities IfcOpeningElement IfcSpace'.")
|
||||
("exclude+", po::value<exclusion_traverse_filter>(&exclude_traverse_filter)->multitoken(),
|
||||
"Same as --exclude but applies filtering also to the decomposition and/or containment "
|
||||
"of the filtered entity. See --include+ for more details.")
|
||||
("no-normals",
|
||||
"Disables computation of normals. Saves time and file size and is useful "
|
||||
"in instances where you're going to recompute normals for the exported "
|
||||
"model in other modelling application in any case.")
|
||||
("deflection-tolerance", po::value<double>(&deflection_tolerance)->default_value(1e-3),
|
||||
"Sets the deflection tolerance of the mesher, 1e-3 by default if not specified.")
|
||||
("generate-uvs",
|
||||
"Generates UVs (texture coordinates) by using simple box projection. Requires normals. "
|
||||
"Not guaranteed to work properly if used with --weld-vertices.");
|
||||
("weld-vertices", "Specifies whether vertices are welded, meaning that the coordinates "
|
||||
"vector will only contain unique xyz-triplets. This results in a "
|
||||
"manifold mesh which is useful for modelling applications, but might "
|
||||
"result in unwanted shading artifacts in rendering applications.")
|
||||
("use-world-coords", "Specifies whether to apply the local placements of building elements "
|
||||
"directly to the coordinates of the representation mesh rather than "
|
||||
"to represent the local placement in the 4x3 matrix, which will in that "
|
||||
"case be the identity matrix.")
|
||||
("convert-back-units", "Specifies whether to convert back geometrical output back to the "
|
||||
"unit of measure in which it is defined in the IFC file. Default is "
|
||||
"to use meters.")
|
||||
("sew-shells", "Specifies whether to sew the faces of IfcConnectedFaceSets together. 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.")
|
||||
("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.")
|
||||
("disable-opening-subtractions", "Specifies whether to disable the boolean subtraction of "
|
||||
"IfcOpeningElement Representations from their RelatingElements.")
|
||||
("ignore-types", boost::program_options::value< std::vector<std::string> >(&ignore_types_vector)->multitoken(),
|
||||
"A list of IFC datatype keywords that should not be included in the geometrical output. "
|
||||
"Defaults to IfcOpeningElement and IfcSpace");
|
||||
|
||||
boost::program_options::options_description cmdline_options;
|
||||
cmdline_options.add(generic_options).add(fileio_options).add(geom_options);
|
||||
|
||||
std::string bounds, offset_str;
|
||||
#ifdef HAVE_ICU
|
||||
std::string unicode_mode;
|
||||
#endif
|
||||
short precision;
|
||||
|
||||
po::options_description serializer_options("Serialization options");
|
||||
serializer_options.add_options()
|
||||
#ifdef HAVE_ICU
|
||||
("unicode", po::value<std::string>(&unicode_mode),
|
||||
"Specifies the Unicode handling behavior when parsing the IFC file. "
|
||||
"Accepted values 'utf8' (the default) and 'escape'.")
|
||||
#endif
|
||||
("bounds", po::value<std::string>(&bounds),
|
||||
"Specifies the bounding rectangle, for example 512x512, to which the "
|
||||
"output will be scaled. Only used when converting to SVG.")
|
||||
("use-element-names",
|
||||
"Use entity names instead of unique IDs for naming elements upon serialization. "
|
||||
"Applicable for OBJ, DAE, and SVG output.")
|
||||
("use-element-guids",
|
||||
"Use entity GUIDs instead of unique IDs for naming elements upon serialization. "
|
||||
"Applicable for OBJ, DAE, and SVG output.")
|
||||
("use-material-names",
|
||||
"Use material names instead of unique IDs for naming materials upon serialization. "
|
||||
"Applicable for OBJ and DAE output.")
|
||||
("center-model",
|
||||
"Centers the elements upon serialization by applying the center point of "
|
||||
"all placements as an offset. Applicable for OBJ and DAE output.")
|
||||
("model-offset", po::value<std::string>(&offset_str),
|
||||
"Applies an arbitrary offset of form 'x;y;z' to all placements. Applicable for OBJ and DAE output.")
|
||||
("precision", po::value<short>(&precision)->default_value(SerializerSettings::DEFAULT_PRECISION),
|
||||
"Sets the precision to be used to format floating-point values, 15 by default. "
|
||||
"Use a negative value to use the system's default precision (should be 6 typically). "
|
||||
"Applicable for OBJ and DAE output. For DAE output, value >= 15 means that up to 16 decimals are used, "
|
||||
" and any other value means that 6 or 7 decimals are used.");
|
||||
|
||||
po::options_description cmdline_options;
|
||||
cmdline_options.add(generic_options).add(fileio_options).add(geom_options).add(serializer_options);
|
||||
|
||||
po::positional_options_description positional_options;
|
||||
boost::program_options::positional_options_description positional_options;
|
||||
positional_options.add("input-file", 1);
|
||||
positional_options.add("output-file", 1);
|
||||
|
||||
po::variables_map vmap;
|
||||
try {
|
||||
po::store(po::command_line_parser(argc, argv).
|
||||
options(cmdline_options).positional(positional_options).run(), vmap);
|
||||
} catch (const po::unknown_option& e) {
|
||||
std::cerr << "[Error] Unknown option '" << e.get_option_name() << "'\n\n";
|
||||
print_usage();
|
||||
return EXIT_FAILURE;
|
||||
} catch (const po::error_with_option_name& e) {
|
||||
std::cerr << "[Error] Invalid usage of '" << e.get_option_name() << "': " << e.what() << "\n\n";
|
||||
return EXIT_FAILURE;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "[Error] " << e.what() << "\n\n";
|
||||
print_usage();
|
||||
return EXIT_FAILURE;
|
||||
} catch (...) {
|
||||
print_usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
boost::program_options::variables_map vmap;
|
||||
try {
|
||||
boost::program_options::store(boost::program_options::command_line_parser(argc, argv).
|
||||
options(cmdline_options).positional(positional_options).run(), vmap);
|
||||
} catch (const boost::program_options::unknown_option& e) {
|
||||
std::cerr << "[Error] Unknown option '" << e.get_option_name() << "'" << std::endl << std::endl;
|
||||
// Usage information will be emitted below
|
||||
}
|
||||
boost::program_options::notify(vmap);
|
||||
|
||||
po::notify(vmap);
|
||||
if (vmap.count("version")) {
|
||||
printVersion();
|
||||
return 1;
|
||||
} else if (vmap.count("help") || !vmap.count("input-file")) {
|
||||
printUsage(generic_options, geom_options);
|
||||
return 1;
|
||||
}
|
||||
|
||||
print_version();
|
||||
|
||||
if (vmap.count("version")) {
|
||||
return EXIT_SUCCESS;
|
||||
} else if (vmap.count("help")) {
|
||||
print_usage(false);
|
||||
print_options(generic_options.add(geom_options).add(serializer_options));
|
||||
return EXIT_SUCCESS;
|
||||
} else if (!vmap.count("input-file")) {
|
||||
std::cerr << "[Error] Input file not specified" << std::endl;
|
||||
print_usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
const bool verbose = vmap.count("verbose") != 0;
|
||||
const bool weld_vertices = vmap.count("weld-vertices") != 0;
|
||||
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;
|
||||
#endif
|
||||
const bool force_ccw_face_orientation = vmap.count("force-ccw-face-orientation") != 0;
|
||||
const bool disable_opening_subtractions = vmap.count("disable-opening-subtractions") != 0;
|
||||
const bool include_plan = vmap.count("plan") != 0;
|
||||
const bool include_model = vmap.count("model") != 0 || (!include_plan);
|
||||
const bool enable_layerset_slicing = vmap.count("enable-layerset-slicing") != 0;
|
||||
const bool use_element_names = vmap.count("use-element-names") != 0;
|
||||
const bool use_element_guids = vmap.count("use-element-guids") != 0 ;
|
||||
const bool use_material_names = vmap.count("use-material-names") != 0;
|
||||
const bool no_normals = vmap.count("no-normals") != 0 ;
|
||||
const bool center_model = vmap.count("center-model") != 0 ;
|
||||
const bool model_offset = vmap.count("model-offset") != 0 ;
|
||||
const bool generate_uvs = vmap.count("generate-uvs") != 0 ;
|
||||
|
||||
#ifdef HAVE_ICU
|
||||
if (!unicode_mode.empty()) {
|
||||
if (unicode_mode == "utf8") {
|
||||
IfcParse::IfcCharacterDecoder::mode = IfcParse::IfcCharacterDecoder::UTF8;
|
||||
} else if (unicode_mode == "escape") {
|
||||
IfcParse::IfcCharacterDecoder::mode = IfcParse::IfcCharacterDecoder::JSON;
|
||||
} else {
|
||||
std::cerr << "[Error] Invalid value for --unicode" << std::endl;
|
||||
print_options(serializer_options);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int bounding_width = -1, bounding_height = -1;
|
||||
if (vmap.count("bounds") == 1) {
|
||||
int w, h;
|
||||
if (sscanf(bounds.c_str(), "%ux%u", &w, &h) == 2 && w > 0 && h > 0) {
|
||||
bounding_width = w;
|
||||
bounding_height = h;
|
||||
} else {
|
||||
std::cerr << "[Error] Invalid use of --bounds" << std::endl;
|
||||
print_options(serializer_options);
|
||||
return EXIT_FAILURE;
|
||||
// Gets the set ifc types to be ignored from the command line.
|
||||
std::set<std::string> ignore_types;
|
||||
for (std::vector<std::string>::const_iterator it = ignore_types_vector.begin(); it != ignore_types_vector.end(); ++it) {
|
||||
std::string lowercase_type = *it;
|
||||
for (std::string::iterator c = lowercase_type.begin(); c != lowercase_type.end(); ++c) {
|
||||
*c = tolower(*c);
|
||||
}
|
||||
ignore_types.insert(lowercase_type);
|
||||
}
|
||||
|
||||
// If none are specified these are the defaults to skip from output
|
||||
if (ignore_types_vector.empty()) {
|
||||
ignore_types.insert("ifcopeningelement");
|
||||
ignore_types.insert("ifcspace");
|
||||
}
|
||||
|
||||
const std::string input_filename = vmap["input-file"].as<std::string>();
|
||||
if (!file_exists(input_filename)) {
|
||||
std::cerr << "[Error] Input file '" << input_filename << "' does not exist" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// If no output filename is specified a Wavefront OBJ file will be output
|
||||
// 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, DEFAULT_EXTENSION);
|
||||
: change_extension(input_filename, "obj");
|
||||
|
||||
if (output_filename.size() < 5) {
|
||||
std::cerr << "[Error] Invalid or unsupported output file '" << output_filename << "' given" << std::endl;
|
||||
print_usage();
|
||||
return EXIT_FAILURE;
|
||||
printUsage(generic_options, geom_options);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (file_exists(output_filename) && !vmap.count("yes")) {
|
||||
std::string answer;
|
||||
std::cout << "A file '" << output_filename << "' already exists. Overwrite the existing file?" << std::endl;
|
||||
std::cin >> answer;
|
||||
if (!boost::iequals(answer, "yes") && !boost::iequals(answer, "y")) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
std::string output_temp_filename = output_filename + TEMP_FILE_EXTENSION;
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS, use_world_coords);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::WELD_VERTICES, weld_vertices);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::SEW_SHELLS, sew_shells);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::CONVERT_BACK_UNITS, convert_back_units);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::FASTER_BOOLEANS, merge_boolean_operands);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::FORCE_CCW_FACE_ORIENTATION, force_ccw_face_orientation);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::DISABLE_OPENING_SUBTRACTIONS, disable_opening_subtractions);
|
||||
|
||||
std::string output_extension = output_filename.substr(output_filename.size()-4);
|
||||
boost::to_lower(output_extension);
|
||||
for (std::string::iterator c = output_extension.begin(); c != output_extension.end(); ++c) {
|
||||
*c = tolower(*c);
|
||||
}
|
||||
|
||||
Logger::SetOutput(&std::cout, &log_stream);
|
||||
Logger::Verbosity(verbose ? Logger::LOG_NOTICE : Logger::LOG_ERROR);
|
||||
|
||||
IfcParse::IfcFile ifc_file;
|
||||
if (!ifc_file.Init(input_filename)) {
|
||||
Logger::Error("Unable to parse input file '" + input_filename + "'");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (output_extension == ".xml") {
|
||||
int exit_code = EXIT_FAILURE;
|
||||
try {
|
||||
XmlSerializer s(output_temp_filename);
|
||||
s.setFile(&ifc_file);
|
||||
Logger::Status("Writing XML output...");
|
||||
s.finalize();
|
||||
Logger::Status("Done!");
|
||||
rename_file(output_temp_filename, output_filename);
|
||||
exit_code = EXIT_SUCCESS;
|
||||
} catch (...) {}
|
||||
write_log();
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
/// @todo Clean up this filter code further.
|
||||
std::vector<geom_filter> used_filters;
|
||||
if (include_filter.type != geom_filter::UNUSED) { used_filters.push_back(include_filter); }
|
||||
if (include_traverse_filter.type != geom_filter::UNUSED) { used_filters.push_back(include_traverse_filter); }
|
||||
if (exclude_filter.type != geom_filter::UNUSED) { used_filters.push_back(exclude_filter); }
|
||||
if (exclude_traverse_filter.type != geom_filter::UNUSED) { used_filters.push_back(exclude_traverse_filter); }
|
||||
|
||||
std::vector<IfcGeom::filter_t> filter_funcs = setup_filters(used_filters, output_extension);
|
||||
if (filter_funcs.empty()) {
|
||||
std::cerr << "[Error] Failed to set up geometry filters\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!entity_filter.values.empty()) { entity_filter.update_description(); Logger::Notice(entity_filter.description); }
|
||||
if (!layer_filter.values.empty()) { layer_filter.update_description(); Logger::Notice(layer_filter.description); }
|
||||
if (!guid_filter.values.empty()) { guid_filter.update_description(); Logger::Notice(guid_filter.description); }
|
||||
if (!name_filter.values.empty()) { name_filter.update_description(); Logger::Notice(name_filter.description); }
|
||||
if (!desc_filter.values.empty()) { desc_filter.update_description(); Logger::Notice(desc_filter.description); }
|
||||
if (!tag_filter.values.empty()) { tag_filter.update_description(); Logger::Notice(tag_filter.description); }
|
||||
|
||||
SerializerSettings settings;
|
||||
/// @todo Make APPLY_DEFAULT_MATERIALS configurable? Quickly tested setting this to false and using obj exporter caused the program to crash and burn.
|
||||
settings.set(IfcGeom::IteratorSettings::APPLY_DEFAULT_MATERIALS, true);
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, use_world_coords);
|
||||
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);
|
||||
#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);
|
||||
settings.set(IfcGeom::IteratorSettings::APPLY_LAYERSETS, enable_layerset_slicing);
|
||||
settings.set(IfcGeom::IteratorSettings::NO_NORMALS, no_normals);
|
||||
settings.set(IfcGeom::IteratorSettings::GENERATE_UVS, generate_uvs);
|
||||
|
||||
settings.set(SerializerSettings::USE_ELEMENT_NAMES, use_element_names);
|
||||
settings.set(SerializerSettings::USE_ELEMENT_GUIDS, use_element_guids);
|
||||
settings.set(SerializerSettings::USE_MATERIAL_NAMES, use_material_names);
|
||||
settings.set_deflection_tolerance(deflection_tolerance);
|
||||
settings.precision = precision;
|
||||
Logger::SetOutput(&std::cout, &log_stream);
|
||||
Logger::Verbosity(verbose ? Logger::LOG_NOTICE : Logger::LOG_ERROR);
|
||||
|
||||
GeometrySerializer* serializer;
|
||||
if (output_extension == ".obj") {
|
||||
// Do not use temp file for MTL as it's such a small file.
|
||||
const std::string mtl_filename = change_extension(output_filename, "mtl");
|
||||
const std::string mtl_filename = output_filename.substr(0,output_filename.size()-3) + "mtl";
|
||||
if (!use_world_coords) {
|
||||
Logger::Notice("Using world coords when writing WaveFront OBJ files");
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Using world coords when writing WaveFront OBJ files");
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS, true);
|
||||
}
|
||||
serializer = new WaveFrontOBJSerializer(output_temp_filename, mtl_filename, settings);
|
||||
serializer = new WaveFrontOBJSerializer(output_filename, mtl_filename);
|
||||
#ifdef WITH_OPENCOLLADA
|
||||
} else if (output_extension == ".dae") {
|
||||
serializer = new ColladaSerializer(output_temp_filename, settings);
|
||||
serializer = new ColladaSerializer(output_filename);
|
||||
#endif
|
||||
} else if (output_extension == ".stp") {
|
||||
serializer = new StepSerializer(output_temp_filename, settings);
|
||||
serializer = new StepSerializer(output_filename);
|
||||
} else if (output_extension == ".igs") {
|
||||
IGESControl_Controller::Init(); // work around Open Cascade bug
|
||||
serializer = new IgesSerializer(output_temp_filename, settings);
|
||||
} else if (output_extension == ".svg") {
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
|
||||
serializer = new SvgSerializer(output_temp_filename, settings);
|
||||
if (bounding_width && bounding_height) {
|
||||
static_cast<SvgSerializer*>(serializer)->setBoundingRectangle(bounding_width, bounding_height);
|
||||
}
|
||||
// Not sure why this is needed, but it is.
|
||||
// See: http://tracker.dev.opencascade.org/view.php?id=23679
|
||||
IGESControl_Controller::Init();
|
||||
serializer = new IgesSerializer(output_filename);
|
||||
} else {
|
||||
Logger::Error("Unknown output filename extension '" + output_extension + "'");
|
||||
Logger::Message(Logger::LOG_ERROR, "Unknown output filename extension");
|
||||
write_log();
|
||||
print_usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const bool is_tesselated = serializer->isTesselated(); // isTesselated() doesn't change at run-time
|
||||
if (!is_tesselated) {
|
||||
if (weld_vertices) {
|
||||
Logger::Notice("Weld vertices setting ignored when writing non-tesselated output");
|
||||
}
|
||||
if (generate_uvs) {
|
||||
Logger::Notice("Generate UVs setting ignored when writing non-tesselated output");
|
||||
}
|
||||
if (center_model || model_offset) {
|
||||
Logger::Notice("Centering/offsetting model setting ignored when writing non-tesselated output");
|
||||
}
|
||||
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
|
||||
printUsage(generic_options, geom_options);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!serializer->ready()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unable to open output file for writing");
|
||||
write_log();
|
||||
return EXIT_FAILURE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!serializer->isTesselated()) {
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::DISABLE_TRIANGULATION, true);
|
||||
if (weld_vertices) {
|
||||
Logger::Message(Logger::LOG_NOTICE, "Weld vertices setting ignored when writing STEP or IGES files");
|
||||
}
|
||||
}
|
||||
|
||||
time_t start,end;
|
||||
time(&start);
|
||||
|
||||
IfcGeom::Iterator<real_t> context_iterator(settings, &ifc_file, filter_funcs);
|
||||
if (!context_iterator.initialize()) {
|
||||
/// @todo It would be nice to know and print separate error prints for a case where we found no entities
|
||||
/// and for a case we found no entities that satisfy our filtering criteria.
|
||||
Logger::Error("No geometrical entities found");
|
||||
write_log();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
serializer->setFile(context_iterator.getFile());
|
||||
// Parse the file supplied in argv[1]. Returns true on succes.
|
||||
if ( ! IfcGeomObjects::Init(input_filename, &std::cout, &log_stream) ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file or no geometrical entities found");
|
||||
write_log();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (convert_back_units) {
|
||||
serializer->setUnitNameAndMagnitude(context_iterator.getUnitName(), static_cast<float>(context_iterator.getUnitMagnitude()));
|
||||
serializer->setUnitNameAndMagnitude(IfcGeomObjects::GetUnitName(), IfcGeomObjects::GetUnitMagnitude());
|
||||
} else {
|
||||
serializer->setUnitNameAndMagnitude("METER", 1.0f);
|
||||
}
|
||||
|
||||
serializer->writeHeader();
|
||||
|
||||
std::set<std::string> materials;
|
||||
|
||||
int old_progress = -1;
|
||||
|
||||
if (center_model || model_offset) {
|
||||
double* offset = serializer->settings().offset;
|
||||
if (center_model) {
|
||||
gp_XYZ center = (context_iterator.bounds_min() + context_iterator.bounds_max()) * 0.5;
|
||||
offset[0] = -center.X();
|
||||
offset[1] = -center.Y();
|
||||
offset[2] = -center.Z();
|
||||
} else {
|
||||
if (sscanf(offset_str.c_str(), "%lf;%lf;%lf", &offset[0], &offset[1], &offset[2]) != 3) {
|
||||
std::cerr << "[Error] Invalid use of --model-offset\n";
|
||||
print_options(serializer_options);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream msg;
|
||||
msg << "Using model offset (" << offset[0] << "," << offset[1] << "," << offset[2] << ")";
|
||||
Logger::Notice(msg.str());
|
||||
}
|
||||
|
||||
Logger::Status("Creating geometry...");
|
||||
|
||||
// The functions IfcGeom::Iterator::get() and IfcGeom::Iterator::next()
|
||||
// wrap an iterator of all geometrical products in the Ifc file.
|
||||
// IfcGeom::Iterator::get() returns an IfcGeom::TriangulationElement or
|
||||
// -BRepElement pointer, based on current settings. (see IfcGeomIterator.h
|
||||
// for definition) IfcGeom::Iterator::next() is used to poll whether more
|
||||
// geometrical entities are available. None of these functions throw
|
||||
// exceptions, neither for parsing errors or geometrical errors. Upon
|
||||
// calling next() the entity to be returned has already been processed, a
|
||||
// non-null return value guarantees that a successfully processed product is
|
||||
// available.
|
||||
size_t num_created = 0;
|
||||
|
||||
// The functions IfcGeomObjects::Get() and IfcGeomObjects::Next() wrap an iterator of all geometrical entities in the Ifc file.
|
||||
// IfcGeomObjects::Get() returns an IfcGeomObjects::IfcGeomObject (see IfcGeomObjects.h for definition)
|
||||
// IfcGeomObjects::Next() is used to poll whether more geometrical entities are available
|
||||
do {
|
||||
IfcGeom::Element<real_t> *geom_object = context_iterator.get();
|
||||
if (is_tesselated) {
|
||||
serializer->write(static_cast<const IfcGeom::TriangulationElement<real_t>*>(geom_object));
|
||||
const IfcGeomObjects::IfcObject* geom_object;
|
||||
|
||||
if (serializer->isTesselated()) {
|
||||
geom_object = IfcGeomObjects::Get();
|
||||
} else {
|
||||
serializer->write(static_cast<const IfcGeom::BRepElement<real_t>*>(geom_object));
|
||||
geom_object = IfcGeomObjects::GetShapeModel();
|
||||
}
|
||||
const int progress = context_iterator.progress() / 2;
|
||||
if (old_progress != progress) Logger::ProgressBar(progress);
|
||||
old_progress = progress;
|
||||
} while (++num_created, context_iterator.next());
|
||||
|
||||
Logger::Status("\rDone creating geometry (" + boost::lexical_cast<std::string>(num_created) +
|
||||
" objects) ");
|
||||
std::string lowercase_type = geom_object->type();
|
||||
for (std::string::iterator c = lowercase_type.begin(); c != lowercase_type.end(); ++c) {
|
||||
*c = tolower(*c);
|
||||
}
|
||||
if (ignore_types.find(lowercase_type) != ignore_types.end()) continue;
|
||||
|
||||
serializer->finalize();
|
||||
if (serializer->isTesselated()) {
|
||||
serializer->writeTesselated(static_cast<const IfcGeomObjects::IfcGeomObject*>(geom_object));
|
||||
} else {
|
||||
serializer->writeShapeModel(static_cast<const IfcGeomObjects::IfcGeomShapeModelObject*>(geom_object));
|
||||
}
|
||||
|
||||
const int progress = IfcGeomObjects::Progress() / 2;
|
||||
if ( old_progress!= progress ) Logger::ProgressBar(progress);
|
||||
old_progress = progress;
|
||||
|
||||
} while ( IfcGeomObjects::Next() );
|
||||
|
||||
serializer->finalize();
|
||||
delete serializer;
|
||||
|
||||
// Renaming might fail (e.g. maybe the existing file was open in a viewer application)
|
||||
// Do not remove the temp file as user can salvage the conversion result from it.
|
||||
bool successful = rename_file(output_temp_filename, output_filename);
|
||||
if (!successful) {
|
||||
Logger::Error("Unable to write output file '" + output_filename + "'");
|
||||
}
|
||||
Logger::Status("\rDone creating geometry ");
|
||||
|
||||
write_log();
|
||||
|
||||
time(&end);
|
||||
|
||||
int seconds = (int)difftime(end, start);
|
||||
std::stringstream msg;
|
||||
int minutes = seconds / 60;
|
||||
seconds = seconds % 60;
|
||||
msg << "\nConversion took";
|
||||
if (minutes > 0) {
|
||||
msg << " " << minutes << " minute";
|
||||
if (minutes > 1) {
|
||||
msg << "s";
|
||||
}
|
||||
}
|
||||
msg << " " << seconds << " second";
|
||||
if (seconds > 1) {
|
||||
msg << "s";
|
||||
}
|
||||
Logger::Status(msg.str());
|
||||
|
||||
return successful ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
int dif = (int) difftime (end,start);
|
||||
printf ("\nConversion took %d seconds\n", dif );
|
||||
}
|
||||
|
||||
void write_log() {
|
||||
std::string log = log_stream.str();
|
||||
if (!log.empty()) {
|
||||
std::cout << "\nLog:\n" << log << std::endl;
|
||||
std::cerr << std::endl << "Log:" << std::endl;
|
||||
std::cerr << log << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void parse_filter(geom_filter &filter, const std::vector<std::string>& values)
|
||||
{
|
||||
if (values.size() == 0) {
|
||||
throw po::validation_error(po::validation_error::at_least_one_value_required);
|
||||
}
|
||||
std::string type = *values.begin();
|
||||
if (type == "entities") {
|
||||
filter.type = geom_filter::ENTITY_TYPE;
|
||||
} else if (type == "layers") {
|
||||
filter.type = geom_filter::LAYER_NAME;
|
||||
} else if (type == "arg") {
|
||||
filter.type = geom_filter::ENTITY_ARG;
|
||||
filter.arg = *(values.begin() + 1);
|
||||
if (std::find(supported_args.begin(), supported_args.end(), filter.arg) == supported_args.end()) {
|
||||
throw po::validation_error(po::validation_error::invalid_option_value);
|
||||
}
|
||||
} else {
|
||||
throw po::validation_error(po::validation_error::invalid_option_value);
|
||||
}
|
||||
filter.values.insert(values.begin() + (filter.type == geom_filter::ENTITY_ARG ? 2 : 1), values.end());
|
||||
}
|
||||
|
||||
void validate(boost::any& v, const std::vector<std::string>& values, inclusion_filter*, int)
|
||||
{
|
||||
/// @todo For now only single --include or --exclude supported. Support having multiple.
|
||||
po::validators::check_first_occurrence(v);
|
||||
inclusion_filter filter;
|
||||
parse_filter(filter, values);
|
||||
v = filter;
|
||||
}
|
||||
|
||||
void validate(boost::any& v, const std::vector<std::string>& values, inclusion_traverse_filter*, int)
|
||||
{
|
||||
po::validators::check_first_occurrence(v);
|
||||
inclusion_traverse_filter filter;
|
||||
parse_filter(filter, values);
|
||||
v = filter;
|
||||
}
|
||||
|
||||
void validate(boost::any& v, const std::vector<std::string>& values, exclusion_filter*, int)
|
||||
{
|
||||
po::validators::check_first_occurrence(v);
|
||||
exclusion_filter filter;
|
||||
parse_filter(filter, values);
|
||||
v = filter;
|
||||
}
|
||||
|
||||
void validate(boost::any& v, const std::vector<std::string>& values, exclusion_traverse_filter*, int)
|
||||
{
|
||||
po::validators::check_first_occurrence(v);
|
||||
exclusion_traverse_filter filter;
|
||||
parse_filter(filter, values);
|
||||
v = filter;
|
||||
}
|
||||
|
||||
|
||||
/// @todo Clean up this filter initialization code further.
|
||||
/// @return References to the used filter functors, if none an error occurred.
|
||||
std::vector<IfcGeom::filter_t> setup_filters(const std::vector<geom_filter>& filters, const std::string& output_extension)
|
||||
{
|
||||
std::vector<IfcGeom::filter_t> filter_funcs;
|
||||
foreach(const geom_filter& f, filters) {
|
||||
if (f.type == geom_filter::ENTITY_TYPE) {
|
||||
entity_filter.include = f.include;
|
||||
entity_filter.traverse = f.traverse;
|
||||
try {
|
||||
entity_filter.populate(f.values);
|
||||
} catch (const IfcParse::IfcException& e) {
|
||||
std::cerr << "[Error] " << e.what() << std::endl;
|
||||
return std::vector<IfcGeom::filter_t>();
|
||||
}
|
||||
} else if (f.type == geom_filter::LAYER_NAME) {
|
||||
layer_filter.include = f.include;
|
||||
layer_filter.traverse = f.traverse;
|
||||
layer_filter.populate(f.values);
|
||||
} else if (f.type == geom_filter::ENTITY_ARG) {
|
||||
if (f.arg == GUID_ARG) {
|
||||
guid_filter.include = f.include;
|
||||
guid_filter.traverse = f.traverse;
|
||||
guid_filter.populate(f.values);
|
||||
} else if (f.arg == NAME_ARG) {
|
||||
name_filter.include = f.include;
|
||||
name_filter.traverse = f.traverse;
|
||||
name_filter.populate(f.values);
|
||||
} else if (f.arg == DESC_ARG) {
|
||||
desc_filter.include = f.include;
|
||||
desc_filter.traverse = f.traverse;
|
||||
desc_filter.populate(f.values);
|
||||
} else if (f.arg == TAG_ARG) {
|
||||
tag_filter.include = f.include;
|
||||
tag_filter.traverse = f.traverse;
|
||||
tag_filter.populate(f.values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no entity names are specified these are the defaults to skip from output
|
||||
if (entity_filter.values.empty()) {
|
||||
try {
|
||||
std::set<std::string> entities;
|
||||
entities.insert("IfcSpace");
|
||||
if (output_extension == ".svg") {
|
||||
entity_filter.include = true;
|
||||
} else {
|
||||
entities.insert("IfcOpeningElement");
|
||||
}
|
||||
entity_filter.populate(entities);
|
||||
} catch (const IfcParse::IfcException& e) {
|
||||
std::cerr << "[Error] " << e.what() << std::endl;
|
||||
return std::vector<IfcGeom::filter_t>();
|
||||
}
|
||||
}
|
||||
|
||||
if (!layer_filter.values.empty()) { filter_funcs.push_back(boost::ref(layer_filter)); }
|
||||
if (!entity_filter.values.empty()) { filter_funcs.push_back(boost::ref(entity_filter)); }
|
||||
if (!guid_filter.values.empty()) { filter_funcs.push_back(boost::ref(guid_filter)); }
|
||||
if (!name_filter.values.empty()) { filter_funcs.push_back(boost::ref(name_filter)); }
|
||||
if (!desc_filter.values.empty()) { filter_funcs.push_back(boost::ref(desc_filter)); }
|
||||
if (!tag_filter.values.empty()) { filter_funcs.push_back(boost::ref(tag_filter)); }
|
||||
|
||||
return filter_funcs;
|
||||
}
|
||||
}
|
||||
@@ -20,20 +20,21 @@
|
||||
#ifndef IGESSERIALIZER_H
|
||||
#define IGESSERIALIZER_H
|
||||
|
||||
#include "OpenCascadeBasedSerializer.h"
|
||||
|
||||
#include <IGESControl_Controller.hxx>
|
||||
#include <IGESControl_Writer.hxx>
|
||||
#include <Interface_Static.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
|
||||
#include "../ifcconvert/OpenCascadeBasedSerializer.h"
|
||||
|
||||
class IgesSerializer : public OpenCascadeBasedSerializer
|
||||
{
|
||||
private:
|
||||
IGESControl_Writer writer;
|
||||
IGESControl_Writer writer;
|
||||
public:
|
||||
/// @note IGESControl_Controller::Init() must be called prior to instantiating IgesSerializer.
|
||||
/// See http://tracker.dev.opencascade.org/view.php?id=23679 for more information.
|
||||
IgesSerializer(const std::string& out_filename, const SerializerSettings& settings)
|
||||
: OpenCascadeBasedSerializer(out_filename, settings)
|
||||
explicit IgesSerializer(const std::string& out_filename)
|
||||
: OpenCascadeBasedSerializer(out_filename)
|
||||
{}
|
||||
virtual ~IgesSerializer() {}
|
||||
void writeShape(const TopoDS_Shape& shape) {
|
||||
@@ -42,13 +43,12 @@ 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -21,7 +21,8 @@
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
|
||||
#include <Standard_Version.hxx>
|
||||
#include <BRepBuilderAPI_GTransform.hxx>
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
|
||||
#include "OpenCascadeBasedSerializer.h"
|
||||
|
||||
@@ -33,39 +34,48 @@ bool OpenCascadeBasedSerializer::ready() {
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement<real_t>* o) {
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) {
|
||||
void OpenCascadeBasedSerializer::writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) {
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->mesh().begin(); it != o->mesh().end(); ++ it) {
|
||||
gp_GTrsf gtrsf = it->Placement();
|
||||
|
||||
const gp_Trsf& o_trsf = o->transformation().data();
|
||||
gtrsf.PreMultiply(o_trsf);
|
||||
|
||||
if (o->geometry().settings().get(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS)) {
|
||||
gp_Trsf scale;
|
||||
scale.SetScaleFactor(1.0 / o->geometry().settings().unit_magnitude());
|
||||
gtrsf.PreMultiply(scale);
|
||||
}
|
||||
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
const TopoDS_Shape moved_shape = IfcGeom::Kernel::apply_transformation(s, gtrsf);
|
||||
// TODO:
|
||||
gp_GTrsf o_trsf;
|
||||
int k = 0;
|
||||
for( int i = 1; i < 5; ++ i )
|
||||
for ( int j = 1; j < 4; ++ j )
|
||||
o_trsf.SetValue(j, i, o->matrix()[k++]);
|
||||
|
||||
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();
|
||||
|
||||
writeShape(moved_shape);
|
||||
}
|
||||
}
|
||||
|
||||
#define RATHER_SMALL (1e-3)
|
||||
#define APPROXIMATELY_THE_SAME(a,b) (fabs(a-b) < RATHER_SMALL)
|
||||
#define ALMOST_THE_SAME(a,b) (fabs(a-b) < RATHER_SMALL)
|
||||
|
||||
const char* OpenCascadeBasedSerializer::getSymbolForUnitMagnitude(float mag) {
|
||||
if (APPROXIMATELY_THE_SAME(mag, 0.001f)) {
|
||||
if (ALMOST_THE_SAME(mag, 0.001f)) {
|
||||
return "MM";
|
||||
} else if (APPROXIMATELY_THE_SAME(mag, 0.01f)) {
|
||||
} else if (ALMOST_THE_SAME(mag, 0.01f)) {
|
||||
return "CM";
|
||||
} else if (APPROXIMATELY_THE_SAME(mag, 1.0f)) {
|
||||
} else if (ALMOST_THE_SAME(mag, 1.0f)) {
|
||||
return "M";
|
||||
} else if (APPROXIMATELY_THE_SAME(mag, 0.3048f)) {
|
||||
} else if (ALMOST_THE_SAME(mag, 0.3048f)) {
|
||||
return "FT";
|
||||
} else if (APPROXIMATELY_THE_SAME(mag, 0.0254f)) {
|
||||
} else if (ALMOST_THE_SAME(mag, 0.0254f)) {
|
||||
return "INCH";
|
||||
} else {
|
||||
return 0;
|
||||
|
||||
@@ -20,29 +20,27 @@
|
||||
#ifndef OPENCASCADEBASEDSERIALIZER_H
|
||||
#define OPENCASCADEBASEDSERIALIZER_H
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
|
||||
#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, const SerializerSettings& settings)
|
||||
: GeometrySerializer(settings)
|
||||
explicit OpenCascadeBasedSerializer(const std::string& out_filename)
|
||||
: GeometrySerializer()
|
||||
, out_filename(out_filename)
|
||||
{}
|
||||
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<real_t>* /*o*/) {}
|
||||
void write(const IfcGeom::BRepElement<real_t>* o);
|
||||
void writeTesselated(const IfcGeomObjects::IfcGeomObject* o) {}
|
||||
void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o);
|
||||
bool isTesselated() const { return false; }
|
||||
void setFile(IfcParse::IfcFile*) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,35 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef SERIALIZER_H
|
||||
#define SERIALIZER_H
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
|
||||
class Serializer {
|
||||
public:
|
||||
virtual ~Serializer() {}
|
||||
|
||||
virtual bool ready() = 0;
|
||||
virtual void writeHeader() = 0;
|
||||
virtual void finalize() = 0;
|
||||
virtual void setFile(IfcParse::IfcFile*) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -20,10 +20,11 @@
|
||||
#ifndef STEPSERIALIZER_H
|
||||
#define STEPSERIALIZER_H
|
||||
|
||||
#include <STEPControl_Controller.hxx>
|
||||
#include <STEPControl_Writer.hxx>
|
||||
#include <Interface_Static.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
|
||||
#include "../ifcconvert/OpenCascadeBasedSerializer.h"
|
||||
|
||||
@@ -32,8 +33,8 @@ class StepSerializer : public OpenCascadeBasedSerializer
|
||||
private:
|
||||
STEPControl_Writer writer;
|
||||
public:
|
||||
explicit StepSerializer(const std::string& out_filename, const SerializerSettings& settings)
|
||||
: OpenCascadeBasedSerializer(out_filename, settings)
|
||||
explicit StepSerializer(const std::string& out_filename)
|
||||
: OpenCascadeBasedSerializer(out_filename)
|
||||
{}
|
||||
virtual ~StepSerializer() {}
|
||||
void writeShape(const TopoDS_Shape& shape) {
|
||||
@@ -48,10 +49,9 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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
|
||||
@@ -1,348 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 <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<real_t>* 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->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->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();
|
||||
const TopoDS_Shape moved_shape = IfcGeom::Kernel::apply_transformation(s, gtrsf);
|
||||
|
||||
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<real_t>* elem)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
const std::string type = "product";
|
||||
const std::string name = (settings().get(SerializerSettings::USE_ELEMENT_GUIDS)
|
||||
? elem->guid() : (settings().get(SerializerSettings::USE_ELEMENT_NAMES)
|
||||
? elem->name() : elem->unique_id()));
|
||||
oss << "id=\"" << type << "-" << name<< "\"";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string SvgSerializer::nameElement(const IfcSchema::IfcProduct* elem) {
|
||||
std::ostringstream oss;
|
||||
const std::string type = elem->is(IfcSchema::Type::IfcBuildingStorey) ? "storey" : "product";
|
||||
oss << "id=\"product-" << IfcParse::IfcGlobalId(elem->GlobalId()).formatted() << "\"";
|
||||
return oss.str();
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 "../ifcconvert/GeometrySerializer.h"
|
||||
#include "../ifcconvert/util.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <limits>
|
||||
|
||||
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:
|
||||
SvgSerializer(const std::string& out_filename, const SerializerSettings& settings)
|
||||
: GeometrySerializer(settings)
|
||||
, svg_file(out_filename.c_str())
|
||||
, xmin(+std::numeric_limits<double>::infinity())
|
||||
, ymin(+std::numeric_limits<double>::infinity())
|
||||
, xmax(-std::numeric_limits<double>::infinity())
|
||||
, ymax(-std::numeric_limits<double>::infinity())
|
||||
, rescale(false)
|
||||
, file(0)
|
||||
{}
|
||||
void addXCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { xcoords.push_back(fi); }
|
||||
void addYCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { ycoords.push_back(fi); }
|
||||
void addSizeComponent(const boost::shared_ptr<util::string_buffer::float_item>& fi) { radii.push_back(fi); }
|
||||
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; }
|
||||
void writeHeader();
|
||||
bool ready();
|
||||
void write(const IfcGeom::TriangulationElement<real_t>* /*o*/) {}
|
||||
void write(const IfcGeom::BRepElement<real_t>* o);
|
||||
void write(path_object& p, const TopoDS_Wire& wire);
|
||||
path_object& start_path(IfcSchema::IfcBuildingStorey* storey, const std::string& id);
|
||||
bool isTesselated() const { return false; }
|
||||
void finalize();
|
||||
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
|
||||
void setFile(IfcParse::IfcFile* f) { file = f; }
|
||||
void setBoundingRectangle(double width, double height);
|
||||
void setSectionHeight(double h) { section_height = h; }
|
||||
std::string nameElement(const IfcGeom::Element<real_t>* elem);
|
||||
std::string nameElement(const IfcSchema::IfcProduct* elem);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -17,12 +17,10 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../ifcgeom/IfcGeomRenderStyles.h"
|
||||
|
||||
#include "WavefrontObjSerializer.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeomRenderStyles.h"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <iomanip>
|
||||
|
||||
bool WaveFrontOBJSerializer::ready() {
|
||||
@@ -42,16 +40,11 @@ void WaveFrontOBJSerializer::writeHeader() {
|
||||
mtl_basename = mtl_basename.substr(slash+1);
|
||||
}
|
||||
obj_stream << "mtllib " << mtl_basename << "\n";
|
||||
mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n";
|
||||
mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n";
|
||||
}
|
||||
|
||||
void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style)
|
||||
{
|
||||
std::string material_name = (settings().get(SerializerSettings::USE_MATERIAL_NAMES)
|
||||
? style.original_name() : style.name());
|
||||
IfcUtil::sanitate_material_name(material_name);
|
||||
mtl_stream << "newmtl " << material_name << "\n";
|
||||
|
||||
void WaveFrontOBJSerializer::writeMaterial(const IfcGeomObjects::Material& style) {
|
||||
mtl_stream << "newmtl " << style.name() << "\n";
|
||||
if (style.hasDiffuse()) {
|
||||
const double* diffuse = style.diffuse();
|
||||
mtl_stream << "Kd " << diffuse[0] << " " << diffuse[1] << " " << diffuse[2] << "\n";
|
||||
@@ -66,55 +59,51 @@ void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style)
|
||||
if (style.hasTransparency()) {
|
||||
const double transparency = 1.0 - style.transparency();
|
||||
if (transparency < 1) {
|
||||
mtl_stream << "Tr " << transparency << "\n";
|
||||
mtl_stream << "d " << transparency << "\n";
|
||||
mtl_stream << "D " << transparency << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
void WaveFrontOBJSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject* o) {
|
||||
|
||||
void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<real_t>* o)
|
||||
{
|
||||
const std::string name = (settings().get(SerializerSettings::USE_ELEMENT_GUIDS)
|
||||
? o->guid() : (settings().get(SerializerSettings::USE_ELEMENT_NAMES)
|
||||
? o->name() : o->unique_id()));
|
||||
obj_stream << "g " << name << "\n";
|
||||
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 << "s 1" << "\n";
|
||||
|
||||
const IfcGeom::Representation::Triangulation<real_t>& mesh = o->geometry();
|
||||
|
||||
const int vcount = (int)mesh.verts().size() / 3;
|
||||
for ( std::vector<real_t>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) {
|
||||
const real_t x = *(it++) + (real_t)settings().offset[0];
|
||||
const real_t y = *(it++) + (real_t)settings().offset[1];
|
||||
const real_t z = *(it++) + (real_t)settings().offset[2];
|
||||
const IfcGeomObjects::IfcRepresentationTriangulation& mesh = o->mesh();
|
||||
|
||||
const int vcount = mesh.verts().size() / 3;
|
||||
for ( std::vector<float>::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<real_t>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) {
|
||||
const real_t x = *(it++);
|
||||
const real_t y = *(it++);
|
||||
const real_t z = *(it++);
|
||||
for ( std::vector<float>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) {
|
||||
const double x = *(it++);
|
||||
const double y = *(it++);
|
||||
const double z = *(it++);
|
||||
obj_stream << "vn " << x << " " << y << " " << z << "\n";
|
||||
}
|
||||
|
||||
for (std::vector<real_t>::const_iterator it = mesh.uvs().begin(); it != mesh.uvs().end();) {
|
||||
const real_t u = *it++;
|
||||
const real_t v = *it++;
|
||||
obj_stream << "vt " << u << " " << v << "\n";
|
||||
}
|
||||
|
||||
int previous_material_id = -2;
|
||||
std::vector<int>::const_iterator material_it = mesh.material_ids().begin();
|
||||
|
||||
const bool has_uvs = !mesh.uvs().empty();
|
||||
const bool has_normals = !mesh.normals().empty();
|
||||
for ( std::vector<int>::const_iterator it = mesh.faces().begin(); it != mesh.faces().end(); ) {
|
||||
|
||||
const int material_id = *(material_it++);
|
||||
if (material_id != previous_material_id) {
|
||||
const IfcGeom::Material& material = mesh.materials()[material_id];
|
||||
std::string material_name = (settings().get(SerializerSettings::USE_MATERIAL_NAMES)
|
||||
? material.original_name() : material.name());
|
||||
IfcUtil::sanitate_material_name(material_name);
|
||||
IfcGeomObjects::Material material(0);
|
||||
if (material_id >= 0) {
|
||||
material = mesh.materials()[material_id];
|
||||
} else {
|
||||
material = IfcGeomObjects::Material(IfcGeom::get_default_style(o->type()));
|
||||
}
|
||||
const std::string material_name = material.name();
|
||||
obj_stream << "usemtl " << material_name << "\n";
|
||||
if (materials.find(material_name) == materials.end()) {
|
||||
writeMaterial(material);
|
||||
@@ -126,52 +115,7 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<real_t>*
|
||||
const int v1 = *(it++)+vcount_total;
|
||||
const int v2 = *(it++)+vcount_total;
|
||||
const int v3 = *(it++)+vcount_total;
|
||||
|
||||
if (has_normals && has_uvs) {
|
||||
obj_stream << "f " << v1 << "/" << v1 << "/" << v1 << " "
|
||||
<< v2 << "/" << v2 << "/" << v2 << " "
|
||||
<< v3 << "/" << v3 << "/" << v3 << "\n";
|
||||
} else if (has_normals) {
|
||||
obj_stream << "f " << v1 << "//" << v1 << " "
|
||||
<< v2 << "//" << v2 << " "
|
||||
<< v3 << "//" << v3 << "\n";
|
||||
} else {
|
||||
obj_stream << "f " << v1 << " " << v2 << " " << v3 << "\n";
|
||||
}
|
||||
|
||||
obj_stream << "f " << v1 << "//" << v1 << " " << v2 << "//" << v2 << " " << v3 << "//" << v3 << "\n";
|
||||
}
|
||||
|
||||
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];
|
||||
std::string material_name = (settings().get(SerializerSettings::USE_MATERIAL_NAMES)
|
||||
? material.original_name() : material.name());
|
||||
IfcUtil::sanitate_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;
|
||||
vcount_total += vcount;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
#include "../ifcconvert/GeometrySerializer.h"
|
||||
|
||||
// http://people.sc.fsu.edu/~jburkardt/txt/obj_format.txt
|
||||
class WaveFrontOBJSerializer : public GeometrySerializer {
|
||||
private:
|
||||
const std::string mtl_filename;
|
||||
@@ -35,27 +34,22 @@ private:
|
||||
unsigned int vcount_total;
|
||||
std::set<std::string> materials;
|
||||
public:
|
||||
WaveFrontOBJSerializer(const std::string& obj_filename, const std::string& mtl_filename, const SerializerSettings& settings)
|
||||
: GeometrySerializer(settings)
|
||||
, mtl_filename(mtl_filename)
|
||||
WaveFrontOBJSerializer(const std::string& obj_filename, const std::string& mtl_filename)
|
||||
: GeometrySerializer()
|
||||
, obj_stream(obj_filename.c_str())
|
||||
, mtl_stream(mtl_filename.c_str())
|
||||
, mtl_filename(mtl_filename)
|
||||
, mtl_stream(mtl_filename.c_str())
|
||||
, vcount_total(1)
|
||||
{
|
||||
obj_stream << std::setprecision(settings.precision);
|
||||
mtl_stream << std::setprecision(settings.precision);
|
||||
}
|
||||
|
||||
{}
|
||||
virtual ~WaveFrontOBJSerializer() {}
|
||||
bool ready();
|
||||
void writeHeader();
|
||||
void writeMaterial(const IfcGeom::Material& style);
|
||||
void write(const IfcGeom::TriangulationElement<real_t>* o);
|
||||
void write(const IfcGeom::BRepElement<real_t>* /*o*/) {}
|
||||
void writeMaterial(const IfcGeomObjects::Material& style);
|
||||
void writeTesselated(const IfcGeomObjects::IfcGeomObject* o);
|
||||
void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) {}
|
||||
void finalize() {}
|
||||
bool isTesselated() const { return true; }
|
||||
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
|
||||
void setFile(IfcParse::IfcFile*) {}
|
||||
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,405 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/xml_parser.hpp>
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#include "XmlSerializer.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "../ifcparse/IfcSIPrefix.h"
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
using boost::property_tree::ptree;
|
||||
using namespace IfcSchema;
|
||||
|
||||
namespace {
|
||||
|
||||
std::map<std::string, std::string> argument_name_map;
|
||||
|
||||
// Format an IFC attribute and maybe returns as string. Only literal scalar
|
||||
// values are converted. Things like entity instances and lists are omitted.
|
||||
boost::optional<std::string> format_attribute(const Argument* argument, IfcUtil::ArgumentType argument_type, const std::string& argument_name) {
|
||||
boost::optional<std::string> value;
|
||||
|
||||
// Hard-code lat-lon as it represents an array
|
||||
// of integers best emitted as a single decimal
|
||||
if (argument_name == "IfcSite.RefLatitude" ||
|
||||
argument_name == "IfcSite.RefLongitude")
|
||||
{
|
||||
std::vector<int> angle = *argument;
|
||||
double deg;
|
||||
if (angle.size() >= 3) {
|
||||
deg = angle[0] + angle[1] / 60. + angle[2] / 3600.;
|
||||
int prec = 8;
|
||||
if (angle.size() == 4) {
|
||||
deg += angle[3] / (1000000. * 3600.);
|
||||
prec = 14;
|
||||
}
|
||||
std::stringstream stream;
|
||||
stream << std::setprecision(prec) << deg;
|
||||
value = stream.str();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
switch(argument_type) {
|
||||
case IfcUtil::Argument_BOOL: {
|
||||
const bool b = *argument;
|
||||
value = b ? "true" : "false";
|
||||
break; }
|
||||
case IfcUtil::Argument_DOUBLE: {
|
||||
const double d = *argument;
|
||||
std::stringstream stream;
|
||||
stream << d;
|
||||
value = stream.str();
|
||||
break; }
|
||||
case IfcUtil::Argument_STRING:
|
||||
case IfcUtil::Argument_ENUMERATION: {
|
||||
value = static_cast<std::string>(*argument);
|
||||
break; }
|
||||
case IfcUtil::Argument_INT: {
|
||||
const int v = *argument;
|
||||
std::stringstream stream;
|
||||
stream << v;
|
||||
value = stream.str();
|
||||
break; }
|
||||
case IfcUtil::Argument_ENTITY_INSTANCE: {
|
||||
IfcUtil::IfcBaseClass* e = *argument;
|
||||
if (Type::IsSimple(e->type())) {
|
||||
IfcUtil::IfcBaseType* f = (IfcUtil::IfcBaseType*) e;
|
||||
value = format_attribute(f->getArgument(0), f->getArgumentType(0), argument_name);
|
||||
} else if (e->is(IfcSchema::Type::IfcSIUnit) || e->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)) {
|
||||
IfcSchema::IfcSIUnit* unit = (IfcSchema::IfcSIUnit*) e;
|
||||
unit_name = IfcSchema::IfcSIUnitName::ToString(unit->Name());
|
||||
if (unit->hasPrefix()) {
|
||||
unit_name = IfcSchema::IfcSIPrefix::ToString(unit->Prefix()) + unit_name;
|
||||
}
|
||||
} else {
|
||||
IfcSchema::IfcConversionBasedUnit* unit = (IfcSchema::IfcConversionBasedUnit*) e;
|
||||
unit_name = unit->Name();
|
||||
}
|
||||
|
||||
value = unit_name;
|
||||
} else if (e->is(IfcSchema::Type::IfcLocalPlacement)) {
|
||||
IfcSchema::IfcLocalPlacement* placement = e->as<IfcSchema::IfcLocalPlacement>();
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::Kernel kernel;
|
||||
if (kernel.convert(placement, trsf)) {
|
||||
std::stringstream stream;
|
||||
for (int i = 1; i < 5; ++i) {
|
||||
for (int j = 1; j < 4; ++j) {
|
||||
const double trsf_value = trsf.Value(j, i);
|
||||
stream << trsf_value << " ";
|
||||
}
|
||||
stream << ((i == 4) ? "1" : "0 ");
|
||||
}
|
||||
value = stream.str();
|
||||
}
|
||||
}
|
||||
break; }
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// Appends to a node with possibly existing attributes
|
||||
ptree& format_entity_instance(IfcUtil::IfcBaseEntity* instance, ptree& child, ptree& tree, bool as_link = false) {
|
||||
const unsigned n = instance->getArgumentCount();
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
const Argument* argument = instance->getArgument(i);
|
||||
if (argument->isNull()) continue;
|
||||
|
||||
std::string argument_name = instance->getArgumentName(i);
|
||||
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 std::string qualified_name = IfcSchema::Type::ToString(instance->type()) + "." + argument_name;
|
||||
boost::optional<std::string> value;
|
||||
try {
|
||||
value = format_attribute(argument, argument_type, qualified_name);
|
||||
} catch (...) {}
|
||||
|
||||
if (value) {
|
||||
if (as_link) {
|
||||
if (argument_name == "id") {
|
||||
child.put("<xmlattr>.xlink:href", std::string("#") + *value);
|
||||
}
|
||||
} else {
|
||||
std::stringstream stream;
|
||||
stream << "<xmlattr>." << argument_name;
|
||||
child.put(stream.str(), *value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tree.add_child(Type::ToString(instance->type()), child);
|
||||
}
|
||||
|
||||
// Formats an entity instances as a ptree node, and insert into the DOM. Recurses
|
||||
// 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;
|
||||
return format_entity_instance(instance, child, tree, as_link);
|
||||
}
|
||||
|
||||
// A function to be called recursively. Template specialization is used
|
||||
// to descend into decomposition, containment and property relationships.
|
||||
template <typename A>
|
||||
ptree& descend(A* instance, ptree& tree) {
|
||||
if (instance->is(IfcSchema::Type::IfcObjectDefinition)) {
|
||||
return descend(instance->template as<IfcSchema::IfcObjectDefinition>(), tree);
|
||||
} else {
|
||||
return format_entity_instance(instance, tree);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns related entity instances using IFC's objectified relationship
|
||||
// model. The second and third argument require a member function pointer.
|
||||
template <typename T, typename U, typename V, typename F, typename G>
|
||||
typename V::list::ptr get_related(T* t, F f, G g) {
|
||||
typename U::list::ptr li = (*t.*f)()->template as<U>();
|
||||
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)()->template as<V>());
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
// Descends into the tree by recursing into IfcRelContainedInSpatialStructure,
|
||||
// IfcRelDecomposes, IfcRelDefinesByType, IfcRelDefinesByProperties relations.
|
||||
template <>
|
||||
ptree& descend(IfcObjectDefinition* product, ptree& tree) {
|
||||
ptree& child = format_entity_instance(product, tree);
|
||||
|
||||
if (product->is(Type::IfcSpatialStructureElement)) {
|
||||
IfcSpatialStructureElement* structure = (IfcSpatialStructureElement*) product;
|
||||
|
||||
IfcObjectDefinition::list::ptr elements = get_related
|
||||
<IfcSpatialStructureElement, IfcRelContainedInSpatialStructure, IfcObjectDefinition>
|
||||
(structure, &IfcSpatialStructureElement::ContainsElements, &IfcRelContainedInSpatialStructure::RelatedElements);
|
||||
|
||||
for (IfcObjectDefinition::list::it it = elements->begin(); it != elements->end(); ++it) {
|
||||
descend(*it, child);
|
||||
}
|
||||
}
|
||||
|
||||
if (product->is(Type::IfcElement)) {
|
||||
IfcElement* element = static_cast<IfcElement*>(product);
|
||||
IfcOpeningElement::list::ptr openings = get_related<IfcElement, IfcRelVoidsElement, IfcOpeningElement>(
|
||||
element, &IfcElement::HasOpenings, &IfcRelVoidsElement::RelatedOpeningElement);
|
||||
|
||||
for (IfcOpeningElement::list::it it = openings->begin(); it != openings->end(); ++it) {
|
||||
descend(*it, child);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef USE_IFC4
|
||||
IfcObjectDefinition::list::ptr structures = get_related
|
||||
<IfcObjectDefinition, IfcRelDecomposes, IfcObjectDefinition>
|
||||
(product, &IfcObjectDefinition::IsDecomposedBy, &IfcRelDecomposes::RelatedObjects);
|
||||
#else
|
||||
IfcObjectDefinition::list::ptr structures = get_related
|
||||
<IfcObjectDefinition, IfcRelAggregates, IfcObjectDefinition>
|
||||
(product, &IfcProduct::IsDecomposedBy, &IfcRelAggregates::RelatedObjects);
|
||||
#endif
|
||||
|
||||
for (IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
|
||||
IfcObjectDefinition* ob = *it;
|
||||
descend(ob, child);
|
||||
}
|
||||
|
||||
if (product->is(IfcSchema::Type::IfcObject)) {
|
||||
IfcSchema::IfcObject* object = product->as<IfcSchema::IfcObject>();
|
||||
|
||||
IfcPropertySetDefinition::list::ptr property_sets = get_related
|
||||
<IfcObject, IfcRelDefinesByProperties, IfcPropertySetDefinition>
|
||||
(object, &IfcObject::IsDefinedBy, &IfcRelDefinesByProperties::RelatingPropertyDefinition);
|
||||
|
||||
for (IfcPropertySetDefinition::list::it it = property_sets->begin(); it != property_sets->end(); ++it) {
|
||||
IfcPropertySetDefinition* pset = *it;
|
||||
if (pset->is(Type::IfcPropertySet)) {
|
||||
format_entity_instance(pset, child, true);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_IFC4
|
||||
IfcTypeObject::list::ptr types = get_related
|
||||
<IfcObject, IfcRelDefinesByType, IfcTypeObject>
|
||||
(object, &IfcObject::IsTypedBy, &IfcRelDefinesByType::RelatingType);
|
||||
#else
|
||||
IfcTypeObject::list::ptr types = get_related
|
||||
<IfcObject, IfcRelDefinesByType, IfcTypeObject>
|
||||
(object, &IfcObject::IsDefinedBy, &IfcRelDefinesByType::RelatingType);
|
||||
#endif
|
||||
|
||||
for (IfcTypeObject::list::it it = types->begin(); it != types->end(); ++it) {
|
||||
IfcTypeObject* type = *it;
|
||||
format_entity_instance(type, child, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (product->is(Type::IfcProduct)) {
|
||||
std::map<std::string, IfcPresentationLayerAssignment*> layers = IfcGeom::Kernel::get_layers(product->as<IfcProduct>());
|
||||
for (std::map<std::string, IfcPresentationLayerAssignment*>::const_iterator it = layers.begin(); it != layers.end(); ++it) {
|
||||
// IfcPresentationLayerAssignments don't have GUIDs (only optional Identifier) so use name as the ID.
|
||||
// Note that the IfcPresentationLayerAssignment passed here doesn't really matter as as_link is true
|
||||
// for the format_entity_instance() call.
|
||||
ptree node;
|
||||
node.put("<xmlattr>.xlink:href", "#" + it->first);
|
||||
format_entity_instance(it->second, node, child, true);
|
||||
}
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
// Format IfcProperty instances and insert into the DOM. IfcComplexProperties are flattened out.
|
||||
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)) {
|
||||
IfcComplexProperty* complex = (IfcComplexProperty*) p;
|
||||
format_properties(complex->HasProperties(), node);
|
||||
} else {
|
||||
format_entity_instance(p, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // ~unnamed namespace
|
||||
|
||||
void XmlSerializer::finalize() {
|
||||
argument_name_map.insert(std::make_pair("GlobalId", "id"));
|
||||
|
||||
IfcProject::list::ptr projects = file->entitiesByType<IfcProject>();
|
||||
if (projects->size() != 1) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Expected a single IfcProject");
|
||||
return;
|
||||
}
|
||||
IfcProject* project = *projects->begin();
|
||||
|
||||
ptree root, header, units, decomposition, properties, types, layers;
|
||||
|
||||
// Write the SPF header as XML nodes.
|
||||
foreach(const std::string& s, file->header().file_description().description()) {
|
||||
header.add_child("file_description.description", ptree(s));
|
||||
}
|
||||
foreach(const std::string& s, file->header().file_name().author()) {
|
||||
header.add_child("file_name.author", ptree(s));
|
||||
}
|
||||
foreach(const std::string& s, file->header().file_name().organization()) {
|
||||
header.add_child("file_name.organization", ptree(s));
|
||||
}
|
||||
foreach(const std::string& s, file->header().file_schema().schema_identifiers()) {
|
||||
header.add_child("file_schema.schema_identifiers", ptree(s));
|
||||
}
|
||||
header.put("file_description.implementation_level", file->header().file_description().implementation_level());
|
||||
header.put("file_name.name", file->header().file_name().name());
|
||||
header.put("file_name.time_stamp", file->header().file_name().time_stamp());
|
||||
header.put("file_name.preprocessor_version", file->header().file_name().preprocessor_version());
|
||||
header.put("file_name.originating_system", file->header().file_name().originating_system());
|
||||
header.put("file_name.authorization", file->header().file_name().authorization());
|
||||
|
||||
// Descend into the decomposition structure of the IFC file.
|
||||
descend(project, decomposition);
|
||||
|
||||
// Write all property sets and values as XML nodes.
|
||||
IfcPropertySet::list::ptr psets = file->entitiesByType<IfcPropertySet>();
|
||||
for (IfcPropertySet::list::it it = psets->begin(); it != psets->end(); ++it) {
|
||||
IfcPropertySet* pset = *it;
|
||||
ptree& node = format_entity_instance(pset, properties);
|
||||
format_properties(pset->HasProperties(), node);
|
||||
}
|
||||
|
||||
// Write all type objects as XML nodes.
|
||||
IfcTypeObject::list::ptr type_objects = file->entitiesByType<IfcTypeObject>();
|
||||
for (IfcTypeObject::list::it it = type_objects->begin(); it != type_objects->end(); ++it) {
|
||||
IfcTypeObject* type_object = *it;
|
||||
ptree& node = descend(type_object, types);
|
||||
// ptree& node = format_entity_instance(type_object, types);
|
||||
|
||||
if (type_object->hasHasPropertySets()) {
|
||||
IfcPropertySetDefinition::list::ptr property_sets = type_object->HasPropertySets();
|
||||
for (IfcPropertySetDefinition::list::it jt = property_sets->begin(); jt != property_sets->end(); ++jt) {
|
||||
IfcPropertySetDefinition* pset = *jt;
|
||||
if (pset->is(Type::IfcPropertySet)) {
|
||||
format_entity_instance(pset, node, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write all assigned units as XML nodes.
|
||||
IfcEntityList::ptr unit_assignments = project->UnitsInContext()->Units();
|
||||
for (IfcEntityList::it it = unit_assignments->begin(); it != unit_assignments->end(); ++it) {
|
||||
if ((*it)->is(IfcSchema::Type::IfcNamedUnit)) {
|
||||
IfcSchema::IfcNamedUnit* named_unit = (*it)->as<IfcSchema::IfcNamedUnit>();
|
||||
ptree& node = format_entity_instance(named_unit, units);
|
||||
node.put("<xmlattr>.SI_equivalent", IfcParse::get_SI_equivalent(named_unit));
|
||||
} else if ((*it)->is(IfcSchema::Type::IfcMonetaryUnit)) {
|
||||
format_entity_instance((*it)->as<IfcSchema::IfcMonetaryUnit>(), units);
|
||||
}
|
||||
}
|
||||
|
||||
// Layer assignments. IfcPresentationLayerAssignments don't have GUIDs (only optional Identifier)
|
||||
// so use names as the IDs and only insert those with unique names. In case of possible duplicate names/IDs
|
||||
// the first IfcPresentationLayerAssignment occurence takes precedence.
|
||||
std::set<std::string> layer_names;
|
||||
IfcPresentationLayerAssignment::list::ptr layer_assignments = file->entitiesByType<IfcPresentationLayerAssignment>();
|
||||
for (IfcPresentationLayerAssignment::list::it it = layer_assignments->begin(); it != layer_assignments->end(); ++it) {
|
||||
const std::string& name = (*it)->Name();
|
||||
if (layer_names.find(name) == layer_names.end()) {
|
||||
layer_names.insert(name);
|
||||
ptree node;
|
||||
node.put("<xmlattr>.id", name);
|
||||
format_entity_instance(*it, node, layers);
|
||||
}
|
||||
}
|
||||
|
||||
root.add_child("ifc.header", header);
|
||||
root.add_child("ifc.units", units);
|
||||
root.add_child("ifc.properties", properties);
|
||||
root.add_child("ifc.types", types);
|
||||
root.add_child("ifc.layers", layers);
|
||||
root.add_child("ifc.decomposition", decomposition);
|
||||
|
||||
root.put("ifc.<xmlattr>.xmlns:xlink", "http://www.w3.org/1999/xlink");
|
||||
|
||||
#if BOOST_VERSION >= 105600
|
||||
boost::property_tree::xml_writer_settings<ptree::key_type> settings = boost::property_tree::xml_writer_make_settings<ptree::key_type>('\t', 1);
|
||||
#else
|
||||
boost::property_tree::xml_writer_settings<char> settings('\t', 1);
|
||||
#endif
|
||||
boost::property_tree::write_xml(xml_filename, root, std::locale(), settings);
|
||||
}
|
||||
@@ -1,41 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef XMLSERIALIZER_H
|
||||
#define XMLSERIALIZER_H
|
||||
|
||||
#include "../ifcconvert/Serializer.h"
|
||||
|
||||
class XmlSerializer : public Serializer {
|
||||
private:
|
||||
IfcParse::IfcFile* file;
|
||||
std::string xml_filename;
|
||||
public:
|
||||
XmlSerializer(const std::string& xml_filename)
|
||||
: Serializer()
|
||||
, xml_filename(xml_filename)
|
||||
{}
|
||||
|
||||
bool ready() { return true; }
|
||||
void writeHeader() {}
|
||||
void finalize();
|
||||
void setFile(IfcParse::IfcFile* f) { file = f; }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,43 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#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();
|
||||
}
|
||||
@@ -1,67 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#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;
|
||||
virtual ~item() {};
|
||||
};
|
||||
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; }
|
||||
virtual ~string_item() {};
|
||||
};
|
||||
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(); }
|
||||
virtual ~float_item() {};
|
||||
};
|
||||
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
|
||||
@@ -0,0 +1,71 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# 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 files uses the documentation files from buildingSMART to generate #
|
||||
# descriptions from EXPRESS names that are suitable for comments in the C++ #
|
||||
# code. The .csv files used by this file are generated from the MS Office #
|
||||
# Access database, which in turn has been generated from the IFC baseline #
|
||||
# documentation by the IFCDOC utility provided by buildingSMART. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import re,csv
|
||||
import csv
|
||||
try: from html.entities import entitydefs
|
||||
except: from htmlentitydefs import entitydefs
|
||||
|
||||
name_to_oid = {}
|
||||
oid_to_desc = {}
|
||||
oid_to_name = {}
|
||||
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']
|
||||
for fn in definition_files:
|
||||
with open(fn) 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:
|
||||
for pid, x, oid in csv.reader(f, delimiter=';', quotechar='"'):
|
||||
oid_to_pid[oid] = pid
|
||||
|
||||
with open('DocAttribute.csv') as f:
|
||||
for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'):
|
||||
pid = oid_to_pid[oid]
|
||||
pname = oid_to_name[pid]
|
||||
name_to_oid[(pname, name)] = oid
|
||||
oid_to_desc[oid] = desc
|
||||
|
||||
def description(item):
|
||||
global name_to_oid, oid_to_desc, oid_to_name, oid_to_pid
|
||||
oid = name_to_oid.get(item,0)
|
||||
desc = oid_to_desc.get(oid,None)
|
||||
if desc:
|
||||
for a,b in entitydefs.items(): desc = desc.replace("&%s;"%a,b)
|
||||
desc = desc.replace("\r","")
|
||||
for r,s in regices[:-1]: desc = r.sub(s,desc)
|
||||
desc = desc.strip()
|
||||
r,s = regices[-1]
|
||||
desc = r.sub(s,desc)
|
||||
return desc
|
||||
@@ -0,0 +1,779 @@
|
||||
header = """
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
""".strip()
|
||||
|
||||
###############################################################################
|
||||
# #
|
||||
# This file can be used to generate C++ code from Express schema files. The #
|
||||
# generated code works alongside the IfcOpenShell IfcParse library. This #
|
||||
# script has only been tested on IFC2X3_TC1.exp and will most probably not #
|
||||
# work on any other schemas. #
|
||||
# #
|
||||
# Note this script uses funcparserlib, which is available at: #
|
||||
# http://code.google.com/p/funcparserlib/ #
|
||||
# The script only works with revision 30f7ee896bc9 because it uses the some() #
|
||||
# parser and is incompatible with other changes as well. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import os, sys
|
||||
import IfcDocumentation
|
||||
|
||||
filename = sys.argv[1]
|
||||
|
||||
#
|
||||
# A class to split the Express schema files into seperate tokens
|
||||
#
|
||||
class Tokenizer(object):
|
||||
comment = ['(*','*)']
|
||||
termchars = ',;()=[]:'
|
||||
def __init__(self, fn):
|
||||
if hasattr(fn,'read'): object.__setattr__(self,'f',fn)
|
||||
else: object.__setattr__(self,'f',open(fn,'rb'))
|
||||
def __getattr__(self, name):
|
||||
return getattr(self.f, name)
|
||||
def __setattr__(self, name, value):
|
||||
setattr(self.f, name, value)
|
||||
def __iter__(self): return self
|
||||
def next(self):
|
||||
def get():
|
||||
buffer = ''
|
||||
in_comment = False
|
||||
in_string = False
|
||||
offset = self.tell()
|
||||
while True:
|
||||
c = self.read(2)
|
||||
if len(c) < 2: raise StopIteration
|
||||
if c in Tokenizer.comment:
|
||||
in_comment = c == Tokenizer.comment[0]
|
||||
continue
|
||||
if in_string and c == "''":
|
||||
buffer += "'"
|
||||
continue
|
||||
self.seek(-1,1)
|
||||
if not in_string and c[0].isspace():
|
||||
if ( len(buffer) ): return buffer
|
||||
else:
|
||||
offset = self.tell()
|
||||
continue
|
||||
if not in_comment:
|
||||
if len(buffer) and (c[0] in Tokenizer.termchars or buffer[-1] in Tokenizer.termchars):
|
||||
self.seek(-1,1)
|
||||
return buffer
|
||||
buffer += c[0]
|
||||
return get()
|
||||
|
||||
#
|
||||
# Some global variables to keep track of variable names
|
||||
#
|
||||
express_to_cpp = {
|
||||
'BOOLEAN':'bool',
|
||||
'LOGICAL':'bool',
|
||||
'INTEGER':'int',
|
||||
'REAL':'double',
|
||||
'NUMBER':'double',
|
||||
'STRING':'std::string'
|
||||
}
|
||||
schema_version = ''
|
||||
enumerations = set()
|
||||
selections = set()
|
||||
entity_names = set()
|
||||
simple_types = {}
|
||||
selectable_simple_types = set()
|
||||
argument_count = {}
|
||||
parent_relations = {}
|
||||
argument_names_and_types = {}
|
||||
entity_map = {}
|
||||
|
||||
#
|
||||
# Since inherited arguments of Express entities are placed in sequence before the
|
||||
# non-inherited ones, we need to keep track of how many inherited arguments exist
|
||||
#
|
||||
def argument_start(c):
|
||||
if c not in parent_relations: return 0
|
||||
i = 0
|
||||
while True:
|
||||
c = parent_relations[c]
|
||||
i += argument_count[c] if c in argument_count else 0
|
||||
if not (c in parent_relations): break
|
||||
return i
|
||||
|
||||
def parent_arguments(c):
|
||||
if c not in parent_relations: return []
|
||||
l = []
|
||||
while True:
|
||||
c = parent_relations[c]
|
||||
i += argument_count[c] if c in argument_count else 0
|
||||
if not (c in parent_relations): break
|
||||
return []
|
||||
|
||||
#
|
||||
# Every constructor also initializes their parent class members, hence they
|
||||
# need be stored as well.
|
||||
#
|
||||
def parent_arguments(c):
|
||||
if c not in parent_relations: return []
|
||||
l = []
|
||||
while True:
|
||||
c = parent_relations[c]
|
||||
i += argument_count[c] if c in argument_count else 0
|
||||
if not (c in parent_relations): break
|
||||
return []
|
||||
|
||||
#
|
||||
# Several classes to generate code from Express types and entities
|
||||
#
|
||||
class ArrayType:
|
||||
def __init__(self,l):
|
||||
self.type = express_to_cpp.get(l[3],l[3])
|
||||
self.upper = l[2]
|
||||
self.lower = l[1]
|
||||
def is_select_list(self): return self.type in selections
|
||||
def __str__(self):
|
||||
if self.type in entity_names:
|
||||
return "SHARED_PTR< IfcTemplatedEntityList< %s > >"%self.type
|
||||
elif self.type in selections:
|
||||
return "SHARED_PTR< IfcTemplatedEntityList< IfcAbstractSelect > >"
|
||||
else:
|
||||
return "std::vector< %(type)s > /*[%(lower)s:%(upper)s]*/"%self.__dict__
|
||||
def is_shared_ptr(self): return self.type in entity_names or self.type in selections
|
||||
def type_enum(self):
|
||||
if self.type in simple_types:
|
||||
t = simple_types[self.type].type_enum()
|
||||
else:
|
||||
t = self.type
|
||||
if t in entity_names or t == "Argument_ENTITY":
|
||||
return "Argument_ENTITY_LIST"
|
||||
elif t in selections:
|
||||
return "Argument_ENTITY_LIST"
|
||||
elif t == "int":
|
||||
return "Argument_VECTOR_INT"
|
||||
elif t == "double" or t == "Argument_DOUBLE":
|
||||
return "Argument_VECTOR_DOUBLE"
|
||||
elif t == "std::string" or t == "Argument_STRING":
|
||||
return "Argument_VECTOR_STRING"
|
||||
elif isinstance(t, BinaryType):
|
||||
return "Argument_UNKNOWN"
|
||||
else:
|
||||
assert False, t
|
||||
|
||||
class ScalarType:
|
||||
def __init__(self,l): self.type = express_to_cpp.get(l,l)
|
||||
def __str__(self): return self.type
|
||||
def is_select_list(self): return False
|
||||
def type_enum(self):
|
||||
if self.type in simple_types:
|
||||
return simple_types[self.type].type_enum()
|
||||
elif self.type in entity_names:
|
||||
return "Argument_ENTITY"
|
||||
else:
|
||||
return { "bool":"Argument_BOOL","int":"Argument_INT","double":"Argument_DOUBLE","std::string":"Argument_STRING"}[self.type]
|
||||
class EnumType:
|
||||
def __init__(self,l):
|
||||
self.v = [(x,'%s_%s'%('%(fancy_name)s',x)) for x in l]
|
||||
self.maxlen = max([len(v) for v in self.v])
|
||||
def __str__(self):
|
||||
if generator_mode == 'HEADER':
|
||||
return "enum {%s}"%", ".join([v2 for v1,v2 in self.v])
|
||||
elif generator_mode == 'SOURCE_TO':
|
||||
return '{ "%s" }'%'","'.join([v1 for v1,v2 in self.v])
|
||||
elif generator_mode == 'SOURCE_FROM':
|
||||
return "".join([' if(s=="%s"%s) return ::%s::%s::%s;\n'%(v1.upper()," "*(self.maxlen-len(v1)),schema_version,"%(name)s",v2) for v1,v2 in self.v])
|
||||
def is_select_list(self): return False
|
||||
def __len__(self): return len(self.v)
|
||||
def type_enum(self):
|
||||
return "Argument_ENUMERATION"
|
||||
class SelectType:
|
||||
def __init__(self,l):
|
||||
for x in l:
|
||||
if x in simple_types: selectable_simple_types.add(x)
|
||||
def __str__(self): return "IfcSchemaEntity"
|
||||
def is_select_list(self): return False
|
||||
def type_enum(self): return "Argument_ENTITY"
|
||||
class BinaryType:
|
||||
def __init__(self,l): self.l = int(l)
|
||||
def __str__(self): return "char[%s]"%self.l
|
||||
def is_select_list(self): return False
|
||||
def type_enum(self): raise NotImplementedError()
|
||||
class InverseType:
|
||||
def __init__(self,l):
|
||||
self.name, self.type, self.reference = l
|
||||
def type_enum(self): return "Argument_ENTITY"
|
||||
def is_select_list(self): return False
|
||||
class Typedef:
|
||||
def __init__(self,l):
|
||||
self.name,self.type=l[1:3]
|
||||
self.fancy_name = self.name[:-4] if self.name.endswith("Enum") else self.name
|
||||
if isinstance(self.type,EnumType):
|
||||
enumerations.add(self.name)
|
||||
self.len = len(self.type)
|
||||
elif isinstance(self.type,SelectType): selections.add(self.name)
|
||||
simple_types[self.name] = self
|
||||
comment = IfcDocumentation.description(self.name)
|
||||
self.comment = comment+"\n" if comment else ''
|
||||
def __str__(self):
|
||||
global generator_mode
|
||||
if generator_mode == 'HEADER' and isinstance(self.type,EnumType):
|
||||
return ("namespace %(name)s {\n%(comment)stypedef %(type)s %(name)s;\nconst char* ToString(%(name)s v);\n%(name)s FromString(const std::string& s);\n}"%self.__dict__)%self.__dict__
|
||||
elif generator_mode == 'HEADER':
|
||||
return "%stypedef %s %s;"%(self.comment,self.type,self.name)
|
||||
elif generator_mode == 'SOURCE' and isinstance(self.type,EnumType):
|
||||
generator_mode = 'SOURCE_TO'
|
||||
s = "const char* %(name)s::ToString(%(name)s v) {\n if ( v < 0 || v >= %(len)d ) throw IfcException(\"Unable to find find keyword in schema\");\n const char* names[] = %(type)s;\n return names[v];\n}\n"%self.__dict__
|
||||
generator_mode = 'SOURCE_FROM'
|
||||
s += ("%(name)s::%(name)s %(name)s::FromString(const std::string& s) {\n%(type)s throw IfcException(\"Unable to find find keyword in schema\");\n}"%self.__dict__)%self.__dict__
|
||||
generator_mode = 'SOURCE'
|
||||
return s
|
||||
def type_enum(self):
|
||||
return self.type.type_enum()
|
||||
class Argument(object):
|
||||
def __init__(self,l):
|
||||
self.name, self.optional, self.type = l
|
||||
def is_enum(self): return str(self.type) in enumerations
|
||||
def type_str(self):
|
||||
if self.type.is_select_list():
|
||||
# This is extremely hackish indeed
|
||||
return "optional< IfcEntities >" if self.optional else "IfcEntities"
|
||||
elif str(self.type) in entity_names:
|
||||
return "%(type)s*"%self.__dict__
|
||||
else:
|
||||
t = "%(type)s::%(type)s"%self.__dict__ if self.is_enum() else self.type
|
||||
return "optional< %s >"%t if self.optional else t
|
||||
class ArgumentList:
|
||||
def __init__(self,l):
|
||||
self.l = [Argument(a) for a in l]
|
||||
self.argstart = 0
|
||||
def __len__(self): return len(self.l)
|
||||
def __str__(self):
|
||||
s = ""
|
||||
argv = self.argstart
|
||||
for a in self.l:
|
||||
class_name = indent = comment = optional_comment = ""
|
||||
is_array = isinstance(a.type,ArrayType) and a.type.is_shared_ptr()
|
||||
return_type = str(a.type)
|
||||
if generator_mode == 'SOURCE':
|
||||
class_name = "%(class_name)s::"
|
||||
if isinstance(a.type,BinaryType) or (isinstance(a.type,ArrayType) and isinstance(a.type.type,BinaryType)):
|
||||
function_body = " { throw; /* Not implemented argument*/ }"
|
||||
elif isinstance(a.type,ArrayType) and str(a.type.type) in entity_names:
|
||||
function_body = " { RETURN_AS_LIST(%s,%d) }"%(a.type.type,argv)
|
||||
elif isinstance(a.type,ArrayType) and str(a.type.type) in selections:
|
||||
function_body = " { RETURN_AS_LIST(IfcAbstractSelect,%d) }"%(argv)
|
||||
elif return_type in entity_names:
|
||||
function_body = " { return reinterpret_pointer_cast<IfcBaseClass,%s>(*entity->getArgument(%d)); }"%(return_type,argv)
|
||||
elif return_type in enumerations:
|
||||
function_body = " { return %s::FromString(*entity->getArgument(%d)); }"%(return_type,argv)
|
||||
else:
|
||||
function_body = " { return *entity->getArgument(%d); }"%argv
|
||||
function_body2 = " { return !entity->getArgument(%d)->isNull(); }"%argv
|
||||
if isinstance(a.type,BinaryType) or (isinstance(a.type,ArrayType) and isinstance(a.type.type,BinaryType)):
|
||||
function_body3 = " { if ( ! entity->isWritable() ) { throw; } }"
|
||||
elif return_type in enumerations:
|
||||
function_body3 = " { if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%d,v%s,%s::ToString(v)); }"%(argv,"->generalize()" if is_array else "",return_type)
|
||||
else:
|
||||
function_body3 = " { if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%d,v%s); }"%(argv,"->generalize()" if is_array else "")
|
||||
else:
|
||||
indent = " "
|
||||
function_body = function_body2 = function_body3 = ";"
|
||||
comment = IfcDocumentation.description((self.class_name,a.name))
|
||||
comment = comment+"\n" if comment else ''
|
||||
comment = comment.replace("///","%s///"%indent)
|
||||
optional_comment = "%s/// Whether the optional attribute %s is defined for this %s\n"%(indent,a.name,self.class_name)
|
||||
if a.optional: s += "\n%s%sbool %shas%s()%s"%(optional_comment,indent,class_name,a.name,function_body2)
|
||||
if ( str(a.type) in enumerations ):
|
||||
return_type = "%(type)s::%(type)s"%a.__dict__
|
||||
elif ( str(a.type) in entity_names ):
|
||||
return_type = "%(type)s*"%a.__dict__
|
||||
s += "\n%s%s%s %s%s()%s"%(comment,indent,return_type,class_name,a.name,function_body)
|
||||
s += "\n%svoid %sset%s(%s v)%s"%(indent,class_name,a.name,return_type,function_body3)
|
||||
argv += 1
|
||||
|
||||
if generator_mode == 'HEADER':
|
||||
s += "\n virtual unsigned int getArgumentCount() const { return %(n_arguments)d; }" % dict(class_name=self.class_name, n_arguments=len(self.l) + argument_start(self.class_name))
|
||||
|
||||
s += "\n virtual ArgumentType getArgumentType(unsigned int i) const {"
|
||||
if len(self.l):
|
||||
s += " switch (i) {"
|
||||
for i, a in enumerate(self.l):
|
||||
s += "case %d: " % (i + argument_start(self.class_name))
|
||||
s += "return %s; " % a.type.type_enum()
|
||||
s += "}"
|
||||
if self.parent_class is not None:
|
||||
s += " return %s::getArgumentType(i); }" % self.parent_class
|
||||
else:
|
||||
s += " throw IfcException(\"argument out of range\"); }"
|
||||
|
||||
s += "\n virtual const char* getArgumentName(unsigned int i) const {"
|
||||
if len(self.l):
|
||||
s += " switch (i) {"
|
||||
for i, a in enumerate(self.l):
|
||||
s += "case %d: " % (i + argument_start(self.class_name))
|
||||
s += "return \"%s\"; " % a.name
|
||||
s += "}"
|
||||
if self.parent_class is not None:
|
||||
s += " return %s::getArgumentName(i); }" % self.parent_class
|
||||
else:
|
||||
s += " throw IfcException(\"argument out of range\"); }"
|
||||
|
||||
s += "\n virtual ArgumentPtr getArgument(unsigned int i) const { return entity->getArgument(i); }"
|
||||
return s
|
||||
class InverseList:
|
||||
def __init__(self,l):
|
||||
self.l = l
|
||||
def __str__(self):
|
||||
if self.l is None: return ""
|
||||
s = ""
|
||||
for i in self.l:
|
||||
if generator_mode == 'HEADER':
|
||||
s += "\n SHARED_PTR< IfcTemplatedEntityList< %s > > %s(); // INVERSE %s::%s"%(i.type.type,i.name,i.type.type,i.reference)
|
||||
elif generator_mode == 'SOURCE':
|
||||
s += "\n%s::list %s::%s() { RETURN_INVERSE(%s) }"%(i.type.type,"%(class_name)s",i.name,i.type.type)
|
||||
return s
|
||||
class Classdef:
|
||||
def __init__(self,l):
|
||||
self.class_name, self.parent_class, self.arguments, self.inverse = l
|
||||
self.arguments.class_name = self.class_name
|
||||
self.arguments.parent_class = self.parent_class
|
||||
entity_names.add(self.class_name)
|
||||
parent_relations[self.class_name] = self.parent_class
|
||||
argument_count[self.class_name] = len(self.arguments)
|
||||
entity_map[self.class_name] = self
|
||||
def get_attributes(self, get_parent=True):
|
||||
s = entity_map[self.parent_class].get_attributes() if get_parent and self.parent_class else []
|
||||
s += [(a.name,not not a.optional,a.type.type_enum(),a.type.type if a.is_enum() else None) for a in self.arguments.l]
|
||||
return s
|
||||
def get_constructor_args(self):
|
||||
s = entity_map[self.parent_class].get_constructor_args() if self.parent_class else []
|
||||
i = len(s) + 1
|
||||
s += ["%s v%d_%s"%(a.type_str(),b+i,a.name) for a,b in zip(self.arguments.l,range(len(self.arguments)))]
|
||||
return s
|
||||
def get_constructor_implementation(self):
|
||||
s = entity_map[self.parent_class].get_constructor_implementation() if self.parent_class else []
|
||||
i = len(s) + 1
|
||||
b = 0
|
||||
for a in self.arguments.l:
|
||||
is_enumeration = str(a.type) in enumerations
|
||||
# boost::optional is not used for pointer types, because they are set to NULL using 0
|
||||
use_boost_optional = a.optional and str(a.type) not in entity_names
|
||||
# boost::optional types need to be dereferenced before passing to the writable entity
|
||||
dereference = "*" if use_boost_optional else ""
|
||||
generalize = "->generalize()" if (isinstance(a.type,ArrayType) and a.type.is_shared_ptr() and not a.type.is_select_list()) else ""
|
||||
if isinstance(a.type,BinaryType) or (isinstance(a.type,ArrayType) and isinstance(a.type.type,BinaryType)):
|
||||
continue
|
||||
if is_enumeration:
|
||||
impl = "e->setArgument(%d,%sv%d_%s,%s::ToString(%sv%d_%s))"%(b+i-1,dereference,b+i,a.name,str(a.type),dereference,b+i,a.name)
|
||||
else:
|
||||
impl = "e->setArgument(%d,(%sv%d_%s)%s)"%(b+i-1,dereference,b+i,a.name,generalize)
|
||||
if use_boost_optional:
|
||||
s.append("if (v%d_%s) { %s; } else { e->setArgument(%d); } "%(b+i,a.name,impl,b+i-1))
|
||||
else: s.append(impl)
|
||||
b += 1
|
||||
return s#"; ".join(s)
|
||||
def __str__(self):
|
||||
self.constructor_args_list = self.get_constructor_args()
|
||||
self.constructor_args = ", ".join(self.constructor_args_list)
|
||||
if generator_mode == 'HEADER':
|
||||
comment = IfcDocumentation.description(self.class_name)
|
||||
comment = comment+"\n" if comment else ''
|
||||
return "%sclass %s : public %s {\npublic:%s%s%s\n};" % (comment,self.class_name,
|
||||
"IfcBaseEntity" if self.parent_class is None else self.parent_class,
|
||||
self.arguments,
|
||||
self.inverse,
|
||||
("\n bool is(Type::Enum v) const;"+
|
||||
"\n Type::Enum type() const;"+
|
||||
"\n static Type::Enum Class();"+
|
||||
"\n %(class_name)s (IfcAbstractEntityPtr e = IfcAbstractEntityPtr());"+
|
||||
("\n %(class_name)s (%(constructor_args)s);" if len(self.constructor_args_list) else "")+
|
||||
"\n typedef %(class_name)s* ptr;"+
|
||||
"\n typedef SHARED_PTR< IfcTemplatedEntityList< %(class_name)s > > list;"+
|
||||
"\n typedef IfcTemplatedEntityList< %(class_name)s >::it it;")%self.__dict__
|
||||
)
|
||||
elif generator_mode == 'SOURCE':
|
||||
self.arguments.argstart = argument_start(self.class_name)
|
||||
self.constructor_implementation = "; ".join(self.get_constructor_implementation())
|
||||
return (("\n// Function implementations for %(class_name)s"+str(self.arguments)+str(self.inverse)+
|
||||
("\nbool %(class_name)s::is(Type::Enum v) const { return v == Type::%(class_name)s; }" if self.parent_class is None else
|
||||
"\nbool %(class_name)s::is(Type::Enum v) const { return v == Type::%(class_name)s || %(parent_class)s::is(v); }")+
|
||||
"\nType::Enum %(class_name)s::type() const { return Type::%(class_name)s; }"+
|
||||
"\nType::Enum %(class_name)s::Class() { return Type::%(class_name)s; }"+
|
||||
"\n%(class_name)s::%(class_name)s(IfcAbstractEntityPtr e) { if (!is(Type::%(class_name)s)) throw IfcException(\"Unable to find find keyword in schema\"); entity = e; }"+
|
||||
("\n%(class_name)s::%(class_name)s(%(constructor_args)s) { IfcWritableEntity* e = new IfcWritableEntity(Class()); %(constructor_implementation)s; entity = e; EntityBuffer::Add(this); }" if len(self.constructor_args_list) else "")
|
||||
)%self.__dict__)%self.__dict__
|
||||
|
||||
|
||||
from funcparserlib.parser import a, skip, many, maybe, some
|
||||
|
||||
#
|
||||
# Lambda functions to map combinator output to classes
|
||||
#
|
||||
array_type = lambda t: ArrayType(t)
|
||||
scalar_type = lambda t: ScalarType(t)
|
||||
enum_type = lambda t: EnumType(t)
|
||||
select_type = lambda t: SelectType(t)
|
||||
binary_type = lambda t: BinaryType(t)
|
||||
inverse_type = lambda t: InverseType(t)
|
||||
format_type = lambda t: Typedef(t)
|
||||
argument_list = lambda t: ArgumentList(t)
|
||||
inverse_list = lambda t: InverseList(t)
|
||||
format_options = lambda t: [t[0]]+t[1]
|
||||
|
||||
#
|
||||
# The actual grammar definition
|
||||
#
|
||||
s = some(lambda t: not t in ['UNIQUE','WHERE','END_ENTITY','END_TYPE','INVERSE','DERIVE'])
|
||||
x = lambda s:skip(a(s))
|
||||
list_or_array = a('ARRAY') | a('LIST') | a('SET')
|
||||
binary = x('BINARY')+x('(') + s + x(')') >> binary_type
|
||||
array = list_or_array + x('[') + s + x(':') + s + x(']') + x('OF') + skip(maybe(a('UNIQUE'))) + (binary|s) >> array_type
|
||||
options = x('(') + s + many(x(',')+s) + x(')') >> format_options
|
||||
enum = x('ENUMERATION') + x('OF') + options >> enum_type
|
||||
select = x('SELECT') + options >> select_type
|
||||
single = s + skip(maybe(x('(')+s+x(')')) + maybe(a('FIXED'))) >> scalar_type
|
||||
type_type = array | enum | select | single
|
||||
type_start = a('TYPE') + s + x('=') + type_type + x(';')
|
||||
type_end = a('END_TYPE') + x(';')
|
||||
|
||||
to_end = many(some(lambda t: t != ';'))
|
||||
clause = s + x(':') + to_end + x(';')
|
||||
where = a('WHERE') + many(clause)
|
||||
|
||||
type = type_start + maybe(where) + type_end >> format_type
|
||||
|
||||
subtype = x('SUBTYPE') + x('OF') + x('(') + s + x(')')
|
||||
supertype = maybe(x('ABSTRACT')) + x('SUPERTYPE') + x('OF') + x('(') + x('ONEOF') + options + x(')')
|
||||
entity_start = x('ENTITY') + s + skip(maybe(supertype)) + maybe(subtype) + x(';')
|
||||
entity_end = x('END_ENTITY') + x(';')
|
||||
key_value = s + x(':') + maybe(a('OPTIONAL')) + (array|binary|single) + x(';')
|
||||
arguments = many(key_value) >> argument_list
|
||||
unique_value = s + x(':') + s + many(a(',')+s) + a(';')
|
||||
unique = skip(a('UNIQUE') + many(unique_value))
|
||||
inverse_def = s + x(':') + (array|single) + x('FOR') + s + x(';') >> inverse_type
|
||||
inverse = maybe(x('INVERSE') + many( inverse_def )) >> inverse_list
|
||||
derive = skip(a('DERIVE') + many(clause))
|
||||
|
||||
entity = entity_start + arguments + skip(maybe(unique)) + skip(maybe(derive)) + inverse + skip(maybe(where)) + entity_end >> Classdef
|
||||
|
||||
schema = skip(a('SCHEMA')) + s + x(';')
|
||||
|
||||
express = schema + many(type) + many(entity)
|
||||
schema_version,types,entities = express.parse(list(Tokenizer(filename)))
|
||||
schema_version = schema_version.capitalize()
|
||||
|
||||
#
|
||||
# Writing of the three generated files starts here
|
||||
#
|
||||
h_file = open("%s.h"%schema_version,'w')
|
||||
h2_file = open("%s-rt.h"%schema_version,'w')
|
||||
enumh_file = open("%senum.h"%schema_version,'w')
|
||||
cpp_file = open("%s.cpp"%schema_version,'w')
|
||||
cpp2_file = open("%s-rt.cpp"%schema_version,'w')
|
||||
|
||||
header += """
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file has been generated from %s. Do not make modifications *
|
||||
* but instead modify the python script that has been used to generate this. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
"""%filename
|
||||
|
||||
generator_mode = 'HEADER'
|
||||
|
||||
print >>h_file, header
|
||||
print >>h2_file, header
|
||||
print >>enumh_file, header
|
||||
print >>cpp_file, header
|
||||
print >>cpp2_file, header
|
||||
print >>h_file, """#ifndef %(schema_upper)s_H
|
||||
#define %(schema_upper)s_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/ArgumentType.h"
|
||||
#include "../ifcparse/%(schema)senum.h"
|
||||
|
||||
using namespace IfcUtil;
|
||||
using IfcParse::IfcException;
|
||||
using boost::optional;
|
||||
|
||||
#define RETURN_INVERSE(T) \\
|
||||
IfcEntities e = entity->getInverse(T::Class()); \\
|
||||
SHARED_PTR< IfcTemplatedEntityList<T> > l ( new IfcTemplatedEntityList<T>() ); \\
|
||||
for ( IfcEntityList::it it = e->begin(); it != e->end(); ++ it ) { \\
|
||||
l->push(reinterpret_pointer_cast<IfcBaseClass,T>(*it)); \\
|
||||
} \\
|
||||
return l;
|
||||
|
||||
#define RETURN_AS_SINGLE(T,a) \\
|
||||
return reinterpret_pointer_cast<IfcBaseClass,T>(*entity->getArgument(a));
|
||||
|
||||
#define RETURN_AS_LIST(T,a) \\
|
||||
IfcEntities e = *entity->getArgument(a); \\
|
||||
SHARED_PTR< IfcTemplatedEntityList<T> > l ( new IfcTemplatedEntityList<T>() ); \\
|
||||
for ( IfcEntityList::it it = e->begin(); it != e->end(); ++ it ) { \\
|
||||
l->push(reinterpret_pointer_cast<IfcBaseClass,T>(*it)); \\
|
||||
} \\
|
||||
return l;
|
||||
|
||||
namespace %(schema)s {
|
||||
"""%{'schema_upper':schema_version.upper(),'schema':schema_version}
|
||||
|
||||
simple_enumerations = sorted(simple_types)
|
||||
entity_enumerations = sorted(entity_names)
|
||||
all_enumerations = simple_enumerations + entity_enumerations
|
||||
|
||||
print >>enumh_file, """#ifndef IFC2X3ENUM_H
|
||||
#define IFC2X3ENUM_H
|
||||
|
||||
#include "../ifcparse/ArgumentType.h"
|
||||
|
||||
namespace Ifc2x3 {
|
||||
|
||||
namespace Type {
|
||||
typedef enum {
|
||||
%(enum)s
|
||||
} Enum;
|
||||
Enum Parent(Enum v);
|
||||
Enum FromString(const std::string& s);
|
||||
std::string ToString(Enum v);
|
||||
bool IsSimple(Enum v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
"""%{'schema_upper':schema_version.upper(),'schema':schema_version,'enum':", ".join(all_enumerations + ["ALL"])}
|
||||
print >>h2_file, """#ifndef IFC2X3RT_H
|
||||
#define IFC2X3RT_H
|
||||
|
||||
#include "../ifcparse/ArgumentType.h"
|
||||
|
||||
namespace Ifc2x3 {
|
||||
namespace Type {
|
||||
int GetAttributeCount(Enum t);
|
||||
int GetAttributeIndex(Enum t, const std::string& a);
|
||||
IfcUtil::ArgumentType GetAttributeType(Enum t, unsigned char a);
|
||||
const std::string& GetAttributeName(Enum t, unsigned char a);
|
||||
bool GetAttributeOptional(Enum t, unsigned char a);
|
||||
std::pair<const char*, int> GetEnumerationIndex(Enum t, const std::string& a);
|
||||
Enum GetAttributeEnumerationClass(Enum t, unsigned char a);
|
||||
}}
|
||||
|
||||
#endif
|
||||
"""
|
||||
|
||||
defined_types = set(express_to_cpp.values())
|
||||
deferred_types = []
|
||||
|
||||
for t in [T for T in types if not (isinstance(T.type,EnumType) or isinstance(T.type,SelectType))]:
|
||||
if isinstance(t.type,ScalarType) and str(t.type) not in defined_types:
|
||||
deferred_types.append(t)
|
||||
else:
|
||||
print >>h_file, t
|
||||
for t in [T for T in types if isinstance(T.type,SelectType)]:
|
||||
print >>h_file, t
|
||||
for t in deferred_types:
|
||||
print >>h_file, t
|
||||
for t in [T for T in types if isinstance(T.type,EnumType)]:
|
||||
print >>h_file, t
|
||||
|
||||
print >>h_file, "// Forward definitions"
|
||||
print >>h_file, "class %s;\n"%"; class ".join([e.class_name for e in entities])
|
||||
|
||||
defined_classes = set()
|
||||
while True:
|
||||
classes = [c for c in entities if c.class_name not in defined_classes]
|
||||
if not len(classes): break
|
||||
for c in classes:
|
||||
if c.parent_class is None or c.parent_class in defined_classes:
|
||||
defined_classes.add(c.class_name)
|
||||
print >>h_file, c
|
||||
|
||||
print >>h_file, "void InitStringMap();"
|
||||
print >>h_file, "IfcSchemaEntity SchemaEntity(IfcAbstractEntityPtr e = 0);"
|
||||
|
||||
print >>h_file, "}\n\n#endif"
|
||||
|
||||
generator_mode = 'SOURCE'
|
||||
print >>cpp2_file, """#include "../ifcparse/%(schema)s.h"
|
||||
#include "../ifcparse/%(schema)s-rt.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/IfcWrite.h"
|
||||
#include "../ifcparse/IfcWritableEntity.h"
|
||||
#include "../ifcparse/ArgumentType.h"
|
||||
|
||||
using namespace %(schema)s;
|
||||
using namespace IfcParse;
|
||||
using namespace IfcWrite;"""%{'schema':schema_version}
|
||||
print >>cpp_file, """#include "../ifcparse/%(schema)s.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/IfcWrite.h"
|
||||
#include "../ifcparse/IfcWritableEntity.h"
|
||||
#include "../ifcparse/ArgumentType.h"
|
||||
|
||||
using namespace %(schema)s;
|
||||
using namespace IfcParse;
|
||||
using namespace IfcWrite;
|
||||
|
||||
IfcSchemaEntity %(schema)s::SchemaEntity(IfcAbstractEntityPtr e) {
|
||||
switch(e->type()){"""%{'schema':schema_version}
|
||||
|
||||
for e in simple_enumerations:
|
||||
print >>cpp_file, " case Type::%s: return new IfcEntitySelect(e); break;"%e
|
||||
for e in entity_enumerations:
|
||||
print >>cpp_file, " case Type::%s: return new %s(e); break;"%(e,e)
|
||||
print >>cpp_file, " default: throw IfcException(\"Unable to find find keyword in schema\"); break; "
|
||||
print >>cpp_file, " }\n}"
|
||||
print >>cpp_file
|
||||
print >>cpp_file, "std::string Type::ToString(Enum v) {"
|
||||
print >>cpp_file, " if (v < 0 || v >= %d) throw IfcException(\"Unable to find find keyword in schema\");"%len(all_enumerations)
|
||||
print >>cpp_file, ' const char* names[] = { "%s" };'%'","'.join(all_enumerations)
|
||||
print >>cpp_file, ' return names[v];'
|
||||
print >>cpp_file, "}"
|
||||
print >>cpp_file
|
||||
|
||||
print >>cpp_file, "std::map<std::string,Type::Enum> string_map;"
|
||||
print >>cpp2_file, "std::map<Type::Enum,IfcEntityDescriptor*> entity_descriptor_map;"
|
||||
print >>cpp2_file, "std::map<Type::Enum,IfcEnumerationDescriptor*> enumeration_descriptor_map;"
|
||||
maxlen = max([len(e) for e in all_enumerations])
|
||||
string_map,attribute_count_map,attribute_index_map,attribute_name_map,attribute_optional_map,attribute_type_map = [""]*6
|
||||
print >>cpp2_file, "void InitDescriptorMap() {"
|
||||
print >>cpp2_file, " IfcEntityDescriptor* current;"
|
||||
for k,v in simple_types.items():
|
||||
if k in enumerations or k in selections: continue
|
||||
print >>cpp2_file, " current = entity_descriptor_map[Type::%s] = new IfcEntityDescriptor(Type::%s,0);"%(k,k)
|
||||
print >>cpp2_file, " current->add(\"wrappedValue\",false,%s);"%(v.type_enum())
|
||||
rt_entities = set()
|
||||
while True:
|
||||
todo = [e for e in entities if e.class_name not in rt_entities]
|
||||
if len(todo) == 0: break
|
||||
for e in todo:
|
||||
if e.parent_class and e.parent_class not in rt_entities: continue
|
||||
rt_entities.add(e.class_name)
|
||||
args = e.get_attributes(False)
|
||||
parent_descriptor = ("entity_descriptor_map.find(Type::%s)->second"%e.parent_class) if e.parent_class else "0"
|
||||
print >>cpp2_file, " current = entity_descriptor_map[Type::%s] = new IfcEntityDescriptor(Type::%s,%s);"%(e.class_name,e.class_name,parent_descriptor)
|
||||
for a,i in zip(args,range(len(args))):
|
||||
name,optional,type,enum_class = a
|
||||
if enum_class:
|
||||
print >>cpp2_file, " current->add(\"%s\",%s,%s,Type::%s);"%(name,"true" if optional else "false",type,enum_class)
|
||||
else:
|
||||
print >>cpp2_file, " current->add(\"%s\",%s,%s);"%(name,"true" if optional else "false",type)
|
||||
print >>cpp2_file, " // Enumerations"
|
||||
print >>cpp2_file, " IfcEnumerationDescriptor* current_enum;"
|
||||
print >>cpp2_file, " std::vector<std::string> values;"
|
||||
for e, name in [(e, name) for name, e in simple_types.items() if name in enumerations]:
|
||||
print >>cpp2_file, " values.clear(); values.reserve(128);"
|
||||
for value in e.type.v:
|
||||
print >>cpp2_file, " values.push_back(\"%s\");"%value[0]
|
||||
print >>cpp2_file, " current_enum = enumeration_descriptor_map[Type::%s] = new IfcEnumerationDescriptor(Type::%s, values);"%(name,name)
|
||||
print >>cpp2_file, "}"
|
||||
|
||||
for e in all_enumerations:
|
||||
string_map += ' string_map["%s"%s] = Type::%s;\n'%(e.upper()," "*(maxlen-len(e)),e)
|
||||
print >>cpp_file, """void Ifc2x3::InitStringMap() {
|
||||
%(string_map)s
|
||||
}"""%locals()
|
||||
|
||||
print >>cpp_file, """Type::Enum Type::FromString(const std::string& s) {
|
||||
if (string_map.empty()) ::Ifc2x3::InitStringMap();
|
||||
std::map<std::string,Type::Enum>::const_iterator it = string_map.find(s);
|
||||
if ( it == string_map.end() ) throw IfcException("Unable to find find keyword in schema");
|
||||
else return it->second;
|
||||
}"""
|
||||
|
||||
print >>cpp_file, "Type::Enum Type::Parent(Enum v){"
|
||||
print >>cpp_file, " if (v < 0 || v >= %d) return (Enum)-1;"%len(all_enumerations)
|
||||
for e in entity_enumerations:
|
||||
if e not in parent_relations or parent_relations[e] is None: continue
|
||||
print >>cpp_file, ' if(v==%s%s) { return %s; }'%(e," "*(maxlen-len(e)),parent_relations[e])
|
||||
print >>cpp_file, " return (Enum)-1;"
|
||||
print >>cpp_file, "}"
|
||||
|
||||
print >>cpp_file, "bool Type::IsSimple(Enum v){"
|
||||
print >>cpp_file, " return v == Type::%s;"%" || v == Type::".join(simple_enumerations)
|
||||
print >>cpp_file, "}"
|
||||
|
||||
for t in [T for T in types if isinstance(T.type,EnumType)]:
|
||||
print >>cpp_file, t
|
||||
for e in entities: print >>cpp_file, e,
|
||||
print >>cpp_file, ""
|
||||
|
||||
print >>cpp2_file, """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);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else return i->second->getArgumentIndex(a);
|
||||
}
|
||||
|
||||
int Type::GetAttributeCount(Enum t) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else return i->second->getArgumentCount();
|
||||
}
|
||||
|
||||
ArgumentType Type::GetAttributeType(Enum t, unsigned char a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else return i->second->getArgumentType(a);
|
||||
}
|
||||
|
||||
const std::string& Type::GetAttributeName(Enum t, unsigned char a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else return i->second->getArgumentName(a);
|
||||
}
|
||||
|
||||
bool Type::GetAttributeOptional(Enum t, unsigned char a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else return i->second->getArgumentOptional(a);
|
||||
}
|
||||
|
||||
std::pair<const char*, int> Type::GetEnumerationIndex(Enum t, const std::string& a) {
|
||||
if (enumeration_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEnumerationDescriptor*>::const_iterator i = enumeration_descriptor_map.find(t);
|
||||
if ( i == enumeration_descriptor_map.end() ) throw IfcException("Value not found");
|
||||
else return i->second->getIndex(a);
|
||||
}
|
||||
|
||||
Type::Enum Type::GetAttributeEnumerationClass(Enum t, unsigned char a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else {
|
||||
Type::Enum t = i->second->getArgumentEnumerationClass(a);
|
||||
if ( t == Type::ALL ) throw IfcException("Not an enumeration");
|
||||
else return t;
|
||||
}
|
||||
}
|
||||
"""
|
||||
@@ -4,8 +4,6 @@ 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 [1] library is required.
|
||||
Express file. A python 3 interpreter with the pyparsing 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
|
||||
|
||||
@@ -19,14 +19,8 @@
|
||||
|
||||
import sys
|
||||
import string
|
||||
import operator
|
||||
import itertools
|
||||
|
||||
from pyparsing import *
|
||||
|
||||
try: from functools import reduce
|
||||
except: pass
|
||||
|
||||
class Expression:
|
||||
def __init__(self, contents):
|
||||
self.contents = contents[0]
|
||||
@@ -62,12 +56,12 @@ class Keyword:
|
||||
class Terminal:
|
||||
def __init__(self, contents):
|
||||
self.contents = contents[0]
|
||||
s = self.contents
|
||||
self.is_keyword = len(s) >= 4 and s[0::len(s)-1] == '""' and \
|
||||
all(c in alphanums+"_" for c in s[1:-1])
|
||||
def __repr__(self):
|
||||
ty = "CaselessKeyword" if self.is_keyword else "CaselessLiteral"
|
||||
return "%s(%s)" % (ty, self.contents)
|
||||
s = self.contents
|
||||
is_keyword = len(s) >= 4 and s[0::len(s)-1] == '""' and \
|
||||
all(c in alphanums+"_" for c in s[1:-1])
|
||||
ty = "CaselessKeyword" if is_keyword else "CaselessLiteral"
|
||||
return "%s(%s)" % (ty, s)
|
||||
|
||||
|
||||
LPAREN = Suppress("(")
|
||||
@@ -100,16 +94,16 @@ grammar.ignore(HASH + restOfLine)
|
||||
|
||||
express = grammar.parseFile(sys.argv[1])
|
||||
|
||||
def find_bytype(expr, ty, li = None):
|
||||
def find_keywords(expr, li = None):
|
||||
if li is None: li = []
|
||||
if isinstance(expr, Term):
|
||||
expr = expr.contents
|
||||
if isinstance(expr, ty):
|
||||
li.append(expr)
|
||||
return set(li)
|
||||
if isinstance(expr, Keyword):
|
||||
li.append(repr(expr))
|
||||
return li
|
||||
elif isinstance(expr, Expression):
|
||||
for term in expr:
|
||||
find_bytype(term, ty, li)
|
||||
find_keywords(term, li)
|
||||
return set(li)
|
||||
|
||||
actions = {
|
||||
@@ -128,8 +122,6 @@ actions = {
|
||||
'inverse_attr' : "lambda t: InverseAttribute(t)",
|
||||
'bound_spec' : "lambda t: BoundSpecification(t)",
|
||||
'explicit_attr' : "lambda t: ExplicitAttribute(t)",
|
||||
'width_spec' : "lambda t: WidthSpec(t)",
|
||||
'string_type' : "lambda t: StringType(t)",
|
||||
}
|
||||
|
||||
to_emit = set(id for id, expr in express)
|
||||
@@ -137,22 +129,18 @@ emitted = set()
|
||||
to_combine = set(["simple_id"])
|
||||
to_ignore = set(["where_clause", "supertype_constraint", "unique_clause"])
|
||||
statements = []
|
||||
|
||||
terminals = reduce(lambda x,y: x | y, (find_bytype(e, Terminal) for id, e in express))
|
||||
keywords = list(filter(operator.attrgetter('is_keyword'), terminals))
|
||||
negated_keywords = map(lambda s: "~%s" % s, keywords)
|
||||
|
||||
while True:
|
||||
emitted_in_loop = set()
|
||||
for id, expr in express:
|
||||
kws = map(repr, find_bytype(expr, Keyword))
|
||||
kws = find_keywords(expr)
|
||||
found = [k in emitted for k in kws]
|
||||
if id in to_emit and all(found):
|
||||
emitted_in_loop.add(id)
|
||||
emitted.add(id)
|
||||
stmt = "(%s)" % expr
|
||||
if id in to_combine:
|
||||
stmt = " + ".join(itertools.chain(negated_keywords, ("originalTextFor(Combine%s)" % stmt,)))
|
||||
stmt = "originalTextFor(Combine%s)" % stmt
|
||||
if id in actions:
|
||||
stmt = "%s.setParseAction(%s)" % (stmt, actions[id])
|
||||
statements.append("%s = %s" % (id, stmt))
|
||||
@@ -182,10 +170,9 @@ import mapping
|
||||
import header
|
||||
import enum_header
|
||||
import implementation
|
||||
import latebound_header
|
||||
import latebound_implementation
|
||||
import rt_header
|
||||
import rt_implementation
|
||||
|
||||
syntax.ignore("--" + restOfLine)
|
||||
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
|
||||
ast = syntax.parseFile(sys.argv[1])
|
||||
schema = schema.Schema(ast)
|
||||
@@ -194,8 +181,13 @@ mapping = mapping.Mapping(schema)
|
||||
header.Header(mapping).emit()
|
||||
enum_header.EnumHeader(mapping).emit()
|
||||
implementation.Implementation(mapping).emit()
|
||||
latebound_header.LateBoundHeader(mapping).emit()
|
||||
latebound_implementation.LateBoundImplementation(mapping).emit()
|
||||
rt_header.RuntimeTypingHeader(mapping).emit()
|
||||
rt_implementation.RuntimeTypingImplementation(mapping).emit()
|
||||
|
||||
sys.stdout.write(schema.name)
|
||||
def retry():
|
||||
import imp
|
||||
imp.reload(rt_header)
|
||||
imp.reload(rt_implementation)
|
||||
rt_header.RuntimeTypingHeader(mapping).emit()
|
||||
rt_implementation.RuntimeTypingImplementation(mapping).emit()
|
||||
"""%('\n'.join(statements)))
|
||||
|
||||
@@ -1,35 +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/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
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,25 +27,18 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import re
|
||||
import os
|
||||
import re,csv
|
||||
import csv
|
||||
|
||||
from schema import OrderedCaseInsensitiveDict
|
||||
|
||||
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 = OrderedCaseInsensitiveDict()
|
||||
name_to_oid = {}
|
||||
oid_to_desc = {}
|
||||
oid_to_name = {}
|
||||
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:
|
||||
for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'):
|
||||
@@ -53,15 +46,15 @@ for fn in definition_files:
|
||||
oid_to_name[oid] = name
|
||||
oid_to_desc[oid] = desc
|
||||
|
||||
with open(make_absolute('DocEntityAttributes.csv')) as f:
|
||||
with open('DocEntityAttributes.csv') as f:
|
||||
for pid, x, oid in csv.reader(f, delimiter=';', quotechar='"'):
|
||||
oid_to_pid[oid] = pid
|
||||
|
||||
with open(make_absolute('DocAttribute.csv')) as f:
|
||||
with open('DocAttribute.csv') as f:
|
||||
for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'):
|
||||
pid = oid_to_pid[oid]
|
||||
pname = oid_to_name[pid]
|
||||
name_to_oid[".".join((pname, name))] = oid
|
||||
name_to_oid[(pname, name)] = oid
|
||||
oid_to_desc[oid] = desc
|
||||
|
||||
def description(item):
|
||||
|
||||
@@ -18,9 +18,8 @@
|
||||
###############################################################################
|
||||
|
||||
import templates
|
||||
import codegen
|
||||
|
||||
class EnumHeader(codegen.Base):
|
||||
class EnumHeader:
|
||||
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()]))
|
||||
|
||||
@@ -31,9 +30,9 @@ class EnumHeader(codegen.Base):
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Taken from http://sourceforge.net/p/exp-engine/expresso/ci/master/tree/docs/iso-10303-11--2004.bnf
|
||||
|
||||
ABS = "abs" .
|
||||
ABSTRACT = "abstract" .
|
||||
ACOS = "acos" .
|
||||
@@ -200,7 +202,7 @@ constructed_types = enumeration_type | select_type .
|
||||
declaration = entity_decl | function_decl | procedure_decl | subtype_constraint_decl | type_decl .
|
||||
derived_attr = attribute_decl ":" parameter_type ":=" expression ";" .
|
||||
derive_clause = DERIVE derived_attr { derived_attr } .
|
||||
domain_rule = [ rule_label_id ":" ] expression .
|
||||
domain_rule = rule_label_id ":" expression .
|
||||
element = expression [ ":" repetition ] .
|
||||
entity_body = { explicit_attr } [ derive_clause ] [ inverse_clause ] [ unique_clause ] [ where_clause ] .
|
||||
entity_constructor = entity_ref "(" [ expression { "," expression } ] ")" .
|
||||
@@ -332,7 +334,7 @@ type_label_id = simple_id .
|
||||
unary_op = "+" | "-" | NOT .
|
||||
underlying_type = constructed_types | concrete_types .
|
||||
unique_clause = UNIQUE unique_rule ";" { unique_rule ";" } .
|
||||
unique_rule = [ rule_label_id ":" ] referenced_attribute { "," referenced_attribute } .
|
||||
unique_rule = rule_label_id ":" referenced_attribute { "," referenced_attribute } .
|
||||
until_control = UNTIL logical_expression .
|
||||
use_clause = USE FROM schema_ref [ "(" named_type_or_rename { "," named_type_or_rename } ")" ] ";" .
|
||||
variable_id = simple_id .
|
||||
|
||||
@@ -17,43 +17,39 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import codegen
|
||||
import templates
|
||||
import documentation
|
||||
|
||||
class Header(codegen.Base):
|
||||
class Header:
|
||||
def __init__(self, mapping):
|
||||
emitted_types = set(mapping.express_to_cpp_typemapping.values())
|
||||
declarations = []
|
||||
|
||||
write = lambda str, **kwargs: declarations.append(str%dict({
|
||||
'documentation': templates.multi_line_comment(documentation.description(kwargs['name']))}, **kwargs))
|
||||
|
||||
forward_names = list(mapping.schema.entities.keys()) + list(mapping.schema.simpletypes.keys())
|
||||
forward_definitions = "".join(["class %s; "%n for n in forward_names])
|
||||
|
||||
|
||||
for name, type in mapping.schema.simpletypes.items():
|
||||
type_str = mapping.make_type_string(type)
|
||||
type_dep = mapping.get_type_dep(type)
|
||||
if type_dep in emitted_types:
|
||||
write(templates.simpletype, name=name, type=type_str)
|
||||
emitted_types.add(name)
|
||||
|
||||
for name, type in mapping.schema.selects.items():
|
||||
write(templates.select, name=name)
|
||||
emitted_types.add(name)
|
||||
|
||||
for name, type in mapping.schema.simpletypes.items():
|
||||
if name not in emitted_types:
|
||||
type_str = mapping.make_type_string(type)
|
||||
write(templates.simpletype, name=name, type=type_str)
|
||||
emitted_types.add(name)
|
||||
|
||||
for name, type in mapping.schema.enumerations.items():
|
||||
short_name = name[:-4] if name.endswith("Enum") else name
|
||||
write(templates.enumeration, name=name, values=", ".join(["%s_%s"%(short_name, v) for v in type.values]))
|
||||
|
||||
emitted_simpletypes = set()
|
||||
while len(emitted_simpletypes) < len(mapping.schema.simpletypes):
|
||||
for name, type in mapping.schema.simpletypes.items():
|
||||
if name.lower() in emitted_simpletypes: continue
|
||||
type_str = mapping.make_type_string(mapping.flatten_type_string(type))
|
||||
attr_type = mapping.make_argument_type(type)
|
||||
superclass = mapping.simple_type_parent(name)
|
||||
if superclass is None:
|
||||
superclass = "IfcUtil::IfcBaseType"
|
||||
elif superclass.lower() not in emitted_simpletypes:
|
||||
continue
|
||||
else:
|
||||
# Case normalize
|
||||
superclass = [k for k in mapping.schema.simpletypes.keys() if k.lower() == superclass.lower()][0]
|
||||
emitted_simpletypes.add(name.lower())
|
||||
write(templates.simpletype, name=name, type=type_str, attr_type=attr_type, superclass=superclass)
|
||||
|
||||
forward_definitions = "".join(["class %s; "%n for n in mapping.schema.entities.keys()])
|
||||
|
||||
class_definitions = []
|
||||
|
||||
@@ -63,17 +59,17 @@ class Header(codegen.Base):
|
||||
emitted_entities = set()
|
||||
while len(emitted_entities) < len(mapping.schema.entities):
|
||||
for name, type in mapping.schema.entities.items():
|
||||
if name.lower() in emitted_entities: continue
|
||||
if len(type.supertypes) == 0 or set(map(str.lower, type.supertypes)) <= emitted_entities:
|
||||
if name in emitted_entities: continue
|
||||
if len(type.supertypes) == 0 or set(type.supertypes) < emitted_entities:
|
||||
attr_lines = []
|
||||
def write_method(attr):
|
||||
if attr.optional:
|
||||
attr_lines.append(templates.optional_attribute_description % (attr.name, name))
|
||||
attr_lines.append("bool has%s() const;"%(attr.name))
|
||||
attr_lines.extend(["/// %s"%d for d in documentation.description(".".join((name, attr.name)))])
|
||||
attr_lines.append("bool has%s();"%(attr.name))
|
||||
attr_lines.extend(["/// %s"%d for d in documentation.description((name, attr.name))])
|
||||
type_str = mapping.get_parameter_type(attr, allow_optional=False, allow_entities=False)
|
||||
if mapping.make_argument_type(attr) != "IfcUtil::Argument_UNKNOWN":
|
||||
attr_lines.append("%s %s() const;"%(type_str, attr.name))
|
||||
attr_lines.append("%s %s();"%(type_str, attr.name))
|
||||
attr_lines.append("void set%s(%s v);"%(attr.name, type_str))
|
||||
|
||||
[write_method(attr) for attr in type.attributes]
|
||||
@@ -91,11 +87,7 @@ class Header(codegen.Base):
|
||||
inverse = "\n".join(["%s%s"%(' '*4, a) for a in inv_lines])
|
||||
if len(inverse): inverse += '\n'
|
||||
|
||||
def case_norm(n):
|
||||
n = n.lower()
|
||||
return [k for k in mapping.schema.entities.keys() if k.lower() == n][0]
|
||||
|
||||
supertypes = map(case_norm, type.supertypes) if len(type.supertypes) else ['IfcUtil::IfcBaseEntity']
|
||||
supertypes = type.supertypes if len(type.supertypes) else ['IfcUtil::IfcBaseEntity']
|
||||
superclass = ": %s "%(", ".join(["public %s"%c for c in supertypes]))
|
||||
|
||||
argument_count = mapping.argument_count(type)
|
||||
@@ -103,19 +95,14 @@ class Header(codegen.Base):
|
||||
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 ' (void)i; throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
|
||||
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 = 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 ' (void)i; throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
|
||||
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 = 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 ' (void)i; throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
|
||||
|
||||
argument_entity_function_body = argument_entity_function_body_switch_stmt + argument_entity_function_body_tail
|
||||
|
||||
constructor_arguments = ", ".join("%(full_type)s v%(index)d_%(name)s"%a for a in mapping.get_assignable_arguments(type))
|
||||
|
||||
@@ -131,9 +118,10 @@ class Header(codegen.Base):
|
||||
}
|
||||
|
||||
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,12 +17,9 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import codegen
|
||||
import templates
|
||||
|
||||
from schema import OrderedCaseInsensitiveDict
|
||||
|
||||
class Implementation(codegen.Base):
|
||||
class Implementation:
|
||||
def __init__(self, mapping):
|
||||
enumeration_functions = []
|
||||
entity_implementations = []
|
||||
@@ -64,27 +61,17 @@ class Implementation(codegen.Base):
|
||||
if not arg['is_inherited'] and not arg['is_derived']:
|
||||
if arg['is_optional']:
|
||||
write_attr(
|
||||
templates.const_function,
|
||||
templates.function,
|
||||
class_name = name,
|
||||
name = 'has%s'%arg['name'],
|
||||
arguments = '',
|
||||
return_type = 'bool',
|
||||
body = templates.optional_attr_stmt % {'index':arg['index']-1}
|
||||
)
|
||||
|
||||
def find_template(arg):
|
||||
simple = mapping.schema.is_simpletype(arg['list_instance_type'])
|
||||
select = arg['list_instance_type'] == "IfcUtil::IfcBaseClass"
|
||||
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'] 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
|
||||
|
||||
tmpl = find_template(arg)
|
||||
tmpl = templates.get_attr_stmt_enum if arg['is_enum'] else templates.get_attr_stmt_array if arg['is_array'] and not mapping.schema.is_simpletype(arg['list_instance_type']) and arg['list_instance_type'] not in mapping.express_to_cpp_typemapping else templates.get_attr_stmt_entity if arg['non_optional_type'].endswith('*') else templates.get_attr_stmt
|
||||
write_attr(
|
||||
templates.const_function,
|
||||
templates.function,
|
||||
class_name = name,
|
||||
name = arg['name'],
|
||||
arguments = '',
|
||||
@@ -93,16 +80,8 @@ class Implementation(codegen.Base):
|
||||
'type' : arg['non_optional_type'].split('::')[0],
|
||||
'list_instance_type' : arg['list_instance_type']}
|
||||
)
|
||||
|
||||
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
|
||||
if arg['is_enum']: return templates.set_attr_stmt_enum
|
||||
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)
|
||||
tmpl = templates.set_attr_stmt_enum if arg['is_enum'] else templates.set_attr_stmt_array if arg['is_array'] and not mapping.schema.is_simpletype(arg['list_instance_type']) and arg['list_instance_type'] not in mapping.express_to_cpp_typemapping else templates.set_attr_stmt
|
||||
write_attr(
|
||||
templates.function,
|
||||
class_name = name,
|
||||
@@ -131,20 +110,16 @@ class Implementation(codegen.Base):
|
||||
'index' : arg['index']-1,
|
||||
'stmt' : impl}
|
||||
constructor_implementations.append(impl)
|
||||
|
||||
def get_attribute_index(entity, attr_name):
|
||||
related_entity = mapping.schema.entities[entity]
|
||||
return [a['name'].lower() for a in mapping.get_assignable_arguments(related_entity, include_derived=True)].index(attr_name.lower())
|
||||
|
||||
inverse = [templates.const_function % {
|
||||
inverse = [templates.function % {
|
||||
'class_name' : name,
|
||||
'name' : i.name,
|
||||
'arguments' : '',
|
||||
'return_type' : '%s::list::ptr' % i.entity,
|
||||
'body' : templates.get_inverse % {'type': i.entity, 'index':get_attribute_index(i.entity, i.attribute)}
|
||||
'return_type' : '%s::list' % i.entity,
|
||||
'body' : templates.get_inverse % {'type': i.entity}
|
||||
} for i in (type.inverse.elements if type.inverse else [])]
|
||||
|
||||
superclass = "%s((IfcAbstractEntity*)0)" % type.supertypes[0] if len(type.supertypes) == 1 else 'IfcUtil::IfcBaseEntity()'
|
||||
superclass = "%s((IfcAbstractEntityPtr)0)" % type.supertypes[0] if len(type.supertypes) == 1 else 'IfcUtil::IfcBaseEntity()'
|
||||
|
||||
write(
|
||||
templates.entity_implementation,
|
||||
@@ -157,8 +132,8 @@ class Implementation(codegen.Base):
|
||||
superclass = superclass
|
||||
)
|
||||
|
||||
selectable_simple_types = sorted(set(sum([b.values for a,b in mapping.schema.selects.items()], [])) & set(map(str, mapping.schema.types.keys())))
|
||||
schema_entity_statements += [templates.schema_entity_stmt%locals() for name, type in mapping.schema.simpletypes.items()]
|
||||
selectable_simple_types = sorted(set(sum([b.values for a,b in mapping.schema.selects.items()], [])) & set(mapping.schema.types.keys()))
|
||||
schema_entity_statements += [templates.schema_simple_stmt%locals() for name in selectable_simple_types]
|
||||
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()]))
|
||||
@@ -169,57 +144,16 @@ class Implementation(codegen.Base):
|
||||
'name' : name,
|
||||
'padding' : ' ' * (max_len - len(name))
|
||||
} for name in enumerable_types]
|
||||
|
||||
enumeration_index_by_str = OrderedCaseInsensitiveDict((j,i) for i,j in enumerate(enumerable_types))
|
||||
def get_parent_id(s):
|
||||
e = mapping.schema.entities.get(s)
|
||||
if e and e.supertypes:
|
||||
return enumeration_index_by_str[e.supertypes[0]]
|
||||
else: return -1
|
||||
|
||||
parent_type_statements = ",".join(map(str, map(get_parent_id, enumerable_types)))
|
||||
parent_type_statements = [templates.parent_type_stmt % {
|
||||
'name' : name,
|
||||
'parent' : type.supertypes[0],
|
||||
'padding' : ' ' * (max_len - len(name))
|
||||
} for name, type in mapping.schema.entities.items() if type.supertypes and len(type.supertypes) == 1]
|
||||
|
||||
max_id = len(enumerable_types)
|
||||
|
||||
simple_type_statements = cator("v == Type::%s"%name for name in selectable_simple_types)
|
||||
|
||||
simple_type_impl = []
|
||||
for class_name, type in mapping.schema.simpletypes.items():
|
||||
type_str = mapping.make_type_string(mapping.flatten_type_string(type))
|
||||
attr_type = mapping.make_argument_type(type)
|
||||
superclass = mapping.simple_type_parent(class_name)
|
||||
|
||||
simpletype_impl_is = templates.simpletype_impl_is_with_supertype if superclass \
|
||||
else templates.simpletype_impl_is_without_supertype
|
||||
|
||||
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 ),
|
||||
('Class', templates.function, 'Type::Enum', (), templates.simpletype_impl_class ),
|
||||
('', constructor, '', ('IfcAbstractEntity* e',), templates.simpletype_impl_explicit_constructor),
|
||||
('', constructor, '', ("%s v" % type_str,), simpletype_impl_constructor ),
|
||||
('', templates.cast_function, type_str, (), simpletype_impl_cast )
|
||||
))))
|
||||
simple_type_impl.append('')
|
||||
|
||||
self.str = templates.implementation % {
|
||||
'schema_name_upper' : mapping.schema.name.upper(),
|
||||
@@ -230,15 +164,15 @@ class Implementation(codegen.Base):
|
||||
'type_name_strings' : type_name_strings,
|
||||
'string_map_statements' : catnl(string_map_statements),
|
||||
'simple_type_statement' : simple_type_statements,
|
||||
'parent_type_statements' : parent_type_statements,
|
||||
'entity_implementations' : catnl(entity_implementations),
|
||||
'simple_type_impl' : catnl(simple_type_impl)
|
||||
'parent_type_statements' : catnl(parent_type_statements),
|
||||
'entity_implementations' : catnl(entity_implementations)
|
||||
}
|
||||
|
||||
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,6 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import nodes
|
||||
import templates
|
||||
|
||||
@@ -31,40 +28,20 @@ class Mapping:
|
||||
'integer' : 'int',
|
||||
'real' : 'double',
|
||||
'number' : 'double',
|
||||
'string' : 'std::string',
|
||||
'binary' : 'boost::dynamic_bitset<>'
|
||||
'string' : 'std::string'
|
||||
}
|
||||
|
||||
supported_argument_types = set([
|
||||
'INT', 'BOOL', 'DOUBLE', 'STRING', 'BINARY', 'ENUMERATION', 'ENTITY_INSTANCE',
|
||||
'AGGREGATE_OF_INT', 'AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_STRING', 'AGGREGATE_OF_BINARY', 'AGGREGATE_OF_ENTITY_INSTANCE',
|
||||
'AGGREGATE_OF_AGGREGATE_OF_INT', 'AGGREGATE_OF_AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE',
|
||||
])
|
||||
|
||||
def __init__(self, schema):
|
||||
self.schema = schema
|
||||
|
||||
def flatten_type_string(self, type):
|
||||
return self.flatten_type_string(self.schema.types[type].type.type) if self.schema.is_simpletype(type) else type
|
||||
|
||||
def flatten_type(self, type):
|
||||
res = self.flatten_type(self.schema.types[type].type.type) if self.schema.is_simpletype(type) else type
|
||||
return res
|
||||
|
||||
def simple_type_parent(self, type):
|
||||
parent = self.schema.types[type].type.type
|
||||
if isinstance(parent, nodes.AggregationType): parent = None
|
||||
return None if str(parent) in self.express_to_cpp_typemapping else parent
|
||||
|
||||
def make_type_string(self, type):
|
||||
if isinstance(type, (str, nodes.BinaryType, nodes.StringType)):
|
||||
return self.express_to_cpp_typemapping.get(str(type), type)
|
||||
if isinstance(type, str):
|
||||
return self.express_to_cpp_typemapping.get(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
|
||||
tmpl = templates.list_type if is_list else templates.array_type
|
||||
return tmpl % {
|
||||
'instance_type' : self.make_type_string(self.flatten_type_string(type.type)),
|
||||
'instance_type' : self.make_type_string(type.type),
|
||||
'lower' : type.bounds.lower,
|
||||
'upper' : type.bounds.upper,
|
||||
}
|
||||
@@ -76,76 +53,61 @@ class Mapping:
|
||||
return self.is_array(self.schema.types[type].type.type)
|
||||
else:
|
||||
return False
|
||||
|
||||
def make_argument_entity(self, attr):
|
||||
type = attr.type if hasattr(attr, 'type') else attr
|
||||
while isinstance(type, nodes.AggregationType): type = type.type
|
||||
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 self.schema.is_entity(type) or isinstance(type, nodes.SelectType):
|
||||
return "ENTITY_INSTANCE"
|
||||
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)
|
||||
elif isinstance(type, nodes.BinaryType):
|
||||
return "BINARY"
|
||||
elif isinstance(type, nodes.StringType):
|
||||
return "STRING"
|
||||
return "UNKNOWN"
|
||||
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 "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 self.supported_argument_types:
|
||||
print("Attribute %r mapped as 'unknown'" % (attr), file=sys.stderr)
|
||||
ty = 'UNKNOWN'
|
||||
return "ENTITY_LIST" if ty == "ENTITY" else ("VECTOR_%s"%ty)
|
||||
else: raise ValueError
|
||||
supported = {'INT', 'BOOL', 'DOUBLE', 'STRING', 'VECTOR_INT', 'VECTOR_DOUBLE', 'VECTOR_STRING', 'ENTITY', 'ENTITY_LIST', 'ENUMERATION'}
|
||||
ty = _make_argument_type(attr.type)
|
||||
if ty not in supported: ty = 'UNKNOWN'
|
||||
return "IfcUtil::Argument_%s" % ty
|
||||
|
||||
def get_type_dep(self, type):
|
||||
if isinstance(type, str):
|
||||
return self.express_to_cpp_typemapping.get(str(type), type)
|
||||
return self.express_to_cpp_typemapping.get(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)
|
||||
|
||||
type_str = self.express_to_cpp_typemapping.get(str(attr.type), attr.type)
|
||||
is_ptr = False
|
||||
|
||||
if self.schema.is_enumeration(attr_type):
|
||||
type_str = '%s::%s'%(attr_type, attr_type)
|
||||
if self.schema.is_enumeration(attr.type):
|
||||
type_str = '%s::%s'%(attr.type, attr.type)
|
||||
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 self.schema.is_select(attr_type.type):
|
||||
ty = self.get_parameter_type(attr.type, False, allow_entities, allow_pointer=False)
|
||||
if allow_entities and self.schema.is_select(attr.type.type):
|
||||
type_str = templates.untyped_list
|
||||
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
|
||||
bounds = (attr_type.bounds.lower, attr_type.bounds.upper) if attr_type.bounds else (-1, -1)
|
||||
type_str = tmpl % {
|
||||
elif self.schema.is_simpletype(ty) or ty in self.express_to_cpp_typemapping.values():
|
||||
type_str = templates.array_type % {
|
||||
'instance_type' : ty,
|
||||
'lower' : bounds[0],
|
||||
'upper' : bounds[1]
|
||||
'lower' : attr.type.bounds.lower,
|
||||
'upper' : attr.type.bounds.upper
|
||||
}
|
||||
else:
|
||||
tmpl = templates.list_list_type if is_nested_list else templates.list_type
|
||||
type_str = tmpl % {
|
||||
type_str = templates.list_type % {
|
||||
'instance_type': ty
|
||||
}
|
||||
elif allow_pointer and (self.schema.is_entity(type_str) or self.schema.is_select(type_str)):
|
||||
elif allow_pointer and self.schema.is_entity(type_str):
|
||||
type_str += '*'
|
||||
is_ptr = True
|
||||
elif not allow_pointer and self.schema.is_select(type_str):
|
||||
type_str = "IfcUtil::IfcBaseClass*"
|
||||
type_str = "IfcUtil::IfcAbstractSelect"
|
||||
is_ptr = True
|
||||
if allow_optional and attr.optional and not is_ptr:
|
||||
type_str = "boost::optional< %s >"%type_str
|
||||
@@ -164,29 +126,19 @@ class Mapping:
|
||||
return c + ([str(s) for s in t.derive.elements] if t.derive else [])
|
||||
|
||||
def list_instance_type(self, attr):
|
||||
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)
|
||||
return None
|
||||
f = lambda v : 'IfcUtil::IfcAbstractSelect' if self.schema.is_select(v) else v
|
||||
if self.is_array(attr.type) and not isinstance(attr.type, str):
|
||||
return f(attr.type.type)
|
||||
elif self.is_array(attr.type) and isinstance(attr.type, str):
|
||||
return f(attr.type)
|
||||
else: 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)
|
||||
if ty is None: return False
|
||||
arr = self.is_array(attr_type)
|
||||
arr = self.is_array(attr.type)
|
||||
simple = self.schema.is_simpletype(ty)
|
||||
express = self.flatten_type_string(ty) in self.express_to_cpp_typemapping
|
||||
select = ty == 'IfcUtil::IfcBaseClass'
|
||||
express = ty in self.express_to_cpp_typemapping
|
||||
select = ty == 'IfcUtil::IfcAbstractSelect'
|
||||
return arr and not simple and not express and not select
|
||||
|
||||
def get_assignable_arguments(self, t, include_derived = False):
|
||||
@@ -211,11 +163,9 @@ class Mapping:
|
||||
'is_inherited' : i < num_inherited,
|
||||
'is_enum' : attr.type in self.schema.enumerations,
|
||||
'is_array' : self.is_array(attr.type),
|
||||
'is_nested' : self.is_array(attr.type) and not isinstance(attr.type, str) and self.is_array(attr.type.type),
|
||||
'is_derived' : attr.name in derived,
|
||||
'is_templated_list' : self.is_templated_list(attr),
|
||||
'argument_type_enum' : self.make_argument_type(attr),
|
||||
'argument_entity' : self.make_argument_entity(attr),
|
||||
'argument_type' : attr.type
|
||||
} for i, attr in attrs if include(attr)]
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ import string
|
||||
import collections
|
||||
|
||||
class Node:
|
||||
def __init__(self, tokens = None):
|
||||
self.tokens = tokens or []
|
||||
def __init__(self, tokens):
|
||||
self.tokens = tokens
|
||||
self.init()
|
||||
def tokens_of_type(self, cls):
|
||||
return [t for t in self.tokens if isinstance(t, cls)]
|
||||
@@ -128,7 +128,7 @@ class AttributeList(Node):
|
||||
class InverseAttribute(Node):
|
||||
name = property(lambda self: self.tokens[0])
|
||||
type = property(lambda self: self.tokens[2])
|
||||
bounds = property(lambda self: None if len(self.tokens) != 9 else self.tokens[3])
|
||||
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])
|
||||
def init(self):
|
||||
@@ -149,7 +149,7 @@ class BinaryType(Node):
|
||||
def init(self):
|
||||
pass
|
||||
def __repr__(self):
|
||||
return "binary"
|
||||
return "BINARY"
|
||||
|
||||
|
||||
class BoundSpecification(Node):
|
||||
@@ -170,23 +170,6 @@ class ExplicitAttribute(Node):
|
||||
def init(self):
|
||||
# NB: This assumes a single name per attribute
|
||||
# definition, which is not necessarily the case.
|
||||
if self.tokens[0] == "self":
|
||||
i = list(self.tokens).index(":")
|
||||
self.tokens = self.tokens[i-1:]
|
||||
assert self.tokens[1] == ':'
|
||||
def __repr__(self):
|
||||
return "%s : %s%s" % (self.name, self.type, " ?" if self.optional else "")
|
||||
|
||||
|
||||
class WidthSpec(Node):
|
||||
def init(self):
|
||||
if self.tokens[-1] == "fixed":
|
||||
self.tokens[-1:] = []
|
||||
assert (self.tokens[0], self.tokens[-1]) == ("(", ")")
|
||||
self.width = int("".join(self.tokens[1:-1]))
|
||||
|
||||
class StringType(Node):
|
||||
def init(self):
|
||||
pass
|
||||
def __repr__(self):
|
||||
return "string"
|
||||
|
||||
@@ -17,20 +17,19 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import codegen
|
||||
import templates
|
||||
|
||||
class LateBoundHeader(codegen.Base):
|
||||
class RuntimeTypingHeader:
|
||||
def __init__(self, mapping):
|
||||
self.str = templates.lb_header % {
|
||||
self.str = templates.rt_header % {
|
||||
'schema_name_upper' : mapping.schema.name.upper(),
|
||||
'schema_name' : mapping.schema.name.capitalize()
|
||||
}
|
||||
|
||||
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-rt.h'%self.schema_name, 'w', encoding='utf-8')
|
||||
f.write(str(self))
|
||||
f.close()
|
||||
+19
-21
@@ -17,10 +17,9 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import codegen
|
||||
import templates
|
||||
|
||||
class LateBoundImplementation(codegen.Base):
|
||||
class RuntimeTypingImplementation:
|
||||
def __init__(self, mapping):
|
||||
schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
@@ -33,7 +32,7 @@ class LateBoundImplementation(codegen.Base):
|
||||
entity_descriptors.append(templates.entity_descriptor % {
|
||||
'type' : name,
|
||||
'parent_statement' : '0',
|
||||
'entity_descriptor_attributes' : templates.entity_descriptor_attribute_without_entity % {
|
||||
'entity_descriptor_attributes' : templates.entity_descriptor_attribute % {
|
||||
'name' : 'wrappedValue',
|
||||
'optional' : 'false',
|
||||
'type' : mapping.make_argument_type(mapping.schema.types[name].type)
|
||||
@@ -41,28 +40,26 @@ class LateBoundImplementation(codegen.Base):
|
||||
})
|
||||
|
||||
emitted_entities = set()
|
||||
entities_to_emit = mapping.schema.entities.keys()
|
||||
while len(emitted_entities) < len(mapping.schema.entities):
|
||||
for name, type in mapping.schema.entities.items():
|
||||
if name.lower() in emitted_entities: continue
|
||||
if len(type.supertypes) == 0 or set(map(str.lower, type.supertypes)) <= emitted_entities:
|
||||
if name in emitted_entities: continue
|
||||
if len(type.supertypes) == 0 or set(type.supertypes) < emitted_entities:
|
||||
constructor_arguments = mapping.get_assignable_arguments(type, include_derived = True)
|
||||
entity_descriptor_attributes = []
|
||||
for arg in constructor_arguments:
|
||||
if not arg['is_inherited']:
|
||||
is_enumeration = arg['argument_type_enum'] == 'IfcUtil::Argument_ENUMERATION'
|
||||
tmpl = templates.entity_descriptor_attribute_with_entity
|
||||
entity_name = arg['argument_type'] if is_enumeration else arg['argument_entity'].split('::')[1]
|
||||
tmpl = templates.entity_descriptor_attribute_enum if arg['argument_type_enum'] == 'IfcUtil::Argument_ENUMERATION' else templates.entity_descriptor_attribute
|
||||
entity_descriptor_attributes.append(tmpl % {
|
||||
'name' : arg['name'],
|
||||
'optional' : 'true' if arg['is_optional'] else 'false',
|
||||
'type' : arg['argument_type_enum'],
|
||||
'entity_name': entity_name
|
||||
'name' : arg['name'],
|
||||
'optional' : 'true' if arg['is_optional'] else 'false',
|
||||
'type' : arg['argument_type_enum'],
|
||||
'enum_type' : arg['argument_type']
|
||||
})
|
||||
|
||||
emitted_entities.add(name)
|
||||
|
||||
parent_statement = '0' if len(type.supertypes) != 1 else templates.entity_descriptor_parent % {
|
||||
'type' : [k for k in mapping.schema.entities.keys() if k.lower() == type.supertypes[0].lower()][0]
|
||||
'type' : type.supertypes[0]
|
||||
}
|
||||
entity_descriptors.append(templates.entity_descriptor % {
|
||||
'type' : name,
|
||||
@@ -92,16 +89,16 @@ class LateBoundImplementation(codegen.Base):
|
||||
if type.inverse:
|
||||
for attr in type.inverse.elements:
|
||||
related_entity = mapping.schema.entities[attr.entity]
|
||||
related_attrs = [a['name'].lower() for a in mapping.get_assignable_arguments(related_entity, include_derived=True)]
|
||||
related_attrs = [a['name'] for a in mapping.get_assignable_arguments(related_entity, include_derived=True)]
|
||||
|
||||
inverse_implementations.append(templates.inverse_implementation % {
|
||||
'type' : name,
|
||||
'name' : attr.name,
|
||||
'related_type' : attr.entity,
|
||||
'index' : related_attrs.index(attr.attribute.lower())
|
||||
'index' : related_attrs.index(attr.attribute)
|
||||
})
|
||||
|
||||
self.str = templates.lb_implementation % {
|
||||
self.str = templates.rt_implementation % {
|
||||
'schema_name_upper' : mapping.schema.name.upper(),
|
||||
'schema_name' : mapping.schema.name.capitalize(),
|
||||
'entity_descriptors' : '\n'.join(entity_descriptors),
|
||||
@@ -111,9 +108,10 @@ class LateBoundImplementation(codegen.Base):
|
||||
}
|
||||
|
||||
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-rt.cpp'%self.schema_name, 'w', encoding='utf-8')
|
||||
f.write(str(self))
|
||||
f.close()
|
||||
|
||||
@@ -18,56 +18,29 @@
|
||||
###############################################################################
|
||||
|
||||
import nodes
|
||||
import platform
|
||||
import collections
|
||||
|
||||
if tuple(map(int, platform.python_version_tuple())) < (2, 7):
|
||||
import ordereddict
|
||||
collections.OrderedDict = ordereddict.OrderedDict
|
||||
|
||||
# According to ISO 10303-11 7.1.2: Letters: "... The case of
|
||||
# letters is significant only within explicit string literals."
|
||||
class OrderedCaseInsensitiveDict(collections.OrderedDict):
|
||||
class KeyObject(str):
|
||||
def __eq__(self, other):
|
||||
return self.lower() == other.lower()
|
||||
def __hash__(self):
|
||||
return hash(self.lower())
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
collections.OrderedDict.__init__(self)
|
||||
for key, value in collections.OrderedDict(*args, **kwargs).items():
|
||||
self[OrderedCaseInsensitiveDict.KeyObject(key)] = value
|
||||
def __setitem__(self, key, value):
|
||||
return collections.OrderedDict.__setitem__(self, OrderedCaseInsensitiveDict.KeyObject(key), value)
|
||||
def __getitem__(self, key):
|
||||
return collections.OrderedDict.__getitem__(self, OrderedCaseInsensitiveDict.KeyObject(key))
|
||||
def get(self, key, *args, **kwargs):
|
||||
return collections.OrderedDict.get(self, OrderedCaseInsensitiveDict.KeyObject(key), *args, **kwargs)
|
||||
def __contains__(self, key):
|
||||
return collections.OrderedDict.__contains__(self, OrderedCaseInsensitiveDict.KeyObject(key))
|
||||
|
||||
class Schema:
|
||||
def is_enumeration(self, v):
|
||||
return str(v) in self.enumerations
|
||||
return v in self.enumerations
|
||||
def is_select(self, v):
|
||||
return str(v) in self.selects
|
||||
return v in self.selects
|
||||
def is_simpletype(self, v):
|
||||
return str(v) in self.simpletypes
|
||||
return v in self.simpletypes
|
||||
def is_type(self, v):
|
||||
return str(v) in self.types
|
||||
return v in self.types
|
||||
def is_entity(self, v):
|
||||
return str(v) in self.entities
|
||||
return v in self.entities
|
||||
def __init__(self, parsetree):
|
||||
self.name = parsetree[1]
|
||||
|
||||
sort = lambda d: OrderedCaseInsensitiveDict(sorted(d))
|
||||
sort = lambda d: collections.OrderedDict(sorted(d.items()))
|
||||
|
||||
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, nodes.BinaryType, nodes.StringType)
|
||||
self.simpletypes = of_type(str, nodes.AggregationType)
|
||||
|
||||
@@ -23,11 +23,10 @@ header = """
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include "../ifcparse/ifc_parse_api.h"
|
||||
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/%(schema_name)senum.h"
|
||||
@@ -36,8 +35,6 @@ header = """
|
||||
|
||||
namespace %(schema_name)s {
|
||||
|
||||
const char* const Identifier = "%(schema_name_upper)s";
|
||||
|
||||
// Forward definitions
|
||||
%(forward_definitions)s
|
||||
|
||||
@@ -45,7 +42,7 @@ const char* const Identifier = "%(schema_name_upper)s";
|
||||
|
||||
%(class_definitions)s
|
||||
void InitStringMap();
|
||||
IfcUtil::IfcBaseClass* SchemaEntity(IfcAbstractEntity* e = 0);
|
||||
IfcUtil::IfcSchemaEntity SchemaEntity(IfcAbstractEntityPtr e = 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -55,22 +52,18 @@ enum_header = """
|
||||
#ifndef %(schema_name_upper)sENUM_H
|
||||
#define %(schema_name_upper)sENUM_H
|
||||
|
||||
#include "../ifcparse/ifc_parse_api.h"
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#define IfcSchema %(schema_name)s
|
||||
|
||||
namespace %(schema_name)s {
|
||||
|
||||
namespace Type {
|
||||
typedef enum {
|
||||
%(types)s, UNDEFINED
|
||||
%(types)s, ALL
|
||||
} Enum;
|
||||
IFC_PARSE_API boost::optional<Enum> Parent(Enum v);
|
||||
IFC_PARSE_API Enum FromString(const std::string& s);
|
||||
IFC_PARSE_API std::string ToString(Enum v);
|
||||
IFC_PARSE_API bool IsSimple(Enum v);
|
||||
Enum Parent(Enum v);
|
||||
Enum FromString(const std::string& s);
|
||||
std::string ToString(Enum v);
|
||||
bool IsSimple(Enum v);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -78,30 +71,28 @@ namespace Type {
|
||||
#endif
|
||||
"""
|
||||
|
||||
lb_header = """
|
||||
rt_header = """
|
||||
#ifndef %(schema_name_upper)sRT_H
|
||||
#define %(schema_name_upper)sRT_H
|
||||
|
||||
#define IfcSchema %(schema_name)s
|
||||
|
||||
#include "../ifcparse/ifc_parse_api.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcEntityDescriptor.h"
|
||||
#include "../ifcparse/IfcWritableEntity.h"
|
||||
|
||||
namespace %(schema_name)s {
|
||||
namespace Type {
|
||||
IFC_PARSE_API int GetAttributeCount(Enum t);
|
||||
IFC_PARSE_API int GetAttributeIndex(Enum t, const std::string& a);
|
||||
IFC_PARSE_API IfcUtil::ArgumentType GetAttributeType(Enum t, unsigned char a);
|
||||
IFC_PARSE_API Enum GetAttributeEntity(Enum t, unsigned char a);
|
||||
IFC_PARSE_API const std::string& GetAttributeName(Enum t, unsigned char a);
|
||||
IFC_PARSE_API bool GetAttributeOptional(Enum t, unsigned char a);
|
||||
IFC_PARSE_API bool GetAttributeDerived(Enum t, unsigned char a);
|
||||
IFC_PARSE_API std::pair<const char*, int> GetEnumerationIndex(Enum t, const std::string& a);
|
||||
IFC_PARSE_API std::pair<Enum, unsigned> GetInverseAttribute(Enum t, const std::string& a);
|
||||
IFC_PARSE_API std::set<std::string> GetInverseAttributeNames(Enum t);
|
||||
IFC_PARSE_API void PopulateDerivedFields(IfcWrite::IfcWritableEntity* e);
|
||||
int GetAttributeCount(Enum t);
|
||||
int GetAttributeIndex(Enum t, const std::string& a);
|
||||
IfcUtil::ArgumentType GetAttributeType(Enum t, unsigned char a);
|
||||
const std::string& GetAttributeName(Enum t, unsigned char a);
|
||||
bool GetAttributeOptional(Enum t, unsigned char a);
|
||||
bool GetAttributeDerived(Enum t, unsigned char a);
|
||||
std::pair<const char*, int> GetEnumerationIndex(Enum t, const std::string& a);
|
||||
std::pair<Enum, unsigned> GetInverseAttribute(Enum t, const std::string& a);
|
||||
Enum GetAttributeEnumerationClass(Enum t, unsigned char a);
|
||||
void PopulateDerivedFields(IfcWrite::IfcWritableEntity* e);
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -113,13 +104,11 @@ implementation= """
|
||||
#include "../ifcparse/IfcWrite.h"
|
||||
#include "../ifcparse/IfcWritableEntity.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
using namespace %(schema_name)s;
|
||||
using namespace IfcParse;
|
||||
using namespace IfcWrite;
|
||||
|
||||
IfcUtil::IfcBaseClass* %(schema_name)s::SchemaEntity(IfcAbstractEntity* e) {
|
||||
IfcUtil::IfcSchemaEntity %(schema_name)s::SchemaEntity(IfcAbstractEntityPtr e) {
|
||||
switch(e->type()) {
|
||||
%(schema_entity_statements)s
|
||||
default: throw IfcException("Unable to find find keyword in schema"); break;
|
||||
@@ -144,14 +133,10 @@ Type::Enum Type::FromString(const std::string& s) {
|
||||
else return it->second;
|
||||
}
|
||||
|
||||
static int parent_map[] = {%(parent_type_statements)s};
|
||||
boost::optional<Type::Enum> Type::Parent(Enum v){
|
||||
const int p = parent_map[static_cast<int>(v)];
|
||||
if (p >= 0) {
|
||||
return static_cast<Type::Enum>(p);
|
||||
} else {
|
||||
return boost::none;
|
||||
}
|
||||
Type::Enum Type::Parent(Enum v){
|
||||
if (v < 0 || v >= %(max_id)d) return (Enum)-1;
|
||||
%(parent_type_statements)s
|
||||
return (Enum)-1;
|
||||
}
|
||||
|
||||
bool Type::IsSimple(Enum v) {
|
||||
@@ -160,16 +145,33 @@ bool Type::IsSimple(Enum v) {
|
||||
|
||||
%(enumeration_functions)s
|
||||
|
||||
%(simple_type_impl)s
|
||||
#define RETURN_INVERSE(T) \
|
||||
IfcEntities e = entity->getInverse(T::Class()); \
|
||||
SHARED_PTR< IfcTemplatedEntityList<T> > l ( new IfcTemplatedEntityList<T>() ); \
|
||||
for ( IfcEntityList::it it = e->begin(); it != e->end(); ++ it ) { \
|
||||
l->push(reinterpret_pointer_cast<IfcBaseClass,T>(*it)); \
|
||||
} \
|
||||
return l;
|
||||
|
||||
#define RETURN_AS_SINGLE(T,a) \
|
||||
return reinterpret_pointer_cast<IfcBaseClass,T>(*entity->getArgument(a));
|
||||
|
||||
#define RETURN_AS_LIST(T,a) \
|
||||
IfcEntities e = *entity->getArgument(a); \
|
||||
SHARED_PTR< IfcTemplatedEntityList<T> > l ( new IfcTemplatedEntityList<T>() ); \
|
||||
for ( IfcEntityList::it it = e->begin(); it != e->end(); ++ it ) { \
|
||||
l->push(reinterpret_pointer_cast<IfcBaseClass,T>(*it)); \
|
||||
} \
|
||||
return l;
|
||||
|
||||
%(entity_implementations)s
|
||||
"""
|
||||
|
||||
lb_implementation = """
|
||||
rt_implementation = """
|
||||
#include <set>
|
||||
|
||||
#include "../ifcparse/%(schema_name)s.h"
|
||||
#include "../ifcparse/%(schema_name)s-latebound.h"
|
||||
#include "../ifcparse/%(schema_name)s-rt.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/IfcWrite.h"
|
||||
#include "../ifcparse/IfcWritableEntity.h"
|
||||
@@ -181,33 +183,20 @@ using namespace IfcParse;
|
||||
using namespace IfcWrite;
|
||||
using namespace IfcUtil;
|
||||
|
||||
typedef std::map<Type::Enum,IfcEntityDescriptor*> entity_descriptor_map_t;
|
||||
typedef std::map<Type::Enum,IfcEnumerationDescriptor*> enumeration_descriptor_map_t;
|
||||
typedef std::map<Type::Enum, std::map<std::string, std::pair<Type::Enum, int> > > inverse_map_t;
|
||||
typedef std::map<Type::Enum,std::set<int> > derived_map_t;
|
||||
|
||||
entity_descriptor_map_t entity_descriptor_map;
|
||||
enumeration_descriptor_map_t enumeration_descriptor_map;
|
||||
inverse_map_t inverse_map;
|
||||
derived_map_t derived_map;
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma optimize( "", off )
|
||||
#endif
|
||||
std::map<Type::Enum,IfcEntityDescriptor*> entity_descriptor_map;
|
||||
std::map<Type::Enum,IfcEnumerationDescriptor*> enumeration_descriptor_map;
|
||||
std::map<std::pair<Type::Enum, std::string>, std::pair<Type::Enum, int> > inverse_map;
|
||||
std::map<Type::Enum,std::set<int> > derived_map;
|
||||
|
||||
void InitDescriptorMap() {
|
||||
IfcEntityDescriptor* current;
|
||||
%(entity_descriptors)s
|
||||
// Enumerations
|
||||
IfcEnumerationDescriptor* current_enum;
|
||||
std::vector<std::string> values;
|
||||
%(enumeration_descriptors)s
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma optimize( "", on )
|
||||
#endif
|
||||
|
||||
void InitInverseMap() {
|
||||
%(inverse_implementations)s
|
||||
}
|
||||
@@ -237,13 +226,6 @@ ArgumentType Type::GetAttributeType(Enum t, unsigned char a) {
|
||||
else return i->second->getArgumentType(a);
|
||||
}
|
||||
|
||||
Type::Enum Type::GetAttributeEntity(Enum t, unsigned char a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else return i->second->getArgumentEntity(a);
|
||||
}
|
||||
|
||||
const std::string& Type::GetAttributeName(Enum t, unsigned char a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
@@ -272,62 +254,35 @@ 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;
|
||||
for(;;) {
|
||||
it = inverse_map.find(t);
|
||||
if (it != inverse_map.end()) {
|
||||
jt = it->second.find(a);
|
||||
if (jt != it->second.end()) {
|
||||
return jt->second;
|
||||
}
|
||||
}
|
||||
boost::optional<Enum> pt = Parent(t);
|
||||
if (pt) {
|
||||
t = *pt;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
if (inverse_map.empty()) ::InitInverseMap();
|
||||
std::map<std::pair<Type::Enum, std::string>, std::pair<Type::Enum, int> >::const_iterator it;
|
||||
std::pair<Type::Enum, std::string> key = std::make_pair(t, a);
|
||||
while (true) {
|
||||
it = inverse_map.find(key);
|
||||
if (it != inverse_map.end()) return it->second;
|
||||
if ((key.first = Parent(key.first)) == -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;
|
||||
|
||||
std::set<std::string> return_value;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
boost::optional<Enum> pt = Parent(t);
|
||||
if (pt) {
|
||||
t = *pt;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
Type::Enum Type::GetAttributeEnumerationClass(Enum t, unsigned char a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else {
|
||||
Type::Enum t = i->second->getArgumentEnumerationClass(a);
|
||||
if ( t == Type::ALL ) throw IfcException("Not an enumeration");
|
||||
else return t;
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
void Type::PopulateDerivedFields(IfcWrite::IfcWritableEntity* e) {
|
||||
if (derived_map.empty()) ::InitDerivedMap();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
@@ -335,12 +290,12 @@ entity_descriptor = """ current = entity_descriptor_map[Type::%(type)s] = new
|
||||
%(entity_descriptor_attributes)s"""
|
||||
|
||||
entity_descriptor_parent = "entity_descriptor_map.find(Type::%(type)s)->second"
|
||||
entity_descriptor_attribute_without_entity = ' current->add("%(name)s",%(optional)s,%(type)s);'
|
||||
entity_descriptor_attribute_with_entity = ' current->add("%(name)s",%(optional)s,%(type)s,Type::%(entity_name)s);'
|
||||
entity_descriptor_attribute = ' current->add("%(name)s",%(optional)s,%(type)s);'
|
||||
entity_descriptor_attribute_enum = ' current->add("%(name)s",%(optional)s,%(type)s,Type::%(enum_type)s);'
|
||||
|
||||
enumeration_descriptor = """ values.clear(); values.reserve(128);
|
||||
%(enumeration_descriptor_values)s
|
||||
enumeration_descriptor_map[Type::%(type)s] = new IfcEnumerationDescriptor(Type::%(type)s, values);"""
|
||||
current_enum = enumeration_descriptor_map[Type::%(type)s] = new IfcEnumerationDescriptor(Type::%(type)s, values);"""
|
||||
|
||||
enumeration_descriptor_value = ' values.push_back("%(name)s");'
|
||||
|
||||
@@ -348,58 +303,36 @@ derived_field_statement = ' {std::set<int> idxs; %(statements)sderived_map[Ty
|
||||
derived_field_statement_attrs = 'idxs.insert(%d); '
|
||||
|
||||
simpletype = """%(documentation)s
|
||||
class IFC_PARSE_API %(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;
|
||||
static Type::Enum Class();
|
||||
explicit %(name)s (IfcAbstractEntity* e);
|
||||
%(name)s (%(type)s v);
|
||||
operator %(type)s() const;
|
||||
};
|
||||
typedef %(type)s %(name)s;
|
||||
"""
|
||||
|
||||
simpletype_impl_comment = "// Function implementations for %(name)s"
|
||||
simpletype_impl_argument_type = "if (i == 0) { return %(attr_type)s; } else { throw IfcParse::IfcAttributeOutOfRangeException(\"Argument index out of range\"); }"
|
||||
simpletype_impl_argument = "return entity->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_constructor_templated = "IfcWritableEntity* e = new IfcWritableEntity(Type::%(class_name)s); e->setArgument(0, v->generalize()); entity = e;"
|
||||
simpletype_impl_cast = "return *entity->getArgument(0);"
|
||||
simpletype_impl_cast_templated = "IfcEntityList::ptr es = *entity->getArgument(0); return es->as<%(underlying_type)s>();"
|
||||
|
||||
select = """%(documentation)s
|
||||
typedef IfcUtil::IfcBaseClass %(name)s;
|
||||
typedef IfcUtil::IfcSchemaEntity %(name)s;
|
||||
"""
|
||||
|
||||
enumeration = """namespace %(name)s {
|
||||
%(documentation)s
|
||||
typedef enum {%(values)s} %(name)s;
|
||||
IFC_PARSE_API const char* ToString(%(name)s v);
|
||||
IFC_PARSE_API %(name)s FromString(const std::string& s);
|
||||
const char* ToString(%(name)s v);
|
||||
%(name)s FromString(const std::string& s);
|
||||
}
|
||||
"""
|
||||
|
||||
entity = """%(documentation)s
|
||||
class IFC_PARSE_API %(name)s %(superclass)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); }
|
||||
virtual ArgumentPtr getArgument(unsigned int i) const { return entity->getArgument(i); }
|
||||
%(inverse)s bool is(Type::Enum v) const;
|
||||
Type::Enum type() const;
|
||||
static Type::Enum Class();
|
||||
%(name)s (IfcAbstractEntity* e);
|
||||
%(name)s (IfcAbstractEntityPtr e);
|
||||
%(name)s (%(constructor_arguments)s);
|
||||
typedef IfcTemplatedEntityList< %(name)s > list;
|
||||
typedef %(name)s* ptr;
|
||||
typedef SHARED_PTR< IfcTemplatedEntityList< %(name)s > > list;
|
||||
typedef IfcTemplatedEntityList< %(name)s >::it it;
|
||||
};
|
||||
"""
|
||||
|
||||
@@ -420,28 +353,23 @@ 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; }
|
||||
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(IfcAbstractEntityPtr 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); }
|
||||
"""
|
||||
|
||||
optional_attribute_description = "/// Whether the optional attribute %s is defined for this %s"
|
||||
|
||||
function = "%(return_type)s %(class_name)s::%(name)s(%(arguments)s) { %(body)s }"
|
||||
const_function = "%(return_type)s %(class_name)s::%(name)s(%(arguments)s) const { %(body)s }"
|
||||
constructor = "%(class_name)s::%(class_name)s(%(arguments)s) { %(body)s }"
|
||||
constructor_single_initlist = "%(class_name)s::%(class_name)s(%(arguments)s) : %(superclass)s(%(superclass_init)s) { %(body)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"
|
||||
inverse_attr = "IfcTemplatedEntityList< %(entity)s >::ptr %(name)s() const; // INVERSE %(entity)s::%(attribute)s"
|
||||
list_type = "SHARED_PTR< IfcTemplatedEntityList< %(instance_type)s > >"
|
||||
untyped_list = "IfcEntities"
|
||||
inverse_attr = "SHARED_PTR< IfcTemplatedEntityList< %(entity)s > > %(name)s(); // INVERSE %(entity)s::%(attribute)s"
|
||||
|
||||
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; }'
|
||||
|
||||
@@ -451,11 +379,10 @@ optional_attr_stmt = "return !entity->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_entity = "return (%(type)s)((IfcUtil::IfcSchemaEntity)(*entity->getArgument(%(index)d)));"
|
||||
get_attr_stmt_array = "RETURN_AS_LIST(%(list_instance_type)s,%(index)d)"
|
||||
|
||||
get_inverse = "return entity->getInverse(Type::%(type)s, %(index)d)->as<%(type)s>();"
|
||||
get_inverse = "RETURN_INVERSE(%(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));"
|
||||
@@ -467,7 +394,7 @@ constructor_stmt_array = " e->setArgument(%(index)d,(%(name)s)->generalize());"
|
||||
constructor_stmt_optional = " if (%(name)s) {%(stmt)s } else { e->setArgument(%(index)d); }"
|
||||
constructor_stmt_derived = " e->setArgumentDerived(%(index)d);"
|
||||
|
||||
inverse_implementation = " inverse_map[Type::%(type)s].insert(std::make_pair(\"%(name)s\", std::make_pair(Type::%(related_type)s, %(index)d)));"
|
||||
inverse_implementation = " inverse_map.insert(std::make_pair(std::make_pair(Type::%(type)s, \"%(name)s\"), std::make_pair(Type::%(related_type)s, %(index)d)));"
|
||||
|
||||
def multi_line_comment(li):
|
||||
return ("/// %s"%("\n/// ".join(li))) if len(li) else ""
|
||||
|
||||
+24
-223
@@ -20,14 +20,8 @@
|
||||
#ifndef IFCGEOM_H
|
||||
#define IFCGEOM_H
|
||||
|
||||
#include <cmath>
|
||||
|
||||
static const double ALMOST_ZERO = 1.e-9;
|
||||
|
||||
template <typename T>
|
||||
inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMOST_ZERO) {
|
||||
return fabs(a-b) < tolerance;
|
||||
}
|
||||
#define ALMOST_ZERO (1e-9)
|
||||
#define ALMOST_THE_SAME(a,b) (fabs(a-b) < ALMOST_ZERO)
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Vec.hxx>
|
||||
@@ -42,92 +36,14 @@ inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMO
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <Geom_Curve.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <TColgp_SequenceOfPnt.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
#include <BOPAlgo_Operation.hxx>
|
||||
|
||||
#include "../ifcparse/IfcParse.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
#include "../ifcgeom/IfcGeomRepresentation.h"
|
||||
#include "../ifcgeom/IfcRepresentationShapeItem.h"
|
||||
#include "../ifcgeom/IfcGeomShapeType.h"
|
||||
#include "ifc_geom_api.h"
|
||||
|
||||
// Define this in case you want to conserve memory usage at all cost. This has been
|
||||
// benchmarked extensively: https://github.com/IfcOpenShell/IfcOpenShell/pull/47
|
||||
// #define NO_CACHE
|
||||
|
||||
#ifdef NO_CACHE
|
||||
|
||||
#define IN_CACHE(T,E,t,e)
|
||||
#define CACHE(T,E,e)
|
||||
|
||||
#else
|
||||
|
||||
#define IN_CACHE(T,E,t,e) std::map<int,t>::const_iterator it = cache.T.find(E->entity->id());\
|
||||
if ( it != cache.T.end() ) { e = it->second; return true; }
|
||||
#define CACHE(T,E,e) cache.T[E->entity->id()] = e;
|
||||
|
||||
#endif
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
class IFC_GEOM_API Cache {
|
||||
public:
|
||||
#include "IfcRegisterCreateCache.h"
|
||||
std::map<int, TopoDS_Shape> Shape;
|
||||
};
|
||||
|
||||
class IFC_GEOM_API Kernel {
|
||||
private:
|
||||
|
||||
double deflection_tolerance;
|
||||
double wire_creation_tolerance;
|
||||
double point_equality_tolerance;
|
||||
double max_faces_to_sew;
|
||||
double ifc_length_unit;
|
||||
double ifc_planeangle_unit;
|
||||
double modelling_precision;
|
||||
double dimensionality;
|
||||
|
||||
#ifndef NO_CACHE
|
||||
Cache cache;
|
||||
#endif
|
||||
|
||||
std::map<int, SurfaceStyle> style_cache;
|
||||
|
||||
const SurfaceStyle* internalize_surface_style(const std::pair<IfcSchema::IfcSurfaceStyle*, IfcSchema::IfcSurfaceStyleShading*>& shading_style);
|
||||
public:
|
||||
Kernel()
|
||||
: deflection_tolerance(0.001)
|
||||
, wire_creation_tolerance(0.0001)
|
||||
, point_equality_tolerance(0.00001)
|
||||
, max_faces_to_sew(-1.0)
|
||||
, ifc_length_unit(1.0)
|
||||
, ifc_planeangle_unit(-1.0)
|
||||
, modelling_precision(0.00001)
|
||||
, dimensionality(1.)
|
||||
{}
|
||||
|
||||
Kernel(const Kernel& other) {
|
||||
*this = other;
|
||||
}
|
||||
|
||||
Kernel& operator=(const Kernel& other) {
|
||||
setValue(GV_DEFLECTION_TOLERANCE, other.getValue(GV_DEFLECTION_TOLERANCE));
|
||||
setValue(GV_WIRE_CREATION_TOLERANCE, other.getValue(GV_WIRE_CREATION_TOLERANCE));
|
||||
setValue(GV_POINT_EQUALITY_TOLERANCE, other.getValue(GV_POINT_EQUALITY_TOLERANCE));
|
||||
setValue(GV_MAX_FACES_TO_SEW, other.getValue(GV_MAX_FACES_TO_SEW));
|
||||
setValue(GV_LENGTH_UNIT, other.getValue(GV_LENGTH_UNIT));
|
||||
setValue(GV_PLANEANGLE_UNIT, other.getValue(GV_PLANEANGLE_UNIT));
|
||||
setValue(GV_PRECISION, other.getValue(GV_PRECISION));
|
||||
setValue(GV_DIMENSIONALITY, other.getValue(GV_DIMENSIONALITY));
|
||||
setValue(GV_DEFLECTION_TOLERANCE, other.getValue(GV_DEFLECTION_TOLERANCE));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Tolerances and settings for various geometrical operations:
|
||||
enum GeomValue {
|
||||
// Specifies the deflection of the mesher
|
||||
@@ -137,7 +53,7 @@ public:
|
||||
// Defailt: 0.0001m / 0.1mm
|
||||
GV_WIRE_CREATION_TOLERANCE,
|
||||
// Specifies the minimal area of a face to be included in an IfcConnectedFaceset
|
||||
// Read-only
|
||||
// Default: 0.000001m 0.01cm2
|
||||
GV_MINIMAL_FACE_AREA,
|
||||
// Specifies the treshold distance under which cartesian points are deemed equal
|
||||
// Default: 0.00001m / 0.01mm
|
||||
@@ -146,6 +62,9 @@ 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
|
||||
@@ -157,57 +76,26 @@ 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,
|
||||
// Whether to process shapes of type Face or higher (1) Wire or lower (-1) or all (0)
|
||||
GV_DIMENSIONALITY
|
||||
GV_PRECISION
|
||||
};
|
||||
|
||||
const int DISABLE_OPENING_SUBTRACTIONS = 1 << 0;
|
||||
const int DISABLE_OBJECT_PLACEMENT = 1 << 1;
|
||||
const int SEW_SHELLS = 1 << 2;
|
||||
const int CONVERT_TO_METERS = 1 << 3;
|
||||
|
||||
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);
|
||||
IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseClass* L);
|
||||
bool is_shape_collection(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);
|
||||
bool convert_curve(const IfcUtil::IfcBaseClass* L, Handle(Geom_Curve)& result);
|
||||
bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
|
||||
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);
|
||||
|
||||
bool convert_layerset(const IfcSchema::IfcProduct*, std::vector<Handle_Geom_Surface>&, std::vector<const SurfaceStyle*>&, std::vector<double>&);
|
||||
bool apply_layerset(const IfcRepresentationShapeItems&, const std::vector<Handle_Geom_Surface>&, const std::vector<const SurfaceStyle*>&, IfcRepresentationShapeItems&);
|
||||
bool apply_folded_layerset(const IfcRepresentationShapeItems&, const std::vector< std::vector<Handle_Geom_Surface> >&, const std::vector<const SurfaceStyle*>&, IfcRepresentationShapeItems&);
|
||||
bool fold_layers(const IfcSchema::IfcWall*, const IfcRepresentationShapeItems&, const std::vector<Handle_Geom_Surface>&, const std::vector<double>&, std::vector< std::vector<Handle_Geom_Surface> >&);
|
||||
|
||||
bool split_solid_by_surface(const TopoDS_Shape&, const Handle_Geom_Surface&, TopoDS_Shape&, TopoDS_Shape&);
|
||||
bool split_solid_by_shell(const TopoDS_Shape&, const TopoDS_Shape& s, TopoDS_Shape&, TopoDS_Shape&);
|
||||
|
||||
#if OCC_VERSION_HEX < 0x60900
|
||||
bool boolean_operation(const TopoDS_Shape&, const TopTools_ListOfShape&, BOPAlgo_Operation, TopoDS_Shape&);
|
||||
bool boolean_operation(const TopoDS_Shape&, const TopoDS_Shape&, BOPAlgo_Operation, TopoDS_Shape&);
|
||||
#else
|
||||
bool boolean_operation(const TopoDS_Shape&, const TopTools_ListOfShape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
|
||||
bool boolean_operation(const TopoDS_Shape&, const TopoDS_Shape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
|
||||
#endif
|
||||
|
||||
const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const Handle_Geom_Surface&);
|
||||
const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const TopoDS_Face&);
|
||||
const Handle_Geom_Curve intersect(const TopoDS_Face&, const Handle_Geom_Surface&);
|
||||
bool intersect(const Handle_Geom_Curve&, const Handle_Geom_Surface&, gp_Pnt&);
|
||||
bool intersect(const Handle_Geom_Curve&, const TopoDS_Face&, gp_Pnt&);
|
||||
bool intersect(const Handle_Geom_Curve&, const TopoDS_Shape&, std::vector<gp_Pnt>&);
|
||||
bool intersect(const Handle_Geom_Surface&, const TopoDS_Shape&, std::vector< std::pair<Handle_Geom_Surface, Handle_Geom_Curve> >&);
|
||||
bool closest(const gp_Pnt&, const std::vector<gp_Pnt>&, gp_Pnt&);
|
||||
bool project(const Handle_Geom_Curve&, const gp_Pnt&, gp_Pnt& p, double& u, double& d);
|
||||
bool project(const Handle_Geom_Surface&, const TopoDS_Shape&, double& u1, double& v1, double& u2, double& v2, double widen=0.1);
|
||||
int count(const TopoDS_Shape&, TopAbs_ShapeEnum);
|
||||
|
||||
bool find_wall_end_points(const IfcSchema::IfcWall*, gp_Pnt& start, gp_Pnt& end);
|
||||
|
||||
bool convert_openings(const IfcSchema::IfcProduct::ptr entity, const IfcSchema::IfcRelVoidsElement::list& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
|
||||
bool convert_openings_fast(const IfcSchema::IfcProduct::ptr entity, const IfcSchema::IfcRelVoidsElement::list& 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 create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& solid);
|
||||
bool is_compound(const TopoDS_Shape& shape);
|
||||
bool is_convex(const TopoDS_Wire& wire);
|
||||
TopoDS_Shape halfspace_from_plane(const gp_Pln& pln,const gp_Pnt& cent);
|
||||
@@ -218,106 +106,19 @@ public:
|
||||
double shape_volume(const TopoDS_Shape& s);
|
||||
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) const;
|
||||
bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape);
|
||||
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);
|
||||
bool approximate_plane_through_wire(const TopoDS_Wire&, gp_Pln&);
|
||||
bool flatten_wire(TopoDS_Wire&);
|
||||
void SetValue(GeomValue var, double value);
|
||||
double GetValue(GeomValue var);
|
||||
std::string create_brep_data(IfcSchema::IfcProduct* s, unsigned int settings);
|
||||
void initialize_units_and_precision(IfcSchema::IfcProject* proj, double& unit_magnitude, std::string& unit_name);
|
||||
bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape);
|
||||
IfcSchema::IfcProductDefinitionShape* tesselate(TopoDS_Shape& shape, double deflection, IfcEntities es);
|
||||
|
||||
static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_Trsf&);
|
||||
static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_GTrsf&);
|
||||
|
||||
bool is_identity_transform(IfcUtil::IfcBaseClass*);
|
||||
|
||||
IfcSchema::IfcRelVoidsElement::list::ptr find_openings(IfcSchema::IfcProduct* product);
|
||||
|
||||
IfcSchema::IfcRepresentation* find_representation(const IfcSchema::IfcProduct*, const std::string&);
|
||||
|
||||
std::pair<std::string, double> initializeUnits(IfcSchema::IfcUnitAssignment*);
|
||||
|
||||
static IfcSchema::IfcObjectDefinition* get_decomposing_entity(IfcSchema::IfcProduct*);
|
||||
|
||||
static std::map<std::string, IfcSchema::IfcPresentationLayerAssignment*> get_layers(IfcSchema::IfcProduct* prod);
|
||||
|
||||
template <typename P>
|
||||
IfcGeom::BRepElement<P>* create_brep_for_representation_and_product(
|
||||
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*);
|
||||
|
||||
template <typename P>
|
||||
IfcGeom::BRepElement<P>* create_brep_for_processed_representation(
|
||||
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::BRepElement<P>*);
|
||||
|
||||
const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem*);
|
||||
const SurfaceStyle* get_style(const IfcSchema::IfcMaterial*);
|
||||
|
||||
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> _get_surface_style(const IfcSchema::IfcStyledItem* si) {
|
||||
#ifdef USE_IFC4
|
||||
IfcEntityList::ptr style_assignments = si->Styles();
|
||||
for (IfcEntityList::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
if (!(*kt)->is(IfcSchema::Type::IfcPresentationStyleAssignment)) {
|
||||
continue;
|
||||
}
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt;
|
||||
#else
|
||||
IfcSchema::IfcPresentationStyleAssignment::list::ptr style_assignments = si->Styles();
|
||||
for (IfcSchema::IfcPresentationStyleAssignment::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment = *kt;
|
||||
#endif
|
||||
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)) {
|
||||
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())) {
|
||||
return std::make_pair(surface_style, (T*) *mt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0,0);
|
||||
namespace Cache {
|
||||
void Purge();
|
||||
void PurgeShapeCache();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (representation_item->as<IfcSchema::IfcStyledItem>()) {
|
||||
return _get_surface_style<T>(representation_item->as<IfcSchema::IfcStyledItem>());
|
||||
}
|
||||
IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem();
|
||||
if (styled_items->size()) {
|
||||
// StyledByItem is a SET [0:1] OF IfcStyledItem, so we return after the first IfcStyledItem:
|
||||
return _get_surface_style<T>(*styled_items->begin());
|
||||
}
|
||||
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0,0);
|
||||
}
|
||||
|
||||
void purge_cache() {
|
||||
// Rather hack-ish, but a stopgap solution to keep memory under control
|
||||
// for large files. SurfaceStyles need to be kept at all costs, as they
|
||||
// are read later on when serializing Collada files.
|
||||
#ifndef NO_CACHE
|
||||
cache = Cache();
|
||||
#endif
|
||||
}
|
||||
|
||||
#include "IfcRegisterGeomHeader.h"
|
||||
|
||||
};
|
||||
|
||||
IFC_GEOM_API IfcSchema::IfcProductDefinitionShape* tesselate(const TopoDS_Shape& shape, double deflection);
|
||||
IFC_GEOM_API IfcSchema::IfcProductDefinitionShape* serialise(const TopoDS_Shape& shape, bool advanced);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -77,34 +77,30 @@
|
||||
|
||||
#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);
|
||||
bool IfcGeom::convert(const IfcSchema::IfcCircle::ptr l, Handle(Geom_Curve)& curve) {
|
||||
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
if ( r < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
|
||||
return false;
|
||||
}
|
||||
gp_Trsf trsf;
|
||||
IfcSchema::IfcAxis2Placement* placement = l->Position();
|
||||
IfcSchema::IfcAxis2Placement placement = l->Position();
|
||||
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
IfcGeom::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
} else {
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d);
|
||||
IfcGeom::convert((IfcAxis2Placement2D*)placement,trsf2d);
|
||||
trsf = trsf2d;
|
||||
}
|
||||
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
|
||||
curve = new Geom_Circle(ax, r);
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipse* l, Handle(Geom_Curve)& curve) {
|
||||
double x = l->SemiAxis1() * getValue(GV_LENGTH_UNIT);
|
||||
double y = l->SemiAxis2() * getValue(GV_LENGTH_UNIT);
|
||||
bool IfcGeom::convert(const IfcSchema::IfcEllipse::ptr l, Handle(Geom_Curve)& curve) {
|
||||
double x = l->SemiAxis1() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
double y = l->SemiAxis2() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
if (x < ALMOST_ZERO || y < ALMOST_ZERO) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
|
||||
return false;
|
||||
@@ -115,12 +111,12 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipse* l, Handle(Geom_Curve)
|
||||
// when creating a trimmed curve off of an ellipse like this.
|
||||
const bool rotated = y > x;
|
||||
gp_Trsf trsf;
|
||||
IfcSchema::IfcAxis2Placement* placement = l->Position();
|
||||
IfcSchema::IfcAxis2Placement placement = l->Position();
|
||||
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
IfcGeom::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
} else {
|
||||
gp_Trsf2d trsf2d;
|
||||
convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d);
|
||||
IfcGeom::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d);
|
||||
trsf = trsf2d;
|
||||
}
|
||||
gp_Ax2 ax = gp_Ax2();
|
||||
@@ -132,65 +128,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipse* l, Handle(Geom_Curve)
|
||||
curve = new Geom_Ellipse(ax, x, y);
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcLine* l, Handle(Geom_Curve)& curve) {
|
||||
bool IfcGeom::convert(const IfcSchema::IfcLine::ptr l, Handle(Geom_Curve)& curve) {
|
||||
gp_Pnt pnt;gp_Vec vec;
|
||||
convert(l->Pnt(),pnt);
|
||||
convert(l->Dir(),vec);
|
||||
IfcGeom::convert(l->Pnt(),pnt);
|
||||
IfcGeom::convert(l->Dir(),vec);
|
||||
// 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 bool is_rational = l->is(IfcSchema::Type::IfcRationalBSplineCurveWithKnots);
|
||||
|
||||
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 Weights(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;
|
||||
|
||||
if (is_rational) {
|
||||
IfcSchema::IfcRationalBSplineCurveWithKnots* rl = (IfcSchema::IfcRationalBSplineCurveWithKnots*)l;
|
||||
std::vector<double> weights = rl->WeightsData();
|
||||
|
||||
i = 0;
|
||||
for (std::vector<double>::const_iterator it = weights.begin(); it != weights.end(); ++it, ++i) {
|
||||
Weights(i) = *it;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (is_rational) {
|
||||
curve = new Geom_BSplineCurve(Poles, Weights, Knots, Mults, Degree, Periodic);
|
||||
} else {
|
||||
curve = new Geom_BSplineCurve(Poles, Knots, Mults, Degree, Periodic);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,170 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMELEMENT_H
|
||||
#define IFCGEOMELEMENT_H
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../ifcparse/IfcGlobalId.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeomRepresentation.h"
|
||||
#include "../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
#include "ifc_geom_api.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
template <typename P>
|
||||
class Matrix {
|
||||
private:
|
||||
std::vector<P> _data;
|
||||
public:
|
||||
Matrix(const ElementSettings& settings, const gp_Trsf& trsf) {
|
||||
// Convert the gp_Trsf into a 4x3 Matrix
|
||||
// Note that in case the CONVERT_BACK_UNITS setting is enabled
|
||||
// the translation component of the matrix needs to be divided
|
||||
// by the magnitude of the IFC model length unit because
|
||||
// internally in IfcOpenShell everything is measured in meters.
|
||||
for(int i = 1; i < 5; ++i) {
|
||||
for (int j = 1; j < 4; ++j) {
|
||||
const double trsf_value = trsf.Value(j,i);
|
||||
const double matrix_value = i == 4 && settings.get(IteratorSettings::CONVERT_BACK_UNITS)
|
||||
? trsf_value / settings.unit_magnitude()
|
||||
: trsf_value;
|
||||
_data.push_back(static_cast<P>(matrix_value));
|
||||
}
|
||||
}
|
||||
}
|
||||
const std::vector<P>& data() const { return _data; }
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
class Transformation {
|
||||
private:
|
||||
gp_Trsf trsf;
|
||||
Matrix<P> _matrix;
|
||||
public:
|
||||
Transformation(const ElementSettings& settings, const gp_Trsf& trsf)
|
||||
: trsf(trsf)
|
||||
, _matrix(settings, trsf)
|
||||
{}
|
||||
const gp_Trsf& data() const { return trsf; }
|
||||
const Matrix<P>& matrix() const { return _matrix; }
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
class Element {
|
||||
private:
|
||||
int _id;
|
||||
int _parent_id;
|
||||
std::string _name;
|
||||
std::string _type;
|
||||
std::string _guid;
|
||||
std::string _context;
|
||||
std::string _unique_id;
|
||||
Transformation<P> _transformation;
|
||||
IfcSchema::IfcProduct* product_;
|
||||
public:
|
||||
int id() const { return _id; }
|
||||
int parent_id() const { return _parent_id; }
|
||||
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; }
|
||||
IfcSchema::IfcProduct* product() const { return product_; }
|
||||
|
||||
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, IfcSchema::IfcProduct *product)
|
||||
: _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _context(context), _transformation(settings, trsf)
|
||||
, product_(product)
|
||||
{
|
||||
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() {}
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
class BRepElement : public Element<P> {
|
||||
private:
|
||||
boost::shared_ptr<Representation::BRep> _geometry;
|
||||
public:
|
||||
const boost::shared_ptr<Representation::BRep>& geometry_pointer() const { return _geometry; }
|
||||
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 std::string& context, const gp_Trsf& trsf, const boost::shared_ptr<Representation::BRep>& geometry,
|
||||
IfcSchema::IfcProduct* product)
|
||||
: Element<P>(geometry->settings(),id,parent_id,name,type,guid,context,trsf, product)
|
||||
, _geometry(geometry)
|
||||
{}
|
||||
private:
|
||||
BRepElement(const BRepElement& other);
|
||||
BRepElement& operator=(const BRepElement& other);
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
class TriangulationElement : public Element<P> {
|
||||
private:
|
||||
boost::shared_ptr< Representation::Triangulation<P> > _geometry;
|
||||
public:
|
||||
const Representation::Triangulation<P>& geometry() const { return *_geometry; }
|
||||
const boost::shared_ptr< Representation::Triangulation<P> >& geometry_pointer() const { return _geometry; }
|
||||
TriangulationElement(const BRepElement<P>& shape_model)
|
||||
: Element<P>(shape_model)
|
||||
, _geometry(boost::shared_ptr<Representation::Triangulation<P> >(new Representation::Triangulation<P>(shape_model.geometry())))
|
||||
{}
|
||||
TriangulationElement(const Element<P>& element, const boost::shared_ptr<Representation::Triangulation<P> >& geometry)
|
||||
: Element<P>(element)
|
||||
, _geometry(geometry)
|
||||
{}
|
||||
private:
|
||||
TriangulationElement(const TriangulationElement& other);
|
||||
TriangulationElement& operator=(const TriangulationElement& other);
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
class SerializedElement : public Element<P> {
|
||||
private:
|
||||
Representation::Serialization* _geometry;
|
||||
public:
|
||||
const Representation::Serialization& geometry() const { return *_geometry; }
|
||||
SerializedElement(const BRepElement<P>& shape_model)
|
||||
: Element<P>(shape_model)
|
||||
, _geometry(new Representation::Serialization(shape_model.geometry()))
|
||||
{}
|
||||
virtual ~SerializedElement() {
|
||||
delete _geometry;
|
||||
}
|
||||
private:
|
||||
SerializedElement(const SerializedElement& other);
|
||||
SerializedElement& operator=(const SerializedElement& other);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
+221
-545
File diff suppressed because it is too large
Load Diff
@@ -1,301 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/** @file IfcGeomFilter.h
|
||||
@brief A set of predefined product filters for IfcGeom::Iterator */
|
||||
|
||||
#ifndef IFCGEOMFILTER_H
|
||||
#define IFCGEOMFILTER_H
|
||||
|
||||
#include "IfcGeom.h"
|
||||
#include "../ifcparse/IfcWritableEntity.h"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace IfcGeom
|
||||
{
|
||||
/// The filter function (free or member function) or function object (use boost::ref() to reference to it)
|
||||
/// should return true if the geometry for the product is wanted to be included in the output.
|
||||
/// http://www.boost.org/doc/libs/1_62_0/doc/html/function/tutorial.html
|
||||
typedef boost::function<bool(IfcSchema::IfcProduct*)> filter_t;
|
||||
|
||||
struct filter
|
||||
{
|
||||
filter() : include(false), traverse(false) {}
|
||||
filter(bool incl, bool trav) : include(incl), traverse(trav) {}
|
||||
/// Should the product be included (true) or excluded (false).
|
||||
bool include;
|
||||
/// If traversal requested, traverse to the parents to see if they satisfy the criteria. E.g. we might be looking for
|
||||
/// children of a storey named "Level 20", or children of entities that have no representation, e.g. IfcCurtainWall.
|
||||
bool traverse;
|
||||
/// Optional description for the filtering criteria of this filter.
|
||||
std::string description;
|
||||
|
||||
bool match(IfcSchema::IfcProduct* prod, const filter_t& pred) const
|
||||
{
|
||||
bool is_match = pred(prod);
|
||||
if (!is_match && traverse) {
|
||||
is_match = traverse_match(prod, pred);
|
||||
}
|
||||
return is_match == include;
|
||||
}
|
||||
|
||||
static bool traverse_match(IfcSchema::IfcProduct* prod, const filter_t& pred)
|
||||
{
|
||||
IfcSchema::IfcProduct* parent, *current = prod;
|
||||
while ((parent = dynamic_cast<IfcSchema::IfcProduct*>(IfcGeom::Kernel::get_decomposing_entity(current))) != 0) {
|
||||
if (pred(parent)) {
|
||||
return true;
|
||||
}
|
||||
current = parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct wildcard_filter : public filter
|
||||
{
|
||||
wildcard_filter() : filter(false, false) {}
|
||||
wildcard_filter(bool include, bool traverse, const std::set<std::string>& patterns)
|
||||
: filter(include, traverse)
|
||||
{
|
||||
populate(patterns);
|
||||
}
|
||||
|
||||
std::set<boost::regex> values;
|
||||
|
||||
void populate(const std::set<std::string>& patterns)
|
||||
{
|
||||
values.clear();
|
||||
foreach(const std::string &pattern, patterns) {
|
||||
values.insert(wildcard_string_to_regex(pattern));
|
||||
}
|
||||
}
|
||||
|
||||
bool match(const std::string &str) const { return match_values(values, str); }
|
||||
|
||||
static bool match_values(const std::set<boost::regex>& values, const std::string &str)
|
||||
{
|
||||
foreach(const boost::regex& r, values) {
|
||||
if (boost::regex_match(str, r)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static boost::regex wildcard_string_to_regex(std::string str)
|
||||
{
|
||||
// Escape all non-"*?" regex special chars
|
||||
static const std::string special_chars = "\\^.$|()[]+/";
|
||||
foreach(char c, special_chars) {
|
||||
std::string char_str(1, c);
|
||||
boost::replace_all(str, char_str, "\\" + char_str);
|
||||
}
|
||||
// Convert "*?" to their regex equivalents
|
||||
boost::replace_all(str, "?", ".");
|
||||
boost::replace_all(str, "*", ".*");
|
||||
return boost::regex(str);
|
||||
}
|
||||
};
|
||||
|
||||
/// @note supports only string arguments for now
|
||||
struct string_arg_filter : public wildcard_filter
|
||||
{
|
||||
// Using this for now in order to overcome the fact that different classes have the argument at different indices.
|
||||
typedef std::map<IfcSchema::Type::Enum, unsigned short> arg_map_t;
|
||||
arg_map_t args;
|
||||
|
||||
/// @todo Take only attribute name when IfcBaseClass and IfcLateBoundEntity are merged.
|
||||
string_arg_filter(arg_map_t args) : args(args) { assert_arguments(); }
|
||||
string_arg_filter(IfcSchema::Type::Enum type, unsigned short index) { args[type] = index; assert_arguments(); }
|
||||
string_arg_filter(
|
||||
IfcSchema::Type::Enum type1, unsigned short index1,
|
||||
IfcSchema::Type::Enum type2, unsigned short index2)
|
||||
{
|
||||
args[type1] = index1;
|
||||
args[type2] = index2;
|
||||
assert_arguments();
|
||||
}
|
||||
|
||||
/// @todo this won't be needed when we have the generic argument name access
|
||||
void assert_arguments()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
for (arg_map_t::const_iterator it = args.begin(); it != args.end(); ++it) {
|
||||
IfcWrite::IfcWritableEntity dummy(it->first);
|
||||
IfcUtil::IfcBaseClass* base = IfcSchema::SchemaEntity(&dummy);
|
||||
assert(it->second < base->getArgumentCount() && "Argument index out of bounds");
|
||||
assert(base->getArgumentType(it->second) == IfcUtil::Argument_STRING && "Argument type not string");
|
||||
delete base;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string value(IfcSchema::IfcProduct* prod) const
|
||||
{
|
||||
for (arg_map_t::const_iterator it = args.begin(); it != args.end(); ++it) {
|
||||
if (prod->is(it->first) && it->second < prod->entity->getArgumentCount() &&
|
||||
prod->getArgumentType(it->second) == IfcUtil::Argument_STRING) {
|
||||
Argument *arg = prod->entity->getArgument(it->second);
|
||||
if (!arg->isNull()) {
|
||||
return *arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool match(IfcSchema::IfcProduct* prod) const { return wildcard_filter::match(value(prod)); }
|
||||
|
||||
bool operator()(IfcSchema::IfcProduct* prod) const
|
||||
{
|
||||
// @note bind1st() and mem_fun() deprecated in C++11, use bind() and mem_fn() when migrating to C++11.
|
||||
return filter::match(prod, std::bind1st(std::mem_fun(&string_arg_filter::match), this));
|
||||
}
|
||||
|
||||
void update_description()
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
ss << (traverse ? "traverse " : "") << (include ? "include" : "exclude");
|
||||
std::vector<std::string> patterns;
|
||||
foreach(const boost::regex& r, values) {
|
||||
patterns.push_back(" \"" + r.str() + "\"");
|
||||
}
|
||||
|
||||
for (arg_map_t::const_iterator it = args.begin(); it != args.end(); ++it) {
|
||||
IfcWrite::IfcWritableEntity dummy(it->first);
|
||||
IfcUtil::IfcBaseClass* base = IfcSchema::SchemaEntity(&dummy);
|
||||
try {
|
||||
ss << " " << IfcSchema::Type::ToString(it->first) << "." << base->getArgumentName(it->second);
|
||||
} catch(...) {}
|
||||
delete base;
|
||||
}
|
||||
|
||||
ss << " values " << boost::algorithm::join(patterns, " ");
|
||||
description = ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct layer_filter : public wildcard_filter
|
||||
{
|
||||
typedef std::map<std::string, IfcSchema::IfcPresentationLayerAssignment*> layer_map_t;
|
||||
|
||||
layer_filter() {}
|
||||
layer_filter(bool include, bool traverse, const std::set<std::string>& patterns)
|
||||
: wildcard_filter(include, traverse, patterns)
|
||||
{
|
||||
}
|
||||
|
||||
bool match(IfcSchema::IfcProduct* prod) const
|
||||
{
|
||||
layer_map_t layers = IfcGeom::Kernel::get_layers(prod);
|
||||
return std::find_if(layers.begin(), layers.end(), wildcards_match(values)) != layers.end();
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcProduct* prod) const
|
||||
{
|
||||
return filter::match(prod, std::bind1st(std::mem_fun(&layer_filter::match), this));
|
||||
}
|
||||
|
||||
struct wildcards_match
|
||||
{
|
||||
wildcards_match(const std::set<boost::regex>& patterns) : patterns(patterns) {}
|
||||
bool operator()(const layer_map_t::value_type& layer_map_value) const
|
||||
{
|
||||
return wildcard_filter::match_values(patterns, layer_map_value.first);
|
||||
}
|
||||
|
||||
std::set<boost::regex> patterns;
|
||||
};
|
||||
|
||||
void update_description()
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << (traverse ? "traverse " : "") << (include ? "include" : "exclude") << " layers";
|
||||
std::vector<std::string> str_values;
|
||||
foreach(const boost::regex& r, values) {
|
||||
str_values.push_back(" \"" + r.str() + "\"");
|
||||
}
|
||||
ss << " " << boost::algorithm::join(str_values, " ");
|
||||
description = ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct entity_filter : public filter
|
||||
{
|
||||
entity_filter() {}
|
||||
entity_filter(bool include, bool traverse/*, const std::set<std::string>& types*/)
|
||||
: filter(include, traverse)
|
||||
{
|
||||
//populate(types);
|
||||
}
|
||||
|
||||
std::set<IfcSchema::Type::Enum> values;
|
||||
|
||||
void populate(const std::set<std::string>& types)
|
||||
{
|
||||
values.clear();
|
||||
foreach(const std::string& type, types) {
|
||||
IfcSchema::Type::Enum ty;
|
||||
try {
|
||||
ty = IfcSchema::Type::FromString(boost::to_upper_copy(type));
|
||||
} catch (const IfcParse::IfcException&) {
|
||||
throw IfcParse::IfcException("'" + type + "' does not name a valid IFC entity");
|
||||
}
|
||||
values.insert(ty);
|
||||
/// @todo Add child classes so that containment in set can be in O(log n)
|
||||
}
|
||||
}
|
||||
|
||||
bool match(IfcSchema::IfcProduct* prod) const
|
||||
{
|
||||
// The set is iterated over to able to filter on subtypes.
|
||||
foreach(IfcSchema::Type::Enum type, values) {
|
||||
if (prod->is(type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcProduct* prod) const
|
||||
{
|
||||
return filter::match(prod, std::bind1st(std::mem_fun(&entity_filter::match), this));
|
||||
}
|
||||
|
||||
void update_description()
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << (traverse ? "traverse " : "") << (include ? "include" : "exclude") << " entities";
|
||||
foreach(IfcSchema::Type::Enum type, values) {
|
||||
ss << " " << IfcSchema::Type::ToString(type);
|
||||
}
|
||||
description = ss.str();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
+381
-2017
File diff suppressed because it is too large
Load Diff
+70
-130
@@ -77,66 +77,29 @@
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
// Helper functions (re)set gp_(G)Trsf(2d) forms explicitly to 'Identity'
|
||||
// so that it can be easily identified in the IfcMappedItem processing
|
||||
|
||||
// For axis placements detect equality early in order for the
|
||||
// relatively computionaly expensive gp_Trsf calculation to be skipped
|
||||
template <typename T>
|
||||
bool axis_equal(const T& a, const T& b, double tolerance);
|
||||
template <>
|
||||
bool axis_equal(const gp_Ax3& a, const gp_Ax3& b, double tolerance) {
|
||||
if (!a.Location().IsEqual(b.Location(), tolerance)) return false;
|
||||
// Note that the tolerance below is angular, above is linear. Since architectural
|
||||
// objects are about 1m'ish in scale, it should be somewhat equivalent. Besides,
|
||||
// this is mostly a filter for NULL or default values in the placements.
|
||||
if (!a.Direction().IsEqual(b.Direction(), tolerance)) return false;
|
||||
if (!a.XDirection().IsEqual(b.XDirection(), tolerance)) return false;
|
||||
if (!a.YDirection().IsEqual(b.YDirection(), tolerance)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool axis_equal(const gp_Ax2d& a, const gp_Ax2d& b, double tolerance) {
|
||||
if (!a.Location().IsEqual(b.Location(), tolerance)) return false;
|
||||
if (!a.Direction().IsEqual(b.Direction(), tolerance)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T> struct dimension_count {};
|
||||
template <> struct dimension_count <gp_Trsf2d > { static const int n = 2; };
|
||||
template <> struct dimension_count <gp_GTrsf2d> { static const int n = 2; };
|
||||
template <> struct dimension_count < gp_Trsf > { static const int n = 3; };
|
||||
template <> struct dimension_count < gp_GTrsf > { static const int n = 3; };
|
||||
|
||||
template <typename T>
|
||||
bool is_identity(const T& t, double tolerance) {
|
||||
// Note the {1, n+1} range due to Open Cascade's 1-based indexing
|
||||
// Note the {1, n+2} range due to the translation part of the matrix
|
||||
for (int i = 1; i < dimension_count<T>::n + 2; ++i) {
|
||||
for (int j = 1; j < dimension_count<T>::n + 1; ++j) {
|
||||
const double iden_value = i == j ? 1. : 0.;
|
||||
const double trsf_value = t.Value(j, i);
|
||||
if (fabs(trsf_value - iden_value) > tolerance) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
namespace IfcGeom {
|
||||
namespace Cache {
|
||||
#include "IfcRegisterCreateCache.h"
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#define IN_CACHE(T,E,t,e) std::map<int,t>::const_iterator it = Cache::T.find(E->entity->id());\
|
||||
if ( it != Cache::T.end() ) { e = it->second; return true; }
|
||||
#define CACHE(T,E,e) Cache::T[E->entity->id()] = e;
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianPoint* l, gp_Pnt& point) {
|
||||
bool IfcGeom::convert(const IfcSchema::IfcCartesianPoint::ptr l, gp_Pnt& point) {
|
||||
IN_CACHE(IfcCartesianPoint,l,gp_Pnt,point)
|
||||
std::vector<double> xyz = l->Coordinates();
|
||||
point = gp_Pnt(
|
||||
xyz.size() ? (xyz[0]*getValue(GV_LENGTH_UNIT)) : 0.0f,
|
||||
xyz.size() > 1 ? (xyz[1]*getValue(GV_LENGTH_UNIT)) : 0.0f,
|
||||
xyz.size() > 2 ? (xyz[2]*getValue(GV_LENGTH_UNIT)) : 0.0f
|
||||
xyz.size() ? (xyz[0]*IfcGeom::GetValue(GV_LENGTH_UNIT)) : 0.0f,
|
||||
xyz.size() > 1 ? (xyz[1]*IfcGeom::GetValue(GV_LENGTH_UNIT)) : 0.0f,
|
||||
xyz.size() > 2 ? (xyz[2]*IfcGeom::GetValue(GV_LENGTH_UNIT)) : 0.0f
|
||||
);
|
||||
CACHE(IfcCartesianPoint,l,point)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcDirection* l, gp_Dir& dir) {
|
||||
bool IfcGeom::convert(const IfcSchema::IfcDirection::ptr l, gp_Dir& dir) {
|
||||
IN_CACHE(IfcDirection,l,gp_Dir,dir)
|
||||
std::vector<double> xyz = l->DirectionRatios();
|
||||
dir = gp_Dir(
|
||||
@@ -148,80 +111,70 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcDirection* l, gp_Dir& dir) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcVector* l, gp_Vec& v) {
|
||||
bool IfcGeom::convert(const IfcSchema::IfcVector::ptr l, gp_Vec& v) {
|
||||
IN_CACHE(IfcVector,l,gp_Vec,v)
|
||||
gp_Dir d;
|
||||
IfcGeom::Kernel::convert(l->Orientation(),d);
|
||||
v = l->Magnitude() * getValue(GV_LENGTH_UNIT) * d;
|
||||
IfcGeom::convert(l->Orientation(),d);
|
||||
v = l->Magnitude() * IfcGeom::GetValue(GV_LENGTH_UNIT) * d;
|
||||
CACHE(IfcVector,l,v)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement3D* l, gp_Trsf& trsf) {
|
||||
bool IfcGeom::convert(const IfcSchema::IfcAxis2Placement3D::ptr l, gp_Trsf& trsf) {
|
||||
IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf)
|
||||
gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);gp_Dir refDirection;
|
||||
IfcGeom::Kernel::convert(l->Location(),o);
|
||||
IfcGeom::convert(l->Location(),o);
|
||||
bool hasRef = l->hasRefDirection();
|
||||
if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(),axis);
|
||||
if ( hasRef ) IfcGeom::Kernel::convert(l->RefDirection(),refDirection);
|
||||
if ( l->hasAxis() ) IfcGeom::convert(l->Axis(),axis);
|
||||
if ( hasRef ) IfcGeom::convert(l->RefDirection(),refDirection);
|
||||
gp_Ax3 ax3;
|
||||
if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection);
|
||||
else ax3 = gp_Ax3(o,axis);
|
||||
|
||||
if (!axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) {
|
||||
trsf.SetTransformation(ax3, gp::XOY());
|
||||
}
|
||||
|
||||
trsf.SetTransformation(ax3, gp_Ax3(gp_Pnt(),gp_Dir(0,0,1),gp_Dir(1,0,0)));
|
||||
CACHE(IfcAxis2Placement3D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis1Placement* l, gp_Ax1& ax) {
|
||||
bool IfcGeom::convert(const IfcSchema::IfcAxis1Placement::ptr l, gp_Ax1& ax) {
|
||||
IN_CACHE(IfcAxis1Placement,l,gp_Ax1,ax)
|
||||
gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);
|
||||
IfcGeom::Kernel::convert(l->Location(),o);
|
||||
if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(), axis);
|
||||
IfcGeom::convert(l->Location(),o);
|
||||
if ( l->hasAxis() ) IfcGeom::convert(l->Axis(), axis);
|
||||
ax = gp_Ax1(o, axis);
|
||||
CACHE(IfcAxis1Placement,l,ax)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator3D* l, gp_Trsf& trsf) {
|
||||
bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator3D::ptr l, gp_Trsf& trsf) {
|
||||
IN_CACHE(IfcCartesianTransformationOperator3D,l,gp_Trsf,trsf)
|
||||
gp_Pnt origin;
|
||||
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
|
||||
IfcGeom::convert(l->LocalOrigin(),origin);
|
||||
gp_Dir axis1 (1.,0.,0.);
|
||||
gp_Dir axis2 (0.,1.,0.);
|
||||
gp_Dir axis3 (0.,0.,1.);
|
||||
if ( l->hasAxis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2);
|
||||
if ( l->hasAxis3() ) IfcGeom::Kernel::convert(l->Axis3(),axis3);
|
||||
gp_Dir axis3;
|
||||
if ( l->hasAxis1() ) IfcGeom::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::convert(l->Axis2(),axis2);
|
||||
if ( l->hasAxis3() ) IfcGeom::convert(l->Axis3(),axis3);
|
||||
else axis3 = axis1.Crossed(axis2);
|
||||
gp_Ax3 ax3 (origin,axis3,axis1);
|
||||
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
|
||||
|
||||
if (!axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) {
|
||||
trsf.SetTransformation(ax3);
|
||||
trsf.Invert();
|
||||
}
|
||||
|
||||
if (l->hasScale() && !ALMOST_THE_SAME(l->Scale(), 1.)) {
|
||||
trsf.SetScaleFactor(l->Scale());
|
||||
}
|
||||
|
||||
trsf.SetTransformation(ax3);
|
||||
trsf.Invert();
|
||||
if ( l->hasScale() ) trsf.SetScaleFactor(l->Scale());
|
||||
CACHE(IfcCartesianTransformationOperator3D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator2D* l, gp_Trsf2d& trsf) {
|
||||
bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator2D::ptr l, gp_Trsf2d& trsf) {
|
||||
IN_CACHE(IfcCartesianTransformationOperator2D,l,gp_Trsf2d,trsf)
|
||||
|
||||
gp_Pnt origin;
|
||||
gp_Dir axis1 (1.,0.,0.);
|
||||
gp_Dir axis2 (0.,1.,0.);
|
||||
|
||||
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
|
||||
if ( l->hasAxis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2);
|
||||
IfcGeom::convert(l->LocalOrigin(),origin);
|
||||
if ( l->hasAxis1() ) IfcGeom::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::convert(l->Axis2(),axis2);
|
||||
|
||||
const gp_Pnt2d origin2d(origin.X(), origin.Y());
|
||||
const gp_Dir2d axis12d(axis1.X(), axis1.Y());
|
||||
@@ -241,27 +194,23 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
|
||||
}
|
||||
|
||||
trsf.Invert();
|
||||
if ( l->hasScale() && !ALMOST_THE_SAME(l->Scale(), 1.) ) trsf.SetScaleFactor(l->Scale());
|
||||
|
||||
if (is_identity(trsf, getValue(GV_PRECISION))) {
|
||||
trsf = gp_Trsf2d();
|
||||
}
|
||||
|
||||
if ( l->hasScale() ) trsf.SetScaleFactor(l->Scale());
|
||||
CACHE(IfcCartesianTransformationOperator2D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* l, gp_GTrsf& gtrsf) {
|
||||
bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform::ptr l, gp_GTrsf& gtrsf) {
|
||||
IN_CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gp_GTrsf,gtrsf)
|
||||
gp_Trsf trsf;
|
||||
gp_Pnt origin;
|
||||
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
|
||||
IfcGeom::convert(l->LocalOrigin(),origin);
|
||||
gp_Dir axis1 (1.,0.,0.);
|
||||
gp_Dir axis2 (0.,1.,0.);
|
||||
gp_Dir axis3 (0.,0.,1.);
|
||||
if ( l->hasAxis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2);
|
||||
if ( l->hasAxis3() ) IfcGeom::Kernel::convert(l->Axis3(),axis3);
|
||||
gp_Dir axis3;
|
||||
if ( l->hasAxis1() ) IfcGeom::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::convert(l->Axis2(),axis2);
|
||||
if ( l->hasAxis3() ) IfcGeom::convert(l->Axis3(),axis3);
|
||||
else axis3 = axis1.Crossed(axis2);
|
||||
gp_Ax3 ax3 (origin,axis3,axis1);
|
||||
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
|
||||
trsf.SetTransformation(ax3);
|
||||
@@ -274,16 +223,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
|
||||
gtrsf.SetValue(2,2,scale2);
|
||||
gtrsf.SetValue(3,3,scale3);
|
||||
gtrsf.PreMultiply(trsf);
|
||||
|
||||
if (is_identity(gtrsf, getValue(GV_PRECISION))) {
|
||||
gtrsf = gp_GTrsf();
|
||||
}
|
||||
|
||||
CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gtrsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* l, gp_GTrsf2d& gtrsf) {
|
||||
bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform::ptr l, gp_GTrsf2d& gtrsf) {
|
||||
IN_CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gp_GTrsf2d,gtrsf)
|
||||
|
||||
gp_Trsf2d trsf;
|
||||
@@ -291,9 +235,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
|
||||
gp_Dir axis1 (1.,0.,0.);
|
||||
gp_Dir axis2 (0.,1.,0.);
|
||||
|
||||
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
|
||||
if ( l->hasAxis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2);
|
||||
IfcGeom::convert(l->LocalOrigin(),origin);
|
||||
if ( l->hasAxis1() ) IfcGeom::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::convert(l->Axis2(),axis2);
|
||||
|
||||
const gp_Pnt2d origin2d(origin.X(), origin.Y());
|
||||
const gp_Dir2d axis12d(axis1.X(), axis1.Y());
|
||||
@@ -315,23 +259,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
|
||||
gtrsf.SetValue(1,1,scale1);
|
||||
gtrsf.SetValue(2,2,scale2);
|
||||
gtrsf.Multiply(trsf);
|
||||
|
||||
if (is_identity(gtrsf, getValue(GV_PRECISION))) {
|
||||
gtrsf = gp_GTrsf2d();
|
||||
}
|
||||
|
||||
CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gtrsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPlane* pln, gp_Pln& plane) {
|
||||
bool IfcGeom::convert(const IfcSchema::IfcPlane::ptr pln, gp_Pln& plane) {
|
||||
IN_CACHE(IfcPlane,pln,gp_Pln,plane)
|
||||
IfcSchema::IfcAxis2Placement3D* l = pln->Position();
|
||||
IfcSchema::IfcAxis2Placement3D::ptr l = pln->Position();
|
||||
gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);gp_Dir refDirection;
|
||||
IfcGeom::Kernel::convert(l->Location(),o);
|
||||
IfcGeom::convert(l->Location(),o);
|
||||
bool hasRef = l->hasRefDirection();
|
||||
if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(),axis);
|
||||
if ( hasRef ) IfcGeom::Kernel::convert(l->RefDirection(),refDirection);
|
||||
if ( l->hasAxis() ) IfcGeom::convert(l->Axis(),axis);
|
||||
if ( hasRef ) IfcGeom::convert(l->RefDirection(),refDirection);
|
||||
gp_Ax3 ax3;
|
||||
if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection);
|
||||
else ax3 = gp_Ax3(o,axis);
|
||||
@@ -340,44 +279,45 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPlane* pln, gp_Pln& plane) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d& trsf) {
|
||||
bool IfcGeom::convert(const IfcSchema::IfcAxis2Placement2D::ptr l, gp_Trsf2d& trsf) {
|
||||
IN_CACHE(IfcAxis2Placement2D,l,gp_Trsf2d,trsf)
|
||||
gp_Pnt P; gp_Dir V (1,0,0);
|
||||
IfcGeom::Kernel::convert(l->Location(),P);
|
||||
IfcGeom::convert(l->Location(),P);
|
||||
if ( l->hasRefDirection() )
|
||||
IfcGeom::Kernel::convert(l->RefDirection(),V);
|
||||
|
||||
gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()), gp_Dir2d(V.X(),V.Y()));
|
||||
|
||||
if (!axis_equal(axis, gp_Ax2d(), getValue(GV_PRECISION))) {
|
||||
trsf.SetTransformation(axis, gp_Ax2d());
|
||||
}
|
||||
IfcGeom::convert(l->RefDirection(),V);
|
||||
|
||||
gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()),gp_Dir2d(V.X(),V.Y()));
|
||||
trsf.SetTransformation(axis,gp_Ax2d());
|
||||
CACHE(IfcAxis2Placement2D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf) {
|
||||
bool IfcGeom::convert(const IfcSchema::IfcObjectPlacement::ptr 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);
|
||||
return false;
|
||||
}
|
||||
IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l;
|
||||
for (;;) {
|
||||
IfcSchema::IfcLocalPlacement::ptr current = reinterpret_pointer_cast<IfcSchema::IfcObjectPlacement,IfcSchema::IfcLocalPlacement>(l);
|
||||
while (1) {
|
||||
gp_Trsf trsf2;
|
||||
IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement();
|
||||
IfcSchema::IfcAxis2Placement relplacement = current->RelativePlacement();
|
||||
if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2);
|
||||
IfcGeom::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2);
|
||||
trsf.PreMultiply(trsf2);
|
||||
}
|
||||
if ( current->hasPlacementRelTo() ) {
|
||||
IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo();
|
||||
IfcSchema::IfcObjectPlacement::ptr relto = current->PlacementRelTo();
|
||||
if ( relto->is(IfcSchema::Type::IfcLocalPlacement) )
|
||||
current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo();
|
||||
current = reinterpret_pointer_cast<IfcSchema::IfcObjectPlacement,IfcSchema::IfcLocalPlacement>(current->PlacementRelTo());
|
||||
else break;
|
||||
} else break;
|
||||
}
|
||||
CACHE(IfcObjectPlacement,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
void IfcGeom::Cache::Purge() {
|
||||
#include "IfcRegisterPurgeCache.h"
|
||||
IfcGeom::Cache::PurgeShapeCache();
|
||||
}
|
||||
@@ -1,717 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) *
|
||||
* and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). *
|
||||
* *
|
||||
* IfcGeom::Representation::Triangulation is a class that represents a *
|
||||
* triangulated IfcShapeRepresentation. *
|
||||
* Triangulation.verts is a 1 dimensional vector of float defining the *
|
||||
* cartesian coordinates of the vertices of the triangulated shape in the *
|
||||
* format of [x1,y1,z1,..,xn,yn,zn] *
|
||||
* Triangulation.faces is a 1 dimensional vector of int containing the *
|
||||
* indices of the triangles referencing positions in Triangulation.verts *
|
||||
* Triangulation.edges is a 1 dimensional vector of int in {0,1} that dictates*
|
||||
* the visibility of the edges that span the faces in Triangulation.faces *
|
||||
* *
|
||||
* IfcGeom::Element represents the actual IfcBuildingElements. *
|
||||
* IfcGeomObject.name is the GUID of the element *
|
||||
* IfcGeomObject.type is the datatype of the element e.g. IfcWindow *
|
||||
* IfcGeomObject.mesh is a pointer to an IfcMesh *
|
||||
* IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the *
|
||||
* orientation and translation of the mesh in relation to the world origin *
|
||||
* *
|
||||
* IfcGeom::Iterator::initialize() *
|
||||
* finds the most suitable representation contexts. Returns true iff *
|
||||
* at least a single representation will process successfully *
|
||||
* *
|
||||
* IfcGeom::Iterator::get() *
|
||||
* returns a pointer to the current IfcGeom::Element *
|
||||
* *
|
||||
* IfcGeom::Iterator::next() *
|
||||
* returns true iff a following entity is available for a successive call to *
|
||||
* IfcGeom::Iterator::get() *
|
||||
* *
|
||||
* IfcGeom::Iterator::progress() *
|
||||
* returns an int in [0..100] that indicates the overall progress *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMITERATOR_H
|
||||
#define IFCGEOMITERATOR_H
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <gp_Mat.hxx>
|
||||
#include <gp_Mat2d.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <gp_GTrsf2d.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
#include "../ifcgeom/IfcGeomMaterial.h"
|
||||
#include "../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
#include "../ifcgeom/IfcRepresentationShapeItem.h"
|
||||
#include "../ifcgeom/IfcGeomFilter.h"
|
||||
|
||||
// The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
template <typename P>
|
||||
class Iterator {
|
||||
private:
|
||||
Iterator(const Iterator&); // N/I
|
||||
Iterator& operator=(const Iterator&); // N/I
|
||||
|
||||
Kernel kernel;
|
||||
IteratorSettings settings;
|
||||
|
||||
IfcParse::IfcFile* ifc_file;
|
||||
|
||||
// A container and iterator for IfcRepresentations
|
||||
IfcSchema::IfcRepresentation::list::ptr representations;
|
||||
IfcSchema::IfcRepresentation::list::it representation_iterator;
|
||||
|
||||
// The object is fetched beforehand to be sure that get() returns a valid element
|
||||
TriangulationElement<P>* current_triangulation;
|
||||
BRepElement<P>* current_shape_model;
|
||||
SerializedElement<P>* current_serialization;
|
||||
|
||||
// A container and iterator for IfcBuildingElements for the current IfcRepresentation referenced by *representation_iterator
|
||||
IfcSchema::IfcProduct::list::ptr ifcproducts;
|
||||
IfcSchema::IfcProduct::list::it ifcproduct_iterator;
|
||||
|
||||
int done;
|
||||
int total;
|
||||
|
||||
std::string unit_name;
|
||||
double unit_magnitude;
|
||||
|
||||
gp_XYZ bounds_min_;
|
||||
gp_XYZ bounds_max_;
|
||||
|
||||
std::vector<filter_t> filters_;
|
||||
|
||||
struct filter_match
|
||||
{
|
||||
filter_match(IfcSchema::IfcProduct *prod) : product(prod) {}
|
||||
bool operator()(const filter_t& filter) const { return filter(product); }
|
||||
|
||||
IfcSchema::IfcProduct* product;
|
||||
};
|
||||
|
||||
void initUnits() {
|
||||
IfcSchema::IfcProject::list::ptr projects = ifc_file->entitiesByType<IfcSchema::IfcProject>();
|
||||
if (projects->size() == 1) {
|
||||
IfcSchema::IfcProject* project = *projects->begin();
|
||||
std::pair<std::string, double> length_unit = kernel.initializeUnits(project->UnitsInContext());
|
||||
unit_name = length_unit.first;
|
||||
unit_magnitude = length_unit.second;
|
||||
}
|
||||
}
|
||||
|
||||
/// @todo public/private sections all over the place: move all public to the beginning of the class
|
||||
public:
|
||||
Iterator(const IteratorSettings& settings, IfcParse::IfcFile* file, std::vector<IfcGeom::filter_t>& filters)
|
||||
: settings(settings)
|
||||
, ifc_file(file)
|
||||
, owns_ifc_file(false)
|
||||
, filters_(filters)
|
||||
{
|
||||
_initialize();
|
||||
}
|
||||
|
||||
bool initialize() {
|
||||
try {
|
||||
initUnits();
|
||||
} catch (...) {}
|
||||
|
||||
std::set<std::string> allowed_context_types;
|
||||
allowed_context_types.insert("model");
|
||||
allowed_context_types.insert("plan");
|
||||
allowed_context_types.insert("notdefined");
|
||||
|
||||
std::set<std::string> context_types;
|
||||
if (!settings.get(IteratorSettings::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");
|
||||
// Some earlier (?) versions DDS-CAD output their own ContextTypes
|
||||
context_types.insert("model view");
|
||||
context_types.insert("detail view");
|
||||
}
|
||||
if (settings.get(IteratorSettings::INCLUDE_CURVES)) {
|
||||
context_types.insert("plan");
|
||||
}
|
||||
|
||||
double lowest_precision_encountered = std::numeric_limits<double>::infinity();
|
||||
bool any_precision_encountered = false;
|
||||
|
||||
representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
|
||||
|
||||
IfcSchema::IfcGeometricRepresentationContext::list::it it;
|
||||
IfcSchema::IfcGeometricRepresentationSubContext::list::it jt;
|
||||
IfcSchema::IfcGeometricRepresentationContext::list::ptr contexts =
|
||||
ifc_file->entitiesByType<IfcSchema::IfcGeometricRepresentationContext>();
|
||||
|
||||
IfcSchema::IfcGeometricRepresentationContext::list::ptr filtered_contexts (new IfcSchema::IfcGeometricRepresentationContext::list);
|
||||
|
||||
for (it = contexts->begin(); it != contexts->end(); ++it) {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
if (context->is(IfcSchema::Type::IfcGeometricRepresentationSubContext)) {
|
||||
// Continue, as the list of subcontexts will be considered
|
||||
// by the parent's context inverse attributes.
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
if (context->hasContextType()) {
|
||||
std::string context_type = context->ContextType();
|
||||
boost::to_lower(context_type);
|
||||
|
||||
if (allowed_context_types.find(context_type) == allowed_context_types.end()) {
|
||||
Logger::Message(Logger::LOG_ERROR, std::string("ContextType '") + context->ContextType() + "' not allowed:", context->entity);
|
||||
}
|
||||
if (context_types.find(context_type) != context_types.end()) {
|
||||
filtered_contexts->push(context);
|
||||
}
|
||||
}
|
||||
} 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->is(IfcSchema::Type::IfcGeometricRepresentationSubContext)) {
|
||||
filtered_contexts->push(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (it = filtered_contexts->begin(); it != filtered_contexts->end(); ++it) {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
|
||||
representations->push(context->RepresentationsInContext());
|
||||
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());
|
||||
}
|
||||
// There is no need for full recursion as the following is governed by the schema:
|
||||
// WR31: The parent context shall not be another geometric representation sub context.
|
||||
}
|
||||
|
||||
if (any_precision_encountered) {
|
||||
// Some arbitrary factor that has proven to work better for the models in the set of test files.
|
||||
lowest_precision_encountered *= 10.;
|
||||
|
||||
lowest_precision_encountered *= unit_magnitude;
|
||||
if (lowest_precision_encountered < 1.e-7) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Precision lower than 0.0000001 meter not enforced");
|
||||
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-7);
|
||||
} else {
|
||||
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, lowest_precision_encountered);
|
||||
}
|
||||
} else {
|
||||
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-5);
|
||||
}
|
||||
|
||||
if (representations->size() == 0) {
|
||||
Logger::Message(Logger::LOG_ERROR, "No geometries found");
|
||||
return false;
|
||||
}
|
||||
|
||||
representation_iterator = representations->begin();
|
||||
ifcproducts.reset();
|
||||
|
||||
if (!create()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
done = 0;
|
||||
total = representations->size();
|
||||
|
||||
for (int i = 1; i < 4; ++i) {
|
||||
bounds_min_.SetCoord(i, std::numeric_limits<double>::infinity());
|
||||
bounds_max_.SetCoord(i, -std::numeric_limits<double>::infinity());
|
||||
}
|
||||
|
||||
IfcSchema::IfcProduct::list::ptr products = ifc_file->entitiesByType<IfcSchema::IfcProduct>();
|
||||
for (IfcSchema::IfcProduct::list::it iter = products->begin(); iter != products->end(); ++iter) {
|
||||
IfcSchema::IfcProduct* product = *iter;
|
||||
if (product->hasObjectPlacement()) {
|
||||
// Use a fresh trsf every time in order to prevent the result to be concatenated
|
||||
gp_Trsf trsf;
|
||||
bool success = false;
|
||||
try {
|
||||
success = kernel.convert(product->ObjectPlacement(), trsf);
|
||||
} catch (...) {}
|
||||
if (!success) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const gp_XYZ& pos = trsf.TranslationPart();
|
||||
bounds_min_.SetX(std::min(bounds_min_.X(), pos.X()));
|
||||
bounds_min_.SetY(std::min(bounds_min_.Y(), pos.Y()));
|
||||
bounds_min_.SetZ(std::min(bounds_min_.Z(), pos.Z()));
|
||||
bounds_max_.SetX(std::max(bounds_max_.X(), pos.X()));
|
||||
bounds_max_.SetY(std::max(bounds_max_.Y(), pos.Y()));
|
||||
bounds_max_.SetZ(std::max(bounds_max_.Z(), pos.Z()));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int progress() const { return 100 * done / total; }
|
||||
|
||||
const std::string& getUnitName() const { return unit_name; }
|
||||
|
||||
/// @note Double always as per IFC specification.
|
||||
double getUnitMagnitude() const { return unit_magnitude; }
|
||||
|
||||
std::string getLog() const { return Logger::GetLog(); }
|
||||
|
||||
IfcParse::IfcFile* getFile() const { return ifc_file; }
|
||||
|
||||
const std::vector<IfcGeom::filter_t>& filters() const { return filters_; }
|
||||
std::vector<IfcGeom::filter_t>& filters() { return filters_; }
|
||||
|
||||
const gp_XYZ& bounds_min() const { return bounds_min_; }
|
||||
const gp_XYZ& bounds_max() const { return bounds_max_; }
|
||||
|
||||
private:
|
||||
// Move to the next IfcRepresentation
|
||||
void _nextShape() {
|
||||
// In order to conserve memory and reduce cache insertion times, the cache is
|
||||
// cleared after an arbitary number of processed representations. This has been
|
||||
// benchmarked extensively: https://github.com/IfcOpenShell/IfcOpenShell/pull/47
|
||||
static const int clear_interval = 64;
|
||||
if (done % clear_interval == clear_interval - 1) {
|
||||
kernel.purge_cache();
|
||||
}
|
||||
ifcproducts.reset();
|
||||
++ representation_iterator;
|
||||
++ done;
|
||||
}
|
||||
|
||||
std::set<IfcSchema::IfcRepresentation*> mapped_representations_processed;
|
||||
|
||||
BRepElement<P>* create_shape_model_for_next_entity() {
|
||||
for (;;) {
|
||||
IfcSchema::IfcRepresentation* representation;
|
||||
|
||||
// Have we reached the end of our list of representations?
|
||||
if ( representation_iterator == representations->end() ) {
|
||||
representations.reset();
|
||||
return 0;
|
||||
}
|
||||
representation = *representation_iterator;
|
||||
|
||||
// Has the list of IfcProducts for this representation been initialized?
|
||||
if (!ifcproducts) {
|
||||
|
||||
ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list);
|
||||
IfcSchema::IfcProduct::list::ptr unfiltered_products(new IfcSchema::IfcProduct::list);
|
||||
|
||||
{
|
||||
IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation();
|
||||
|
||||
for (IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it) {
|
||||
if ((*it)->is(IfcSchema::Type::IfcProductDefinitionShape)) {
|
||||
IfcSchema::IfcProductDefinitionShape* pds = (IfcSchema::IfcProductDefinitionShape*)*it;
|
||||
unfiltered_products->push(pds->ShapeOfProduct());
|
||||
}
|
||||
else {
|
||||
// http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm
|
||||
// IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards.
|
||||
// It will be changed into an ABSTRACT supertype in future releases of IFC.
|
||||
|
||||
// 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>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool has_openings = false;
|
||||
bool has_layers = false;
|
||||
|
||||
for (IfcSchema::IfcProduct::list::it it = unfiltered_products->begin(); it != unfiltered_products->end(); ++it) {
|
||||
if (kernel.find_openings(*it)->size()) {
|
||||
has_openings = true;
|
||||
}
|
||||
IfcSchema::IfcRelAssociates::list::ptr associations = (*it)->HasAssociations();
|
||||
for (IfcSchema::IfcRelAssociates::list::it jt = associations->begin(); jt != associations->end(); ++jt) {
|
||||
IfcSchema::IfcRelAssociatesMaterial* assoc = (*jt)->as<IfcSchema::IfcRelAssociatesMaterial>();
|
||||
if (assoc) {
|
||||
if (assoc->RelatingMaterial()->is(IfcSchema::Type::IfcMaterialLayerSetUsage)) {
|
||||
has_layers = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// With world coords enabled, object transformations are directly applied to
|
||||
// the BRep. There is no way to re-use the geometry for multiple products.
|
||||
const bool process_maps_for_current_representation = !settings.get(IteratorSettings::USE_WORLD_COORDS) &&
|
||||
(!has_openings || settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS)) &&
|
||||
(!has_layers || !settings.get(IteratorSettings::APPLY_LAYERSETS));
|
||||
bool representation_processed_as_mapped_item = false;
|
||||
|
||||
IfcSchema::IfcRepresentation* representation_mapped_to = 0;
|
||||
|
||||
if (process_maps_for_current_representation) {
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items = representation->Items();
|
||||
if (items->size() == 1) {
|
||||
IfcSchema::IfcRepresentationItem* item = *items->begin();
|
||||
if (item->is(IfcSchema::Type::IfcMappedItem)) {
|
||||
if (item->StyledByItem()->size() == 0) {
|
||||
IfcSchema::IfcMappedItem* mapped_item = item->as<IfcSchema::IfcMappedItem>();
|
||||
if (kernel.is_identity_transform(mapped_item->MappingTarget())) {
|
||||
IfcSchema::IfcRepresentationMap* map = mapped_item->MappingSource();
|
||||
if (kernel.is_identity_transform(map->MappingOrigin())) {
|
||||
representation_mapped_to = map->MappedRepresentation();
|
||||
IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation_mapped_to->OfProductRepresentation();
|
||||
|
||||
bool all_product_without_openings = true;
|
||||
IfcSchema::IfcProduct::list::ptr products;
|
||||
|
||||
for (IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it) {
|
||||
IfcSchema::IfcProduct::list::ptr products_of_prodrep = (*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>();
|
||||
products->push(products_of_prodrep);
|
||||
for (IfcSchema::IfcProduct::list::it jt = products_of_prodrep->begin(); jt != products_of_prodrep->end(); ++jt) {
|
||||
if (kernel.find_openings(*jt)->size() > 0 && !settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS)) {
|
||||
all_product_without_openings = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (all_product_without_openings) {
|
||||
representation_processed_as_mapped_item = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (representation_mapped_to) {
|
||||
if (mapped_representations_processed.find(representation_mapped_to) != mapped_representations_processed.end()) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
mapped_representations_processed.insert(representation_mapped_to);
|
||||
}
|
||||
|
||||
if (representation_processed_as_mapped_item) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap();
|
||||
|
||||
if (process_maps_for_current_representation && maps->size() == 1) {
|
||||
IfcSchema::IfcRepresentationMap* map = *maps->begin();
|
||||
if (kernel.is_identity_transform(map->MappingOrigin())) {
|
||||
IfcSchema::IfcMappedItem::list::ptr items = map->MapUsage();
|
||||
for (IfcSchema::IfcMappedItem::list::it it = items->begin(); it != items->end(); ++it) {
|
||||
IfcSchema::IfcMappedItem* item = *it;
|
||||
if (item->StyledByItem()->size() != 0) continue;
|
||||
|
||||
if (!kernel.is_identity_transform(item->MappingTarget())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps = item->entity->getInverse(IfcSchema::Type::IfcRepresentation, -1)->as<IfcSchema::IfcRepresentation>();
|
||||
for (IfcSchema::IfcRepresentation::list::it jt = reps->begin(); jt != reps->end(); ++jt) {
|
||||
IfcSchema::IfcRepresentation* rep = *jt;
|
||||
if (rep->Items()->size() != 1) continue;
|
||||
IfcSchema::IfcProductRepresentation::list::ptr prodreps = rep->OfProductRepresentation();
|
||||
for (IfcSchema::IfcProductRepresentation::list::it kt = prodreps->begin(); kt != prodreps->end(); ++kt) {
|
||||
IfcSchema::IfcProduct::list::ptr prods = (*kt)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>();
|
||||
for (IfcSchema::IfcProduct::list::it lt = prods->begin(); lt != prods->end(); ++lt) {
|
||||
if (kernel.find_openings(*lt)->size() == 0 || settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS)) {
|
||||
if (!unfiltered_products->contains(*lt)) {
|
||||
unfiltered_products->push(*lt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter the products based on the set of entities and/or names being included or excluded for processing.
|
||||
for (IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin(); jt != unfiltered_products->end(); ++jt) {
|
||||
IfcSchema::IfcProduct* prod = *jt;
|
||||
if (boost::all(filters_, filter_match(prod))) {
|
||||
ifcproducts->push(prod);
|
||||
}
|
||||
}
|
||||
|
||||
ifcproduct_iterator = ifcproducts->begin();
|
||||
}
|
||||
|
||||
// Have we reached the end of our list of IfcProducts?
|
||||
if ( ifcproduct_iterator == ifcproducts->end() ) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
IfcSchema::IfcProduct* product = *ifcproduct_iterator;
|
||||
|
||||
Logger::SetProduct(product);
|
||||
|
||||
BRepElement<P>* element;
|
||||
if (ifcproduct_iterator == ifcproducts->begin() || !settings.get(IteratorSettings::USE_WORLD_COORDS)) {
|
||||
element = kernel.create_brep_for_representation_and_product<P>(settings, representation, product);
|
||||
} else {
|
||||
element = kernel.create_brep_for_processed_representation(settings, representation, product, current_shape_model);
|
||||
}
|
||||
|
||||
Logger::SetProduct(boost::none);
|
||||
|
||||
if (!element) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
void free_shapes() {
|
||||
// Free all possible representations of the current geometrical entity
|
||||
delete current_triangulation;
|
||||
current_triangulation = 0;
|
||||
delete current_serialization;
|
||||
current_serialization = 0;
|
||||
delete current_shape_model;
|
||||
current_shape_model = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
/// Returns what would be the product for the next shape representation
|
||||
/// @todo Double-check and test the impl.
|
||||
//IfcSchema::IfcProduct* peek_next() const
|
||||
//{
|
||||
// if (ifcproducts && ifcproduct_iterator + 1 != ifcproducts->end()){
|
||||
// return *(ifcproduct_iterator + 1);
|
||||
// } else {
|
||||
// return 0;
|
||||
// }
|
||||
//}
|
||||
|
||||
/// @todo Would this be as simple as the following code?
|
||||
//void skip_next() { if (ifcproducts) { ++ifcproduct_iterator; } }
|
||||
|
||||
/// Moves to the next shape representation, create its geometry, and returns the associated product.
|
||||
/// Use get() to retrieve the created geometry.
|
||||
IfcSchema::IfcProduct* next() {
|
||||
// Increment the iterator over the list of products using the current
|
||||
// shape representation
|
||||
if (ifcproducts) {
|
||||
++ifcproduct_iterator;
|
||||
}
|
||||
|
||||
return create();
|
||||
}
|
||||
|
||||
/// Gets the representation of the current geometrical entity.
|
||||
Element<P>* get()
|
||||
{
|
||||
// TODO: Test settings and throw
|
||||
Element<P>* ret = 0;
|
||||
if (current_triangulation) { ret = current_triangulation; }
|
||||
else if (current_serialization) { ret = current_serialization; }
|
||||
else if (current_shape_model) { ret = current_shape_model; }
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Gets the native (Open Cascade) representation of the current geometrical entity.
|
||||
BRepElement<P>* get_native()
|
||||
{
|
||||
// TODO: Test settings and throw
|
||||
return current_shape_model;
|
||||
}
|
||||
|
||||
const Element<P>* getObject(int id) {
|
||||
|
||||
gp_Trsf trsf;
|
||||
int parent_id = -1;
|
||||
std::string instance_type, product_name, product_guid;
|
||||
IfcSchema::IfcProduct* ifc_product = 0;
|
||||
|
||||
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) ) {
|
||||
ifc_product = (IfcSchema::IfcProduct*)ifc_entity;
|
||||
|
||||
product_guid = ifc_product->GlobalId();
|
||||
product_name = ifc_product->hasName() ? ifc_product->Name() : "";
|
||||
|
||||
parent_id = -1;
|
||||
try {
|
||||
IfcSchema::IfcObjectDefinition* parent_object = kernel.get_decomposing_entity(ifc_product);
|
||||
if (parent_object) {
|
||||
parent_id = parent_object->entity->id();
|
||||
}
|
||||
} catch (...) {}
|
||||
|
||||
try {
|
||||
kernel.convert(ifc_product->ObjectPlacement(), trsf);
|
||||
} catch (...) {}
|
||||
}
|
||||
} 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, ifc_product);
|
||||
|
||||
return ifc_object;
|
||||
}
|
||||
|
||||
IfcSchema::IfcProduct* create() {
|
||||
IfcGeom::BRepElement<P>* next_shape_model = 0;
|
||||
IfcGeom::SerializedElement<P>* next_serialization = 0;
|
||||
IfcGeom::TriangulationElement<P>* next_triangulation = 0;
|
||||
|
||||
try {
|
||||
next_shape_model = create_shape_model_for_next_entity();
|
||||
} catch (...) {}
|
||||
|
||||
if (next_shape_model) {
|
||||
if (settings.get(IteratorSettings::USE_BREP_DATA)) {
|
||||
try {
|
||||
next_serialization = new SerializedElement<P>(*next_shape_model);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Getting a serialized element from model failed.");
|
||||
}
|
||||
} else if (!settings.get(IteratorSettings::DISABLE_TRIANGULATION)) {
|
||||
try {
|
||||
if (ifcproduct_iterator == ifcproducts->begin() || settings.get(IteratorSettings::USE_WORLD_COORDS)) {
|
||||
next_triangulation = new TriangulationElement<P>(*next_shape_model);
|
||||
} else {
|
||||
next_triangulation = new TriangulationElement<P>(*next_shape_model, current_triangulation->geometry_pointer());
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free_shapes();
|
||||
|
||||
current_shape_model = next_shape_model;
|
||||
current_serialization = next_serialization;
|
||||
current_triangulation = next_triangulation;
|
||||
|
||||
return next_shape_model ? next_shape_model->product() : 0;
|
||||
}
|
||||
private:
|
||||
void _initialize() {
|
||||
current_triangulation = 0;
|
||||
current_shape_model = 0;
|
||||
current_serialization = 0;
|
||||
|
||||
unit_name = "METER";
|
||||
unit_magnitude = 1.f;
|
||||
|
||||
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.get(IteratorSettings::SEW_SHELLS) ? 1000 : -1);
|
||||
kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.get(IteratorSettings::INCLUDE_CURVES)
|
||||
? (settings.get(IteratorSettings::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();
|
||||
}
|
||||
Iterator(const IteratorSettings& settings, const std::string& filename)
|
||||
: settings(settings)
|
||||
, ifc_file(new IfcParse::IfcFile)
|
||||
, owns_ifc_file(true)
|
||||
{
|
||||
ifc_file->Init(filename);
|
||||
_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();
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
~Iterator() {
|
||||
if (owns_ifc_file) {
|
||||
delete ifc_file;
|
||||
}
|
||||
|
||||
free_shapes();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,151 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMITERATORSETTINGS_H
|
||||
#define IFCGEOMITERATORSETTINGS_H
|
||||
|
||||
#include "ifc_geom_api.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
|
||||
namespace IfcGeom
|
||||
{
|
||||
class IFC_GEOM_API IteratorSettings
|
||||
{
|
||||
public:
|
||||
/// Enumeration of setting identifiers. These settings define the
|
||||
/// behaviour of various aspects of IfcOpenShell.
|
||||
enum Setting
|
||||
{
|
||||
/// Specifies whether vertices are welded, meaning that the coordinates
|
||||
/// vector will only contain unique xyz-triplets. This results in a
|
||||
/// manifold mesh which is useful for modelling applications, but might
|
||||
/// result in unwanted shading artifacts in rendering applications.
|
||||
WELD_VERTICES = 1,
|
||||
/// Specifies whether to apply the local placements of building elements
|
||||
/// directly to the coordinates of the representation mesh rather than
|
||||
/// to represent the local placement in the 4x3 matrix, which will in that
|
||||
/// case be the identity matrix.
|
||||
USE_WORLD_COORDS = 1 << 1,
|
||||
/// Internally IfcOpenShell measures everything in meters. This settings
|
||||
/// specifies whether to convert IfcGeomObjects back to the units in which
|
||||
/// the geometry in the IFC file is specified.
|
||||
CONVERT_BACK_UNITS = 1 << 2,
|
||||
/// Specifies whether to use the Open Cascade BREP format for representation
|
||||
/// items rather than to create triangle meshes. This is useful is IfcOpenShell
|
||||
/// is used as a library in an application that is also built on Open Cascade.
|
||||
USE_BREP_DATA = 1 << 3,
|
||||
/// Specifies whether to sew IfcConnectedFaceSets (open and closed shells) to
|
||||
/// TopoDS_Shells or whether to keep them as a loose collection of faces.
|
||||
SEW_SHELLS = 1 << 4,
|
||||
/// Specifies whether to compose IfcOpeningElements into a single compound
|
||||
/// in order to speed up the processing of opening subtractions.
|
||||
FASTER_BOOLEANS = 1 << 5,
|
||||
/// Disables the subtraction of IfcOpeningElement representations from
|
||||
/// the related building element representations.
|
||||
DISABLE_OPENING_SUBTRACTIONS = 1 << 6,
|
||||
/// Disables the triangulation of the topological representations. Useful if
|
||||
/// the client application understands Open Cascade's native format.
|
||||
DISABLE_TRIANGULATION = 1 << 7,
|
||||
/// Applies default materials to entity instances without a surface style.
|
||||
APPLY_DEFAULT_MATERIALS = 1 << 8,
|
||||
/// Specifies whether to include subtypes of IfcCurve.
|
||||
INCLUDE_CURVES = 1 << 9,
|
||||
/// Specifies whether to exclude subtypes of IfcSolidModel and IfcSurface.
|
||||
EXCLUDE_SOLIDS_AND_SURFACES = 1 << 10,
|
||||
/// Disables computation of normals. Saves time and file size and is useful
|
||||
/// in instances where you're going to recompute normals for the exported
|
||||
/// model in other modelling application in any case.
|
||||
NO_NORMALS = 1 << 11,
|
||||
/// Generates UVs by using simple box projection. Requires normals.
|
||||
/// Applicable for OBJ and DAE output.
|
||||
GENERATE_UVS = 1 << 12,
|
||||
/// Specifies whether to slice representations according to associated IfcLayerSets.
|
||||
APPLY_LAYERSETS = 1 << 13,
|
||||
/// Number of different setting flags.
|
||||
NUM_SETTINGS = 13
|
||||
};
|
||||
/// Used to store logical OR combination of setting flags.
|
||||
typedef unsigned SettingField;
|
||||
|
||||
IteratorSettings()
|
||||
: settings_(WELD_VERTICES) // OR options that default to true here
|
||||
, deflection_tolerance_(1.e-3)
|
||||
{
|
||||
}
|
||||
|
||||
/// Note that this is independent of the IFC length unit, one millimeter by default.
|
||||
double deflection_tolerance() const { return deflection_tolerance_; }
|
||||
|
||||
void set_deflection_tolerance(double value)
|
||||
{
|
||||
/// @todo Using deflection tolerance of 1e-6 or smaller hangs the conversion, research more in-depth.
|
||||
/// This bug can be reproduced e.g. with the Duplex model that can be found from http://www.nibs.org/?page=bsa_commonbimfiles#project1
|
||||
deflection_tolerance_ = value;
|
||||
if (deflection_tolerance_ <= 1e-6) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Deflection tolerance cannot be set to <= 1e-6; using the default value 1e-3");
|
||||
deflection_tolerance_ = 1e-3;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get boolean value for a single settings or for a combination of settings.
|
||||
bool get(SettingField setting) const
|
||||
{
|
||||
/// @todo If unknown setting value/combination: throw IfcParse::IfcException("Invalid IteratorSetting")?
|
||||
return (settings_ & setting) != 0;
|
||||
}
|
||||
|
||||
/// Set boolean value for a single settings or for a combination of settings.
|
||||
void set(SettingField setting, bool value)
|
||||
{
|
||||
/// @todo If unknown setting value/combination: throw IfcParse::IfcException("Invalid IteratorSetting")?
|
||||
if (value) {
|
||||
settings_ |= setting;
|
||||
} else {
|
||||
settings_ &= ~setting;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
SettingField settings_;
|
||||
double deflection_tolerance_;
|
||||
};
|
||||
|
||||
class IFC_GEOM_API ElementSettings : public IteratorSettings
|
||||
{
|
||||
public:
|
||||
ElementSettings(const IteratorSettings& settings,
|
||||
double unit_magnitude,
|
||||
const std::string& element_type)
|
||||
: IteratorSettings(settings)
|
||||
, unit_magnitude_(unit_magnitude)
|
||||
, element_type_(element_type)
|
||||
{
|
||||
}
|
||||
|
||||
double unit_magnitude() const { return unit_magnitude_; }
|
||||
const std::string& element_type() const { return element_type_; }
|
||||
|
||||
private:
|
||||
double unit_magnitude_;
|
||||
std::string element_type_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,35 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "IfcGeomMaterial.h"
|
||||
|
||||
static double black[3] = {0.,0.,0.};
|
||||
|
||||
IfcGeom::Material::Material(const IfcGeom::SurfaceStyle* style) : style(style) {}
|
||||
bool IfcGeom::Material::hasDiffuse() const { return style->Diffuse() ? true : false; }
|
||||
bool IfcGeom::Material::hasSpecular() const { return style->Specular() ? true : false; }
|
||||
bool IfcGeom::Material::hasTransparency() const { return style->Transparency() ? true : false; }
|
||||
bool IfcGeom::Material::hasSpecularity() const { return style->Specularity() ? true : false; }
|
||||
const double* IfcGeom::Material::diffuse() const { if (hasDiffuse()) return &((*style->Diffuse()).R()); else return black; }
|
||||
const double* IfcGeom::Material::specular() const { if (hasSpecular()) return &((*style->Specular()).R()); else return black; }
|
||||
double IfcGeom::Material::transparency() const { if (hasTransparency()) return *style->Transparency(); else return 0; }
|
||||
double IfcGeom::Material::specularity() const { if (hasSpecularity()) return *style->Specularity(); else return 0; }
|
||||
const std::string &IfcGeom::Material::name() const { return style->Name(); }
|
||||
const std::string &IfcGeom::Material::original_name() const { return style->original_name(); }
|
||||
bool IfcGeom::Material::operator==(const IfcGeom::Material& other) const { return style == other.style; }
|
||||
@@ -1,51 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMMATERIAL_H
|
||||
#define IFCGEOMMATERIAL_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "../ifcgeom/IfcGeomRenderStyles.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
class IFC_GEOM_API Material {
|
||||
private:
|
||||
const IfcGeom::SurfaceStyle* style;
|
||||
public:
|
||||
explicit Material(const IfcGeom::SurfaceStyle* style = 0); // TODO default constructor for vector?
|
||||
// Material(const Material& other);
|
||||
// Material& operator=(const Material& other);
|
||||
bool hasDiffuse() const;
|
||||
bool hasSpecular() const;
|
||||
bool hasTransparency() const;
|
||||
bool hasSpecularity() const;
|
||||
const double* diffuse() const;
|
||||
const double* specular() const;
|
||||
double transparency() const;
|
||||
double specularity() const;
|
||||
const std::string &name() const;
|
||||
const std::string &original_name() const;
|
||||
bool operator==(const Material& other) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,727 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 <stdexcept>
|
||||
#include <limits>
|
||||
|
||||
#include <gp_Mat.hxx>
|
||||
#include <gp_Mat2d.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <gp_GTrsf2d.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
#include <TopoDS_Compound.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <BRepMesh.hxx>
|
||||
#include <Poly_Triangulation.hxx>
|
||||
#include <Poly_PolygonOnTriangulation.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColgp_Array1OfPnt2d.hxx>
|
||||
#include <TShort_Array1OfShortReal.hxx>
|
||||
#include <Poly_Array1OfTriangle.hxx>
|
||||
#include <StdFail_NotDone.hxx>
|
||||
#include <BRepGProp_Face.hxx>
|
||||
#include <BRepBuilderAPI_GTransform.hxx>
|
||||
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
// Welds vertices that belong to different faces
|
||||
static bool weld_vertices = true;
|
||||
|
||||
static bool convert_back_units = false;
|
||||
static bool use_faster_booleans = false;
|
||||
static bool disable_subtractions = false;
|
||||
static bool disable_triangulation = false;
|
||||
|
||||
int IfcGeomObjects::IfcRepresentationTriangulation::addvert(int material_index, const gp_XYZ& p) {
|
||||
const float X = convert_back_units ? (float) (p.X() / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)) : (float)p.X();
|
||||
const float Y = convert_back_units ? (float) (p.Y() / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)) : (float)p.Y();
|
||||
const float Z = convert_back_units ? (float) (p.Z() / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)) : (float)p.Z();
|
||||
int i = (int) _verts.size() / 3;
|
||||
if ( weld_vertices ) {
|
||||
const VertKey key = std::make_pair(material_index, std::make_pair(X, std::make_pair(Y, Z)));
|
||||
VertKeyMap::const_iterator it = welds.find(key);
|
||||
if ( it != welds.end() ) return it->second;
|
||||
i = (int) welds.size();
|
||||
welds[key] = i;
|
||||
}
|
||||
_verts.push_back(X);
|
||||
_verts.push_back(Y);
|
||||
_verts.push_back(Z);
|
||||
return i;
|
||||
}
|
||||
|
||||
static bool use_world_coords = false;
|
||||
static bool use_brep_data = false;
|
||||
|
||||
static IfcParse::IfcFile* ifc_file = 0;
|
||||
|
||||
IfcGeomObjects::IfcRepresentationBrepData::IfcRepresentationBrepData(const IfcRepresentationShapeModel& shapes)
|
||||
: _id(shapes.getId())
|
||||
{
|
||||
try {
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) {
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
gp_GTrsf trsf = it->Placement();
|
||||
if (convert_back_units) {
|
||||
gp_Trsf scale;
|
||||
scale.SetScaleFactor(1.0 / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT));
|
||||
trsf.PreMultiply(scale);
|
||||
}
|
||||
bool trsf_valid = false;
|
||||
gp_Trsf _trsf;
|
||||
try {
|
||||
_trsf = trsf.Trsf();
|
||||
trsf_valid = true;
|
||||
} catch (...) {}
|
||||
const TopoDS_Shape moved_shape = trsf_valid ? s.Moved(_trsf) :
|
||||
BRepBuilderAPI_GTransform(s,trsf,true).Shape();
|
||||
builder.Add(compound,moved_shape);
|
||||
}
|
||||
std::stringstream sstream;
|
||||
BRepTools::Write(compound,sstream);
|
||||
_brep_data = sstream.str();
|
||||
} catch(...) {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to serialize shape:",ifc_file->EntityById(_id)->entity);
|
||||
}
|
||||
}
|
||||
|
||||
IfcGeomObjects::IfcRepresentationTriangulation::IfcRepresentationTriangulation(const IfcRepresentationShapeModel& shapes)
|
||||
: _id(shapes.getId())
|
||||
{
|
||||
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) {
|
||||
|
||||
int surface_style_id = -1;
|
||||
if (it->hasStyle()) {
|
||||
Material adapter(&it->Style());
|
||||
std::vector<Material>::const_iterator jt = std::find(_materials.begin(), _materials.end(), adapter);
|
||||
if (jt == _materials.end()) {
|
||||
surface_style_id = _materials.size();
|
||||
_materials.push_back(adapter);
|
||||
} else {
|
||||
surface_style_id = jt - _materials.begin();
|
||||
}
|
||||
}
|
||||
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
const gp_GTrsf& trsf = it->Placement();
|
||||
|
||||
// Triangulate the shape
|
||||
try {
|
||||
// BRepTools::Clean(s);
|
||||
BRepMesh::Mesh(s, IfcGeom::GetValue(IfcGeom::GV_DEFLECTION_TOLERANCE));
|
||||
} catch(...) {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape:",ifc_file->EntityById(_id)->entity);
|
||||
continue;
|
||||
}
|
||||
TopExp_Explorer exp;
|
||||
|
||||
// Iterates over the faces of the shape
|
||||
for ( exp.Init(s,TopAbs_FACE); exp.More(); exp.Next() ) {
|
||||
TopoDS_Face face = TopoDS::Face(exp.Current());
|
||||
TopLoc_Location loc;
|
||||
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face,loc);
|
||||
|
||||
if ( ! tri.IsNull() ) {
|
||||
|
||||
// A 3x3 matrix to rotate the vertex normals
|
||||
const gp_Mat rotation_matrix = trsf.VectorialPart();
|
||||
|
||||
// Keep track of the number of times an edge is used
|
||||
// Manifold edges (i.e. edges used twice) are deemed invisible
|
||||
std::map<std::pair<int,int>,int> edgecount;
|
||||
std::vector<std::pair<int,int> > edges_temp;
|
||||
|
||||
const TColgp_Array1OfPnt& nodes = tri->Nodes();
|
||||
const TColgp_Array1OfPnt2d& uvs = tri->UVNodes();
|
||||
std::vector<gp_XYZ> coords;
|
||||
BRepGProp_Face prop(face);
|
||||
std::map<int,int> dict;
|
||||
|
||||
// Vertex normals are only calculated if vertices are not welded
|
||||
const bool calculate_normals = ! weld_vertices;
|
||||
|
||||
for( int i = 1; i <= nodes.Length(); ++ i ) {
|
||||
coords.push_back(nodes(i).Transformed(loc).XYZ());
|
||||
trsf.Transforms(*coords.rbegin());
|
||||
dict[i] = addvert(surface_style_id, *coords.rbegin());
|
||||
|
||||
if ( calculate_normals ) {
|
||||
const gp_Pnt2d& uv = uvs(i);
|
||||
gp_Pnt p;
|
||||
gp_Vec normal_direction;
|
||||
prop.Normal(uv.X(),uv.Y(),p,normal_direction);
|
||||
gp_Vec normal(0., 0., 0.);
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
const Poly_Array1OfTriangle& triangles = tri->Triangles();
|
||||
for( int i = 1; i <= triangles.Length(); ++ i ) {
|
||||
int n1,n2,n3;
|
||||
if ( face.Orientation() == TopAbs_REVERSED )
|
||||
triangles(i).Get(n3,n2,n1);
|
||||
else triangles(i).Get(n1,n2,n3);
|
||||
|
||||
/* An alternative would be to calculate normals based
|
||||
* on the coordinates of the mesh vertices */
|
||||
/*
|
||||
const gp_XYZ pt1 = coords[n1-1];
|
||||
const gp_XYZ pt2 = coords[n2-1];
|
||||
const gp_XYZ pt3 = coords[n3-1];
|
||||
const gp_XYZ v1 = pt2-pt1;
|
||||
const gp_XYZ v2 = pt3-pt2;
|
||||
gp_Dir normal = gp_Dir(v1^v2);
|
||||
_normals.push_back((float)normal.X());
|
||||
_normals.push_back((float)normal.Y());
|
||||
_normals.push_back((float)normal.Z());
|
||||
*/
|
||||
|
||||
_faces.push_back(dict[n1]);
|
||||
_faces.push_back(dict[n2]);
|
||||
_faces.push_back(dict[n3]);
|
||||
|
||||
_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);
|
||||
}
|
||||
for ( std::vector<std::pair<int,int> >::const_iterator it = edges_temp.begin(); it != edges_temp.end(); ++it ) {
|
||||
_edges.push_back(edgecount[*it]==1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IfcGeomObjects::IfcObject::IfcObject(
|
||||
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)
|
||||
{
|
||||
// Convert the gp_Trsf into a 4x3 Matrix
|
||||
// Note that in case the CONVERT_BACK_UNITS setting is enabled
|
||||
// the translation component of the matrix needs to be divided
|
||||
// by the magnitude of the IFC model length unit because
|
||||
// internally in IfcOpenShell everything is measured in meters.
|
||||
for(int i = 1; i < 5; ++i) {
|
||||
for (int j = 1; j < 4; ++j) {
|
||||
const double trsf_value = trsf.Value(j,i);
|
||||
const double matrix_value = i == 4 && convert_back_units
|
||||
? trsf_value / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)
|
||||
: trsf_value;
|
||||
_matrix.push_back(static_cast<float>(matrix_value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IfcGeomObjects::IfcGeomShapeModelObject::IfcGeomShapeModelObject(
|
||||
int id,
|
||||
int parent_id,
|
||||
const std::string& name,
|
||||
const std::string& type,
|
||||
const std::string& guid,
|
||||
const gp_Trsf& trsf,
|
||||
IfcRepresentationShapeModel* shapes)
|
||||
: IfcObject(id,parent_id,name,type,guid,trsf)
|
||||
, _mesh(shapes)
|
||||
{}
|
||||
|
||||
IfcGeomObjects::IfcGeomBrepDataObject::IfcGeomBrepDataObject(
|
||||
const IfcGeomShapeModelObject& shape_model)
|
||||
: IfcObject(shape_model)
|
||||
, _mesh(new IfcRepresentationBrepData(shape_model.mesh()))
|
||||
{}
|
||||
|
||||
IfcGeomObjects::IfcGeomObject::IfcGeomObject(
|
||||
const IfcGeomShapeModelObject& shape_model)
|
||||
: IfcObject(shape_model)
|
||||
, _mesh(new IfcRepresentationTriangulation(shape_model.mesh()))
|
||||
{}
|
||||
|
||||
// A container and iterator for IfcShapeRepresentations
|
||||
static IfcSchema::IfcShapeRepresentation::list shapereps;
|
||||
static IfcSchema::IfcShapeRepresentation::it shaperep_iterator;
|
||||
|
||||
// The object is fetched beforehand to be positive an entity actually exists
|
||||
static IfcGeomObjects::IfcGeomObject* current_geom_obj = 0;
|
||||
static IfcGeomObjects::IfcGeomShapeModelObject* current_shape_model_obj = 0;
|
||||
static IfcGeomObjects::IfcGeomBrepDataObject* current_brep_data_obj = 0;
|
||||
|
||||
// A container and iterator for IfcBuildingElements for the current IfcShapeRepresentation referenced by *shaperep_iterator
|
||||
static IfcSchema::IfcProduct::list entities;
|
||||
static IfcSchema::IfcProduct::it ifcproduct_iterator;
|
||||
|
||||
static int done;
|
||||
static int total;
|
||||
|
||||
// Move the the next IfcShapeRepresentation
|
||||
void _nextShape() {
|
||||
entities.reset();
|
||||
++ shaperep_iterator;
|
||||
++ done;
|
||||
}
|
||||
|
||||
int _getParentId(const IfcSchema::IfcProduct::ptr ifc_product) {
|
||||
int parent_id = -1;
|
||||
// In case of an opening element, parent to the RelatingBuildingElement
|
||||
if ( ifc_product->is(IfcSchema::Type::IfcOpeningElement ) ) {
|
||||
IfcSchema::IfcOpeningElement::ptr opening = reinterpret_pointer_cast<IfcSchema::IfcProduct,IfcSchema::IfcOpeningElement>(ifc_product);
|
||||
IfcSchema::IfcRelVoidsElement::list voids = opening->VoidsElements();
|
||||
if ( voids->Size() ) {
|
||||
IfcSchema::IfcRelVoidsElement::ptr ifc_void = *voids->begin();
|
||||
parent_id = ifc_void->RelatingBuildingElement()->entity->id();
|
||||
}
|
||||
} else if ( ifc_product->is(IfcSchema::Type::IfcElement ) ) {
|
||||
IfcSchema::IfcElement::ptr element = reinterpret_pointer_cast<IfcSchema::IfcProduct,IfcSchema::IfcElement>(ifc_product);
|
||||
IfcSchema::IfcRelFillsElement::list fills = element->FillsVoids();
|
||||
// Incase of a RelatedBuildingElement parent to the opening element
|
||||
if ( fills->Size() ) {
|
||||
for ( IfcSchema::IfcRelFillsElement::it it = fills->begin(); it != fills->end(); ++ it ) {
|
||||
IfcSchema::IfcRelFillsElement::ptr fill = *it;
|
||||
IfcSchema::IfcObjectDefinition* ifc_objectdef = fill->RelatingOpeningElement();
|
||||
if ( ifc_product == ifc_objectdef ) continue;
|
||||
parent_id = ifc_objectdef->entity->id();
|
||||
}
|
||||
}
|
||||
// Else simply parent to the containing structure
|
||||
if ( parent_id == -1 ) {
|
||||
IfcSchema::IfcRelContainedInSpatialStructure::list parents = element->ContainedInStructure();
|
||||
if ( parents->Size() ) {
|
||||
IfcSchema::IfcRelContainedInSpatialStructure::ptr parent = *parents->begin();
|
||||
parent_id = parent->RelatingStructure()->entity->id();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Parent decompositions to the RelatingObject
|
||||
if ( parent_id == -1 ) {
|
||||
IfcEntities parents = ifc_product->entity->getInverse(IfcSchema::Type::IfcRelAggregates);
|
||||
parents->push(ifc_product->entity->getInverse(IfcSchema::Type::IfcRelNests));
|
||||
for ( IfcEntityList::it it = parents->begin(); it != parents->end(); ++ it ) {
|
||||
IfcSchema::IfcRelDecomposes::ptr decompose = reinterpret_pointer_cast<IfcUtil::IfcBaseClass,IfcSchema::IfcRelDecomposes>(*it);
|
||||
IfcSchema::IfcObjectDefinition* ifc_objectdef;
|
||||
#ifdef USE_IFC4
|
||||
if (decompose->is(IfcSchema::Type::IfcRelAggregates)) {
|
||||
ifc_objectdef = ((IfcSchema::IfcRelAggregates*)decompose)->RelatingObject();
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
ifc_objectdef = decompose->RelatingObject();
|
||||
#endif
|
||||
if ( ifc_product == ifc_objectdef ) continue;
|
||||
parent_id = ifc_objectdef->entity->id();
|
||||
}
|
||||
}
|
||||
return parent_id;
|
||||
}
|
||||
|
||||
IfcGeomObjects::IfcGeomShapeModelObject* create_shape_model_for_next_entity() {
|
||||
while ( true ) {
|
||||
IfcSchema::IfcShapeRepresentation::ptr shaperep;
|
||||
|
||||
// Have we reached the end of our list of representations?
|
||||
if ( shaperep_iterator == shapereps->end() ) {
|
||||
shapereps.reset();
|
||||
return 0;
|
||||
}
|
||||
shaperep = *shaperep_iterator;
|
||||
|
||||
// Has the list of IfcProducts for this representation been initialized?
|
||||
if ( ! entities ) {
|
||||
if ( shaperep->hasRepresentationIdentifier() ) {
|
||||
const std::string representation_identifier = shaperep->RepresentationIdentifier();
|
||||
if ( shaperep->hasRepresentationType() && representation_identifier == "IAI" && shaperep->RepresentationType() != "BoundingBox" ) {
|
||||
// Allow for Ifc 2x compatibility
|
||||
} else if ( representation_identifier != "Body" &&
|
||||
representation_identifier != "Facetation" ) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
IfcSchema::IfcProductRepresentation::list prodreps = shaperep->OfProductRepresentation();
|
||||
entities = IfcSchema::IfcProduct::list( new IfcTemplatedEntityList<IfcSchema::IfcProduct>() );
|
||||
for ( IfcSchema::IfcProductRepresentation::it it = prodreps->begin(); it != prodreps->end(); ++it ) {
|
||||
if ( (*it)->is(IfcSchema::Type::IfcProductDefinitionShape) ) {
|
||||
IfcSchema::IfcProductDefinitionShape::ptr pds = reinterpret_pointer_cast<IfcSchema::IfcProductRepresentation,IfcSchema::IfcProductDefinitionShape>(*it);
|
||||
entities->push(pds->ShapeOfProduct());
|
||||
} else {
|
||||
// http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm
|
||||
// IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards.
|
||||
// It will be changed into an ABSTRACT supertype in future releases of IFC.
|
||||
|
||||
// IfcProductRepresentation also lacks the INVERSE relation to IfcProduct
|
||||
// Let's find the IfcProducts that reference the IfcProductRepresentation anyway
|
||||
IfcEntities products = (*it)->entity->getInverse(IfcSchema::Type::IfcProduct);
|
||||
for ( IfcEntityList::it it = products->begin(); it != products->end(); ++ it ) {
|
||||
entities->push(reinterpret_pointer_cast<IfcUtil::IfcBaseClass,IfcSchema::IfcProduct>(*it));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Does this representation have any IfcProducts?
|
||||
if ( ! entities->Size() ) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
ifcproduct_iterator = entities->begin();
|
||||
}
|
||||
// Have we reached the end of our list of IfcProducts?
|
||||
if ( ifcproduct_iterator == entities->end() ) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
IfcGeomObjects::IfcRepresentationShapeModel* shape;
|
||||
IfcGeom::IfcRepresentationShapeItems shapes;
|
||||
|
||||
if ( !IfcGeom::convert_shapes(shaperep,shapes) ) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
IfcSchema::IfcProduct::ptr ifc_product = *ifcproduct_iterator;
|
||||
|
||||
int parent_id = -1;
|
||||
try {
|
||||
parent_id = _getParentId(ifc_product);
|
||||
} catch (...) {}
|
||||
|
||||
const std::string name = ifc_product->hasName() ? ifc_product->Name() : "";
|
||||
const std::string guid = ifc_product->GlobalId();
|
||||
|
||||
gp_Trsf trsf;
|
||||
try {
|
||||
IfcGeom::convert(ifc_product->ObjectPlacement(),trsf);
|
||||
} catch (...) {}
|
||||
|
||||
// Does the IfcElement have any IfcOpenings?
|
||||
// Note that openings for IfcOpeningElements are not processed
|
||||
IfcSchema::IfcRelVoidsElement::list openings = IfcSchema::IfcRelVoidsElement::list();
|
||||
if ( ifc_product->is(IfcSchema::Type::IfcElement) && !ifc_product->is(IfcSchema::Type::IfcOpeningElement) ) {
|
||||
IfcSchema::IfcElement::ptr element = reinterpret_pointer_cast<IfcSchema::IfcProduct,IfcSchema::IfcElement>(ifc_product);
|
||||
openings = element->HasOpenings();
|
||||
}
|
||||
// Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements?
|
||||
if ( ifc_product->is(IfcSchema::Type::IfcBuildingElementPart ) ) {
|
||||
IfcSchema::IfcBuildingElementPart::ptr part = reinterpret_pointer_cast<IfcSchema::IfcProduct,IfcSchema::IfcBuildingElementPart>(ifc_product);
|
||||
#ifdef USE_IFC4
|
||||
IfcSchema::IfcRelAggregates::list decomposes = part->Decomposes();
|
||||
for ( IfcSchema::IfcRelAggregates::it it = decomposes->begin(); it != decomposes->end(); ++ it ) {
|
||||
#else
|
||||
IfcSchema::IfcRelDecomposes::list decomposes = part->Decomposes();
|
||||
for ( IfcSchema::IfcRelDecomposes::it it = decomposes->begin(); it != decomposes->end(); ++ it ) {
|
||||
#endif
|
||||
IfcSchema::IfcObjectDefinition::ptr obdef = (*it)->RelatingObject();
|
||||
if ( obdef->is(IfcSchema::Type::IfcElement) ) {
|
||||
IfcSchema::IfcElement::ptr element = reinterpret_pointer_cast<IfcSchema::IfcObjectDefinition,IfcSchema::IfcElement>(obdef);
|
||||
openings->push(element->HasOpenings());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !disable_subtractions && openings && openings->Size() ) {
|
||||
IfcGeom::IfcRepresentationShapeItems opened_shapes;
|
||||
try {
|
||||
if ( use_faster_booleans ) {
|
||||
bool succes = IfcGeom::convert_openings_fast(ifc_product,openings,shapes,trsf,opened_shapes);
|
||||
if ( ! succes ) {
|
||||
opened_shapes.clear();
|
||||
IfcGeom::convert_openings(ifc_product,openings,shapes,trsf,opened_shapes);
|
||||
}
|
||||
} else {
|
||||
IfcGeom::convert_openings(ifc_product,openings,shapes,trsf,opened_shapes);
|
||||
}
|
||||
} catch(...) {
|
||||
Logger::Message(Logger::LOG_ERROR,"Error processing openings for:",ifc_product->entity);
|
||||
}
|
||||
if ( use_world_coords ) {
|
||||
for ( IfcGeom::IfcRepresentationShapeItems::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) {
|
||||
it->prepend(trsf);
|
||||
}
|
||||
trsf = gp_Trsf();
|
||||
}
|
||||
shape = new IfcGeomObjects::IfcRepresentationShapeModel(shaperep->entity->id(),opened_shapes);
|
||||
} else if ( use_world_coords ) {
|
||||
for ( IfcGeom::IfcRepresentationShapeItems::iterator it = shapes.begin(); it != shapes.end(); ++ it ) {
|
||||
it->prepend(trsf);
|
||||
}
|
||||
trsf = gp_Trsf();
|
||||
shape = new IfcGeomObjects::IfcRepresentationShapeModel(shaperep->entity->id(),shapes);
|
||||
} else {
|
||||
shape = new IfcGeomObjects::IfcRepresentationShapeModel(shaperep->entity->id(),shapes);
|
||||
}
|
||||
|
||||
return new IfcGeomObjects::IfcGeomShapeModelObject(ifc_product->entity->id(), parent_id, name,
|
||||
IfcSchema::Type::ToString(ifc_product->type()), guid, trsf, shape);
|
||||
}
|
||||
}
|
||||
|
||||
bool try_and_create_representations_for_current_entity() {
|
||||
current_shape_model_obj = create_shape_model_for_next_entity();
|
||||
if (current_shape_model_obj == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (use_brep_data) {
|
||||
current_brep_data_obj = new IfcGeomObjects::IfcGeomBrepDataObject(*current_shape_model_obj);
|
||||
if (current_brep_data_obj == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!disable_triangulation) {
|
||||
current_geom_obj = new IfcGeomObjects::IfcGeomObject(*current_shape_model_obj);
|
||||
if (current_geom_obj == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeomObjects::Next() {
|
||||
// Free all possible representations of the current geometrical entity
|
||||
delete current_geom_obj;
|
||||
delete current_brep_data_obj;
|
||||
delete current_shape_model_obj;
|
||||
current_geom_obj = 0;
|
||||
current_brep_data_obj = 0;
|
||||
current_shape_model_obj = 0;
|
||||
|
||||
// Increment the iterator over the list of products using the current
|
||||
// shape representation
|
||||
if (entities) {
|
||||
++ifcproduct_iterator;
|
||||
}
|
||||
|
||||
return try_and_create_representations_for_current_entity();
|
||||
}
|
||||
|
||||
static std::vector<IfcGeomObjects::IfcObject*> returned_objects;
|
||||
bool IfcGeomObjects::CleanUp() {
|
||||
// TODO: Correctly implement destructor for IfcFile
|
||||
delete ifc_file;
|
||||
IfcGeom::Cache::Purge();
|
||||
std::vector<IfcGeomObjects::IfcObject*>::const_iterator it;
|
||||
for (it = returned_objects.begin(); it != returned_objects.end(); ++ it ) {
|
||||
delete *it;
|
||||
}
|
||||
returned_objects.clear();
|
||||
return true;
|
||||
}
|
||||
const IfcGeomObjects::IfcObject* IfcGeomObjects::GetObject(int id) {
|
||||
IfcObject* ifc_object = 0;
|
||||
try {
|
||||
const IfcParse::IfcEntity& ifc_entity = ifc_file->EntityById(id);
|
||||
if ( ifc_entity->is(IfcSchema::Type::IfcProduct) ) {
|
||||
IfcSchema::IfcProduct::ptr ifc_product = reinterpret_pointer_cast<IfcUtil::IfcBaseClass,IfcSchema::IfcProduct>(ifc_entity);
|
||||
int parent_id = -1;
|
||||
try {
|
||||
parent_id = _getParentId(ifc_product);
|
||||
} catch (...) {}
|
||||
const std::string name = ifc_product->hasName() ? ifc_product->Name() : "";
|
||||
gp_Trsf trsf;
|
||||
try {
|
||||
IfcGeom::convert(ifc_product->ObjectPlacement(),trsf);
|
||||
} catch (...) {}
|
||||
ifc_object = new IfcObject(ifc_product->entity->id(),parent_id,name,
|
||||
IfcSchema::Type::ToString(ifc_product->type()),ifc_product->GlobalId(),trsf);
|
||||
}
|
||||
} catch(...) {}
|
||||
if ( !ifc_object ) ifc_object = new IfcObject(-1,-1,"","","",gp_Trsf());
|
||||
returned_objects.push_back(ifc_object);
|
||||
return ifc_object;
|
||||
}
|
||||
const IfcGeomObjects::IfcGeomObject* IfcGeomObjects::Get() {
|
||||
if (disable_triangulation) {
|
||||
throw std::runtime_error("No triangulation available");
|
||||
}
|
||||
return current_geom_obj;
|
||||
}
|
||||
const IfcGeomObjects::IfcGeomShapeModelObject* IfcGeomObjects::GetShapeModel() {
|
||||
return current_shape_model_obj;
|
||||
}
|
||||
const IfcGeomObjects::IfcGeomBrepDataObject* IfcGeomObjects::GetBrepData() {
|
||||
if (!use_brep_data) {
|
||||
throw std::runtime_error("No BRep data available");
|
||||
}
|
||||
return current_brep_data_obj;
|
||||
}
|
||||
|
||||
static std::string unit_name = "METER";
|
||||
static float unit_magnitude = 1.0f;
|
||||
|
||||
void IfcGeomObjects::InitUnits() {
|
||||
IfcSchema::IfcProject::list projects = ifc_file->EntitiesByType<IfcSchema::IfcProject>();
|
||||
if (projects->Size() == 1) {
|
||||
double unit_magnitude_double;
|
||||
IfcGeom::initialize_units_and_precision(*projects->begin(), unit_magnitude_double, unit_name);
|
||||
unit_magnitude = static_cast<float>(unit_magnitude_double);
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeomObjects::Init(const std::string fn) {
|
||||
return IfcGeomObjects::Init(fn, 0, 0);
|
||||
}
|
||||
bool _Init() {
|
||||
IfcGeomObjects::InitUnits();
|
||||
|
||||
shapereps = ifc_file->EntitiesByType<IfcSchema::IfcShapeRepresentation>();
|
||||
if ( ! shapereps ) return false;
|
||||
|
||||
shaperep_iterator = shapereps->begin();
|
||||
entities.reset();
|
||||
|
||||
if (!try_and_create_representations_for_current_entity()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
done = 0;
|
||||
total = shapereps->Size();
|
||||
return true;
|
||||
}
|
||||
bool IfcGeomObjects::Init(const std::string fn, std::ostream* log1, std::ostream* log2) {
|
||||
Logger::SetOutput(log1,log2);
|
||||
ifc_file = new IfcParse::IfcFile();
|
||||
if ( !ifc_file->Init(fn) ) return false;
|
||||
return _Init();
|
||||
}
|
||||
bool IfcGeomObjects::Init(std::istream& f, int len, std::ostream* log1, std::ostream* log2) {
|
||||
Logger::SetOutput(log1,log2);
|
||||
ifc_file = new IfcParse::IfcFile();
|
||||
if ( !ifc_file->Init(f, len) ) return false;
|
||||
return _Init();
|
||||
}
|
||||
bool IfcGeomObjects::Init(void* data, int len) {
|
||||
Logger::SetOutput(0,0);
|
||||
ifc_file = new IfcParse::IfcFile();
|
||||
if ( !ifc_file->Init(data, len) ) return false;
|
||||
return _Init();
|
||||
}
|
||||
void IfcGeomObjects::Settings(int setting, bool value) {
|
||||
switch ( setting ) {
|
||||
case USE_WORLD_COORDS:
|
||||
use_world_coords = value;
|
||||
break;
|
||||
case WELD_VERTICES:
|
||||
weld_vertices = value;
|
||||
break;
|
||||
case CONVERT_BACK_UNITS:
|
||||
convert_back_units = value;
|
||||
break;
|
||||
case USE_BREP_DATA:
|
||||
use_brep_data = value;
|
||||
break;
|
||||
case FASTER_BOOLEANS:
|
||||
use_faster_booleans = value;
|
||||
break;
|
||||
case SEW_SHELLS:
|
||||
IfcGeom::SetValue(IfcGeom::GV_MAX_FACES_TO_SEW,value ? 1000 : -1);
|
||||
break;
|
||||
case FORCE_CCW_FACE_ORIENTATION:
|
||||
IfcGeom::SetValue(IfcGeom::GV_FORCE_CCW_FACE_ORIENTATION,value ? 1 : -1);
|
||||
break;
|
||||
case DISABLE_OPENING_SUBTRACTIONS:
|
||||
disable_subtractions = value;
|
||||
break;
|
||||
case DISABLE_TRIANGULATION:
|
||||
disable_triangulation = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int IfcGeomObjects::Progress() {
|
||||
return 100 * done / total;
|
||||
}
|
||||
|
||||
const std::string& IfcGeomObjects::GetUnitName() {
|
||||
return unit_name;
|
||||
}
|
||||
|
||||
const float IfcGeomObjects::GetUnitMagnitude() {
|
||||
return unit_magnitude;
|
||||
}
|
||||
|
||||
const std::string IfcGeomObjects::GetLog() {
|
||||
return Logger::GetLog();
|
||||
}
|
||||
|
||||
IfcParse::IfcFile* IfcGeomObjects::GetFile() {
|
||||
return ifc_file;
|
||||
}
|
||||
|
||||
static double black[3] = {0,0,0};
|
||||
|
||||
IfcGeomObjects::Material::Material(const IfcGeom::SurfaceStyle* style) : style(style) {}
|
||||
bool IfcGeomObjects::Material::hasDiffuse() const { return style->Diffuse(); }
|
||||
bool IfcGeomObjects::Material::hasSpecular() const { return style->Specular(); }
|
||||
bool IfcGeomObjects::Material::hasTransparency() const { return style->Transparency(); }
|
||||
bool IfcGeomObjects::Material::hasSpecularity() const { return style->Specularity(); }
|
||||
const double* IfcGeomObjects::Material::diffuse() const { if (hasDiffuse()) return &((*style->Diffuse()).R()); else return black; }
|
||||
const double* IfcGeomObjects::Material::specular() const { if (hasSpecular()) return &((*style->Specular()).R()); else return black; }
|
||||
double IfcGeomObjects::Material::transparency() const { if (hasTransparency()) return *style->Transparency(); else return 0; }
|
||||
double IfcGeomObjects::Material::specularity() const { if (hasSpecularity()) return *style->Specularity(); else return 0; }
|
||||
const std::string IfcGeomObjects::Material::name() const { return style->Name(); }
|
||||
bool IfcGeomObjects::Material::operator==(const IfcGeomObjects::Material& other) const { return style == other.style; }
|
||||
|
||||
int IfcGeomObjects::IfcRepresentationBrepData::id() const { return _id; }
|
||||
const std::string& IfcGeomObjects::IfcRepresentationBrepData::brep_data() const { return _brep_data; }
|
||||
|
||||
int IfcGeomObjects::IfcRepresentationTriangulation::id() const { return _id; }
|
||||
const std::vector<float>& IfcGeomObjects::IfcRepresentationTriangulation::verts() const { return _verts; }
|
||||
const std::vector<int>& IfcGeomObjects::IfcRepresentationTriangulation::faces() const { return _faces; }
|
||||
const std::vector<int>& IfcGeomObjects::IfcRepresentationTriangulation::edges() const { return _edges; }
|
||||
const std::vector<float>& IfcGeomObjects::IfcRepresentationTriangulation::normals() const { return _normals; }
|
||||
const std::vector<int>& IfcGeomObjects::IfcRepresentationTriangulation::material_ids() const { return _material_ids; }
|
||||
const std::vector<IfcGeomObjects::Material>& IfcGeomObjects::IfcRepresentationTriangulation::materials() const { return _materials; }
|
||||
|
||||
int IfcGeomObjects::IfcObject::id() const { return _id; }
|
||||
int IfcGeomObjects::IfcObject::parent_id() const { return _parent_id; }
|
||||
const std::string& IfcGeomObjects::IfcObject::name() const { return _name; }
|
||||
const std::string& IfcGeomObjects::IfcObject::type() const { return _type; }
|
||||
const std::string& IfcGeomObjects::IfcObject::guid() const { return _guid; }
|
||||
const std::vector<float>& IfcGeomObjects::IfcObject::matrix() const { return _matrix; }
|
||||
|
||||
const IfcGeomObjects::IfcRepresentationShapeModel& IfcGeomObjects::IfcGeomShapeModelObject::mesh() const { return *_mesh; }
|
||||
const IfcGeomObjects::IfcRepresentationTriangulation& IfcGeomObjects::IfcGeomObject::mesh() const { return *_mesh; }
|
||||
const IfcGeomObjects::IfcRepresentationBrepData& IfcGeomObjects::IfcGeomBrepDataObject::mesh() const { return *_mesh; }
|
||||
|
||||
@@ -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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) *
|
||||
* and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). *
|
||||
* *
|
||||
* IfcMesh is a class that represents a triangulated IfcShapeRepresentation. *
|
||||
* IfcMesh.verts is a 1 dimensional vector of float defining the cartesian *
|
||||
* coordinates of the vertices of the triangulated shape in the format of *
|
||||
* [x1,y1,z1,..,xn,yn,zn] *
|
||||
* IfcMesh.faces is a 1 dimensional vector of int containing the indices of *
|
||||
* the triangles referencing positions in IfcMesh.verts *
|
||||
* IfcMesh.edges is a 1 dimensional vector of int in {0,1} that dictates *
|
||||
* the visibility of the edges that span the faces in IfcMesh.faces *
|
||||
* *
|
||||
* IfcGeomObject represents the actual IfcBuildingElements. *
|
||||
* IfcGeomObject.name is the GUID of the element *
|
||||
* IfcGeomObject.type is the datatype of the element e.g. IfcWindow *
|
||||
* IfcGeomObject.mesh is a pointer to an IfcMesh *
|
||||
* IfcGeomObject.matrix is a 4x3 matrix that defines the orientation and *
|
||||
* translation of the mesh in relation to the world origin *
|
||||
* *
|
||||
* Init(char* fn) parses the IFC file in fn, returns true on succes. *
|
||||
* *
|
||||
* Get() returns a pointer to the current IfcGeomObject *
|
||||
* *
|
||||
* Next() returns true if there is an entity yet available *
|
||||
* *
|
||||
* Progress() returns an int in [0..100] that indicates the overall progress *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCOBJECTS_H
|
||||
#define IFCOBJECTS_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <gp_Mat.hxx>
|
||||
#include <gp_Mat2d.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <gp_GTrsf2d.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
|
||||
#include "../ifcparse/IfcParse.h"
|
||||
#include "../ifcgeom/IfcRepresentationShapeItem.h"
|
||||
|
||||
namespace IfcGeomObjects {
|
||||
|
||||
// Enumeration of setting identifiers. These settings define the
|
||||
// behaviour of various aspects of IfcOpenShell.
|
||||
|
||||
// Specifies whether vertices are welded, meaning that the coordinates
|
||||
// vector will only contain unique xyz-triplets. This results in a
|
||||
// manifold mesh which is useful for modelling applications, but might
|
||||
// result in unwanted shading artifacts in rendering applications.
|
||||
const int WELD_VERTICES = 1;
|
||||
// Specifies whether to apply the local placements of building elements
|
||||
// directly to the coordinates of the representation mesh rather than
|
||||
// to represent the local placement in the 4x3 matrix, which will in that
|
||||
// case be the identity matrix.
|
||||
const int USE_WORLD_COORDS = 2;
|
||||
// Internally IfcOpenShell measures everything in meters. This settings
|
||||
// specifies whether to convert IfcGeomObjects back to the units in which
|
||||
// the geometry in the IFC file is specified.
|
||||
const int CONVERT_BACK_UNITS = 3;
|
||||
// Specifies whether to use the Open Cascade BREP format for representation
|
||||
// items rather than to create triangle meshes. This is useful is IfcOpenShell
|
||||
// is used as a library in an application that is also built on Open Cascade.
|
||||
const int USE_BREP_DATA = 4;
|
||||
// Specifies whether to sew IfcConnectedFaceSets (open and closed shells) to
|
||||
// TopoDS_Shells or whether to keep them as a loose collection of faces.
|
||||
const int SEW_SHELLS = 5;
|
||||
// Specifies whether to compose IfcOpeningElements into a single compound
|
||||
// in order to speed up the processing of opening subtractions.
|
||||
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.
|
||||
const int FORCE_CCW_FACE_ORIENTATION = 7;
|
||||
// Disables the subtraction of IfcOpeningElement representations from
|
||||
// the related building element representations.
|
||||
const int DISABLE_OPENING_SUBTRACTIONS = 8;
|
||||
// Disables the triangulation of the topological representations. Useful if
|
||||
// the client application understands Open Cascade's native format.
|
||||
const int DISABLE_TRIANGULATION = 9;
|
||||
|
||||
// End of settings enumeration.
|
||||
|
||||
// A nested pair of floats and a material index to be able to store an XYZ coordinate in a map.
|
||||
// TODO: Make this a std::tuple when compilers add support for that.
|
||||
typedef std::pair<int, std::pair<float,std::pair<float,float> > > VertKey;
|
||||
typedef std::map<VertKey,int> VertKeyMap;
|
||||
typedef std::pair<int,int> Edge;
|
||||
|
||||
class Material {
|
||||
private:
|
||||
const IfcGeom::SurfaceStyle* style;
|
||||
public:
|
||||
explicit Material(const IfcGeom::SurfaceStyle* style);
|
||||
// Material(const Material& other);
|
||||
// Material& operator=(const Material& other);
|
||||
bool hasDiffuse() const;
|
||||
bool hasSpecular() const;
|
||||
bool hasTransparency() const;
|
||||
bool hasSpecularity() const;
|
||||
const double* diffuse() const;
|
||||
const double* specular() const;
|
||||
double transparency() const;
|
||||
double specularity() const;
|
||||
const std::string name() const;
|
||||
bool operator==(const Material& other) const;
|
||||
};
|
||||
|
||||
class IfcRepresentationShapeModel {
|
||||
private:
|
||||
unsigned int id;
|
||||
const IfcGeom::IfcRepresentationShapeItems shapes;
|
||||
IfcRepresentationShapeModel(const IfcRepresentationShapeModel& other);
|
||||
IfcRepresentationShapeModel& operator=(const IfcRepresentationShapeModel& other);
|
||||
public:
|
||||
IfcRepresentationShapeModel(unsigned int id, const IfcGeom::IfcRepresentationShapeItems& shapes)
|
||||
: id(id)
|
||||
, shapes(shapes)
|
||||
{}
|
||||
virtual ~IfcRepresentationShapeModel() {}
|
||||
IfcGeom::IfcRepresentationShapeItems::const_iterator begin() const { return shapes.begin(); }
|
||||
IfcGeom::IfcRepresentationShapeItems::const_iterator end() const { return shapes.end(); }
|
||||
const unsigned int& getId() const { return id; }
|
||||
};
|
||||
|
||||
class IfcRepresentationBrepData {
|
||||
private:
|
||||
int _id;
|
||||
std::string _brep_data;
|
||||
public:
|
||||
int id() const;
|
||||
const std::string& brep_data() const;
|
||||
IfcRepresentationBrepData(const IfcRepresentationShapeModel& s);
|
||||
virtual ~IfcRepresentationBrepData() {}
|
||||
private:
|
||||
IfcRepresentationBrepData();
|
||||
IfcRepresentationBrepData(const IfcRepresentationBrepData&);
|
||||
IfcRepresentationBrepData& operator=(const IfcRepresentationBrepData&);
|
||||
};
|
||||
|
||||
class IfcRepresentationTriangulation {
|
||||
private:
|
||||
int _id;
|
||||
std::vector<float> _verts;
|
||||
std::vector<int> _faces;
|
||||
std::vector<int> _edges;
|
||||
std::vector<float> _normals;
|
||||
std::vector<int> _material_ids;
|
||||
std::vector<Material> _materials;
|
||||
VertKeyMap welds;
|
||||
public:
|
||||
int id() const;
|
||||
const std::vector<float>& verts() const;
|
||||
const std::vector<int>& faces() const;
|
||||
const std::vector<int>& edges() const;
|
||||
const std::vector<float>& normals() const;
|
||||
const std::vector<int>& material_ids() const;
|
||||
const std::vector<Material>& materials() const;
|
||||
IfcRepresentationTriangulation(const IfcRepresentationShapeModel& s);
|
||||
virtual ~IfcRepresentationTriangulation() {}
|
||||
private:
|
||||
int addvert(int material_index, const gp_XYZ& p);
|
||||
inline void addedge(int n1, int n2, std::map<std::pair<int,int>,int>& edgecount, std::vector<std::pair<int,int> >& edges_temp) {
|
||||
const Edge e = Edge( (std::min)(n1,n2),(std::max)(n1,n2) );
|
||||
if ( edgecount.find(e) == edgecount.end() ) edgecount[e] = 1;
|
||||
else edgecount[e] ++;
|
||||
edges_temp.push_back(e);
|
||||
}
|
||||
IfcRepresentationTriangulation();
|
||||
IfcRepresentationTriangulation(const IfcRepresentationTriangulation&);
|
||||
IfcRepresentationTriangulation& operator=(const IfcRepresentationTriangulation&);
|
||||
};
|
||||
|
||||
class IfcObject {
|
||||
private:
|
||||
int _id;
|
||||
int _parent_id;
|
||||
std::string _name;
|
||||
std::string _type;
|
||||
std::string _guid;
|
||||
std::vector<float> _matrix;
|
||||
public:
|
||||
int id() const;
|
||||
int parent_id() const;
|
||||
const std::string& name() const;
|
||||
const std::string& type() const;
|
||||
const std::string& guid() const;
|
||||
const std::vector<float>& matrix() const;
|
||||
IfcObject(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf);
|
||||
virtual ~IfcObject() {}
|
||||
};
|
||||
|
||||
class IfcGeomShapeModelObject : public IfcObject {
|
||||
private:
|
||||
IfcRepresentationShapeModel* _mesh;
|
||||
public:
|
||||
const IfcRepresentationShapeModel& mesh() const;
|
||||
IfcGeomShapeModelObject(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf, IfcRepresentationShapeModel* mesh);
|
||||
virtual ~IfcGeomShapeModelObject() {
|
||||
delete _mesh;
|
||||
}
|
||||
private:
|
||||
IfcGeomShapeModelObject(const IfcGeomShapeModelObject& other);
|
||||
IfcGeomShapeModelObject& operator=(const IfcGeomShapeModelObject& other);
|
||||
};
|
||||
|
||||
class IfcGeomObject : public IfcObject {
|
||||
private:
|
||||
IfcRepresentationTriangulation* _mesh;
|
||||
public:
|
||||
const IfcRepresentationTriangulation& mesh() const;
|
||||
IfcGeomObject(const IfcGeomShapeModelObject& shape_model);
|
||||
virtual ~IfcGeomObject() {
|
||||
delete _mesh;
|
||||
}
|
||||
private:
|
||||
IfcGeomObject(const IfcGeomObject& other);
|
||||
IfcGeomObject& operator=(const IfcGeomObject& other);
|
||||
};
|
||||
|
||||
class IfcGeomBrepDataObject : public IfcObject {
|
||||
private:
|
||||
IfcRepresentationBrepData* _mesh;
|
||||
public:
|
||||
const IfcRepresentationBrepData& mesh() const;
|
||||
IfcGeomBrepDataObject(const IfcGeomShapeModelObject& shape_model);
|
||||
virtual ~IfcGeomBrepDataObject() {
|
||||
delete _mesh;
|
||||
}
|
||||
private:
|
||||
IfcGeomBrepDataObject(const IfcGeomBrepDataObject& other);
|
||||
IfcGeomBrepDataObject& operator=(const IfcGeomBrepDataObject& other);
|
||||
};
|
||||
|
||||
bool Init(const std::string fn);
|
||||
bool Init(void* data, int len);
|
||||
bool Init(const std::string fn, std::ostream* log1= 0, std::ostream* log2= 0);
|
||||
bool Init(std::istream& f, int len, std::ostream* log1= 0, std::ostream* log2= 0);
|
||||
|
||||
void Settings(int setting, bool value);
|
||||
void InitUnits();
|
||||
void InitPrecision();
|
||||
|
||||
const IfcGeomObject* Get();
|
||||
const IfcObject* GetObject(int id);
|
||||
const IfcGeomBrepDataObject* GetBrepData();
|
||||
const IfcGeomShapeModelObject* GetShapeModel();
|
||||
|
||||
bool Next();
|
||||
int Progress();
|
||||
|
||||
const std::string& GetUnitName();
|
||||
const float GetUnitMagnitude();
|
||||
|
||||
const std::string GetLog();
|
||||
IfcParse::IfcFile* GetFile();
|
||||
|
||||
bool CleanUp();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -19,9 +19,18 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "IfcGeom.h"
|
||||
#include "IfcGeomRenderStyles.h"
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourRgb* colour, double* rgb) {
|
||||
namespace IfcGeom {
|
||||
namespace Cache {
|
||||
std::map<int,SurfaceStyle> Style;
|
||||
void PurgeStyleCache() {
|
||||
Style.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourRgb* colour, std::tr1::array<double, 3>& rgb) {
|
||||
if (colour != 0) {
|
||||
rgb[0] = colour->Red();
|
||||
rgb[1] = colour->Green();
|
||||
@@ -30,33 +39,34 @@ bool process_colour(IfcSchema::IfcColourRgb* colour, double* rgb) {
|
||||
return colour != 0;
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, double* rgb) {
|
||||
bool process_colour(IfcUtil::IfcBaseEntity* factor, std::tr1::array<double, 3>& rgb) {
|
||||
if (factor != 0) {
|
||||
const double f = *factor;
|
||||
const double f = *factor->entity->getArgument(0);
|
||||
rgb[0] = rgb[1] = rgb[2] = f;
|
||||
}
|
||||
return factor != 0;
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, double* rgb) {
|
||||
bool process_colour(IfcSchema::IfcColourOrFactor colour_or_factor, std::tr1::array<double, 3>& rgb) {
|
||||
if (colour_or_factor == 0) {
|
||||
return false;
|
||||
} else if (colour_or_factor->is(IfcSchema::Type::IfcColourRgb)) {
|
||||
return process_colour(static_cast<IfcSchema::IfcColourRgb*>(colour_or_factor), rgb);
|
||||
} else if (colour_or_factor->is(IfcSchema::Type::IfcNormalisedRatioMeasure)) {
|
||||
return process_colour(static_cast<IfcSchema::IfcNormalisedRatioMeasure*>(colour_or_factor), rgb);
|
||||
return process_colour(static_cast<IfcUtil::IfcBaseEntity*>(colour_or_factor), rgb);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::internalize_surface_style(const std::pair<IfcSchema::IfcSurfaceStyle*, IfcSchema::IfcSurfaceStyleShading*>& shading_styles) {
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::get_style(IfcSchema::IfcRepresentationItem* item) {
|
||||
std::pair<IfcSchema::IfcSurfaceStyle*, IfcSchema::IfcSurfaceStyleShading*> shading_styles = get_surface_style<IfcSchema::IfcSurfaceStyleShading>(item);
|
||||
if (shading_styles.second == 0) {
|
||||
return 0;
|
||||
}
|
||||
int surface_style_id = shading_styles.first->entity->id();
|
||||
std::map<int,SurfaceStyle>::const_iterator it = style_cache.find(surface_style_id);
|
||||
if (it != style_cache.end()) {
|
||||
std::map<int,SurfaceStyle>::const_iterator it = Cache::Style.find(surface_style_id);
|
||||
if (it != Cache::Style.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
SurfaceStyle surface_style;
|
||||
@@ -65,7 +75,7 @@ const IfcGeom::SurfaceStyle* IfcGeom::Kernel::internalize_surface_style(const st
|
||||
} else {
|
||||
surface_style = SurfaceStyle(surface_style_id);
|
||||
}
|
||||
double rgb[3];
|
||||
std::tr1::array<double, 3> rgb;
|
||||
if (process_colour(shading_styles.second->SurfaceColour(), rgb)) {
|
||||
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
|
||||
}
|
||||
@@ -85,15 +95,7 @@ const IfcGeom::SurfaceStyle* IfcGeom::Kernel::internalize_surface_style(const st
|
||||
surface_style.Specular().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
|
||||
}
|
||||
if (rendering_style->hasSpecularHighlight()) {
|
||||
IfcSchema::IfcSpecularHighlightSelect* highlight = rendering_style->SpecularHighlight();
|
||||
if (highlight->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)) {
|
||||
surface_style.Specularity().reset(*((IfcSchema::IfcSpecularExponent*)highlight));
|
||||
}
|
||||
// Not supported
|
||||
}
|
||||
if (rendering_style->hasTransmissionColour()) {
|
||||
// Not supported
|
||||
@@ -103,29 +105,7 @@ const IfcGeom::SurfaceStyle* IfcGeom::Kernel::internalize_surface_style(const st
|
||||
surface_style.Transparency().reset(d);
|
||||
}
|
||||
}
|
||||
return &(style_cache[surface_style_id] = surface_style);
|
||||
}
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepresentationItem* item) {
|
||||
return internalize_surface_style(get_surface_style<IfcSchema::IfcSurfaceStyleShading>(item));
|
||||
}
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcMaterial* material) {
|
||||
IfcSchema::IfcMaterialDefinitionRepresentation::list::ptr defs = material->HasRepresentation();
|
||||
for (IfcSchema::IfcMaterialDefinitionRepresentation::list::it jt = defs->begin(); jt != defs->end(); ++jt) {
|
||||
IfcSchema::IfcRepresentation::list::ptr reps = (*jt)->Representations();
|
||||
IfcSchema::IfcStyledItem::list::ptr styles(new IfcSchema::IfcStyledItem::list);
|
||||
for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) {
|
||||
styles->push((**it).Items()->as<IfcSchema::IfcStyledItem>());
|
||||
}
|
||||
for (IfcSchema::IfcStyledItem::list::it it = styles->begin(); it != styles->end(); ++it) {
|
||||
const std::pair<IfcSchema::IfcSurfaceStyle*, IfcSchema::IfcSurfaceStyleShading*> ss = get_surface_style<IfcSchema::IfcSurfaceStyleShading>(*it);
|
||||
if (ss.second) {
|
||||
return internalize_surface_style(ss);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return &(Cache::Style[surface_style_id] = surface_style);
|
||||
}
|
||||
|
||||
static std::map<std::string, IfcGeom::SurfaceStyle> default_materials;
|
||||
@@ -173,11 +153,9 @@ void InitDefaultMaterials() {
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::get_default_style(const std::string& s) {
|
||||
if (!default_materials_initialized) InitDefaultMaterials();
|
||||
std::map<std::string, IfcGeom::SurfaceStyle>::const_iterator it = default_materials.find(s);
|
||||
if (it == default_materials.end()) {
|
||||
default_materials.insert(std::make_pair(s, IfcGeom::SurfaceStyle(s)));
|
||||
default_materials[s].Diffuse().reset(*default_material.Diffuse());
|
||||
it = default_materials.find(s);
|
||||
if (it == default_materials.end()) return &default_material;
|
||||
else {
|
||||
const IfcGeom::SurfaceStyle& surface_style = it->second;
|
||||
return &surface_style;
|
||||
}
|
||||
const IfcGeom::SurfaceStyle& surface_style = it->second;
|
||||
return &surface_style;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,12 @@
|
||||
#ifndef IFCGEOMRENDERSTYLES_H
|
||||
#define IFCGEOMRENDERSTYLES_H
|
||||
|
||||
#include "ifc_geom_api.h"
|
||||
#ifdef __GNUC__
|
||||
#include <tr1/array>
|
||||
#else
|
||||
#include <array>
|
||||
#endif
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include "../ifcparse/Ifc4.h"
|
||||
#else
|
||||
@@ -28,11 +33,11 @@
|
||||
#endif
|
||||
|
||||
namespace IfcGeom {
|
||||
class IFC_GEOM_API SurfaceStyle {
|
||||
class SurfaceStyle {
|
||||
public:
|
||||
class ColorComponent {
|
||||
private:
|
||||
double data[3];
|
||||
std::tr1::array<double, 3> data;
|
||||
public:
|
||||
ColorComponent(double r, double g, double b) {
|
||||
data[0] = r; data[1] = g; data[2] = b;
|
||||
@@ -45,43 +50,46 @@ namespace IfcGeom {
|
||||
double& B() { return data[2]; }
|
||||
};
|
||||
private:
|
||||
std::string name;
|
||||
std::string original_name_;
|
||||
boost::optional<std::string> name;
|
||||
boost::optional<int> id;
|
||||
boost::optional<ColorComponent> diffuse, specular;
|
||||
boost::optional<double> transparency;
|
||||
boost::optional<double> specularity;
|
||||
public:
|
||||
SurfaceStyle() : name("surface-style") {}
|
||||
SurfaceStyle(int id) : id(id) {
|
||||
std::stringstream sstr;
|
||||
sstr << "surface-style-" << id;
|
||||
this->name = sstr.str();
|
||||
}
|
||||
SurfaceStyle(const std::string& name) : name(name), original_name_(name) {}
|
||||
SurfaceStyle(int id, const std::string& name) : original_name_(name), id(id)
|
||||
{
|
||||
std::stringstream sstr;
|
||||
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();
|
||||
}
|
||||
SurfaceStyle() {}
|
||||
SurfaceStyle(int id) : id(id) {}
|
||||
SurfaceStyle(const std::string& name) : name(name) {}
|
||||
SurfaceStyle(int id, const std::string& name) : id(id), name(name) {}
|
||||
|
||||
// Not used at this point. In fact, equality testing in the current
|
||||
// architecture can just as easily be accomplished by comparing the
|
||||
// pointer addresses of the styles, as they are always referenced
|
||||
// from out of a global map of some sort.
|
||||
bool operator==(const SurfaceStyle& other) {
|
||||
return name == other.name;
|
||||
if (name && other.name) {
|
||||
return *name == *other.name;
|
||||
} else if (id && other.id) {
|
||||
return *id == *other.id;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// ID name, e.g. "surface-style-66675-metal---aluminium"
|
||||
const std::string& Name() const { return name; }
|
||||
|
||||
/// Original name, if available, e.g. "Metal - Aluminium"
|
||||
const std::string& original_name() const { return original_name_; }
|
||||
const std::string Name() const {
|
||||
if (name && id) {
|
||||
std::stringstream sstr;
|
||||
sstr << (*id) << "_" << (*name);
|
||||
return sstr.str();
|
||||
} else if (name) {
|
||||
return *name;
|
||||
} else if (id) {
|
||||
std::stringstream sstr;
|
||||
sstr << "IfcSurfaceStyleShading_" << (*id);
|
||||
return sstr.str();
|
||||
} else {
|
||||
return "IfcSurfaceStyleShading";
|
||||
}
|
||||
}
|
||||
|
||||
const boost::optional<ColorComponent>& Diffuse() const { return diffuse; }
|
||||
const boost::optional<ColorComponent>& Specular() const { return specular; }
|
||||
@@ -93,7 +101,52 @@ namespace IfcGeom {
|
||||
boost::optional<double>& Specularity() { return specularity; }
|
||||
};
|
||||
|
||||
IFC_GEOM_API const SurfaceStyle* get_default_style(const std::string& ifc_type);
|
||||
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> get_surface_style(IfcSchema::IfcRepresentationItem* representation_item) {
|
||||
IfcSchema::IfcStyledItem::list styled_items = representation_item->StyledByItem();
|
||||
for (IfcSchema::IfcStyledItem::it jt = styled_items->begin(); jt != styled_items->end(); ++jt) {
|
||||
#ifdef USE_IFC4
|
||||
IfcUtil::IfcAbstractSelect::list style_assignments = (*jt)->Styles();
|
||||
for (IfcUtil::IfcAbstractSelect::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
if (!(*kt)->is(IfcSchema::Type::IfcPresentationStyleAssignment)) {
|
||||
continue;
|
||||
}
|
||||
IfcSchema::IfcPresentationStyleAssignment::ptr style_assignment = (IfcSchema::IfcPresentationStyleAssignment::ptr) *kt;
|
||||
#else
|
||||
IfcSchema::IfcPresentationStyleAssignment::list style_assignments = (*jt)->Styles();
|
||||
for (IfcSchema::IfcPresentationStyleAssignment::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
IfcSchema::IfcPresentationStyleAssignment::ptr style_assignment = *kt;
|
||||
#endif
|
||||
IfcUtil::IfcAbstractSelect::list styles = style_assignment->Styles();
|
||||
for (IfcUtil::IfcAbstractSelect::it lt = styles->begin(); lt != styles->end(); ++lt) {
|
||||
IfcUtil::IfcAbstractSelect::ptr style = *lt;
|
||||
if (style->is(IfcSchema::Type::IfcSurfaceStyle)) {
|
||||
IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style;
|
||||
if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) {
|
||||
IfcUtil::IfcAbstractSelect::list styles_elements = surface_style->Styles();
|
||||
for (IfcUtil::IfcAbstractSelect::it mt = styles_elements->begin(); mt != styles_elements->end(); ++mt) {
|
||||
if ((*mt)->is(T::Class())) {
|
||||
return std::make_pair(surface_style, (T*) *mt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// StyledByItem is a SET [0:1] OF IfcStyledItem, so we
|
||||
// break after encountering the first IfcStyledItem
|
||||
break;
|
||||
}
|
||||
|
||||
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0,0);
|
||||
}
|
||||
|
||||
const SurfaceStyle* get_style(IfcSchema::IfcRepresentationItem* representation_item);
|
||||
const SurfaceStyle* get_default_style(const std::string& ifc_type);
|
||||
|
||||
namespace Cache {
|
||||
void PurgeStyleCache();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,70 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
|
||||
#include <TopoDS_Compound.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
#include "IfcGeomRepresentation.h"
|
||||
|
||||
IfcGeom::Representation::Serialization::Serialization(const BRep& brep)
|
||||
: Representation(brep.settings())
|
||||
, _id(brep.getId())
|
||||
{
|
||||
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 (it->hasStyle() && it->Style().Diffuse()) {
|
||||
const IfcGeom::SurfaceStyle::ColorComponent& clr = *it->Style().Diffuse();
|
||||
_surface_styles.push_back(clr.R());
|
||||
_surface_styles.push_back(clr.G());
|
||||
_surface_styles.push_back(clr.B());
|
||||
} else {
|
||||
_surface_styles.push_back(-1.);
|
||||
_surface_styles.push_back(-1.);
|
||||
_surface_styles.push_back(-1.);
|
||||
}
|
||||
if (it->hasStyle() && it->Style().Transparency()) {
|
||||
_surface_styles.push_back(1. - *it->Style().Transparency());
|
||||
} else {
|
||||
_surface_styles.push_back(1.);
|
||||
}
|
||||
|
||||
if (settings().get(IteratorSettings::CONVERT_BACK_UNITS)) {
|
||||
gp_Trsf scale;
|
||||
scale.SetScaleFactor(1.0 / settings().unit_magnitude());
|
||||
trsf.PreMultiply(scale);
|
||||
}
|
||||
|
||||
const TopoDS_Shape moved_shape = IfcGeom::Kernel::apply_transformation(s, trsf);
|
||||
|
||||
builder.Add(compound, moved_shape);
|
||||
}
|
||||
std::stringstream sstream;
|
||||
BRepTools::Write(compound,sstream);
|
||||
_brep_data = sstream.str();
|
||||
}
|
||||
@@ -1,410 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMREPRESENTATION_H
|
||||
#define IFCGEOMREPRESENTATION_H
|
||||
|
||||
#include <BRepMesh_IncrementalMesh.hxx>
|
||||
#include <BRepGProp_Face.hxx>
|
||||
|
||||
#include <Poly_Triangulation.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColgp_Array1OfPnt2d.hxx>
|
||||
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <GCPnts_QuasiUniformDeflection.hxx>
|
||||
#include <Geom_SphericalSurface.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
#include "../ifcgeom/IfcGeomMaterial.h"
|
||||
#include "../ifcgeom/IfcRepresentationShapeItem.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
namespace Representation {
|
||||
|
||||
class IFC_GEOM_API Representation {
|
||||
Representation(const Representation&); //N/A
|
||||
Representation& operator =(const Representation&); //N/A
|
||||
protected:
|
||||
const ElementSettings _settings;
|
||||
public:
|
||||
explicit Representation(const ElementSettings& settings)
|
||||
: _settings(settings)
|
||||
{}
|
||||
const ElementSettings& settings() const { return _settings; }
|
||||
virtual ~Representation() {}
|
||||
};
|
||||
|
||||
class IFC_GEOM_API BRep : public Representation {
|
||||
private:
|
||||
unsigned int id;
|
||||
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)
|
||||
{}
|
||||
virtual ~BRep() {}
|
||||
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; }
|
||||
};
|
||||
|
||||
class IFC_GEOM_API Serialization : public Representation {
|
||||
private:
|
||||
int _id;
|
||||
std::string _brep_data;
|
||||
std::vector<double> _surface_styles;
|
||||
public:
|
||||
int id() const { return _id; }
|
||||
const std::string& brep_data() const { return _brep_data; }
|
||||
const std::vector<double>& surface_styles() const { return _surface_styles; }
|
||||
Serialization(const BRep& brep);
|
||||
virtual ~Serialization() {}
|
||||
private:
|
||||
Serialization();
|
||||
Serialization(const Serialization&);
|
||||
Serialization& operator=(const Serialization&);
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
class Triangulation : public Representation {
|
||||
private:
|
||||
// A nested pair of floats and a material index to be able to store an XYZ coordinate in a map.
|
||||
// TODO: Make this a std::tuple when compilers add support for that.
|
||||
typedef typename std::pair<P, std::pair<P, P> > Coordinate;
|
||||
typedef typename std::pair<int, Coordinate> VertexKey;
|
||||
typedef std::map<VertexKey, int> VertexKeyMap;
|
||||
typedef std::pair<int, int> Edge;
|
||||
|
||||
int _id;
|
||||
std::vector<P> _verts;
|
||||
std::vector<int> _faces;
|
||||
std::vector<int> _edges;
|
||||
std::vector<P> _normals;
|
||||
std::vector<P> uvs_;
|
||||
std::vector<int> _material_ids;
|
||||
std::vector<Material> _materials;
|
||||
VertexKeyMap welds;
|
||||
|
||||
public:
|
||||
int id() const { return _id; }
|
||||
const std::vector<P>& verts() const { return _verts; }
|
||||
const std::vector<int>& faces() const { return _faces; }
|
||||
const std::vector<int>& edges() const { return _edges; }
|
||||
const std::vector<P>& normals() const { return _normals; }
|
||||
const std::vector<P>& uvs() const { return uvs_; }
|
||||
const std::vector<int>& material_ids() const { return _material_ids; }
|
||||
const std::vector<Material>& materials() const { return _materials; }
|
||||
|
||||
Triangulation(const BRep& shape_model)
|
||||
: Representation(shape_model.settings())
|
||||
, _id(shape_model.getId())
|
||||
{
|
||||
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++ iit ) {
|
||||
|
||||
int surface_style_id = -1;
|
||||
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 = (int)_materials.size();
|
||||
_materials.push_back(adapter);
|
||||
} else {
|
||||
surface_style_id = (int)(jt - _materials.begin());
|
||||
}
|
||||
}
|
||||
|
||||
if (settings().get(IteratorSettings::APPLY_DEFAULT_MATERIALS) && surface_style_id == -1) {
|
||||
Material material(IfcGeom::get_default_style(settings().element_type()));
|
||||
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 = (int)(mit - _materials.begin());
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Iterates over the faces of the shape
|
||||
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);
|
||||
|
||||
if ( ! tri.IsNull() ) {
|
||||
|
||||
// A 3x3 matrix to rotate the vertex normals
|
||||
const gp_Mat rotation_matrix = trsf.VectorialPart();
|
||||
|
||||
// Keep track of the number of times an edge is used
|
||||
// Manifold edges (i.e. edges used twice) are deemed invisible
|
||||
std::map<std::pair<int,int>,int> edgecount;
|
||||
std::vector<std::pair<int,int> > edges_temp;
|
||||
|
||||
const TColgp_Array1OfPnt& nodes = tri->Nodes();
|
||||
const TColgp_Array1OfPnt2d& uvs = tri->UVNodes();
|
||||
std::vector<gp_XYZ> coords;
|
||||
BRepGProp_Face prop(face);
|
||||
std::map<int,int> dict;
|
||||
|
||||
// Vertex normals are only calculated if vertices are not welded and calculation is not disable explicitly.
|
||||
const bool calculate_normals = !settings().get(IteratorSettings::WELD_VERTICES) &&
|
||||
!settings().get(IteratorSettings::NO_NORMALS);
|
||||
|
||||
for( int i = 1; i <= nodes.Length(); ++ i ) {
|
||||
coords.push_back(nodes(i).Transformed(loc).XYZ());
|
||||
trsf.Transforms(*coords.rbegin());
|
||||
dict[i] = addVertex(surface_style_id, *coords.rbegin());
|
||||
|
||||
if ( calculate_normals ) {
|
||||
const gp_Pnt2d& uv = uvs(i);
|
||||
gp_Pnt p;
|
||||
gp_Vec normal_direction;
|
||||
prop.Normal(uv.X(),uv.Y(),p,normal_direction);
|
||||
gp_Vec normal(0., 0., 0.);
|
||||
if (normal_direction.Magnitude() > ALMOST_ZERO) {
|
||||
normal = gp_Dir(normal_direction.XYZ() * rotation_matrix);
|
||||
} else {
|
||||
Handle_Geom_Surface surf = BRep_Tool::Surface(face);
|
||||
// Special case the normal at the poles of a spherical surface
|
||||
if (surf->DynamicType() == STANDARD_TYPE(Geom_SphericalSurface)) {
|
||||
if (ALMOST_THE_SAME(fabs(uv.Y()), M_PI / 2.)) {
|
||||
const bool is_top = uv.Y() > 0;
|
||||
const bool is_forward = face.Orientation() == TopAbs_FORWARD;
|
||||
const double z = (is_top == is_forward) ? 1. : -1.;
|
||||
normal = gp_Dir(gp_XYZ(0, 0, z) * rotation_matrix);
|
||||
}
|
||||
}
|
||||
// TODO: Do the same for conical surfaces, but they are rare in IFC.
|
||||
}
|
||||
_normals.push_back(static_cast<P>(normal.X()));
|
||||
_normals.push_back(static_cast<P>(normal.Y()));
|
||||
_normals.push_back(static_cast<P>(normal.Z()));
|
||||
}
|
||||
}
|
||||
|
||||
const Poly_Array1OfTriangle& triangles = tri->Triangles();
|
||||
for( int i = 1; i <= triangles.Length(); ++ i ) {
|
||||
int n1,n2,n3;
|
||||
if ( face.Orientation() == TopAbs_REVERSED )
|
||||
triangles(i).Get(n3,n2,n1);
|
||||
else triangles(i).Get(n1,n2,n3);
|
||||
|
||||
/* An alternative would be to calculate normals based
|
||||
* on the coordinates of the mesh vertices */
|
||||
/*
|
||||
const gp_XYZ pt1 = coords[n1-1];
|
||||
const gp_XYZ pt2 = coords[n2-1];
|
||||
const gp_XYZ pt3 = coords[n3-1];
|
||||
const gp_XYZ v1 = pt2-pt1;
|
||||
const gp_XYZ v2 = pt3-pt2;
|
||||
gp_Dir normal = gp_Dir(v1^v2);
|
||||
_normals.push_back((float)normal.X());
|
||||
_normals.push_back((float)normal.Y());
|
||||
_normals.push_back((float)normal.Z());
|
||||
*/
|
||||
|
||||
_faces.push_back(dict[n1]);
|
||||
_faces.push_back(dict[n2]);
|
||||
_faces.push_back(dict[n3]);
|
||||
|
||||
_material_ids.push_back(surface_style_id);
|
||||
|
||||
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 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 (!_normals.empty() && settings().get(IfcGeom::IteratorSettings::GENERATE_UVS)) {
|
||||
uvs_ = box_project_uvs(_verts, _normals);
|
||||
}
|
||||
|
||||
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_Explorer texp(s, TopAbs_EDGE, TopAbs_FACE) 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();
|
||||
|
||||
/*
|
||||
// In case you want direction arrows on your edges
|
||||
double u = tessellater.Parameter(i);
|
||||
gp_XYZ p2, p3;
|
||||
gp_Pnt tmp;
|
||||
gp_Vec tmp2;
|
||||
crv.D1(u, tmp, tmp2);
|
||||
gp_Dir d1, d2, d3, d4;
|
||||
d1 = tmp2;
|
||||
if (texp.Current().Orientation() == TopAbs_REVERSED) {
|
||||
d1 = -d1;
|
||||
}
|
||||
if (fabs(d1.Z()) < 0.5) {
|
||||
d2 = d1.Crossed(gp::DZ());
|
||||
} else {
|
||||
d2 = d1.Crossed(gp::DY());
|
||||
}
|
||||
d3 = d1.XYZ() + d2.XYZ();
|
||||
d4 = d1.XYZ() - d2.XYZ();
|
||||
p2 = p - d3.XYZ() / 10.;
|
||||
p3 = p - d4.XYZ() / 10.;
|
||||
trsf.Transforms(p2);
|
||||
trsf.Transforms(p3);
|
||||
_material_ids.push_back(surface_style_id);
|
||||
_material_ids.push_back(surface_style_id);
|
||||
_verts.push_back(static_cast<P>(p2.X()));
|
||||
_verts.push_back(static_cast<P>(p2.Y()));
|
||||
_verts.push_back(static_cast<P>(p2.Z()));
|
||||
_verts.push_back(static_cast<P>(p3.X()));
|
||||
_verts.push_back(static_cast<P>(p3.Y()));
|
||||
_verts.push_back(static_cast<P>(p3.Z()));
|
||||
*/
|
||||
|
||||
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);
|
||||
// _edges.push_back(start + 3 * (i - 2) + 2);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 2);
|
||||
}
|
||||
|
||||
// _edges.push_back(start + 3 * (i - 1) + 0);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 2);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 1);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BRepTools::Clean(s);
|
||||
}
|
||||
}
|
||||
virtual ~Triangulation() {}
|
||||
|
||||
/// Generates UVs for a single mesh using box projection.
|
||||
/// @todo Very simple impl. Assumes that input vertices and normals match 1:1.
|
||||
static std::vector<P> box_project_uvs(const std::vector<P> &vertices, const std::vector<P> &normals)
|
||||
{
|
||||
std::vector<P> uvs;
|
||||
uvs.resize(vertices.size() / 3 * 2);
|
||||
for (size_t uv_idx = 0, v_idx = 0;
|
||||
uv_idx < uvs.size() && v_idx < vertices.size() && v_idx < normals.size();
|
||||
uv_idx += 2, v_idx += 3) {
|
||||
|
||||
P n_x = normals[v_idx], n_y = normals[v_idx + 1], n_z = normals[v_idx + 2];
|
||||
P v_x = vertices[v_idx], v_y = vertices[v_idx + 1], v_z = vertices[v_idx + 2];
|
||||
|
||||
if (std::abs(n_x) > std::abs(n_y) && std::abs(n_x) > std::abs(n_z)) {
|
||||
uvs[uv_idx] = v_z;
|
||||
uvs[uv_idx + 1] = v_y;
|
||||
}
|
||||
if (std::abs(n_y) > std::abs(n_x) && std::abs(n_y) > std::abs(n_z)) {
|
||||
uvs[uv_idx] = v_x;
|
||||
uvs[uv_idx + 1] = v_z;
|
||||
}
|
||||
if (std::abs(n_z) > std::abs(n_x) && std::abs(n_z) > std::abs(n_y)) {
|
||||
uvs[uv_idx] = v_x;
|
||||
uvs[uv_idx + 1] = v_y;
|
||||
}
|
||||
}
|
||||
|
||||
return uvs;
|
||||
}
|
||||
|
||||
private:
|
||||
// Welds vertices that belong to different faces
|
||||
int addVertex(int material_index, const gp_XYZ& p) {
|
||||
const bool convert = settings().get(IteratorSettings::CONVERT_BACK_UNITS);
|
||||
const P X = static_cast<P>(convert ? (p.X() / settings().unit_magnitude()) : p.X());
|
||||
const P Y = static_cast<P>(convert ? (p.Y() / settings().unit_magnitude()) : p.Y());
|
||||
const P Z = static_cast<P>(convert ? (p.Z() / settings().unit_magnitude()) : p.Z());
|
||||
int i = (int) _verts.size() / 3;
|
||||
if (settings().get(IteratorSettings::WELD_VERTICES)) {
|
||||
const VertexKey key = std::make_pair(material_index, std::make_pair(X, std::make_pair(Y, Z)));
|
||||
typename VertexKeyMap::const_iterator it = welds.find(key);
|
||||
if ( it != welds.end() ) return it->second;
|
||||
i = (int) welds.size();
|
||||
welds[key] = i;
|
||||
}
|
||||
_verts.push_back(X);
|
||||
_verts.push_back(Y);
|
||||
_verts.push_back(Z);
|
||||
return i;
|
||||
}
|
||||
inline void addEdge(int n1, int n2, std::map<std::pair<int,int>,int>& edgecount, std::vector<std::pair<int,int> >& edges_temp) {
|
||||
const Edge e = Edge( (std::min)(n1,n2),(std::max)(n1,n2) );
|
||||
if ( edgecount.find(e) == edgecount.end() ) edgecount[e] = 1;
|
||||
else edgecount[e] ++;
|
||||
edges_temp.push_back(e);
|
||||
}
|
||||
Triangulation();
|
||||
Triangulation(const Triangulation&);
|
||||
Triangulation& operator=(const Triangulation&);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,649 +0,0 @@
|
||||
#include <Geom_Line.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include <Geom_BSplineCurve.hxx>
|
||||
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <Geom_BSplineSurface.hxx>
|
||||
#include <Geom_CylindricalSurface.hxx>
|
||||
|
||||
#include <BRepTools_WireExplorer.hxx>
|
||||
|
||||
#include <TColgp_Array2OfPnt.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array2OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
|
||||
#include "IfcGeom.h"
|
||||
|
||||
template <typename T, typename U>
|
||||
int convert_to_ifc(const T& t, U*& u, bool /*advanced*/) {
|
||||
std::vector<double> coords(3);
|
||||
coords[0] = t.X(); coords[1] = t.Y(); coords[2] = t.Z();
|
||||
u = new U(coords);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Vertex& v, IfcSchema::IfcCartesianPoint*& p, bool advanced) {
|
||||
gp_Pnt pnt = BRep_Tool::Pnt(v);
|
||||
return convert_to_ifc(pnt, p, advanced);
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Vertex& v, IfcSchema::IfcVertex*& vertex, bool advanced) {
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
convert_to_ifc(v, p, advanced);
|
||||
vertex = new IfcSchema::IfcVertexPoint(p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const gp_Ax2& a, IfcSchema::IfcAxis2Placement3D*& ax, bool advanced) {
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
IfcSchema::IfcDirection *x, *z;
|
||||
if (!(convert_to_ifc(a.Location(), p, advanced) && convert_to_ifc(a.Direction(), z, advanced) && convert_to_ifc(a.XDirection(), x, advanced))) {
|
||||
ax = 0;
|
||||
return 0;
|
||||
}
|
||||
ax = new IfcSchema::IfcAxis2Placement3D(p, z, x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
void opencascade_array_to_vector(T& t, std::vector<U>& u) {
|
||||
u.reserve(t.Length());
|
||||
for (int i = t.Lower(); i <= t.Upper(); ++i) {
|
||||
u.push_back(t.Value(i));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
void opencascade_array_to_vector2(T& t, std::vector< std::vector<U> >& u) {
|
||||
u.reserve(t.RowLength());
|
||||
for (int j = t.LowerRow(); j <= t.UpperRow(); ++j) {
|
||||
std::vector<U> v;
|
||||
v.reserve(t.ColLength());
|
||||
for (int i = t.LowerCol(); i <= t.UpperCol(); ++i) {
|
||||
v.push_back(t.Value(j, i));
|
||||
}
|
||||
u.push_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_IFC4
|
||||
IfcSchema::IfcKnotType::IfcKnotType opencascade_knotspec_to_ifc(GeomAbs_BSplKnotDistribution bspline_knot_spec) {
|
||||
IfcSchema::IfcKnotType::IfcKnotType knot_spec = IfcSchema::IfcKnotType::IfcKnotType_UNSPECIFIED;
|
||||
if (bspline_knot_spec == GeomAbs_Uniform) {
|
||||
knot_spec = IfcSchema::IfcKnotType::IfcKnotType_UNIFORM_KNOTS;
|
||||
} else if (bspline_knot_spec == GeomAbs_QuasiUniform) {
|
||||
knot_spec = IfcSchema::IfcKnotType::IfcKnotType_QUASI_UNIFORM_KNOTS;
|
||||
} else if (bspline_knot_spec == GeomAbs_PiecewiseBezier) {
|
||||
knot_spec = IfcSchema::IfcKnotType::IfcKnotType_PIECEWISE_BEZIER_KNOTS;
|
||||
}
|
||||
return knot_spec;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const Handle_Geom_Curve& c, IfcSchema::IfcCurve*& curve, bool advanced) {
|
||||
if (c->DynamicType() == STANDARD_TYPE(Geom_Line)) {
|
||||
IfcSchema::IfcDirection* d;
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
|
||||
Handle_Geom_Line line = Handle_Geom_Line::DownCast(c);
|
||||
|
||||
if (!convert_to_ifc(line->Position().Location(), p, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
if (!convert_to_ifc(line->Position().Direction(), d, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
IfcSchema::IfcVector* v = new IfcSchema::IfcVector(d, 1.);
|
||||
curve = new IfcSchema::IfcLine(p, v);
|
||||
|
||||
return 1;
|
||||
} else if (c->DynamicType() == STANDARD_TYPE(Geom_Circle)) {
|
||||
IfcSchema::IfcAxis2Placement3D* ax;
|
||||
|
||||
Handle_Geom_Circle circle = Handle_Geom_Circle::DownCast(c);
|
||||
|
||||
convert_to_ifc(circle->Position(), ax, advanced);
|
||||
curve = new IfcSchema::IfcCircle(ax, circle->Radius());
|
||||
|
||||
return 1;
|
||||
} else if (c->DynamicType() == STANDARD_TYPE(Geom_Ellipse)) {
|
||||
IfcSchema::IfcAxis2Placement3D* ax;
|
||||
|
||||
Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(c);
|
||||
|
||||
convert_to_ifc(ellipse->Position(), ax, advanced);
|
||||
curve = new IfcSchema::IfcEllipse(ax, ellipse->MajorRadius(), ellipse->MinorRadius());
|
||||
|
||||
return 1;
|
||||
}
|
||||
#ifdef USE_IFC4
|
||||
else if (c->DynamicType() == STANDARD_TYPE(Geom_BSplineCurve)) {
|
||||
Handle_Geom_BSplineCurve bspline = Handle_Geom_BSplineCurve::DownCast(c);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
|
||||
TColgp_Array1OfPnt poles(1, bspline->NbPoles());
|
||||
bspline->Poles(poles);
|
||||
for (int i = 1; i <= bspline->NbPoles(); ++i) {
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
if (!convert_to_ifc(poles.Value(i), p, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
points->push(p);
|
||||
}
|
||||
IfcSchema::IfcKnotType::IfcKnotType knot_spec = opencascade_knotspec_to_ifc(bspline->KnotDistribution());
|
||||
|
||||
std::vector<int> mults;
|
||||
std::vector<double> knots;
|
||||
std::vector<double> weights;
|
||||
|
||||
TColStd_Array1OfInteger bspline_mults(1, bspline->NbKnots());
|
||||
TColStd_Array1OfReal bspline_knots(1, bspline->NbKnots());
|
||||
TColStd_Array1OfReal bspline_weights(1, bspline->NbPoles());
|
||||
|
||||
bspline->Multiplicities(bspline_mults);
|
||||
bspline->Knots(bspline_knots);
|
||||
bspline->Weights(bspline_weights);
|
||||
|
||||
opencascade_array_to_vector(bspline_mults, mults);
|
||||
opencascade_array_to_vector(bspline_knots, knots);
|
||||
opencascade_array_to_vector(bspline_weights, weights);
|
||||
|
||||
bool rational = false;
|
||||
for (std::vector<double>::const_iterator it = weights.begin(); it != weights.end(); ++it) {
|
||||
if ((*it) != 1.) {
|
||||
rational = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rational) {
|
||||
curve = new IfcSchema::IfcRationalBSplineCurveWithKnots(
|
||||
bspline->Degree(),
|
||||
points,
|
||||
IfcSchema::IfcBSplineCurveForm::IfcBSplineCurveForm_UNSPECIFIED,
|
||||
bspline->IsClosed() != 0,
|
||||
false,
|
||||
mults,
|
||||
knots,
|
||||
knot_spec,
|
||||
weights
|
||||
);
|
||||
} else {
|
||||
curve = new IfcSchema::IfcBSplineCurveWithKnots(
|
||||
bspline->Degree(),
|
||||
points,
|
||||
IfcSchema::IfcBSplineCurveForm::IfcBSplineCurveForm_UNSPECIFIED,
|
||||
bspline->IsClosed() != 0,
|
||||
false,
|
||||
mults,
|
||||
knots,
|
||||
knot_spec
|
||||
);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const Handle_Geom_Surface& s, IfcSchema::IfcSurface*& surface, bool advanced) {
|
||||
if (s->DynamicType() == STANDARD_TYPE(Geom_Plane)) {
|
||||
Handle_Geom_Plane plane = Handle_Geom_Plane::DownCast(s);
|
||||
IfcSchema::IfcAxis2Placement3D* place;
|
||||
/// @todo: Note that the Ax3 is converted to an Ax2 here
|
||||
if (!convert_to_ifc(plane->Position().Ax2(), place, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
surface = new IfcSchema::IfcPlane(place);
|
||||
return 1;
|
||||
}
|
||||
#ifdef USE_IFC4
|
||||
else if (s->DynamicType() == STANDARD_TYPE(Geom_CylindricalSurface)) {
|
||||
Handle_Geom_CylindricalSurface cyl = Handle_Geom_CylindricalSurface::DownCast(s);
|
||||
IfcSchema::IfcAxis2Placement3D* place;
|
||||
/// @todo: Note that the Ax3 is converted to an Ax2 here
|
||||
if (!convert_to_ifc(cyl->Position().Ax2(), place, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
surface = new IfcSchema::IfcCylindricalSurface(place, cyl->Radius());
|
||||
return 1;
|
||||
} else if (s->DynamicType() == STANDARD_TYPE(Geom_BSplineSurface)) {
|
||||
typedef IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint> points_t;
|
||||
|
||||
Handle_Geom_BSplineSurface bspline = Handle_Geom_BSplineSurface::DownCast(s);
|
||||
points_t::ptr points(new points_t);
|
||||
|
||||
TColgp_Array2OfPnt poles(1, bspline->NbUPoles(), 1, bspline->NbVPoles());
|
||||
bspline->Poles(poles);
|
||||
for (int i = 1; i <= bspline->NbUPoles(); ++i) {
|
||||
std::vector<IfcSchema::IfcCartesianPoint*> ps;
|
||||
ps.reserve(bspline->NbVPoles());
|
||||
for (int j = 1; j <= bspline->NbVPoles(); ++j) {
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
if (!convert_to_ifc(poles.Value(i, j), p, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
ps.push_back(p);
|
||||
}
|
||||
points->push(ps);
|
||||
}
|
||||
|
||||
IfcSchema::IfcKnotType::IfcKnotType knot_spec_u = opencascade_knotspec_to_ifc(bspline->UKnotDistribution());
|
||||
IfcSchema::IfcKnotType::IfcKnotType knot_spec_v = opencascade_knotspec_to_ifc(bspline->VKnotDistribution());
|
||||
|
||||
if (knot_spec_u != knot_spec_v) {
|
||||
knot_spec_u = IfcSchema::IfcKnotType::IfcKnotType_UNSPECIFIED;
|
||||
}
|
||||
|
||||
std::vector<int> umults;
|
||||
std::vector<int> vmults;
|
||||
std::vector<double> uknots;
|
||||
std::vector<double> vknots;
|
||||
std::vector< std::vector<double> > weights;
|
||||
|
||||
TColStd_Array1OfInteger bspline_umults(1, bspline->NbUKnots());
|
||||
TColStd_Array1OfInteger bspline_vmults(1, bspline->NbVKnots());
|
||||
TColStd_Array1OfReal bspline_uknots(1, bspline->NbUKnots());
|
||||
TColStd_Array1OfReal bspline_vknots(1, bspline->NbVKnots());
|
||||
TColStd_Array2OfReal bspline_weights(1, bspline->NbUPoles(), 1, bspline->NbVPoles());
|
||||
|
||||
bspline->UMultiplicities(bspline_umults);
|
||||
bspline->VMultiplicities(bspline_vmults);
|
||||
bspline->UKnots(bspline_uknots);
|
||||
bspline->VKnots(bspline_vknots);
|
||||
bspline->Weights(bspline_weights);
|
||||
|
||||
opencascade_array_to_vector(bspline_umults, umults);
|
||||
opencascade_array_to_vector(bspline_vmults, vmults);
|
||||
opencascade_array_to_vector(bspline_uknots, uknots);
|
||||
opencascade_array_to_vector(bspline_vknots, vknots);
|
||||
opencascade_array_to_vector2(bspline_weights, weights);
|
||||
|
||||
bool rational = false;
|
||||
for (std::vector< std::vector<double> >::const_iterator it = weights.begin(); it != weights.end(); ++it) {
|
||||
for (std::vector<double>::const_iterator jt = it->begin(); jt != it->end(); ++jt) {
|
||||
if ((*jt) != 1.) {
|
||||
rational = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rational) {
|
||||
surface = new IfcSchema::IfcRationalBSplineSurfaceWithKnots(
|
||||
bspline->UDegree(),
|
||||
bspline->VDegree(),
|
||||
points,
|
||||
IfcSchema::IfcBSplineSurfaceForm::IfcBSplineSurfaceForm_UNSPECIFIED,
|
||||
bspline->IsUClosed() != 0,
|
||||
bspline->IsVClosed() != 0,
|
||||
false,
|
||||
umults,
|
||||
vmults,
|
||||
uknots,
|
||||
vknots,
|
||||
knot_spec_u,
|
||||
weights
|
||||
);
|
||||
} else {
|
||||
surface = new IfcSchema::IfcBSplineSurfaceWithKnots(
|
||||
bspline->UDegree(),
|
||||
bspline->VDegree(),
|
||||
points,
|
||||
IfcSchema::IfcBSplineSurfaceForm::IfcBSplineSurfaceForm_UNSPECIFIED,
|
||||
bspline->IsUClosed() != 0,
|
||||
bspline->IsVClosed() != 0,
|
||||
false,
|
||||
umults,
|
||||
vmults,
|
||||
uknots,
|
||||
vknots,
|
||||
knot_spec_u
|
||||
);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Edge& e, IfcSchema::IfcCurve*& c, bool advanced) {
|
||||
double a, b;
|
||||
IfcSchema::IfcCurve* base;
|
||||
|
||||
Handle_Geom_Curve crv = BRep_Tool::Curve(e, a, b);
|
||||
if (!convert_to_ifc(crv, base, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
trim1->push(new IfcSchema::IfcParameterValue(a));
|
||||
trim2->push(new IfcSchema::IfcParameterValue(b));
|
||||
|
||||
c = new IfcSchema::IfcTrimmedCurve(base, trim1, trim2, true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Edge& e, IfcSchema::IfcEdge*& edge, bool advanced) {
|
||||
double a, b;
|
||||
|
||||
TopExp_Explorer exp(e, TopAbs_VERTEX);
|
||||
if (!exp.More()) return 0;
|
||||
TopoDS_Vertex v1 = TopoDS::Vertex(exp.Current());
|
||||
exp.Next();
|
||||
if (!exp.More()) return 0;
|
||||
TopoDS_Vertex v2 = TopoDS::Vertex(exp.Current());
|
||||
|
||||
IfcSchema::IfcVertex *vertex1, *vertex2;
|
||||
if (!(convert_to_ifc(v1, vertex1, advanced) && convert_to_ifc(v2, vertex2, advanced))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Handle_Geom_Curve crv = BRep_Tool::Curve(e, a, b);
|
||||
|
||||
if (crv.IsNull()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (crv->DynamicType() == STANDARD_TYPE(Geom_Line) && !advanced) {
|
||||
IfcSchema::IfcEdge* edge2 = new IfcSchema::IfcEdge(vertex1, vertex2);
|
||||
edge = new IfcSchema::IfcOrientedEdge(edge2, true);
|
||||
return 1;
|
||||
} else {
|
||||
IfcSchema::IfcCurve* curve;
|
||||
if (!convert_to_ifc(crv, curve, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
/// @todo probably not correct
|
||||
const bool sense = e.Orientation() == TopAbs_FORWARD;
|
||||
IfcSchema::IfcEdge* edge2 = new IfcSchema::IfcEdgeCurve(vertex1, vertex2, curve, true);
|
||||
edge = new IfcSchema::IfcOrientedEdge(edge2, sense);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Wire& wire, IfcSchema::IfcLoop*& loop, bool advanced) {
|
||||
bool polygonal = true;
|
||||
for (TopExp_Explorer exp(wire, TopAbs_EDGE); exp.More(); exp.Next()) {
|
||||
double a, b;
|
||||
Handle_Geom_Curve crv = BRep_Tool::Curve(TopoDS::Edge(exp.Current()), a, b);
|
||||
if (crv.IsNull()) {
|
||||
continue;
|
||||
}
|
||||
if (crv->DynamicType() != STANDARD_TYPE(Geom_Line)) {
|
||||
polygonal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!polygonal && !advanced) {
|
||||
return 0;
|
||||
} else if (polygonal && !advanced) {
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
|
||||
BRepTools_WireExplorer exp(wire);
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
for (; exp.More(); exp.Next()) {
|
||||
if (convert_to_ifc(exp.CurrentVertex(), p, advanced)) {
|
||||
points->push(p);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
loop = new IfcSchema::IfcPolyLoop(points);
|
||||
return 1;
|
||||
} else {
|
||||
IfcSchema::IfcOrientedEdge::list::ptr edges(new IfcSchema::IfcOrientedEdge::list);
|
||||
BRepTools_WireExplorer exp(wire);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcEdge* edge;
|
||||
// With advanced set to true convert_to_ifc(TopoDS_Edge&) will always create an IfcOrientedEdge
|
||||
if (!convert_to_ifc(exp.Current(), edge, true)) {
|
||||
double a, b;
|
||||
if (BRep_Tool::Curve(TopoDS::Edge(exp.Current()), a, b).IsNull()) {
|
||||
continue;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
edges->push(edge->as<IfcSchema::IfcOrientedEdge>());
|
||||
}
|
||||
loop = new IfcSchema::IfcEdgeLoop(edges);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Face& f, IfcSchema::IfcFace*& face, bool advanced) {
|
||||
Handle_Geom_Surface surf = BRep_Tool::Surface(f);
|
||||
TopExp_Explorer exp(f, TopAbs_WIRE);
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds(new IfcSchema::IfcFaceBound::list);
|
||||
int index = 0;
|
||||
for (; exp.More(); exp.Next(), ++index) {
|
||||
IfcSchema::IfcLoop* loop;
|
||||
if (!convert_to_ifc(TopoDS::Wire(exp.Current()), loop, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
IfcSchema::IfcFaceBound* bnd;
|
||||
if (index == 0) {
|
||||
bnd = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
} else {
|
||||
bnd = new IfcSchema::IfcFaceBound(loop, true);
|
||||
}
|
||||
bounds->push(bnd);
|
||||
}
|
||||
|
||||
const bool is_planar = surf->DynamicType() == STANDARD_TYPE(Geom_Plane);
|
||||
|
||||
if (!is_planar && !advanced) {
|
||||
return 0;
|
||||
}
|
||||
if (is_planar && !advanced) {
|
||||
face = new IfcSchema::IfcFace(bounds);
|
||||
return 1;
|
||||
} else {
|
||||
#ifdef USE_IFC4
|
||||
IfcSchema::IfcSurface* surface;
|
||||
if (!convert_to_ifc(surf, surface, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
face = new IfcSchema::IfcAdvancedFace(bounds, surface, f.Orientation() == TopAbs_FORWARD);
|
||||
return 1;
|
||||
#else
|
||||
// No IfcAdvancedFace in Ifc2x3
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
int convert_to_ifc(const TopoDS_Shape& s, U*& item, bool advanced) {
|
||||
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
|
||||
IfcSchema::IfcFace* f;
|
||||
for (TopExp_Explorer exp(s, TopAbs_FACE); exp.More(); exp.Next()) {
|
||||
if (convert_to_ifc(TopoDS::Face(exp.Current()), f, advanced)) {
|
||||
faces->push(f);
|
||||
}
|
||||
}
|
||||
item = new U(faces);
|
||||
return faces->size();
|
||||
}
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* IfcGeom::serialise(const TopoDS_Shape& shape, bool advanced) {
|
||||
#ifndef USE_IFC4
|
||||
advanced = false;
|
||||
#endif
|
||||
|
||||
for (TopExp_Explorer exp(shape, TopAbs_COMPSOLID); exp.More();) {
|
||||
/// @todo CompSolids are not supported
|
||||
return 0;
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentation* rep = 0;
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
|
||||
|
||||
// First check if there is a solid with one or more shells
|
||||
for (TopExp_Explorer exp(shape, TopAbs_SOLID); exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcClosedShell* outer = 0;
|
||||
IfcSchema::IfcClosedShell::list::ptr inner(new IfcSchema::IfcClosedShell::list);
|
||||
for (TopExp_Explorer exp2(exp.Current(), TopAbs_SHELL); exp2.More(); exp2.Next()) {
|
||||
IfcSchema::IfcClosedShell* shell;
|
||||
if (!convert_to_ifc(exp2.Current(), shell, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
/// @todo Are shells always in this order or does Orientation() needs to be checked?
|
||||
if (outer) {
|
||||
inner->push(shell);
|
||||
} else {
|
||||
outer = shell;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_IFC4
|
||||
if (advanced) {
|
||||
if (inner->size()) {
|
||||
items->push(new IfcSchema::IfcAdvancedBrepWithVoids(outer, inner));
|
||||
} else {
|
||||
items->push(new IfcSchema::IfcAdvancedBrep(outer));
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
|
||||
/// @todo this is not necessarily correct as the shell is not necessarily facetted.
|
||||
if (inner->size()) {
|
||||
items->push(new IfcSchema::IfcFacetedBrepWithVoids(outer, inner));
|
||||
} else {
|
||||
items->push(new IfcSchema::IfcFacetedBrep(outer));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (items->size() > 0) {
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Body"), std::string("Brep"), items);
|
||||
} else {
|
||||
|
||||
// If not, see if there is a shell
|
||||
IfcSchema::IfcOpenShell::list::ptr shells(new IfcSchema::IfcOpenShell::list);
|
||||
for (TopExp_Explorer exp(shape, TopAbs_SHELL); exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcOpenShell* shell;
|
||||
if (!convert_to_ifc(exp.Current(), shell, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
shells->push(shell);
|
||||
}
|
||||
|
||||
if (shells->size() > 0) {
|
||||
items->push(new IfcSchema::IfcShellBasedSurfaceModel(shells->generalize()));
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Body"), std::string("Brep"), items);
|
||||
} else {
|
||||
|
||||
// If not, see if there is are one of more faces. Note that they will be grouped into a shell.
|
||||
IfcSchema::IfcOpenShell* shell;
|
||||
int face_count = convert_to_ifc(shape, shell, advanced);
|
||||
|
||||
if (face_count > 0) {
|
||||
items->push(shell);
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Body"), std::string("Brep"), items);
|
||||
} else {
|
||||
|
||||
// If not, see if there are any edges. Note that wires are skipped as
|
||||
// they are not commonly top-level geometrical descriptions in IFC.
|
||||
// Also note that edges are written as trimmed curves rather than edges.
|
||||
|
||||
IfcEntityList::ptr edges(new IfcEntityList);
|
||||
|
||||
for (TopExp_Explorer exp(shape, TopAbs_EDGE); exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcCurve* c;
|
||||
if (!convert_to_ifc(TopoDS::Edge(exp.Current()), c, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
edges->push(c);
|
||||
}
|
||||
|
||||
if (edges->size() == 0) {
|
||||
return 0;
|
||||
} else if (edges->size() == 1) {
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Axis"), std::string("Curve2D"), edges->as<IfcSchema::IfcRepresentationItem>());
|
||||
} else {
|
||||
// A geometric set is created as that probably (?) makes more sense in IFC
|
||||
IfcSchema::IfcGeometricCurveSet* curves = new IfcSchema::IfcGeometricCurveSet(edges);
|
||||
items->push(curves);
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Axis"), std::string("GeometricCurveSet"), items->as<IfcSchema::IfcRepresentationItem>());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
|
||||
reps->push(rep);
|
||||
return new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
}
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* IfcGeom::tesselate(const TopoDS_Shape& shape, double deflection) {
|
||||
BRepMesh_IncrementalMesh(shape, deflection);
|
||||
|
||||
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
|
||||
|
||||
for (TopExp_Explorer exp(shape, TopAbs_FACE); exp.More(); exp.Next()) {
|
||||
const TopoDS_Face& face = TopoDS::Face(exp.Current());
|
||||
TopLoc_Location loc;
|
||||
Handle(Poly_Triangulation) tri = BRep_Tool::Triangulation(face, loc);
|
||||
|
||||
if (!tri.IsNull()) {
|
||||
const TColgp_Array1OfPnt& nodes = tri->Nodes();
|
||||
std::vector<IfcSchema::IfcCartesianPoint*> vertices;
|
||||
for (int i = 1; i <= nodes.Length(); ++i) {
|
||||
gp_Pnt pnt = nodes(i).Transformed(loc);
|
||||
std::vector<double> xyz; xyz.push_back(pnt.X()); xyz.push_back(pnt.Y()); xyz.push_back(pnt.Z());
|
||||
IfcSchema::IfcCartesianPoint* cpnt = new IfcSchema::IfcCartesianPoint(xyz);
|
||||
vertices.push_back(cpnt);
|
||||
}
|
||||
const Poly_Array1OfTriangle& triangles = tri->Triangles();
|
||||
for (int i = 1; i <= triangles.Length(); ++i) {
|
||||
int n1, n2, n3;
|
||||
triangles(i).Get(n1, n2, n3);
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(vertices[n1 - 1]);
|
||||
points->push(vertices[n2 - 1]);
|
||||
points->push(vertices[n3 - 1]);
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
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* face2 = new IfcSchema::IfcFace(bounds);
|
||||
faces->push(face2);
|
||||
}
|
||||
}
|
||||
}
|
||||
IfcSchema::IfcOpenShell* shell = new IfcSchema::IfcOpenShell(faces);
|
||||
IfcSchema::IfcConnectedFaceSet::list::ptr shells(new IfcSchema::IfcConnectedFaceSet::list);
|
||||
shells->push(shell);
|
||||
IfcSchema::IfcFaceBasedSurfaceModel* surface_model = new IfcSchema::IfcFaceBasedSurfaceModel(shells);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
|
||||
|
||||
items->push(surface_model);
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
0, std::string("Facetation"), std::string("SurfaceModel"), items);
|
||||
|
||||
reps->push(rep);
|
||||
IfcSchema::IfcProductDefinitionShape* shapedef = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
|
||||
return shapedef;
|
||||
}
|
||||
@@ -1,38 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#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
|
||||
+240
-641
File diff suppressed because it is too large
Load Diff
+72
-276
@@ -47,53 +47,47 @@
|
||||
#include <TColgp_Array1OfPnt2d.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
|
||||
#include <Geom_Line.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include <Geom_TrimmedCurve.hxx>
|
||||
|
||||
#include <BRepBuilderAPI_MakeVertex.hxx>
|
||||
#include <BRepOffsetAPI_Sewing.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <BRepBuilderAPI_MakeShell.hxx>
|
||||
#include <BRepBuilderAPI_MakeSolid.hxx>
|
||||
#include <BRepBuilderAPI_MakePolygon.hxx>
|
||||
#include <BRepBuilderAPI_MakeVertex.hxx>
|
||||
|
||||
#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>
|
||||
|
||||
#include <BRepAlgoAPI_Cut.hxx>
|
||||
#include <BRepOffsetAPI_Sewing.hxx>
|
||||
#include <BRepPrimAPI_MakePrism.hxx>
|
||||
#include <BRepBuilderAPI_MakeShell.hxx>
|
||||
#include <BRepBuilderAPI_MakeSolid.hxx>
|
||||
#include <BRepPrimAPI_MakeHalfSpace.hxx>
|
||||
#include <BRepFilletAPI_MakeFillet2d.hxx>
|
||||
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepAlgoAPI_Cut.hxx>
|
||||
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
#include <ShapeFix_ShapeTolerance.hxx>
|
||||
#include <ShapeFix_Solid.hxx>
|
||||
|
||||
#include <Geom_BSplineCurve.hxx>
|
||||
#include <BRepTools_WireExplorer.hxx>
|
||||
#include <BRepFilletAPI_MakeFillet2d.hxx>
|
||||
|
||||
#include <TopLoc_Location.hxx>
|
||||
|
||||
#include <BRep_Tool.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire& wire) {
|
||||
if ( getValue(GV_PLANEANGLE_UNIT)<0 ) {
|
||||
bool IfcGeom::convert(const IfcSchema::IfcCompositeCurve::ptr l, TopoDS_Wire& wire) {
|
||||
if ( IfcGeom::GetValue(GV_PLANEANGLE_UNIT)<0 ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l->entity);
|
||||
|
||||
// Temporarily pretend we do have unit information
|
||||
setValue(GV_PLANEANGLE_UNIT,1.0);
|
||||
IfcGeom::SetValue(GV_PLANEANGLE_UNIT,1.0);
|
||||
|
||||
bool succes_radians = false;
|
||||
bool succes_degrees = false;
|
||||
@@ -103,17 +97,17 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
|
||||
// First try radians
|
||||
TopoDS_Wire wire_radians, wire_degrees;
|
||||
try {
|
||||
succes_radians = IfcGeom::Kernel::convert(l,wire_radians);
|
||||
succes_radians = IfcGeom::convert(l,wire_radians);
|
||||
} catch (...) {}
|
||||
|
||||
// Now try degrees
|
||||
setValue(GV_PLANEANGLE_UNIT,0.0174532925199433);
|
||||
IfcGeom::SetValue(GV_PLANEANGLE_UNIT,0.0174532925199433);
|
||||
try {
|
||||
succes_degrees = IfcGeom::Kernel::convert(l,wire_degrees);
|
||||
succes_degrees = IfcGeom::convert(l,wire_degrees);
|
||||
} catch (...) {}
|
||||
|
||||
// Restore to unknown unit state
|
||||
setValue(GV_PLANEANGLE_UNIT,-1.0);
|
||||
IfcGeom::SetValue(GV_PLANEANGLE_UNIT,-1.0);
|
||||
|
||||
if ( succes_degrees && ! succes_radians ) {
|
||||
use_degrees = true;
|
||||
@@ -144,19 +138,19 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
|
||||
|
||||
return use_radians || use_degrees;
|
||||
}
|
||||
IfcSchema::IfcCompositeCurveSegment::list::ptr segments = l->Segments();
|
||||
IfcSchema::IfcCompositeCurveSegment::list segments = l->Segments();
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
//TopoDS_Vertex last_vertex;
|
||||
for( IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++ it ) {
|
||||
IfcSchema::IfcCurve* curve = (*it)->ParentCurve();
|
||||
for( IfcSchema::IfcCompositeCurveSegment::it it = segments->begin(); it != segments->end(); ++ it ) {
|
||||
const IfcSchema::IfcCurve::ptr curve = (*it)->ParentCurve();
|
||||
TopoDS_Wire wire2;
|
||||
if ( !convert_wire(curve,wire2) ) {
|
||||
if ( ! IfcGeom::convert_wire(curve,wire2) ) {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve->entity);
|
||||
continue;
|
||||
}
|
||||
if ( ! (*it)->SameSense() ) wire2.Reverse();
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
FTol.SetTolerance(wire2, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_WIRE);
|
||||
FTol.SetTolerance(wire2, GetValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_WIRE);
|
||||
/*if ( it != segments->begin() ) {
|
||||
TopExp_Explorer exp (wire2,TopAbs_VERTEX);
|
||||
const TopoDS_Vertex& first_vertex = TopoDS::Vertex(exp.Current());
|
||||
@@ -171,65 +165,47 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
|
||||
//last_vertex = w.Vertex();
|
||||
if ( w.Error() != BRepBuilderAPI_WireDone ) {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to join curve segments:",l->entity);
|
||||
|
||||
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)->entity);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
wire = w.Wire();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& wire) {
|
||||
IfcSchema::IfcCurve* basis_curve = l->BasisCurve();
|
||||
bool IfcGeom::convert(const IfcSchema::IfcTrimmedCurve::ptr l, TopoDS_Wire& wire) {
|
||||
IfcSchema::IfcCurve::ptr basis_curve = l->BasisCurve();
|
||||
bool isConic = basis_curve->is(IfcSchema::Type::IfcConic);
|
||||
double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT);
|
||||
double parameterFactor = isConic ? IfcGeom::GetValue(GV_PLANEANGLE_UNIT) : IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
Handle(Geom_Curve) curve;
|
||||
if ( !convert_curve(basis_curve,curve) ) return false;
|
||||
bool trim_cartesian = l->MasterRepresentation() != IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER;
|
||||
IfcEntityList::ptr trims1 = l->Trim1();
|
||||
IfcEntityList::ptr trims2 = l->Trim2();
|
||||
if ( ! IfcGeom::convert_curve(basis_curve,curve) ) return false;
|
||||
bool trim_cartesian = l->MasterRepresentation() == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN;
|
||||
IfcUtil::IfcAbstractSelect::list trims1 = l->Trim1();
|
||||
IfcUtil::IfcAbstractSelect::list trims2 = l->Trim2();
|
||||
bool trimmed1 = false;
|
||||
bool trimmed2 = false;
|
||||
unsigned sense_agreement = l->SenseAgreement() ? 0 : 1;
|
||||
double flts[2];
|
||||
gp_Pnt pnts[2];
|
||||
bool has_flts[2] = {false,false};
|
||||
bool has_pnts[2] = {false,false};
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) {
|
||||
IfcUtil::IfcBaseClass* i = *it;
|
||||
for ( IfcUtil::IfcAbstractSelect::it it = trims1->begin(); it != trims1->end(); it ++ ) {
|
||||
const IfcUtil::IfcAbstractSelect::ptr i = *it;
|
||||
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] );
|
||||
IfcGeom::convert(reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,IfcSchema::IfcCartesianPoint>(i), pnts[sense_agreement] );
|
||||
has_pnts[sense_agreement] = true;
|
||||
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
|
||||
const double value = *((IfcSchema::IfcParameterValue*)i);
|
||||
const double value = *((IfcUtil::IfcBaseEntity*)i)->entity->getArgument(0);
|
||||
flts[sense_agreement] = value * parameterFactor;
|
||||
has_flts[sense_agreement] = true;
|
||||
}
|
||||
}
|
||||
for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) {
|
||||
IfcUtil::IfcBaseClass* i = *it;
|
||||
for ( IfcUtil::IfcAbstractSelect::it it = trims2->begin(); it != trims2->end(); it ++ ) {
|
||||
const IfcUtil::IfcAbstractSelect::ptr i = *it;
|
||||
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] );
|
||||
IfcGeom::convert(reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,IfcSchema::IfcCartesianPoint>(i), pnts[1-sense_agreement] );
|
||||
has_pnts[1-sense_agreement] = true;
|
||||
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
|
||||
const double value = *((IfcSchema::IfcParameterValue*)i);
|
||||
const double value = *((IfcUtil::IfcBaseEntity*)i)->entity->getArgument(0);
|
||||
flts[1-sense_agreement] = value * parameterFactor;
|
||||
has_flts[1-sense_agreement] = true;
|
||||
}
|
||||
@@ -237,15 +213,15 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
|
||||
trim_cartesian &= has_pnts[0] && has_pnts[1];
|
||||
bool trim_cartesian_failed = !trim_cartesian;
|
||||
if ( trim_cartesian ) {
|
||||
if ( pnts[0].Distance(pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE) ) {
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(pnts[0]);
|
||||
TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(pnts[1]);
|
||||
FTol.SetTolerance(v1, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
|
||||
FTol.SetTolerance(v2, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
|
||||
FTol.SetTolerance(v1, GetValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
|
||||
FTol.SetTolerance(v2, GetValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
|
||||
BRepBuilderAPI_MakeEdge e (curve,v1,v2);
|
||||
if ( ! e.IsDone() ) {
|
||||
BRepBuilderAPI_EdgeError err = e.Error();
|
||||
@@ -269,15 +245,15 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
|
||||
}
|
||||
if ( basis_curve->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);
|
||||
double x = ellipse->SemiAxis1() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
double y = ellipse->SemiAxis2() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
const bool rotated = y > x;
|
||||
if (rotated) {
|
||||
flts[0] -= M_PI / 2.;
|
||||
flts[1] -= M_PI / 2.;
|
||||
}
|
||||
}
|
||||
if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],M_PI*2.),0.) ) {
|
||||
if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],(double)(M_PI*2.0)),0.0f) ) {
|
||||
w.Add(BRepBuilderAPI_MakeEdge(curve));
|
||||
} else {
|
||||
BRepBuilderAPI_MakeEdge e (curve,flts[0],flts[1]);
|
||||
@@ -293,224 +269,44 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool IfcGeom::convert(const IfcSchema::IfcPolyline::ptr l, TopoDS_Wire& result) {
|
||||
IfcSchema::IfcCartesianPoint::list points = l->Points();
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& result) {
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points = l->Points();
|
||||
|
||||
// Parse and store the points in a sequence
|
||||
TColgp_SequenceOfPnt polygon;
|
||||
for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) {
|
||||
gp_Pnt pnt;
|
||||
IfcGeom::Kernel::convert(*it, pnt);
|
||||
polygon.Append(pnt);
|
||||
}
|
||||
|
||||
// Remove points that are too close to one another
|
||||
remove_duplicate_points_from_loop(polygon, false);
|
||||
|
||||
BRepBuilderAPI_MakePolygon w;
|
||||
for (int i = 1; i <= polygon.Length(); ++i) {
|
||||
w.Add(polygon.Value(i));
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
gp_Pnt P1;gp_Pnt P2;
|
||||
for( IfcSchema::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it ) {
|
||||
IfcGeom::convert(*it,P2);
|
||||
if ( it != points->begin() && ( !P1.IsEqual(P2,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) )
|
||||
w.Add(BRepBuilderAPI_MakeEdge(P1,P2));
|
||||
P1 = P2;
|
||||
}
|
||||
|
||||
result = w.Wire();
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const IfcSchema::IfcPolyLoop::ptr l, TopoDS_Wire& result) {
|
||||
IfcSchema::IfcCartesianPoint::list points = l->Polygon();
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& result) {
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points = l->Polygon();
|
||||
|
||||
// Parse and store the points in a sequence
|
||||
TColgp_SequenceOfPnt polygon;
|
||||
for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) {
|
||||
gp_Pnt pnt;
|
||||
IfcGeom::Kernel::convert(*it, pnt);
|
||||
polygon.Append(pnt);
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
gp_Pnt P1;gp_Pnt P2;gp_Pnt F;
|
||||
int count = 0;
|
||||
for( IfcSchema::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it ) {
|
||||
IfcGeom::convert(*it,P2);
|
||||
if ( it != points->begin() && ( !P1.IsEqual(P2,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) ) {
|
||||
w.Add(BRepBuilderAPI_MakeEdge(P1,P2));
|
||||
count ++;
|
||||
} else if ( ! count ) F = P2;
|
||||
P1 = P2;
|
||||
}
|
||||
|
||||
// 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);
|
||||
return false;
|
||||
if ( !P1.IsEqual(F,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) {
|
||||
w.Add(BRepBuilderAPI_MakeEdge(P1,F));
|
||||
count ++;
|
||||
}
|
||||
if ( count < 3 ) return false;
|
||||
|
||||
// Remove points that are too close to one another
|
||||
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);
|
||||
}
|
||||
|
||||
if (count < 3) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakePolygon w;
|
||||
for (int i = 1; i <= polygon.Length(); ++i) {
|
||||
w.Add(polygon.Value(i));
|
||||
}
|
||||
w.Close();
|
||||
|
||||
result = w.Wire();
|
||||
result = w.Wire();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryOpenProfileDef* l, TopoDS_Wire& result) {
|
||||
return convert_wire(l->Curve(), result);
|
||||
bool IfcGeom::convert(const IfcSchema::IfcArbitraryOpenProfileDef::ptr l, TopoDS_Wire& result) {
|
||||
return IfcGeom::convert_wire(l->Curve(), result);
|
||||
}
|
||||
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Pnt p1, p2;
|
||||
if (!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
|
||||
!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeWire mw;
|
||||
Handle_Geom_Curve crv;
|
||||
|
||||
// The lack of a clear separation between topological and geometrical entities
|
||||
// is starting to get problematic. If the underlying curve is bounded it is
|
||||
// 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);
|
||||
|
||||
if (!is_bounded && convert_curve(l->EdgeGeometry(), crv)) {
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(crv, p1, p2));
|
||||
result = mw;
|
||||
return true;
|
||||
} else if (is_bounded && convert_wire(l->EdgeGeometry(), result)) {
|
||||
if (!l->SameSense()) {
|
||||
result.Reverse();
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
TopExp_Explorer exp(result, TopAbs_EDGE);
|
||||
|
||||
while (exp.More()) {
|
||||
const TopoDS_Edge& ed = TopoDS::Edge(exp.Current());
|
||||
Standard_Real u1, u2;
|
||||
Handle(Geom_Curve) ecrv = BRep_Tool::Curve(ed, u1, u2);
|
||||
exp.Next();
|
||||
const bool last = !exp.More();
|
||||
|
||||
gp_Pnt a, b;
|
||||
|
||||
if (first && last) {
|
||||
a = p1;
|
||||
b = p2;
|
||||
} else if (first) {
|
||||
a = p1;
|
||||
ecrv->D0(u2, b);
|
||||
} else if (last) {
|
||||
ecrv->D0(u1, a);
|
||||
b = p2;
|
||||
} else {
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, u1, u2));
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
BRep_Builder builder;
|
||||
TopoDS_Vertex v1, v2;
|
||||
/// @todo project first and emit warnings accordingly
|
||||
builder.MakeVertex(v1, a, getValue(GV_PRECISION));
|
||||
builder.MakeVertex(v2, b, getValue(GV_PRECISION));
|
||||
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, v1, v2));
|
||||
|
||||
first = false;
|
||||
}
|
||||
result = mw;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeLoop* l, TopoDS_Wire& result) {
|
||||
IfcSchema::IfcOrientedEdge::list::ptr li = l->EdgeList();
|
||||
BRepBuilderAPI_MakeWire mw;
|
||||
for (IfcSchema::IfcOrientedEdge::list::it it = li->begin(); it != li->end(); ++it) {
|
||||
TopoDS_Wire w;
|
||||
if (convert_wire(*it, w)) {
|
||||
mw.Add(TopoDS::Edge(TopoDS_Iterator(w).Value()));
|
||||
}
|
||||
}
|
||||
result = mw;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdge* l, TopoDS_Wire& result) {
|
||||
if (!l->EdgeStart()->is(IfcSchema::Type::IfcVertexPoint) || !l->EdgeEnd()->is(IfcSchema::Type::IfcVertexPoint)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcVertexPoints are supported for EdgeStart and -End", l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+27
-72
@@ -18,104 +18,59 @@
|
||||
********************************************************************************/
|
||||
|
||||
#include "IfcGeom.h"
|
||||
#include "IfcGeomShapeType.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
namespace Cache {
|
||||
std::map<int,TopoDS_Shape> Shape;
|
||||
void PurgeShapeCache() {
|
||||
Shape.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert_shapes(const IfcBaseClass* l, IfcRepresentationShapeItems& r) {
|
||||
#include "IfcRegisterConvertShapes.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
IfcGeom::ShapeType IfcGeom::Kernel::shape_type(const IfcBaseClass* l) {
|
||||
#include "IfcRegisterShapeType.h"
|
||||
return ST_OTHER;
|
||||
bool IfcGeom::is_shape_collection(const IfcBaseClass* l) {
|
||||
#include "IfcRegisterIsShapeCollection.h"
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) {
|
||||
bool IfcGeom::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) {
|
||||
const unsigned int id = l->entity->id();
|
||||
bool success = false;
|
||||
bool processed = false;
|
||||
bool ignored = false;
|
||||
|
||||
#ifndef NO_CACHE
|
||||
std::map<int,TopoDS_Shape>::const_iterator it = cache.Shape.find(id);
|
||||
if ( it != cache.Shape.end() ) { r = it->second; return true; }
|
||||
#endif
|
||||
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) {
|
||||
std::map<int,TopoDS_Shape>::const_iterator it = Cache::Shape.find(id);
|
||||
if ( it != Cache::Shape.end() ) { r = it->second; return true; }
|
||||
#include "IfcRegisterConvertShape.h"
|
||||
} 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);
|
||||
#ifndef NO_CACHE
|
||||
cache.Shape[id] = r;
|
||||
#endif
|
||||
} else if (!ignored) {
|
||||
const char* const msg = processed
|
||||
? "Failed to convert:"
|
||||
: "No operation defined for:";
|
||||
Logger::Message(Logger::LOG_ERROR, msg, l->entity);
|
||||
if ( processed ) {
|
||||
const double precision = IfcGeom::GetValue(GV_PRECISION);
|
||||
IfcGeom::apply_tolerance(r, precision);
|
||||
Cache::Shape[id] = r;
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert_wire(const IfcBaseClass* l, TopoDS_Wire& r) {
|
||||
bool IfcGeom::convert_wire(const IfcBaseClass* l, TopoDS_Wire& r) {
|
||||
#include "IfcRegisterConvertWire.h"
|
||||
Handle(Geom_Curve) curve;
|
||||
if (IfcGeom::Kernel::convert_curve(l, curve)) {
|
||||
return IfcGeom::Kernel::convert_curve_to_wire(curve, r);
|
||||
if (IfcGeom::convert_curve(l, curve)) {
|
||||
return IfcGeom::convert_curve_to_wire(curve, r);
|
||||
}
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert_face(const IfcBaseClass* l, TopoDS_Shape& r) {
|
||||
bool IfcGeom::convert_face(const IfcBaseClass* l, TopoDS_Shape& r) {
|
||||
#include "IfcRegisterConvertFace.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert_curve(const IfcBaseClass* l, Handle(Geom_Curve)& r) {
|
||||
bool IfcGeom::convert_curve(const IfcBaseClass* l, Handle(Geom_Curve)& r) {
|
||||
#include "IfcRegisterConvertCurve.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
return false;
|
||||
|
||||
@@ -41,33 +41,21 @@
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcParse.h"
|
||||
|
||||
using namespace IfcSchema;
|
||||
|
||||
SHAPES(IfcShellBasedSurfaceModel);
|
||||
SHAPES(IfcFaceBasedSurfaceModel);
|
||||
SHAPES(IfcRepresentation);
|
||||
SHAPES(IfcShapeRepresentation);
|
||||
SHAPES(IfcMappedItem);
|
||||
// IfcFacetedBrep included
|
||||
// IfcAdvancedBrep included
|
||||
// IfcFacetedBrepWithVoids included
|
||||
// IfcAdvancedBrepWithVoids included
|
||||
SHAPES(IfcManifoldSolidBrep);
|
||||
SHAPES(IfcFacetedBrep);
|
||||
SHAPES(IfcGeometricSet);
|
||||
|
||||
#ifdef USE_IFC4
|
||||
SHAPE(IfcCylindricalSurface);
|
||||
SHAPE(IfcAdvancedBrep);
|
||||
// FIXME: Surfaces should have a shape type of their own
|
||||
SHAPE(IfcBSplineSurfaceWithKnots);
|
||||
SHAPE(IfcTriangulatedFaceSet);
|
||||
SHAPE(IfcExtrudedAreaSolidTapered);
|
||||
#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);
|
||||
@@ -80,6 +68,9 @@ SHAPE(IfcCurveBoundedPlane);
|
||||
SHAPE(IfcRectangularTrimmedSurface);
|
||||
SHAPE(IfcSurfaceCurveSweptAreaSolid);
|
||||
SHAPE(IfcSweptDiskSolid);
|
||||
#ifdef USE_IFC4
|
||||
SHAPE(IfcCylindricalSurface);
|
||||
#endif
|
||||
|
||||
FACE(IfcArbitraryProfileDefWithVoids);
|
||||
FACE(IfcArbitraryClosedProfileDef);
|
||||
@@ -88,7 +79,6 @@ FACE(IfcRectangleHollowProfileDef);
|
||||
FACE(IfcRectangleProfileDef);
|
||||
FACE(IfcTrapeziumProfileDef)
|
||||
FACE(IfcCShapeProfileDef);
|
||||
// IfcAsymmetricIShapeProfileDef included
|
||||
FACE(IfcIShapeProfileDef);
|
||||
FACE(IfcLShapeProfileDef);
|
||||
FACE(IfcTShapeProfileDef);
|
||||
@@ -100,15 +90,8 @@ 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);
|
||||
WIRE(IfcCompositeCurve);
|
||||
@@ -118,10 +101,6 @@ WIRE(IfcArbitraryOpenProfileDef);
|
||||
CURVE(IfcCircle);
|
||||
CURVE(IfcEllipse);
|
||||
CURVE(IfcLine);
|
||||
#ifdef USE_IFC4
|
||||
// IfcRationalBSplineCurveWithKnots included
|
||||
CURVE(IfcBSplineCurveWithKnots);
|
||||
#endif
|
||||
|
||||
CLASS(IfcCartesianPoint,gp_Pnt);
|
||||
CLASS(IfcDirection,gp_Dir);
|
||||
|
||||
@@ -6,17 +6,8 @@
|
||||
if ( convert((T*)l,r) ) { \
|
||||
success = true; \
|
||||
} \
|
||||
} catch (const std::exception& e) { \
|
||||
Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l->entity); \
|
||||
return false; \
|
||||
} catch (const Standard_Failure& f) { \
|
||||
if (f.GetMessageString() && strlen(f.GetMessageString())) \
|
||||
Logger::Message(Logger::LOG_ERROR, std::string("Error in: ") + f.GetMessageString() + "\nFailed to convert:", l->entity); \
|
||||
else \
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to convert:", l->entity); \
|
||||
return false; \
|
||||
} \
|
||||
if (!success) { \
|
||||
} catch(...) { } \
|
||||
if ( !success) { \
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
|
||||
return false; \
|
||||
} \
|
||||
|
||||
@@ -2,15 +2,9 @@
|
||||
#define SHAPES(T) \
|
||||
if ( l->is(T::Class()) ) { \
|
||||
try { \
|
||||
return convert((T*)l,r); \
|
||||
} catch (const std::exception& e) { \
|
||||
Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l->entity); \
|
||||
} catch (const Standard_Failure& f) { \
|
||||
if (f.GetMessageString()) \
|
||||
Logger::Message(Logger::LOG_ERROR, std::string("Error in: ") + f.GetMessageString() + "\nFailed to convert:", l->entity); \
|
||||
else \
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to convert:", l->entity); \
|
||||
} \
|
||||
return IfcGeom::convert((T*)l,r); \
|
||||
} catch (...) { } \
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
|
||||
return false; \
|
||||
}
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define CLASS(T,V) bool convert(const IfcSchema::T* L, V& r);
|
||||
#define CLASS(T,V) bool convert(const T::ptr L, V& r);
|
||||
#define SHAPES(T) CLASS(T,IfcRepresentationShapeItems)
|
||||
#define SHAPE(T) CLASS(T,TopoDS_Shape)
|
||||
#define WIRE(T) CLASS(T,TopoDS_Wire)
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define SHAPES(T) \
|
||||
if ( l->is(T::Class()) ) return true;
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
#include "IfcRegister.h"
|
||||
@@ -1,14 +0,0 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define SHAPES(T) \
|
||||
if ( l->is(T::Class()) ) return ST_SHAPELIST;
|
||||
#define SHAPE(T) \
|
||||
if ( l->is(T::Class()) ) return ST_SHAPE;
|
||||
#define WIRE(T) \
|
||||
if ( l->is(T::Class()) ) return ST_WIRE;
|
||||
#define FACE(T) \
|
||||
if ( l->is(T::Class()) ) return ST_FACE;
|
||||
#define CURVE(T) \
|
||||
if ( l->is(T::Class()) ) return ST_CURVE;
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
#include "IfcRegister.h"
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "../ifcgeom/IfcGeomRenderStyles.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
class IFC_GEOM_API IfcRepresentationShapeItem {
|
||||
class IfcRepresentationShapeItem {
|
||||
private:
|
||||
gp_GTrsf placement;
|
||||
TopoDS_Shape shape;
|
||||
@@ -46,7 +46,6 @@ 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;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -17,15 +17,14 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCSIPREFIX
|
||||
#define IFCSIPREFIX
|
||||
#ifndef IFCSHAPELIST_H
|
||||
#define IFCSHAPELIST_H
|
||||
|
||||
#include "../ifcparse/IfcParse.h"
|
||||
#include "ifc_parse_api.h"
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
|
||||
namespace IfcParse {
|
||||
IFC_PARSE_API double IfcSIPrefixToValue(IfcSchema::IfcSIPrefix::IfcSIPrefix);
|
||||
IFC_PARSE_API double get_SI_equivalent(IfcSchema::IfcNamedUnit*);
|
||||
namespace IfcGeom {
|
||||
typedef std::pair<gp_GTrsf*,const TopoDS_Shape*> LocationShape;
|
||||
typedef std::vector<LocationShape> ShapeList;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,37 +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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFC_GEOM_API_H
|
||||
#define IFC_GEOM_API_H
|
||||
|
||||
#ifdef IFC_SHARED_BUILD
|
||||
#ifdef _WIN32
|
||||
#ifdef IFC_GEOM_EXPORTS
|
||||
#define IFC_GEOM_API __declspec(dllexport)
|
||||
#else
|
||||
#define IFC_GEOM_API __declspec(dllimport)
|
||||
#endif
|
||||
#else // simply assume *nix + GCC-like compiler
|
||||
#define IFC_GEOM_API __attribute__((visibility("default")))
|
||||
#endif
|
||||
#else
|
||||
#define IFC_GEOM_API
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -27,40 +27,23 @@
|
||||
#include <iostream>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
// NB: Streams are only re-opened as binary when compiled with MSVC currently.
|
||||
// It is unclear what the correct behaviour would be compiled with e.g MinGW
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
#define SET_BINARY_STREAMS
|
||||
#endif
|
||||
|
||||
#ifdef SET_BINARY_STREAMS
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
#endif
|
||||
|
||||
#include <GProp_GProps.hxx>
|
||||
#include <BRepGProp.hxx>
|
||||
#include <Geom_Plane.hxx>
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
|
||||
using namespace boost;
|
||||
|
||||
template <typename T>
|
||||
union data_field {
|
||||
char buffer[sizeof(T)];
|
||||
T value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
T sread(std::istream& s) {
|
||||
data_field<T> data;
|
||||
s.read(data.buffer, sizeof(T));
|
||||
return data.value;
|
||||
char buf[sizeof(T)];
|
||||
s.read(buf, sizeof(T));
|
||||
return *((T*)buf);
|
||||
}
|
||||
|
||||
template <>
|
||||
@@ -71,21 +54,10 @@ std::string sread(std::istream& s) {
|
||||
buf[len] = 0;
|
||||
while (len++ % 4) s.get();
|
||||
std::string str(buf);
|
||||
delete[] buf;
|
||||
delete buf;
|
||||
return str;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string format_json(const T& t) {
|
||||
return boost::lexical_cast<std::string>(t);
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string format_json(const std::string& s) {
|
||||
// NB: No escaping whatsoever. Only use alphanumeric values.
|
||||
return "\"" + s + "\"";
|
||||
}
|
||||
|
||||
static std::streambuf *stdout_orig, *stdout_redir;
|
||||
|
||||
template <typename T>
|
||||
@@ -97,7 +69,7 @@ void swrite(std::ostream& s, T t) {
|
||||
|
||||
template <>
|
||||
void swrite(std::ostream& s, std::string t) {
|
||||
int32_t len = (int32_t)t.size();
|
||||
int32_t len = t.size();
|
||||
swrite(s, len);
|
||||
s.write(t.c_str(), len);
|
||||
while (len++ % 4) s.put(0);
|
||||
@@ -137,8 +109,6 @@ const int32_t NEXT = MORE + 1;
|
||||
const int32_t BYE = NEXT + 1;
|
||||
const int32_t GET_LOG = BYE + 1;
|
||||
const int32_t LOG = GET_LOG + 1;
|
||||
const int32_t DEFLECTION = LOG + 1;
|
||||
const int32_t SETTING = DEFLECTION + 1;
|
||||
|
||||
class Hello : public Command {
|
||||
private:
|
||||
@@ -152,7 +122,7 @@ protected:
|
||||
}
|
||||
public:
|
||||
const std::string& string() { return str; }
|
||||
Hello() : Command(HELLO), str("IfcOpenShell-" IFCOPENSHELL_VERSION "-2") {}
|
||||
Hello() : Command(HELLO), str("IfcOpenShell-" IFCOPENSHELL_VERSION) {}
|
||||
};
|
||||
|
||||
class More : public Command {
|
||||
@@ -186,16 +156,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) {};
|
||||
};
|
||||
@@ -214,25 +184,18 @@ public:
|
||||
WriteLog(const std::string& str) : Command(LOG), str(str) {};
|
||||
};
|
||||
|
||||
class EntityExtension {
|
||||
public:
|
||||
virtual void write_contents(std::ostream& s) = 0;
|
||||
};
|
||||
|
||||
class Entity : public Command {
|
||||
private:
|
||||
const IfcGeom::TriangulationElement<float>* geom;
|
||||
bool append_line_data;
|
||||
EntityExtension* eext_;
|
||||
const IfcGeomObjects::IfcGeomObject* geom;
|
||||
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());
|
||||
swrite(s, geom->name());
|
||||
swrite(s, geom->type());
|
||||
swrite<int32_t>(s, geom->parent_id());
|
||||
const std::vector<float>& m = geom->transformation().matrix().data();
|
||||
const std::vector<float>& m = geom->matrix();
|
||||
const float matrix_array[16] = {
|
||||
m[0], m[3], m[6], m[ 9],
|
||||
m[1], m[4], m[7], m[10],
|
||||
@@ -240,43 +203,19 @@ protected:
|
||||
0, 0, 0, 1
|
||||
};
|
||||
swrite(s, std::string((char*)matrix_array, 16 * sizeof(float)));
|
||||
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;
|
||||
const std::vector<int>& faces = geom->geometry().faces();
|
||||
indices.reserve(faces.size());
|
||||
for (std::vector<int>::const_iterator it = faces.begin(); it != faces.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)));
|
||||
}
|
||||
}
|
||||
swrite<int32_t>(s, geom->mesh().id());
|
||||
swrite(s, std::string((char*)geom->mesh().verts().data(), geom->mesh().verts().size() * sizeof(float)));
|
||||
swrite(s, std::string((char*)geom->mesh().normals().data(), geom->mesh().normals().size() * sizeof(float)));
|
||||
{ std::vector<int32_t> indices;
|
||||
for (std::vector<int>::const_iterator it = geom->mesh().faces().begin(); it != geom->mesh().faces().end(); ++it) {
|
||||
indices.push_back(*it);
|
||||
}
|
||||
swrite(s, std::string((char*) indices.data(), indices.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& mat = *it;
|
||||
if (mat.hasDiffuse()) {
|
||||
const double* color = mat.diffuse();
|
||||
for (std::vector<IfcGeomObjects::Material>::const_iterator it = geom->mesh().materials().begin(); it != geom->mesh().materials().end(); ++it) {
|
||||
const IfcGeomObjects::Material& m = *it;
|
||||
if (m.hasDiffuse()) {
|
||||
const double* color = m.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]));
|
||||
@@ -285,173 +224,44 @@ protected:
|
||||
diffuse_color_array.push_back(0.f);
|
||||
diffuse_color_array.push_back(0.f);
|
||||
}
|
||||
if (mat.hasTransparency()) {
|
||||
diffuse_color_array.push_back(static_cast<float>(1. - mat.transparency()));
|
||||
if (m.hasTransparency()) {
|
||||
diffuse_color_array.push_back(static_cast<float>(1. - m.transparency()));
|
||||
} else {
|
||||
diffuse_color_array.push_back(1.f);
|
||||
}
|
||||
}
|
||||
swrite(s, std::string((char*) diffuse_color_array.data(), diffuse_color_array.size() * sizeof(float))); }
|
||||
{ std::vector<int32_t> material_indices;
|
||||
for (std::vector<int>::const_iterator it = geom->geometry().material_ids().begin(); it != geom->geometry().material_ids().end(); ++it) {
|
||||
for (std::vector<int>::const_iterator it = geom->mesh().material_ids().begin(); it != geom->mesh().material_ids().end(); ++it) {
|
||||
material_indices.push_back(*it);
|
||||
}
|
||||
swrite(s, std::string((char*) material_indices.data(), material_indices.size() * sizeof(int32_t))); }
|
||||
if (eext_) {
|
||||
eext_->write_contents(s);
|
||||
}
|
||||
}
|
||||
public:
|
||||
Entity(const IfcGeom::TriangulationElement<float>* geom, EntityExtension* eext = 0) : Command(ENTITY), geom(geom), append_line_data(false), eext_(eext) {};
|
||||
Entity(const IfcGeomObjects::IfcGeomObject* geom) : Command(ENTITY), geom(geom) {};
|
||||
};
|
||||
|
||||
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) {};
|
||||
};
|
||||
|
||||
class Deflection : public Command {
|
||||
private:
|
||||
double deflection_;
|
||||
protected:
|
||||
void read_content(std::istream& s) {
|
||||
deflection_ = sread<double>(s);
|
||||
int main (int argc, char** argv) {
|
||||
if (sizeof(float) != 4 || sizeof(int32_t) != 4) {
|
||||
return 1;
|
||||
}
|
||||
void write_content(std::ostream& s) {
|
||||
swrite(s, deflection_);
|
||||
}
|
||||
public:
|
||||
Deflection(double d = 0.) : Command(DEFLECTION), deflection_(d) {};
|
||||
double deflection() const { return deflection_; }
|
||||
};
|
||||
|
||||
class Setting : public Command {
|
||||
private:
|
||||
uint32_t id_;
|
||||
uint32_t value_;
|
||||
protected:
|
||||
void read_content(std::istream& s) {
|
||||
id_ = sread<uint32_t>(s);
|
||||
value_ = sread<uint32_t>(s);
|
||||
}
|
||||
void write_content(std::ostream& s) {
|
||||
swrite(s, id_);
|
||||
swrite(s, value_);
|
||||
}
|
||||
public:
|
||||
Setting(uint32_t k = 0, uint32_t v = 0) : Command(DEFLECTION), id_(k), value_(v) {};
|
||||
uint32_t id() const { return id_; }
|
||||
uint32_t value() const { return value_; }
|
||||
};
|
||||
|
||||
static const std::string TOTAL_SURFACE_AREA = "TOTAL_SURFACE_AREA";
|
||||
static const std::string TOTAL_SHAPE_VOLUME = "TOTAL_SHAPE_VOLUME";
|
||||
static const std::string WALKABLE_SURFACE_AREA = "WALKABLE_SURFACE_AREA";
|
||||
static const double MAX_WALKABLE_SURFACE_ANGLE_DEGREES = 15.;
|
||||
|
||||
class QuantityWriter : public EntityExtension {
|
||||
private:
|
||||
const IfcGeom::BRepElement<float>* elem_;
|
||||
public:
|
||||
QuantityWriter(const IfcGeom::BRepElement<float>* elem) :
|
||||
elem_(elem)
|
||||
{}
|
||||
void write_contents(std::ostream& s) {
|
||||
|
||||
double total_surface_area = 0.;
|
||||
double total_shape_volume = 0.;
|
||||
double walkable_surface_area = 0.;
|
||||
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = elem_->geometry().begin(); it != elem_->geometry().end(); ++it) {
|
||||
gp_GTrsf gtrsf = it->Placement();
|
||||
const gp_Trsf& o_trsf = elem_->transformation().data();
|
||||
gtrsf.PreMultiply(o_trsf);
|
||||
const TopoDS_Shape& shp = it->Shape();
|
||||
const TopoDS_Shape moved_shape = IfcGeom::Kernel::apply_transformation(shp, gtrsf);
|
||||
|
||||
{
|
||||
GProp_GProps prop_area;
|
||||
BRepGProp::SurfaceProperties(moved_shape, prop_area);
|
||||
total_surface_area += prop_area.Mass();
|
||||
}
|
||||
|
||||
{
|
||||
GProp_GProps prop_volume;
|
||||
BRepGProp::VolumeProperties(moved_shape, prop_volume);
|
||||
total_shape_volume += prop_volume.Mass();
|
||||
}
|
||||
|
||||
if (elem_->type() == "IfcSpace") {
|
||||
TopExp_Explorer exp(moved_shape, TopAbs_FACE);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
const TopoDS_Face& face = TopoDS::Face(exp.Current());
|
||||
Handle(Geom_Surface) surf = BRep_Tool::Surface(face);
|
||||
|
||||
// Assume we can only walk on planar surfaces
|
||||
if (surf->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BRepGProp_Face prop(face);
|
||||
double u0, u1, v0, v1;
|
||||
BRepTools::UVBounds(face, u0, u1, v0, v1);
|
||||
gp_Pnt p;
|
||||
gp_Vec normal_direction;
|
||||
prop.Normal((u0 + u1) / 2., (v0 + v1) / 2., p, normal_direction);
|
||||
|
||||
gp_Vec normal(0., 0., 0.);
|
||||
if (normal_direction.Magnitude() > ALMOST_ZERO) {
|
||||
normal = gp_Dir(normal_direction.XYZ());
|
||||
}
|
||||
|
||||
if (normal.Angle(gp::DZ()) < (MAX_WALKABLE_SURFACE_ANGLE_DEGREES * M_PI / 180.0)) {
|
||||
GProp_GProps prop_face;
|
||||
BRepGProp::SurfaceProperties(face, prop_face);
|
||||
walkable_surface_area += prop_face.Mass();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Manual JSON formatting is always a bad idea
|
||||
std::ostringstream ss;
|
||||
ss.write("{", 1);
|
||||
ss << format_json(TOTAL_SURFACE_AREA);
|
||||
ss.write(":", 1);
|
||||
ss << format_json(total_surface_area);
|
||||
ss.write(",", 1);
|
||||
ss << format_json(TOTAL_SHAPE_VOLUME);
|
||||
ss.write(":", 1);
|
||||
ss << format_json(total_shape_volume);
|
||||
if (elem_->type() == "IfcSpace") {
|
||||
ss.write(",", 1);
|
||||
ss << format_json(WALKABLE_SURFACE_AREA);
|
||||
ss.write(":", 1);
|
||||
ss << format_json(walkable_surface_area);
|
||||
}
|
||||
ss.write("}", 1);
|
||||
|
||||
// We do a 4-byte manual alignment
|
||||
std::string payload = ss.str();
|
||||
s << payload;
|
||||
if (payload.size() % 4) {
|
||||
s << std::string(4 - (payload.size() % 4), ' ');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main () {
|
||||
// Redirect stdout to this stream, so that involuntary
|
||||
// writes to stdout do not interfere with our protocol.
|
||||
std::ostringstream oss;
|
||||
@@ -466,16 +276,12 @@ int main () {
|
||||
std::cin.setf(std::ios_base::binary);
|
||||
#endif
|
||||
|
||||
double deflection = 1.e-3;
|
||||
bool has_more = false;
|
||||
|
||||
IfcGeom::Iterator<float>* iterator = 0;
|
||||
std::vector< std::pair<uint32_t, uint32_t> > setting_pairs;
|
||||
|
||||
Hello().write(std::cout);
|
||||
|
||||
int exit_code = 0;
|
||||
for (;;) {
|
||||
while (1) {
|
||||
const int32_t msg_type = sread<int32_t>(std::cin);
|
||||
switch (msg_type) {
|
||||
case IFC_MODEL: {
|
||||
@@ -484,22 +290,12 @@ int main () {
|
||||
char* data = new char[len];
|
||||
memcpy(data, m.string().c_str(), len);
|
||||
|
||||
IfcGeom::IteratorSettings settings;
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false);
|
||||
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false);
|
||||
settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, true);
|
||||
// settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, true);
|
||||
|
||||
std::vector< std::pair<uint32_t, uint32_t> >::const_iterator it = setting_pairs.begin();
|
||||
for (; it != setting_pairs.end(); ++it) {
|
||||
settings.set(it->first, it->second != 0);
|
||||
}
|
||||
|
||||
settings.set_deflection_tolerance(deflection);
|
||||
|
||||
iterator = new IfcGeom::Iterator<float>(settings, data, (int)len);
|
||||
has_more = iterator->initialize();
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS, false);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::WELD_VERTICES, false);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::CONVERT_BACK_UNITS, true);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::FORCE_CCW_FACE_ORIENTATION, true);
|
||||
|
||||
has_more = IfcGeomObjects::Init(data, len);
|
||||
More(has_more).write(std::cout);
|
||||
continue;
|
||||
}
|
||||
@@ -509,24 +305,22 @@ int main () {
|
||||
exit_code = 1;
|
||||
break;
|
||||
}
|
||||
const IfcGeom::TriangulationElement<float>* geom = static_cast<const IfcGeom::TriangulationElement<float>*>(iterator->get());
|
||||
QuantityWriter eext(iterator->get_native());
|
||||
Entity(geom, &eext).write(std::cout);
|
||||
const IfcGeomObjects::IfcGeomObject* geom = IfcGeomObjects::Get();
|
||||
Entity(geom).write(std::cout);
|
||||
continue;
|
||||
}
|
||||
case NEXT: {
|
||||
Next n; n.read(std::cin);
|
||||
has_more = iterator->next() != 0;
|
||||
has_more = IfcGeomObjects::Next();
|
||||
if (!has_more) {
|
||||
delete iterator;
|
||||
iterator = 0;
|
||||
IfcGeomObjects::CleanUp();
|
||||
}
|
||||
More(has_more).write(std::cout);
|
||||
continue;
|
||||
}
|
||||
case GET_LOG: {
|
||||
GetLog gl; gl.read(std::cin);
|
||||
WriteLog(iterator->getLog()).write(std::cout);
|
||||
WriteLog(IfcGeomObjects::GetLog()).write(std::cout);
|
||||
continue;
|
||||
}
|
||||
case BYE: {
|
||||
@@ -534,27 +328,7 @@ int main () {
|
||||
exit_code = 0;
|
||||
break;
|
||||
}
|
||||
case DEFLECTION: {
|
||||
Deflection d; d.read(std::cin);
|
||||
if (!iterator) {
|
||||
deflection = d.deflection();
|
||||
continue;
|
||||
} else {
|
||||
exit_code = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
case SETTING: {
|
||||
Setting s; s.read(std::cin);
|
||||
if (!iterator) {
|
||||
setting_pairs.push_back(std::make_pair(s.id(), s.value()));
|
||||
continue;
|
||||
} else {
|
||||
exit_code = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
default:
|
||||
exit_code = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
IfcGeomServer
|
||||
-------------
|
||||
|
||||
A command-line executable intented to be ran as a child process that receives an IFC model from stdin and will send binary geometry information of products found in the IFC file in separate messages on stdout. The advantage over conventional static or dynamic linking is that, in case the IfcOpenShell process would crash (either due to invalid input, heap overflow, bugs, ...), this does not affect the main process. Currently, the only implementation of a consumer for this process is the Java module over at: https://github.com/opensourceBIM/IfcOpenShell-BIMserver-plugin/blob/master/src/org/ifcopenshell/IfcGeomServerClient.java
|
||||
@@ -1,40 +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/>. #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} ${ICU_INCLUDE_DIR}
|
||||
${Boost_INCLUDE_DIRS} ${THREEDS_MAX_SDK_HOME}/include
|
||||
)
|
||||
|
||||
# All recent versions of 3ds Max (2014 and newer) are 64-bit only so assume lib/x64 directory
|
||||
LINK_DIRECTORIES(${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} ${OPENCOLLADA_LIBRARY_DIR}
|
||||
${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS} ${THREEDS_MAX_SDK_HOME}/lib/x64/Release
|
||||
)
|
||||
|
||||
ADD_LIBRARY(IfcMax SHARED IfcMax.h IfcMax.cpp)
|
||||
|
||||
# TODO: find the minimal subset of 3dsmax libraries to reference
|
||||
TARGET_LINK_LIBRARIES(IfcMax ${IFCOPENSHELL_LIBRARIES} Comctl32.lib zlibdll.lib bmm.lib core.lib CustDlg.lib edmodel.lib expr.lib
|
||||
flt.lib geom.lib gfx.lib gup.lib imageViewers.lib ManipSys.lib maxnet.lib Maxscrpt.lib
|
||||
maxutil.lib MenuMan.lib menus.lib mesh.lib MNMath.lib Paramblk2.lib particle.lib Poly.lib RenderUtil.lib
|
||||
tessint.lib viewfile.lib ${OPENCASCADE_LIBRARIES}
|
||||
)
|
||||
|
||||
SET_TARGET_PROPERTIES(IfcMax PROPERTIES SUFFIX ".dli")
|
||||
|
||||
INSTALL(TARGETS IfcMax RUNTIME DESTINATION ${BINDIR})
|
||||
+61
-101
@@ -17,57 +17,49 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include <Max.h>
|
||||
#include <stdmat.h>
|
||||
#include <istdplug.h>
|
||||
|
||||
#include "IfcMax.h"
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
#include "../ifcmax/IfcMax.h"
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
|
||||
static const int NUM_MATERIAL_SLOTS = 24;
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE /*hinstDLL*/, ULONG /*fdwReason*/, LPVOID /*lpvReserved*/) {
|
||||
static int controlsInit = false;
|
||||
int controlsInit = false;
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) {
|
||||
if (!controlsInit) {
|
||||
controlsInit = true;
|
||||
InitCommonControls();
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static class IFCImpClassDesc :public ClassDesc {
|
||||
__declspec( dllexport ) const TCHAR* LibDescription() {
|
||||
return _T("IfcOpenShell IFC Importer");
|
||||
}
|
||||
|
||||
__declspec( dllexport ) int LibNumberClasses() { return 1; }
|
||||
|
||||
static class IFCImpClassDesc:public ClassDesc {
|
||||
public:
|
||||
int IsPublic() { return 1; }
|
||||
void * Create(BOOL /*loading = FALSE*/) { return new IFCImp; }
|
||||
// TODO Delete() function?
|
||||
const TCHAR * ClassName() { return _T("IFCImp"); }
|
||||
SClass_ID SuperClassID() { return SCENE_IMPORT_CLASS_ID; }
|
||||
Class_ID ClassID() { return Class_ID(0x3f230dbf, 0x5b3015c2); }
|
||||
const TCHAR* Category() { return _T("Chrutilities"); }
|
||||
int IsPublic() {return 1;}
|
||||
void * Create(BOOL loading = FALSE) {return new IFCImp;}
|
||||
const TCHAR * ClassName() {return _T("IFCImp");}
|
||||
SClass_ID SuperClassID() {return SCENE_IMPORT_CLASS_ID;}
|
||||
Class_ID ClassID() {return Class_ID(0x3f230dbf, 0x5b3015c2);}
|
||||
const TCHAR* Category() {return _T("Chrutilities");}
|
||||
} IFCImpDesc;
|
||||
|
||||
#define DLLEXPORT __declspec(dllexport)
|
||||
|
||||
extern "C" {
|
||||
|
||||
DLLEXPORT const TCHAR* LibDescription() {
|
||||
return _T("IfcOpenShell IFC Importer");
|
||||
__declspec( dllexport ) ClassDesc* LibClassDesc(int i) {
|
||||
return i == 0 ? &IFCImpDesc : 0;
|
||||
}
|
||||
|
||||
DLLEXPORT int LibNumberClasses() { return 1; }
|
||||
|
||||
DLLEXPORT ClassDesc* LibClassDesc(int i) {
|
||||
return i == 0 ? &IFCImpDesc : 0;
|
||||
__declspec( dllexport ) ULONG LibVersion() {
|
||||
return VERSION_3DSMAX;
|
||||
}
|
||||
|
||||
DLLEXPORT ULONG LibVersion() {
|
||||
return VERSION_3DSMAX;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
int IFCImp::ExtCount() { return 1; }
|
||||
|
||||
const TCHAR * IFCImp::Ext(int n) {
|
||||
@@ -87,7 +79,7 @@ const TCHAR * IFCImp::AuthorName() {
|
||||
}
|
||||
|
||||
const TCHAR * IFCImp::CopyrightMessage() {
|
||||
return _T("Copyright (c) 2011-2016 IfcOpenShell");
|
||||
return _T("Copyight (c) 2011 IfcOpenShell");
|
||||
}
|
||||
|
||||
const TCHAR * IFCImp::OtherMessage1() {
|
||||
@@ -102,14 +94,13 @@ unsigned int IFCImp::Version() {
|
||||
return 12;
|
||||
}
|
||||
|
||||
// TODO Use this in IFCImp::ShowAbout() if/when wanted
|
||||
//static BOOL CALLBACK AboutBoxDlgProc(HWND /*hWnd*/, UINT /*msg*/, WPARAM /*wParam*/, LPARAM /*lParam*/) {
|
||||
// return TRUE;
|
||||
//}
|
||||
static BOOL CALLBACK AboutBoxDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void IFCImp::ShowAbout(HWND /*hWnd*/) {}
|
||||
void IFCImp::ShowAbout(HWND hWnd) {}
|
||||
|
||||
DWORD WINAPI fn(LPVOID /*arg*/) { return 0; }
|
||||
DWORD WINAPI fn(LPVOID arg) { return 0; }
|
||||
|
||||
#if MAX_RELEASE > 14000
|
||||
# define S(x) (TSTR::FromCStr(x.c_str()))
|
||||
@@ -119,9 +110,8 @@ DWORD WINAPI fn(LPVOID /*arg*/) { return 0; }
|
||||
# define S(x) (CStr(x.c_str()))
|
||||
#endif
|
||||
|
||||
static Mtl* FindMaterialByName(MtlBaseLib* library, const std::string& material_name) {
|
||||
TSTR mat_name = S(material_name);
|
||||
const int mat_index = library->FindMtlByName(mat_name);
|
||||
Mtl* FindMaterialByName(MtlBaseLib* library, const std::string& material_name) {
|
||||
const int mat_index = library->FindMtlByName(S(material_name));
|
||||
Mtl* m = 0;
|
||||
if (mat_index != -1) {
|
||||
m = static_cast<Mtl*>((*library)[mat_index]);
|
||||
@@ -129,7 +119,7 @@ static Mtl* FindMaterialByName(MtlBaseLib* library, const std::string& material_
|
||||
return m;
|
||||
}
|
||||
|
||||
static Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& slot, const IfcGeom::Material& material) {
|
||||
Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& slot, const IfcGeomObjects::Material& material) {
|
||||
Mtl* m = FindMaterialByName(library, material.name());
|
||||
if (m == 0) {
|
||||
StdMat2* stdm = NewDefaultStdMat();
|
||||
@@ -143,10 +133,10 @@ static Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface,
|
||||
stdm->SetSpecular(Color(specular[0], specular[1], specular[2]),t);
|
||||
}
|
||||
if (material.hasSpecularity()) {
|
||||
stdm->SetShininess((float)material.specularity(), t);
|
||||
stdm->SetShininess(material.specularity(), t);
|
||||
}
|
||||
if (material.hasTransparency()) {
|
||||
stdm->SetOpacity(1.0f - (float)material.transparency(), t);
|
||||
stdm->SetOpacity(1.0 - material.transparency(), t);
|
||||
}
|
||||
m = stdm;
|
||||
m->SetName(S(material.name()));
|
||||
@@ -158,10 +148,7 @@ static Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface,
|
||||
return m;
|
||||
}
|
||||
|
||||
static Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi_mats, MtlBaseLib* library,
|
||||
Interface* max_interface, int& slot, const std::vector<IfcGeom::Material>& materials,
|
||||
const std::string& object_type, const std::vector<int>& material_ids)
|
||||
{
|
||||
Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi_mats, MtlBaseLib* library, Interface* max_interface, int& slot, const std::vector<IfcGeomObjects::Material>& materials, const std::string& object_type, const std::vector<int>& material_ids) {
|
||||
std::vector<std::string> material_names;
|
||||
bool needs_default = std::find(material_ids.begin(), material_ids.end(), -1) != material_ids.end();
|
||||
if (needs_default) {
|
||||
@@ -194,7 +181,7 @@ static Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi
|
||||
return i->second;
|
||||
}
|
||||
MultiMtl* multi_mat = NewDefaultMultiMtl();
|
||||
multi_mat->SetNumSubMtls((int)material_names.size());
|
||||
multi_mat->SetNumSubMtls(material_names.size());
|
||||
int mtl_id = 0;
|
||||
if (needs_default) {
|
||||
multi_mat->SetSubMtlAndName(mtl_id ++, default_material, default_material->GetName());
|
||||
@@ -211,12 +198,11 @@ static Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi
|
||||
return multi_mat;
|
||||
}
|
||||
|
||||
int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, BOOL /*suppressPrompts*/) {
|
||||
int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, BOOL suppressPrompts) {
|
||||
|
||||
IfcGeom::IteratorSettings settings;
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false);
|
||||
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, true);
|
||||
settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, true);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS,false);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::WELD_VERTICES,true);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::SEW_SHELLS,true);
|
||||
|
||||
#ifdef _UNICODE
|
||||
int fn_buffer_size = WideCharToMultiByte(CP_UTF8, 0, name, -1, 0, 0, 0, 0);
|
||||
@@ -226,9 +212,7 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
|
||||
const char* fn_mb = name;
|
||||
#endif
|
||||
|
||||
IfcGeom::Iterator<float> iterator(settings, fn_mb);
|
||||
delete fn_mb;
|
||||
if (!iterator.initialize()) return false;
|
||||
if ( ! IfcGeomObjects::Init(fn_mb,0,0) ) return false;
|
||||
|
||||
itfc->ProgressStart(_T("Importing file..."), TRUE, fn, NULL);
|
||||
|
||||
@@ -238,56 +222,31 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
|
||||
std::map<std::vector<std::string>, Mtl*> material_cache;
|
||||
|
||||
do{
|
||||
const IfcGeom::TriangulationElement<float>* o = static_cast<const IfcGeom::TriangulationElement<float>*>(iterator.get());
|
||||
|
||||
const IfcGeomObjects::IfcGeomObject* o = IfcGeomObjects::Get();
|
||||
|
||||
TSTR o_type = S(o->type());
|
||||
TSTR o_guid = S(o->guid());
|
||||
|
||||
Mtl *m = ComposeMultiMaterial(material_cache, mats, itfc, slot, o->geometry().materials(), o->type(), o->geometry().material_ids());
|
||||
Mtl *m = ComposeMultiMaterial(material_cache, mats, itfc, slot, o->mesh().materials(), o->type(), o->mesh().material_ids());
|
||||
|
||||
TriObject* tri = CreateNewTriObject();
|
||||
|
||||
const int numVerts = (int)o->geometry().verts().size()/3;
|
||||
const int numVerts = o->mesh().verts().size()/3;
|
||||
tri->mesh.setNumVerts(numVerts);
|
||||
for( int i = 0; i < numVerts; i ++ ) {
|
||||
tri->mesh.setVert(i,o->geometry().verts()[3*i+0],o->geometry().verts()[3*i+1],o->geometry().verts()[3*i+2]);
|
||||
tri->mesh.setVert(i,o->mesh().verts()[3*i+0],o->mesh().verts()[3*i+1],o->mesh().verts()[3*i+2]);
|
||||
}
|
||||
const int numFaces = (int)o->geometry().faces().size()/3;
|
||||
const int numFaces = o->mesh().faces().size()/3;
|
||||
tri->mesh.setNumFaces(numFaces);
|
||||
|
||||
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);
|
||||
}
|
||||
bool needs_default = std::find(o->mesh().material_ids().begin(), o->mesh().material_ids().end(), -1) != o->mesh().material_ids().end();
|
||||
|
||||
for( int i = 0; i < numFaces; i ++ ) {
|
||||
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 = (MtlID)o->geometry().material_ids()[i];
|
||||
if (needs_default) {
|
||||
mtlid ++;
|
||||
}
|
||||
tri->mesh.faces[i].setVerts(o->mesh().faces()[3*i+0],o->mesh().faces()[3*i+1],o->mesh().faces()[3*i+2]);
|
||||
tri->mesh.faces[i].setEdgeVisFlags(o->mesh().edges()[3*i+0],o->mesh().edges()[3*i+1],o->mesh().edges()[3*i+2]);
|
||||
MtlID mtlid = o->mesh().material_ids()[i];
|
||||
if (needs_default) mtlid ++;
|
||||
tri->mesh.faces[i].setMatID(mtlid);
|
||||
}
|
||||
|
||||
@@ -308,16 +267,17 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
|
||||
if (m) {
|
||||
node->GetINode()->SetMtl(m);
|
||||
}
|
||||
const std::vector<float>& matrix_data = o->transformation().matrix().data();
|
||||
node->SetTransform(0,Matrix3 ( Point3(matrix_data[0],matrix_data[1],matrix_data[2]),Point3(matrix_data[3],matrix_data[4],matrix_data[5]),
|
||||
Point3(matrix_data[6],matrix_data[7],matrix_data[8]),Point3(matrix_data[9],matrix_data[10],matrix_data[11]) ));
|
||||
node->SetTransform(0,Matrix3 ( Point3(o->matrix()[0],o->matrix()[1],o->matrix()[2]),Point3(o->matrix()[3],o->matrix()[4],o->matrix()[5]),
|
||||
Point3(o->matrix()[6],o->matrix()[7],o->matrix()[8]),Point3(o->matrix()[9],o->matrix()[10],o->matrix()[11]) ));
|
||||
impitfc->AddNodeToScene(node);
|
||||
|
||||
itfc->ProgressUpdate(iterator.progress(), true, _T(""));
|
||||
itfc->ProgressUpdate(IfcGeomObjects::Progress(),true,_T(""));
|
||||
|
||||
} while (iterator.next());
|
||||
} while ( IfcGeomObjects::Next() );
|
||||
|
||||
IfcGeomObjects::CleanUp();
|
||||
|
||||
itfc->ProgressEnd();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
LIBRARY ifcmax.dli
|
||||
EXPORTS
|
||||
LibDescription @1
|
||||
LibNumberClasses @2
|
||||
LibClassDesc @3
|
||||
LibVersion @4
|
||||
SECTIONS
|
||||
.data READ WRITE
|
||||
+7
-1
@@ -21,6 +21,12 @@
|
||||
#define IFCMAX_H
|
||||
|
||||
#include "Max.h"
|
||||
#include "istdplug.h"
|
||||
#include "stdmat.h"
|
||||
#include "decomp.h"
|
||||
#include "shape.h"
|
||||
#include "splshape.h"
|
||||
#include "dummy.h"
|
||||
|
||||
extern ClassDesc* GetIFCImpDesc();
|
||||
|
||||
@@ -32,7 +38,7 @@ public:
|
||||
const TCHAR * LongDesc(); // = "IfcOpenShell IFC Importer for 3ds Max"
|
||||
const TCHAR * ShortDesc(); // = "Industry Foundation Classes"
|
||||
const TCHAR * AuthorName(); // = "Thomas Krijnen"
|
||||
const TCHAR * CopyrightMessage(); // = "Copyright (c) 2011-2016 IfcOpenShell"
|
||||
const TCHAR * CopyrightMessage(); // = "Copyight (c) 2011 IfcOpenShell"
|
||||
const TCHAR * OtherMessage1(); // = ""
|
||||
const TCHAR * OtherMessage2(); // = ""
|
||||
unsigned int Version(); // = 12
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 materials for use in 3ds Max for several IFC datatypes *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Max.h"
|
||||
#include "stdmat.h"
|
||||
|
||||
StdMat2* GetMaterial(const std::string& s) {
|
||||
StdMat2* mat = NewDefaultStdMat();
|
||||
TimeValue t (-1);
|
||||
mat->SetSpecular(Color(0.2f,0.2f,0.2f),t);
|
||||
mat->SetAmbient(Color(0.1f,0.1f,0.1f),t);
|
||||
mat->SetWire( s == "IfcSpace" || s == "IfcOpeningElement" );
|
||||
if ( s == "IfcSite" ) { mat->SetDiffuse(Color(0.75f,0.8f,0.65f),t); }
|
||||
if ( s == "IfcSlab" ) { mat->SetDiffuse(Color(0.4f,0.4f,0.4f),t); }
|
||||
if ( s == "IfcWallStandardCase" ) { mat->SetDiffuse(Color(0.9f,0.9f,0.9f),t); }
|
||||
if ( s == "IfcWall" ) { mat->SetDiffuse(Color(0.9f,0.9f,0.9f),t); }
|
||||
if ( s == "IfcWindow" ) { mat->SetDiffuse(Color(0.75f,0.8f,0.75f),t); mat->SetSpecular(Color(1.0f,1.0f,1.0f),t);
|
||||
mat->SetAmbient(Color(0.0f,0.0f,0.0f),t); mat->SetShininess(500.0f,t); mat->SetOpacity(0.3f,t); }
|
||||
if ( s == "IfcDoor" ) { mat->SetDiffuse(Color(0.55f,0.3f,0.15f),t); }
|
||||
if ( s == "IfcBeam" ) { mat->SetDiffuse(Color(0.75f,0.7f,0.7f),t); }
|
||||
if ( s == "IfcRailing" ) { mat->SetDiffuse(Color(0.75f,0.7f,0.7f),t); }
|
||||
if ( s == "IfcMember" ) { mat->SetDiffuse(Color(0.75f,0.7f,0.7f),t); }
|
||||
return mat;
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 is a brief example of how IfcOpenShell can be interfaced from within *
|
||||
* a C++ context. The application reads an .ifc file and outputs geometry in *
|
||||
* the Wavefront .obj file format. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <time.h>
|
||||
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
#include "../ifcobj/ObjMaterials.h"
|
||||
|
||||
int main ( int argc, char** argv ) {
|
||||
if ( argc != 2 ) {
|
||||
std::cout << "usage: IfcObj <filename.ifc>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
const std::string fnObj = std::string(argv[1]) + ".obj";
|
||||
const std::string fnMtl = std::string(argv[1]) + ".mtl";
|
||||
ofstream fObj(fnObj.c_str());
|
||||
ofstream fMtl(fnMtl.c_str());
|
||||
if ( ! ( fObj.is_open() && fMtl.is_open() ) ) {
|
||||
std::cout << "[Error] unable to open output file for writing" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS,true);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::WELD_VERTICES,false);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::SEW_SHELLS,true);
|
||||
|
||||
// Stream for log messages, we don't want to interupt our new progress bar...
|
||||
std::stringstream ss;
|
||||
|
||||
// Parse the file supplied in argv[1]. Returns true on succes.
|
||||
if ( ! IfcGeomObjects::Init(argv[1],&std::cout,&ss) ) {
|
||||
std::cout << "[Error] unable to parse .ifc file or no geometrical entities found" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
fObj << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << std::endl;
|
||||
fObj << "mtllib " << fnMtl << std::endl;
|
||||
std::set<std::string> materials;
|
||||
|
||||
time_t start,end;
|
||||
time(&start);
|
||||
int old_progress = -1;
|
||||
std::cout << "Creating geometry..." << std::endl;
|
||||
|
||||
// The functions IfcGeomObjects::Get() and IfcGeomObjects::Next() wrap an iterator of all geometrical entities in the Ifc file.
|
||||
// IfcGeomObjects::Get() returns an IfcGeomObjects::IfcGeomObject (see IfcObjects.h for definition)
|
||||
// IfcGeomObjects::Next() is used to poll whether more geometrical entities are available
|
||||
int vcount_total = 1;
|
||||
do {
|
||||
const IfcGeomObjects::IfcGeomObject* o = IfcGeomObjects::Get();
|
||||
if ( o->type == "IfcSpace" || o->type == "IfcOpeningElement" ) continue;
|
||||
const std::string name = o->name.empty() ? o->guid : o->name;
|
||||
fObj << "g " << name << std::endl;
|
||||
fObj << "s 1" << std::endl;
|
||||
fObj << "usemtl " << o->type << std::endl;
|
||||
materials.insert(o->type);
|
||||
const int vcount = o->mesh->verts.size() / 3;
|
||||
for ( IfcGeomObjects::FltIt it = o->mesh->verts.begin(); it != o->mesh->verts.end(); ) {
|
||||
const double x = *(it++);
|
||||
const double y = *(it++);
|
||||
const double z = *(it++);
|
||||
fObj << "v " << x << " " << y << " " << z << std::endl;
|
||||
}
|
||||
for ( IfcGeomObjects::FltIt it = o->mesh->normals.begin(); it != o->mesh->normals.end(); ) {
|
||||
const double x = *(it++);
|
||||
const double y = *(it++);
|
||||
const double z = *(it++);
|
||||
fObj << "vn " << x << " " << y << " " << z << std::endl;
|
||||
}
|
||||
for ( IfcGeomObjects::IntIt it = o->mesh->faces.begin(); it != o->mesh->faces.end(); ) {
|
||||
const int v1 = *(it++)+vcount_total;
|
||||
const int v2 = *(it++)+vcount_total;
|
||||
const int v3 = *(it++)+vcount_total;
|
||||
fObj << "f " << v1 << "//" << v1 << " " << v2 << "//" << v2 << " " << v3 << "//" << v3 << std::endl;
|
||||
}
|
||||
vcount_total += vcount;
|
||||
|
||||
const int progress = IfcGeomObjects::Progress() / 2;
|
||||
if ( old_progress!= progress ) std::cout << "\r[" << std::string(progress,'#') << std::string(50 - progress,' ') << "]" << std::flush;
|
||||
old_progress = progress;
|
||||
|
||||
} while ( IfcGeomObjects::Next() );
|
||||
std::cout << "\rDone creating geometry " << std::endl;
|
||||
|
||||
// Writes the material settings, defined in Materials.h
|
||||
fMtl << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << std::endl;
|
||||
for( std::set<std::string>::iterator it = materials.begin(); it != materials.end(); ++ it ) {
|
||||
fMtl << GetMaterial(*it);
|
||||
}
|
||||
|
||||
std::string log = ss.str();
|
||||
if ( log.size() ) {
|
||||
std::cout << std::endl << "Log:" << std::endl;
|
||||
std::cout << ss.str();
|
||||
}
|
||||
|
||||
time(&end);
|
||||
int dif = (int) difftime (end,start);
|
||||
printf ("\nConversion took %d seconds\n", dif );
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#include "../IfcObj/Materials.h"
|
||||
|
||||
void InitMaterials() {
|
||||
materials["IFCSITE"] = ObjMaterial("IFCSITE",0.7f,0.8f,0.5f);
|
||||
}
|
||||
@@ -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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file defines materials in .mtl format for several IFC datatypes *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
class ObjMaterial {
|
||||
private:
|
||||
std::string data;
|
||||
public:
|
||||
ObjMaterial(const std::string& name,
|
||||
double Kd_r = 0.7f,double Kd_g = 0.7f,double Kd_b = 0.7f,
|
||||
double Ks_r = 0.2f,double Ks_g = 0.2f,double Ks_b = 0.2f,
|
||||
double Ka_r = 0.1f,double Ka_g = 0.1f,double Ka_b = 0.1f,
|
||||
double Ns = 10.0f, double Tr = 1.0f) {
|
||||
std::stringstream ss;
|
||||
ss << "newmtl " << name << std::endl;
|
||||
ss << "Kd " << Kd_r << " " << Kd_g << " " << Kd_b << std::endl;
|
||||
ss << "Ks " << Ks_r << " " << Ks_g << " " << Ks_b << std::endl;
|
||||
ss << "Ka " << Ka_r << " " << Ka_g << " " << Ka_b << std::endl;
|
||||
ss << "Ns " << Ns << std::endl;
|
||||
ss << "Tr " << Tr << std::endl;
|
||||
ss << "d " << Tr << std::endl;
|
||||
ss << "D " << Tr << std::endl;
|
||||
data = ss.str();
|
||||
}
|
||||
friend ostream& operator<<(ostream& o, const ObjMaterial& m) {o << m.data; return o;}
|
||||
};
|
||||
|
||||
ObjMaterial GetMaterial(const std::string& s) {
|
||||
if ( s == "IfcSite" ) { return ObjMaterial("IfcSite",0.75f,0.8f,0.65f); }
|
||||
if ( s == "IfcSlab" ) { return ObjMaterial("IfcSlab",0.4f,0.4f,0.4f); }
|
||||
if ( s == "IfcWallStandardCase" ) { return ObjMaterial("IfcWallStandardCase",0.9f,0.9f,0.9f); }
|
||||
if ( s == "IfcWall" ) { return ObjMaterial("IfcWall",0.9f,0.9f,0.9f); }
|
||||
if ( s == "IfcWindow" ) { return ObjMaterial("IfcWindow",0.75f,0.8f,0.75f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,500.0f,0.3f); }
|
||||
if ( s == "IfcDoor" ) { return ObjMaterial("IfcDoor",0.55f,0.3f,0.15f); }
|
||||
if ( s == "IfcBeam" ) { return ObjMaterial("IfcBeam",0.75f,0.7f,0.7f); }
|
||||
if ( s == "IfcRailing" ) { return ObjMaterial("IfcRailing",0.65f,0.6f,0.6f); }
|
||||
if ( s == "IfcMember" ) { return ObjMaterial("IfcMember",0.65f,0.6f,0.6f); }
|
||||
if ( s == "IfcPlate" ) { return ObjMaterial("IfcPlate",0.8f,0.8f,0.8f); }
|
||||
return ObjMaterial(s);
|
||||
}
|
||||
@@ -1,72 +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/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
if hasattr(os, 'uname'):
|
||||
platform_system = os.uname()[0].lower()
|
||||
else:
|
||||
platform_system = 'windows'
|
||||
|
||||
if sys.maxsize == (1 << 31) - 1:
|
||||
platform_architecture = '32bit'
|
||||
else:
|
||||
platform_architecture = '64bit'
|
||||
|
||||
python_version_tuple = tuple(sys.version.split(' ')[0].split('.'))
|
||||
|
||||
python_distribution = os.path.join(platform_system,
|
||||
platform_architecture,
|
||||
'python%s.%s' % python_version_tuple[:2])
|
||||
sys.path.append(os.path.abspath(os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
'lib', python_distribution)))
|
||||
|
||||
try:
|
||||
from . import ifcopenshell_wrapper
|
||||
except Exception as e:
|
||||
if int(python_version_tuple[0]) == 2:
|
||||
# Only for py2, as py3 has exception chaining
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
print('-' * 64)
|
||||
raise ImportError("IfcOpenShell not built for '%s'" % python_distribution)
|
||||
|
||||
from . import guid
|
||||
from .file import file
|
||||
from .entity_instance import entity_instance
|
||||
|
||||
def open(fn=None):
|
||||
return file(ifcopenshell_wrapper.open(os.path.abspath(fn))) if fn else file()
|
||||
|
||||
|
||||
def create_entity(type,*args,**kwargs):
|
||||
e = entity_instance(ifcopenshell_wrapper.entity_instance(type))
|
||||
attrs = list(enumerate(args)) + \
|
||||
[(e.wrapped_data.get_argument_index(name), arg) for name, arg in kwargs.items()]
|
||||
for idx, arg in attrs: e[idx] = arg
|
||||
return e
|
||||
|
||||
|
||||
version = ifcopenshell_wrapper.version()
|
||||
schema_identifier = ifcopenshell_wrapper.schema_identifier()
|
||||
get_supertype = ifcopenshell_wrapper.get_supertype
|
||||
@@ -1,138 +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/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
from __future__ import print_function
|
||||
|
||||
import functools
|
||||
import numbers
|
||||
import itertools
|
||||
|
||||
from . import ifcopenshell_wrapper
|
||||
|
||||
try:
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
except ImportError as e:
|
||||
log = type('logger', (object,), {'exception': lambda s: print(s)})
|
||||
|
||||
|
||||
class entity_instance(object):
|
||||
def __init__(self, e):
|
||||
super(entity_instance, self).__setattr__('wrapped_data', e)
|
||||
|
||||
def __getattr__(self, 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 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)
|
||||
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, 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)
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
self[self.wrapped_data.get_argument_index(key)] = value
|
||||
|
||||
def __getitem__(self, key):
|
||||
return entity_instance.wrap_value(self.wrapped_data.get_argument(key))
|
||||
|
||||
def __setitem__(self, idx, 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)
|
||||
|
||||
def id(self):
|
||||
return self.wrapped_data.id()
|
||||
|
||||
def __eq__(self, other):
|
||||
if type(self) != type(other): return False
|
||||
return self.wrapped_data == other.wrapped_data
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.id(), self.wrapped_data.file_pointer()))
|
||||
|
||||
def __dir__(self):
|
||||
return sorted(set(itertools.chain(
|
||||
dir(type(self)),
|
||||
self.wrapped_data.get_attribute_names(),
|
||||
self.wrapped_data.get_inverse_attribute_names()
|
||||
)))
|
||||
|
||||
def get_info(self):
|
||||
_info = {}
|
||||
try:
|
||||
_info["id"] = self.id()
|
||||
_info["type"] = self.is_a()
|
||||
except:
|
||||
log.exception("unhandled exception while getting id / type info on {}".format(self))
|
||||
for i in range(len(self)):
|
||||
try:
|
||||
_info[self.attribute_name(i)] = self[i]
|
||||
except:
|
||||
log.exception("unhandled exception occured setting attribute name for {}".format(self))
|
||||
return _info
|
||||
|
||||
__dict__ = property(get_info)
|
||||
@@ -1,61 +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/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import numbers
|
||||
import functools
|
||||
|
||||
from . import ifcopenshell_wrapper
|
||||
from .entity_instance import entity_instance
|
||||
|
||||
class file(object):
|
||||
def __init__(self, f=None):
|
||||
self.wrapped_data = f or ifcopenshell_wrapper.file(True)
|
||||
def create_entity(self,type,*args,**kwargs):
|
||||
e = entity_instance(ifcopenshell_wrapper.entity_instance(type))
|
||||
attrs = list(enumerate(args)) + \
|
||||
[(e.wrapped_data.get_argument_index(name), arg) for name, arg in kwargs.items()]
|
||||
for idx, arg in attrs: e[idx] = arg
|
||||
self.wrapped_data.add(e.wrapped_data)
|
||||
e.wrapped_data.this.disown()
|
||||
return e
|
||||
def __getattr__(self, attr):
|
||||
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, 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))
|
||||
def by_type(self, type):
|
||||
return [entity_instance(e) for e in self.wrapped_data.by_type(type)]
|
||||
def traverse(self, inst, max_levels=None):
|
||||
if max_levels is None:
|
||||
max_levels = -1
|
||||
return [entity_instance(e) for e in self.wrapped_data.traverse(inst.wrapped_data, max_levels)]
|
||||
def get_inverse(self, inst):
|
||||
return [entity_instance(e) for e in self.wrapped_data.get_inverse(inst.wrapped_data)]
|
||||
def remove(self, inst):
|
||||
return self.wrapped_data.remove(inst.wrapped_data)
|
||||
def __iter__(self):
|
||||
return iter(self[id] for id in self.wrapped_data.entity_names())
|
||||
@@ -1,21 +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/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
from . import occ_utils as utils
|
||||
from .main import *
|
||||
@@ -1,586 +0,0 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import operator
|
||||
import functools
|
||||
|
||||
import OCC.AIS
|
||||
|
||||
from collections import defaultdict, Iterable, OrderedDict
|
||||
|
||||
os.environ['QT_API'] = 'pyqt4'
|
||||
try:
|
||||
from pyqode.qt import QtCore
|
||||
except: pass
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
|
||||
from .code_editor_pane import code_edit
|
||||
|
||||
try: from OCC.Display.pyqt4Display import qtViewer3d
|
||||
except:
|
||||
import OCC.Display
|
||||
|
||||
try: import OCC.Display.backend
|
||||
except: pass
|
||||
|
||||
try: OCC.Display.backend.get_backend("qt-pyqt4")
|
||||
except: OCC.Display.backend.load_backend("qt-pyqt4")
|
||||
|
||||
from OCC.Display.qtDisplay import qtViewer3d
|
||||
|
||||
|
||||
from .main import settings, iterator
|
||||
from .occ_utils import display_shape
|
||||
|
||||
from .. import open as open_ifc_file
|
||||
from .. import get_supertype
|
||||
|
||||
# Depending on Python version and what not there may or may not be a QString
|
||||
try:
|
||||
from PyQt4.QtCore import QString
|
||||
except ImportError:
|
||||
QString = str
|
||||
|
||||
class configuration(object):
|
||||
def __init__(self):
|
||||
try:
|
||||
import ConfigParser
|
||||
Cfg = ConfigParser.RawConfigParser
|
||||
except:
|
||||
import configparser
|
||||
Cfg = configparser.ConfigParser(interpolation=None)
|
||||
|
||||
conf_file = os.path.expanduser(os.path.join("~", ".ifcopenshell", "app", "snippets.conf"))
|
||||
if conf_file.startswith("~"):
|
||||
conf_file = None
|
||||
return
|
||||
|
||||
self.config_encode = lambda s: s.replace("\\", "\\\\").replace("\n", "\n|")
|
||||
self.config_decode = lambda s: s.replace("\n|", "\n").replace("\\\\", "\\")
|
||||
|
||||
if not os.path.exists(os.path.dirname(conf_file)):
|
||||
os.makedirs(os.path.dirname(conf_file))
|
||||
|
||||
if not os.path.exists(conf_file):
|
||||
config = Cfg()
|
||||
config.add_section("snippets")
|
||||
config.set("snippets", "print all wall ids", self.config_encode("""
|
||||
###########################################################################
|
||||
# A simple script that iterates over all walls in the current model #
|
||||
# and prints their Globally unique IDs (GUIDS) to the console window #
|
||||
###########################################################################
|
||||
|
||||
for wall in model.by_type("IfcWall"):
|
||||
print ("wall with global id: "+str(wall.GlobalId))
|
||||
""".lstrip()))
|
||||
|
||||
config.set("snippets", "print properties of current selection", self.config_encode("""
|
||||
###########################################################################
|
||||
# A simple script that iterates over all IfcPropertySets of the currently #
|
||||
# selected object and prints them to the console #
|
||||
###########################################################################
|
||||
|
||||
# check if something is selected
|
||||
if selection:
|
||||
#get the IfcProduct that is stored in the global variable 'selection'
|
||||
obj = selection
|
||||
for relDefinesByProperties in obj.IsDefinedBy:
|
||||
print("[{0}]".format(relDefinesByProperties.RelatingPropertyDefinition.Name))
|
||||
for prop in relDefinesByProperties.RelatingPropertyDefinition.HasProperties:
|
||||
print ("{:<20} :{}".format(prop.Name,prop.NominalValue.wrappedValue))
|
||||
print ("\\n")
|
||||
""".lstrip()))
|
||||
with open(conf_file, 'w') as configfile:
|
||||
config.write(configfile)
|
||||
|
||||
self.config = Cfg()
|
||||
self.config.read(conf_file)
|
||||
|
||||
def options(self, s):
|
||||
return OrderedDict([(k, self.config_decode(self.config.get(s, k))) for k in self.config.options(s)])
|
||||
|
||||
|
||||
class application(QtGui.QApplication):
|
||||
|
||||
"""A pythonOCC, PyQt based IfcOpenShell application
|
||||
with two tree views and a graphical 3d view"""
|
||||
|
||||
class abstract_treeview(QtGui.QTreeWidget):
|
||||
|
||||
"""Base class for the two treeview controls"""
|
||||
|
||||
instanceSelected = QtCore.pyqtSignal([object])
|
||||
instanceVisibilityChanged = QtCore.pyqtSignal([object, int])
|
||||
instanceDisplayModeChanged = QtCore.pyqtSignal([object, int])
|
||||
|
||||
def __init__(self):
|
||||
QtGui.QTreeView.__init__(self)
|
||||
self.setColumnCount(len(self.ATTRIBUTES))
|
||||
self.setHeaderLabels(self.ATTRIBUTES)
|
||||
self.children = defaultdict(list)
|
||||
|
||||
def get_children(self, inst):
|
||||
c = [inst]
|
||||
i = 0
|
||||
while i < len(c):
|
||||
c.extend(self.children[c[i]])
|
||||
i += 1
|
||||
return c
|
||||
|
||||
def contextMenuEvent(self, event):
|
||||
menu = QtGui.QMenu(self)
|
||||
visibility = [menu.addAction("Show"), menu.addAction("Hide")]
|
||||
displaymode = [menu.addAction("Solid"), menu.addAction("Wireframe")]
|
||||
action = menu.exec_(self.mapToGlobal(event.pos()))
|
||||
index = self.selectionModel().currentIndex()
|
||||
inst = index.data(QtCore.Qt.UserRole)
|
||||
if hasattr(inst, 'toPyObject'):
|
||||
inst = inst.toPyObject()
|
||||
if action in visibility:
|
||||
self.instanceVisibilityChanged.emit(inst, visibility.index(action))
|
||||
elif action in displaymode:
|
||||
self.instanceDisplayModeChanged.emit(inst, displaymode.index(action))
|
||||
|
||||
def clicked(self, index):
|
||||
inst = index.data(QtCore.Qt.UserRole)
|
||||
if hasattr(inst, 'toPyObject'):
|
||||
inst = inst.toPyObject()
|
||||
if inst:
|
||||
self.instanceSelected.emit(inst)
|
||||
|
||||
def select(self, product):
|
||||
itm = self.product_to_item.get(product)
|
||||
if itm is None: return
|
||||
self.selectionModel().setCurrentIndex(itm, QtGui.QItemSelectionModel.SelectCurrent | QtGui.QItemSelectionModel.Rows);
|
||||
|
||||
class decomposition_treeview(abstract_treeview):
|
||||
|
||||
"""Treeview with typical IFC decomposition relationships"""
|
||||
|
||||
ATTRIBUTES = ['Entity', 'GlobalId', 'Name']
|
||||
|
||||
def parent(self, instance):
|
||||
if instance.is_a("IfcOpeningElement"):
|
||||
return instance.VoidsElements[0].RelatingBuildingElement
|
||||
if instance.is_a("IfcElement"):
|
||||
fills = instance.FillsVoids
|
||||
if len(fills):
|
||||
return fills[0].RelatingOpeningElement
|
||||
containments = instance.ContainedInStructure
|
||||
if len(containments):
|
||||
return containments[0].RelatingStructure
|
||||
if instance.is_a("IfcObjectDefinition"):
|
||||
decompositions = instance.Decomposes
|
||||
if len(decompositions):
|
||||
return decompositions[0].RelatingObject
|
||||
|
||||
def load_file(self, f, **kwargs):
|
||||
products = list(f.by_type("IfcProduct")) + list(f.by_type("IfcProject"))
|
||||
parents = list(map(self.parent, products))
|
||||
items = {}
|
||||
skipped = 0
|
||||
ATTRS = self.ATTRIBUTES
|
||||
while len(items) + skipped < len(products):
|
||||
for product, parent in zip(products, parents):
|
||||
if parent is None and not product.is_a("IfcProject"):
|
||||
skipped += 1
|
||||
continue
|
||||
if (parent is None or parent in items) and product not in items:
|
||||
sl = []
|
||||
for attr in ATTRS:
|
||||
if attr == 'Entity':
|
||||
sl.append(product.is_a())
|
||||
else:
|
||||
sl.append(getattr(product, attr) or '')
|
||||
itm = items[product] = QtGui.QTreeWidgetItem(items.get(parent, self), sl)
|
||||
itm.setData(0, QtCore.Qt.UserRole, product)
|
||||
self.children[parent].append(product)
|
||||
self.product_to_item = dict(zip(items.keys(), map(self.indexFromItem, items.values())))
|
||||
self.connect(self, QtCore.SIGNAL("clicked(const QModelIndex &)"), self.clicked)
|
||||
self.expandAll()
|
||||
|
||||
class type_treeview(abstract_treeview):
|
||||
|
||||
"""Treeview with typical IFC decomposition relationships"""
|
||||
|
||||
ATTRIBUTES = ['Name']
|
||||
|
||||
def load_file(self, f, **kwargs):
|
||||
products = list(f.by_type("IfcProduct"))
|
||||
types = set(map(lambda i: i.is_a(), products))
|
||||
items = {}
|
||||
for t in types:
|
||||
def add(t):
|
||||
s = get_supertype(t)
|
||||
if s: add(s)
|
||||
s2, t2 = map(QString, (s,t))
|
||||
if t2 not in items:
|
||||
itm = items[t2] = QtGui.QTreeWidgetItem(items.get(s2, self), [t2])
|
||||
itm.setData(0, QtCore.Qt.UserRole, t2)
|
||||
self.children[s2].append(t2)
|
||||
add(t)
|
||||
|
||||
for p in products:
|
||||
t = QString(p.is_a())
|
||||
itm = items[p] = QtGui.QTreeWidgetItem(items.get(t, self), [p.Name or '<no name>'])
|
||||
itm.setData(0, QtCore.Qt.UserRole, t)
|
||||
self.children[t].append(p)
|
||||
|
||||
self.product_to_item = dict(zip(items.keys(), map(self.indexFromItem, items.values())))
|
||||
self.connect(self, QtCore.SIGNAL("clicked(const QModelIndex &)"), self.clicked)
|
||||
self.expandAll()
|
||||
|
||||
|
||||
|
||||
class property_table(QtGui.QWidget):
|
||||
|
||||
def __init__(self):
|
||||
QtGui.QWidget.__init__(self)
|
||||
self.layout= QtGui.QVBoxLayout(self)
|
||||
self.setLayout(self.layout)
|
||||
self.scroll = QtGui.QScrollArea(self)
|
||||
self.layout.addWidget(self.scroll)
|
||||
self.scroll.setWidgetResizable(True)
|
||||
self.scrollContent = QtGui.QWidget(self.scroll)
|
||||
self.scrollLayout = QtGui.QVBoxLayout(self.scrollContent)
|
||||
self.scrollContent.setLayout(self.scrollLayout)
|
||||
self.scroll.setWidget(self.scrollContent)
|
||||
self.prop_dict = {}
|
||||
|
||||
#triggered by selection event in either component of parent
|
||||
def select(self, product):
|
||||
|
||||
# Clear the old contents if any
|
||||
while self.scrollLayout.count():
|
||||
child = self.scrollLayout.takeAt(0)
|
||||
if child is not None:
|
||||
if child.widget() is not None:
|
||||
child.widget().deleteLater()
|
||||
|
||||
self.scroll = QtGui.QScrollArea()
|
||||
self.scroll.setWidgetResizable(True)
|
||||
|
||||
prop_sets = self.prop_dict.get(str(product))
|
||||
|
||||
if prop_sets is not None:
|
||||
for k,v in prop_sets:
|
||||
group_box = QtGui.QGroupBox()
|
||||
|
||||
group_box.setTitle(k)
|
||||
group_layout = QtGui.QVBoxLayout()
|
||||
group_box.setLayout(group_layout)
|
||||
|
||||
for name, value in v.items():
|
||||
prop_name = str(name)
|
||||
|
||||
value_str = value
|
||||
if hasattr(value_str, "wrappedValue"):
|
||||
value_str = value_str.wrappedValue
|
||||
|
||||
if isinstance(value_str, unicode):
|
||||
value_str = value_str.encode('utf-8')
|
||||
else:
|
||||
value_str = str(value_str)
|
||||
|
||||
if hasattr(value, "is_a"):
|
||||
type_str = " <i>(%s)</i>" % value.is_a()
|
||||
else:
|
||||
type_str = ""
|
||||
label = QtGui.QLabel("<b>%s</b>: %s%s" % (prop_name, value_str, type_str))
|
||||
group_layout.addWidget(label)
|
||||
|
||||
group_layout.addStretch()
|
||||
self.scrollLayout.addWidget(group_box)
|
||||
|
||||
self.scrollLayout.addStretch()
|
||||
else:
|
||||
label = QtGui.QLabel("No IfcPropertySets asscociated with selected entity instance" )
|
||||
self.scrollLayout.addWidget(label)
|
||||
|
||||
|
||||
def load_file(self, f, **kwargs):
|
||||
for p in f.by_type("IfcProduct"):
|
||||
propsets = []
|
||||
|
||||
def process_pset(prop_def):
|
||||
if prop_def is not None:
|
||||
prop_set_name = prop_def.Name
|
||||
props = {}
|
||||
if prop_def.is_a("IfcElementQuantity"):
|
||||
for q in prop_def.Quantities:
|
||||
if q.is_a("IfcPhysicalSimpleQuantity"):
|
||||
props[q.Name]=q[3]
|
||||
elif prop_def.is_a("IfcPropertySet"):
|
||||
for prop in prop_def.HasProperties:
|
||||
if prop.is_a("IfcPropertySingleValue"):
|
||||
props[prop.Name]=prop.NominalValue
|
||||
else:
|
||||
# Entity introduced in IFC4
|
||||
# prop_def.is_a("IfcPreDefinedPropertySet"):
|
||||
for prop in range(4, len(prop_def)):
|
||||
props[prop_def.attribute_name(prop)]=prop_def[prop]
|
||||
return prop_set_name, props
|
||||
|
||||
try:
|
||||
for is_def_by in p.IsDefinedBy:
|
||||
if is_def_by.is_a("IfcRelDefinesByProperties"):
|
||||
propsets.append(process_pset(is_def_by.RelatingPropertyDefinition))
|
||||
elif is_def_by.is_a("IfcRelDefinesByType"):
|
||||
type_psets = is_def_by.RelatingType.HasPropertySets
|
||||
if type_psets is None: continue
|
||||
for propset in type_psets:
|
||||
propsets.append(process_pset(propset))
|
||||
except Exception, e:
|
||||
import traceback
|
||||
print("failed to load properties: {}".format(e))
|
||||
traceback.print_exc()
|
||||
|
||||
if len(propsets):
|
||||
self.prop_dict[str(p)] = propsets
|
||||
|
||||
print ("property set dictionary has {} entries".format(len(self.prop_dict)))
|
||||
|
||||
class viewer(qtViewer3d):
|
||||
|
||||
instanceSelected = QtCore.pyqtSignal([object])
|
||||
|
||||
@staticmethod
|
||||
def ais_to_key(ais_handle):
|
||||
def yield_shapes():
|
||||
ais = ais_handle.GetObject()
|
||||
if hasattr(ais, 'Shape'):
|
||||
yield ais.Shape()
|
||||
return
|
||||
shp = OCC.AIS.Handle_AIS_Shape.DownCast(ais_handle)
|
||||
if not shp.IsNull(): yield shp.Shape()
|
||||
return
|
||||
mult = ais_handle
|
||||
if mult.IsNull():
|
||||
shp = OCC.AIS.Handle_AIS_Shape.DownCast(ais_handle)
|
||||
if not shp.IsNull(): yield shp
|
||||
else:
|
||||
li = mult.GetObject().ConnectedTo()
|
||||
for i in range(li.Length()):
|
||||
shp = OCC.AIS.Handle_AIS_Shape.DownCast(li.Value(i+1))
|
||||
if not shp.IsNull(): yield shp
|
||||
return tuple(shp.HashCode(1 << 24) for shp in yield_shapes())
|
||||
|
||||
def __init__(self, widget):
|
||||
qtViewer3d.__init__(self, widget)
|
||||
self.ais_to_product = {}
|
||||
self.product_to_ais = {}
|
||||
self.counter = 0
|
||||
self.window = widget
|
||||
|
||||
def initialize(self):
|
||||
self.InitDriver()
|
||||
self._display.Select = self.HandleSelection
|
||||
|
||||
def load_file(self, f, setting=None):
|
||||
|
||||
if setting is None:
|
||||
setting = settings()
|
||||
setting.set(setting.USE_PYTHON_OPENCASCADE, True)
|
||||
|
||||
v = self._display
|
||||
|
||||
t = {0: time.time()}
|
||||
def update(dt = None):
|
||||
t1 = time.time()
|
||||
if t1 - t[0] > (dt or -1):
|
||||
v.FitAll()
|
||||
v.Repaint()
|
||||
t[0] = t1
|
||||
|
||||
terminate = [False]
|
||||
self.window.window_closed.connect(lambda *args: operator.setitem(terminate, 0, True))
|
||||
|
||||
t0 = time.time()
|
||||
|
||||
it = iterator(setting, f)
|
||||
if not it.initialize():
|
||||
return
|
||||
|
||||
old_progress = -1
|
||||
while True:
|
||||
if terminate[0]: break
|
||||
shape = it.get()
|
||||
product = f[shape.data.id]
|
||||
ais = display_shape(shape, viewer_handle=v)
|
||||
ais.GetObject().SetSelectionPriority(self.counter)
|
||||
self.ais_to_product[self.counter] = product
|
||||
self.product_to_ais[product] = ais
|
||||
self.counter += 1
|
||||
QtGui.QApplication.processEvents()
|
||||
if product.is_a() in {'IfcSpace', 'IfcOpeningElement'}:
|
||||
v.Context.Erase(ais, True)
|
||||
progress = it.progress() // 2
|
||||
if progress > old_progress:
|
||||
print("\r[" + "#" * progress + " " * (50 - progress) + "]", end="")
|
||||
old_progress = progress
|
||||
if not it.next():
|
||||
break
|
||||
update(0.2)
|
||||
|
||||
print("\rOpened file in %.2f seconds%s" % (time.time() - t0, " "*25))
|
||||
|
||||
update()
|
||||
|
||||
def select(self, product):
|
||||
ais = self.product_to_ais.get(product)
|
||||
if ais is None: return
|
||||
v = self._display.Context
|
||||
v.ClearSelected(False)
|
||||
v.SetSelected(ais, True)
|
||||
|
||||
def toggle(self, product_or_products, fn):
|
||||
if not isinstance(product_or_products, Iterable):
|
||||
product_or_products = [product_or_products]
|
||||
aiss = list(filter(None, map(self.product_to_ais.get, product_or_products)))
|
||||
last = len(aiss) - 1
|
||||
for i, ais in enumerate(aiss):
|
||||
fn(ais, i == last)
|
||||
|
||||
def toggle_visibility(self, product_or_products, flag):
|
||||
v = self._display.Context
|
||||
if flag:
|
||||
def visibility(ais, last):
|
||||
v.Erase(ais, last)
|
||||
else:
|
||||
def visibility(ais, last):
|
||||
v.Display(ais, last)
|
||||
self.toggle(product_or_products, visibility)
|
||||
|
||||
def toggle_wireframe(self, product_or_products, flag):
|
||||
v = self._display.Context
|
||||
if flag:
|
||||
def wireframe(ais, last):
|
||||
if v.IsDisplayed(ais):
|
||||
v.SetDisplayMode(ais, 0, last)
|
||||
else:
|
||||
def wireframe(ais, last):
|
||||
if v.IsDisplayed(ais):
|
||||
v.SetDisplayMode(ais, 1, last)
|
||||
self.toggle(product_or_products, wireframe)
|
||||
|
||||
def HandleSelection(self, X, Y):
|
||||
v = self._display.Context
|
||||
v.Select()
|
||||
v.InitSelected()
|
||||
if v.MoreSelected():
|
||||
ais = v.SelectedInteractive()
|
||||
inst = self.ais_to_product[ais.GetObject().SelectionPriority()]
|
||||
self.instanceSelected.emit(inst)
|
||||
|
||||
class window(QtGui.QMainWindow):
|
||||
|
||||
TITLE = "IfcOpenShell IFC viewer"
|
||||
|
||||
window_closed = QtCore.pyqtSignal([])
|
||||
|
||||
def __init__(self):
|
||||
QtGui.QMainWindow.__init__(self)
|
||||
self.setWindowTitle(self.TITLE)
|
||||
self.menu = self.menuBar()
|
||||
self.menus = {}
|
||||
|
||||
def closeEvent(self, *args):
|
||||
self.window_closed.emit()
|
||||
|
||||
def add_menu_item(self, menu, label, callback, icon=None, shortcut=None):
|
||||
m = self.menus.get(menu)
|
||||
if m is None:
|
||||
m = self.menu.addMenu(menu)
|
||||
self.menus[menu] = m
|
||||
|
||||
if icon:
|
||||
a = QtGui.QAction(QtGui.QIcon(icon), label, self)
|
||||
else:
|
||||
a = QtGui.QAction(label, self)
|
||||
|
||||
if shortcut:
|
||||
a.setShortcut(shortcut)
|
||||
|
||||
a.triggered.connect(callback)
|
||||
m.addAction(a)
|
||||
|
||||
|
||||
def makeSelectionHandler(self, component):
|
||||
def handler(inst):
|
||||
for c in self.components:
|
||||
if c != component:
|
||||
c.select(inst)
|
||||
return handler
|
||||
|
||||
def __init__(self, settings=None):
|
||||
QtGui.QApplication.__init__(self, sys.argv)
|
||||
self.window = application.window()
|
||||
self.tree = application.decomposition_treeview()
|
||||
self.tree2 = application.type_treeview()
|
||||
self.propview = self.property_table()
|
||||
self.canvas = application.viewer(self.window)
|
||||
self.tabs = QtGui.QTabWidget()
|
||||
self.window.resize(800, 600)
|
||||
splitter = QtGui.QSplitter(QtCore.Qt.Horizontal)
|
||||
splitter.addWidget(self.tabs)
|
||||
self.tabs.addTab(self.tree, 'Decomposition')
|
||||
self.tabs.addTab(self.tree2, 'Types')
|
||||
self.tabs.addTab(self.propview, "Properties")
|
||||
splitter2 = QtGui.QSplitter(QtCore.Qt.Vertical)
|
||||
splitter2.addWidget(self.canvas)
|
||||
self.editor = code_edit(self.canvas, configuration().options('snippets'))
|
||||
splitter2.addWidget(self.editor)
|
||||
splitter.addWidget(splitter2)
|
||||
splitter.setSizes([200,600])
|
||||
splitter2.setSizes([400,200])
|
||||
self.window.setCentralWidget(splitter)
|
||||
self.canvas.initialize()
|
||||
self.components = [self.tree, self.tree2, self.canvas, self.propview, self.editor]
|
||||
self.files = {}
|
||||
|
||||
self.window.add_menu_item('File', '&Open', self.browse, shortcut='CTRL+O')
|
||||
self.window.add_menu_item('File', '&Close', self.clear, shortcut='CTRL+W')
|
||||
self.window.add_menu_item('File', '&Exit', self.window.close, shortcut='ALT+F4')
|
||||
|
||||
self.tree.instanceSelected.connect(self.makeSelectionHandler(self.tree))
|
||||
self.tree2.instanceSelected.connect(self.makeSelectionHandler(self.tree2))
|
||||
self.canvas.instanceSelected.connect(self.makeSelectionHandler(self.canvas))
|
||||
for t in [self.tree, self.tree2]:
|
||||
t.instanceVisibilityChanged.connect(functools.partial(self.change_visibility, t))
|
||||
t.instanceDisplayModeChanged.connect(functools.partial(self.change_displaymode, t))
|
||||
|
||||
self.settings = settings
|
||||
|
||||
def change_visibility(self, tree, inst, flag):
|
||||
insts = tree.get_children(inst)
|
||||
self.canvas.toggle_visibility(insts, flag)
|
||||
|
||||
def change_displaymode(self, tree, inst, flag):
|
||||
insts = tree.get_children(inst)
|
||||
self.canvas.toggle_wireframe(insts, flag)
|
||||
|
||||
def start(self):
|
||||
self.window.show()
|
||||
sys.exit(self.exec_())
|
||||
|
||||
def browse(self):
|
||||
filename = QtGui.QFileDialog.getOpenFileName(self.window, 'Open file',".","Industry Foundation Classes (*.ifc)")
|
||||
self.load(filename)
|
||||
|
||||
def clear(self):
|
||||
self.canvas._display.Context.RemoveAll()
|
||||
self.tree.clear()
|
||||
self.files.clear()
|
||||
|
||||
def load(self, fn):
|
||||
if fn in self.files: return
|
||||
f = open_ifc_file(str(fn))
|
||||
self.files[fn] = f
|
||||
for c in self.components:
|
||||
c.load_file(f, setting=self.settings)
|
||||
|
||||
if __name__ == "__main__":
|
||||
application().start()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user