Compare commits

..

76 Commits

Author SHA1 Message Date
Thomas Krijnen ba00526e1b Update documentation for filename change 2014-11-05 18:15:27 +01:00
Yorik van Havre e744ba404e Renamed ifc.py to ifcopenshell.py and made it installable 2014-07-29 11:26:49 -03:00
Yorik van Havre eb39eeb30b Added a function to add a new entity without inserting it into the ifc file 2014-07-25 18:03:40 -03:00
Yorik van Havre 286e9d183a Made ifc.py compatible with python2 2014-07-20 12:43:10 -03:00
Thomas Krijnen d4e4ca3a2a Add id() and is_a() functions to entity_instance class Make filename argument to open() function optional 2014-07-19 13:57:47 +02:00
Thomas Krijnen f7adeb9cc1 parse units and precision when a file is opened from the python interface 2014-07-10 16:51:26 +02:00
Thomas Krijnen 607f7bd015 Update CMakeLists for new SWIG module name 2014-07-07 13:52:39 +02:00
Thomas Krijnen bd00d3287e Add missing #include 2014-07-07 13:42:00 +02:00
Thomas Krijnen f674493843 Fixed retrieving attributes derived in subtype Convert argument type enumeration to python string Add ability to iterate over all instances from python 2014-07-04 16:37:21 +02:00
Thomas Krijnen dbc60bedd6 Update install directives in cmake script for wrapper 2014-07-04 14:10:35 +02:00
Thomas Krijnen f7f949b37b Qualify typename rather than 'auto' keyword 2014-07-02 11:53:44 +02:00
Thomas Krijnen 31ca1ac1b5 IfcConvert segfaults #12 2014-07-02 11:53:03 +02:00
Ivano Ras 99d83fce42 Update README.md 2014-06-27 15:11:27 +02:00
Thomas Krijnen 4158424c25 Wrap values of attributes that return entity instances 2014-06-26 15:13:11 +02:00
Thomas Krijnen 1d8616883c Missing file for more idiomatic wrapper wrapper 2014-06-21 19:02:51 +02:00
Thomas Krijnen 8851641d94 Add more idiomatic wrapper wrapper 2014-06-20 14:18:29 +02:00
Thomas Krijnen 0a7b1dd7f4 Merge pull request #13 from iras/patch-1 2014-06-26 16:52:13 +02:00
Thomas Krijnen bb2a983a00 Expose the option to sew shells from connected face sets 2014-06-08 19:32:25 +02:00
Thomas Krijnen 604358b48e Increase precision for writing floats 2014-06-07 14:28:30 +02:00
Thomas Krijnen 68e60f0586 Fix serialization of simple type attributes 2014-06-07 11:47:26 +02:00
Thomas Krijnen e4f141b107 Fixes for inverse attributes 2014-06-03 18:50:29 +02:00
Thomas Krijnen fe172672e9 Add function to retrieve inverse attributes from Python 2014-06-03 16:33:38 +02:00
aothms 69a27e3591 More fixes for parsing files with comments 2014-04-19 09:35:08 +00:00
Thomas Krijnen d91e5d31f6 DISABLE_OPENING_SUBTRACTIONS and DISABLE_OBJECT_PLACEMENT settings for create_shape() / create_brep_data() 2014-04-17 10:50:42 +02:00
aothms a4c3fdfd18 Add support for IfcSweptDiskSolid 2014-04-16 16:51:03 +00:00
aothms b235320d8c Process IfcStyledItems directly applied to an IfcFacetedBrep 2014-04-09 10:57:45 +00:00
aothms e9a3464c26 Account for unit magnitude in matrix translation part when CONVERT_BACK_UNITS is enabled 2014-04-08 07:28:07 +00:00
aothms e08db74706 Fix product's 4x4 matrix on the IfcGeomServer 2014-04-07 17:59:20 +00:00
aothms 3a971d63f8 When writing collada files, postfix geometry instance nodes to make them distinct from their geometry library references 2014-04-07 14:01:16 +00:00
aothms 9a75a1f12d IfcGeomServer, small fixes: refrain from using auto type and restore std::cout rdbuf on exit so implicit flush doesn't segfault 2014-04-06 12:50:51 +00:00
aothms 64f88cbf25 Revamp the 'IfcGeomServer' idea to have an executable rather than a library to interface with. This way IFC processing runs in a separate process from the client application, so that crashes or out of memory issues do not bring down the client application. 2014-04-06 11:16:20 +00:00
aothms ca66aac1c1 Increased verbosity in unsupported entity instances 2014-04-02 15:28:04 +00:00
aothms 9262ea1890 Fixes for parsing files with comments 2014-04-02 15:04:09 +00:00
aothms 81537bee95 Measure conversion time of IfcConvert more faithfully 2014-03-31 14:03:06 +00:00
aothms f9e94f5e01 IfcSurfaceCurveSweptAreaSolid improvements 2014-03-31 14:00:02 +00:00
aothms 691e5766c4 Take into account face location when serializing shape as tesselated faceset. 2014-03-22 21:13:02 +00:00
aothms 0770d91a3c IfcConvert: Handle invalid command line options gracefully and notify user 2014-03-22 13:12:22 +00:00
aothms f3531276c8 No longer accept and silently convert invalid REAL tokens to zero 2014-03-22 13:02:21 +00:00
aothms ffe1eddb00 Handle missing or invalid unit and precision information more gracefully during IfcGeomObject initialization 2014-03-22 12:56:08 +00:00
aothms ba0ba1973a For .obj conversion terminate lines with "\n" rather than std::endl causing a significant speed increase due to longer intermittently flushing the stream 2014-03-22 11:12:50 +00:00
aothms b4e1b15da5 Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface. Add CSG example. 2014-03-22 10:31:51 +00:00
aothms a2b2add58f Add missing header to installation files. Thanks Fred. 2014-03-22 09:22:27 +00:00
aothms c70517f3ba Update build scripts to include TKOffset 2014-03-19 09:47:24 +00:00
aothms d79e28157f Add example file to generate file with IfcCompositeProfileDef and IfcDerivedProfileDef 2014-03-16 13:35:14 +00:00
aothms 4a36816f8f Support for IfcCompositeProfileDef and IfcDerivedProfileDef 2014-03-16 13:34:01 +00:00
aothms 83ac741b59 Add support for IfcGeometricSet IfcRevolvedAreaSolid IfcSurfaceOfLinearExtrusion IfcSurfaceOfRevolution IfcCenterLineProfileDef IfcArbitraryOpenProfileDef 2014-03-15 11:51:23 +00:00
aothms 2fb4be2edc Implementations for more parameterized profile definitions 2014-03-08 17:21:39 +00:00
aothms 868bd6efc8 Add support for ellipses with SemiAxis2 > SemiAxis1 2014-03-03 19:07:39 +00:00
aothms 27e18386d2 Add parameterized profile test files and script to generate them 2014-02-23 11:25:35 +00:00
Thomas Krijnen 562210b862 Fix for products with openings 2014-04-12 23:20:21 +02:00
Yorik van Havre 39b3e03fc5 Added a clean() function to the python wrapper 2014-04-11 15:24:41 -03:00
Thomas Krijnen ba7eec2c0b Fix for empty shape reps 2014-02-26 10:56:22 +01:00
Thomas Krijnen 357357ad78 Initialise string to type map 2014-02-26 10:12:25 +01:00
Yorik van Havre b3bf86e697 Fixes includes for building on Linux 2014-02-24 20:54:48 -03:00
Thomas Krijnen 6b65402611 Merge developments from master into the python_wrapper branch 2014-02-22 11:38:03 +01:00
aothms c7355f03e7 Add Boost as a required dependency in the CMake build file 2012-11-04 11:04:55 +00:00
aothms 5274d73fd0 Add an option to disable the subtraction of IfcOpeningElements from relating building elements to the IfcGeomObject settings 2012-10-19 08:20:43 +00:00
Yorik van Havre 88f6242804 Allowed to enter booleans as arguments, and removed unused line that cause compilation error 2013-12-13 16:22:37 -02:00
Yorik van Havre e936ba8391 Fix for building with gcc 2013-08-02 11:48:26 -03:00
Thomas Krijnen 9136b83223 Accept list of entity instances from Python 2013-07-27 15:55:23 -07:00
Thomas Krijnen 4987753a47 Allow setting enumeration values from python based on string 2013-07-23 23:17:37 -07:00
Thomas Krijnen 871ee13e05 Merge branch 'master' of https://github.com/aothms/IfcOpenShell.git 2013-07-22 20:09:38 -07:00
Yorik van Havre 9c4040345a Merge branch 'master' of https://github.com/aothms/IfcOpenShell 2013-07-22 15:41:10 -03:00
Thomas Krijnen aa4f6c0a7b Merge pull request #1 from yorikvanhavre/master 2013-07-21 14:10:52 -07:00
Yorik van Havre 5471f345d8 Fixed character encoding bug 2013-07-22 15:38:37 -03:00
Yorik van Havre 9679d450fc Fixed string conversion error 2013-07-21 13:41:27 -03:00
Yorik van Havre d8d221dce3 Merge branch 'master' of https://github.com/aothms/IfcOpenShell 2013-07-21 13:31:24 -03:00
Yorik van Havre ed5f879b9f Merge pull request #1 from aothms/master 2012-10-30 04:47:28 -07:00
Thomas Krijnen 3bc3331983 Increase reference count when returning Py_None 2013-07-22 20:06:52 -07:00
Thomas Krijnen 10657416ea Allow optional arguments to be set from Python with None, e.g: ifc_person.set_argument(0, None) 2013-07-20 13:51:06 -07:00
Thomas Krijnen e5abdb7de8 Fix for inline entity instance regression 2013-07-09 09:04:33 -07:00
Thomas Krijnen 7b57c8b5b3 Merge branch 'master' of https://github.com/aothms/IfcOpenShell 2013-07-09 09:01:06 -07:00
Thomas Krijnen 22563f7283 Use a char* instead of a std::string for the std::ofstream constructor 2013-06-21 10:25:05 -07:00
Thomas Krijnen d35e775407 Return empty list when for ifc datatypes not encountered in file 2013-07-09 08:57:09 -07:00
Thomas Krijnen a5684f0996 Correctly take inline entity instances for select types into account in the Python wrapper 2013-06-21 08:49:08 -07:00
Thomas Krijnen 509c34d66a Initial attempt at new python wrapper 2012-10-21 17:54:09 +02:00
208 changed files with 47657 additions and 108669 deletions
-10
View File
@@ -1,10 +0,0 @@
# Dependency and build folders created by the build scripts
/deps*/
/build*/
/install*/
/win/BuildDepsCache*.txt
# IfcExpressParser residue
/src/ifcexpressparser/__pycache__
/src/ifcexpressparser/express_parser.py
# Python test residue
/test/__pycache__
-165
View File
@@ -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.
+80 -118
View File
@@ -1,126 +1,26 @@
IfcOpenShell
============
Open source (LGPL) software library for working with the IFC ([IFC2x3 TC1] and [IFC4]) file format.
[http://ifcopenshell.org](http://ifcopenshell.org)
[http://academy.ifcopenshell.org](http://academy.ifcopenshell.org)
open source (LGPL) software library for working with the IFC file format
Prerequisites
=============
* Git, CMake (2.6 or newer), Visual Studio 2008 or newer with C++ toolset (Windows), or GCC (*nix, Clang untested).
http://IfcOpenShell.org
About this repository
=====================
Dependencies
============
* [Boost](http://www.boost.org/)
* Open Cascade - *optional*, but required for building IfcGeom
([official](http://www.opencascade.org/getocc/download/loadocc/) or [community edition](https://github.com/tpaviot/oce))
For converting IFC representation items into BRep solids and tesselated meshes
* [ICU](http://site.icu-project.org/) - *optional*
For handling code pages and Unicode in the parser
* [OpenCOLLADA](https://github.com/khronosGroup/OpenCOLLADA/) - *optional*
For IfcConvert to be able to write tessellated Collada (.dae) files
* [SWIG](http://www.swig.org/), [Python](https://www.python.org/) libraries - *optional*
For building the IfcOpenShell Python interface and the Blender add-on
* 3ds Max SDK - *optional*
For building the 3ds Max plug-in
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.
The following interactive session illustrates its use:
Compiling on Windows
====================
Users are advised to build IfcOpenShell using the CMake file provided in
the cmake/ folder.
The preferred way to fetch and build this project's dependencies is to use the build scripts
in win/ folder. **See [win/readme.md] for more information**. Instructions in a nutshell
(**assuming Visual Studio 2015 x64 environment variables set**):
> git clone https://github.com/IfcOpenShell/IfcOpenShell.git
> cd IfcOpenShell\win
> build-deps.cmd
> run-cmake.bat
You can now open and build the solution file in Visual Studio:
> ..\build-vs2015-x64\IfcOpenShell.sln
As the scripts default to using the `RelWithDebInfo` configuration, and a freshly created solution by CMake defaults
to `Debug`, make sure to switch the used build configuration. Build the `INSTALL` project (right-click -> Project
Only) to deploy the headers and binaries into a single location if wanted/needed.
Alternatively, one can use the utility batch files to build and install the project easily from the command-line:
> build-ifcopenshell.cmd
> install-ifcopenshell.cmd
Alternatively, the old Visual Studio solution and project files requiring manual work can
be found from the win/sln folder.
Compiling on *nix
=================
Users are advised to build IfcOpenShell using the CMake file provided in
the cmake/ folder. There might be an Open CASCADE package in your operating
system's software repository. If not, you will need to compile Open
CASCADE yourself. See http://opencascade.org.
For building the IfcPython wrapper, SWIG and Python development are
required.
Additionally, on Ubuntu (and possibly other linux flavors) the following steps
install some of the prerequisites:
$ sudo apt-get install git swig cmake gcc g++ libftgl-dev libtbb2 libtbb-dev libboost-all-dev libgl1-mesa-dev libfreetype6-dev
$ git clone https://github.com/tpaviot/oce.git
$ cd oce
$ mkdir build && cd build
$ cmake ..
$ make
$ sudo make install
To build IfcOpenShell please take the following steps:
$ cd /path/to/IfcOpenShell/cmake
$ mkdir build
$ cd build
Optionally:
$ OCC_INCLUDE_PATH="/path/to/OpenCASCADE/include"
$ OCC_LIBRARY_PATH="/path/to/OpenCASCADE/lib"
$ export OCC_INCLUDE_PATH
$ export OCC_LIBRARY_PATH
$ cmake ../
$ make
If all worked out correctly you can now use IfcOpenShell. See the examples below.
Usage examples
==============
**Invoking IfcConvert from the command line**
$ wget ftp://ftp.dds.no/pub/ifc/Munkerud/Munkerud_hus6_BE.zip
$ unzip Munkerud_hus6_BE.zip
$ ./IfcConvert Munkerud_hus6_BE.ifc
$ less Munkerud_hus6_BE.obj
**Using the IfcOpenShell Python interface**
$ wget -O duplex.zip http://projects.buildingsmartalliance.org/files/?artifact_id=4278
$ unzip duplex.zip
$ python
>>> import ifcopenshell
>>> f = ifcopenshell.open("Duplex_A_20110907_optimized.ifc")
>>>
>>> # Accessing entity instances by type:
>>> f.by_type("ifcwall")[:2]
[#91=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FL9r',#1,'Basic Wall:Interior - Partition (92mm Stud):144586',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5198,#18806,'144586'), #92=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FLIE',#1,'Basic Wall:Interior - Partition (92mm Stud):143921',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5206,#18805,'143921')]
>>> wall = _[0]
>>> 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
@@ -142,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'
@@ -155,16 +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")
[win/readme.md]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/win/readme.md "win/readme.md"
[IFC2x3 TC1]: http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc2x3-tc1-release "IFC2x3 TC1"
[IFC4]: http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc4-release "IFC4"
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.
+169 -402
View File
@@ -1,90 +1,17 @@
################################################################################
# #
# 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(HDF5_SUPPORT "Enable HDF5 support (requires HDF5, zlib)" ON)
OPTION(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF)
#TODO OPTION(IFCCONVERT_DOUBLE_PRECISION "IfcConvert: Use double precision floating-point numbers." OFF)
OPTION(USE_IFC4 "Use IFC 4 instead of IFC 2x3 (full rebuild recommended when switching this)" OFF)
OPTION(BUILD_IFCPYTHON "Build IfcPython." ON)
OPTION(BUILD_EXAMPLES "Build example applications." ON)
OPTION(USE_VLD "Use Visual Leak Detector for debugging memory leaks, MSVC-only." OFF)
# TODO QtViewer is deprecated ATM as it uses the 0.4 API
# OPTION(BUILD_QTVIEWER "Build IfcOpenShell Qt GUI Viewer (requires Qt 4 framework)." OFF)
# Create cache entries if absent for environment variables
MACRO(UNIFY_ENVVARS_AND_CACHE VAR)
IF ((NOT DEFINED ${VAR}) AND (NOT "$ENV{${VAR}}" STREQUAL ""))
SET(${VAR} "$ENV{${VAR}}" CACHE STRING "${VAR}" FORCE)
ENDIF()
ENDMACRO()
UNIFY_ENVVARS_AND_CACHE(OCC_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(OCC_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(ICU_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(ICU_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(HDF5_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(HDF5_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(PCRE_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE)
# Find Boost
IF(MSVC)
SET(Boost_USE_STATIC_LIBS ON)
SET(Boost_USE_STATIC_RUNTIME ON)
SET(Boost_USE_MULTITHREADED ON)
ENDIF()
FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options)
MESSAGE(STATUS "Boost include files found in ${Boost_INCLUDE_DIRS}")
MESSAGE(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}")
# Usage:
# SET(SOME_LIRARIES foo bar)
# ADD_DEBUG_VARIANTS(SOME_LIRARIES "${SOME_LIRARIES}" "d")
# "foo bar" -> "optimized foo debug food optimized bar debug bard"
FUNCTION(ADD_DEBUG_VARIANTS NAME LIBRARIES POSTFIX)
SET(LIBRARIES_STR "${LIBRARIES}")
SET(LIBRARIES "")
FOREACH(lib ${LIBRARIES_STR})
SET(LIBRARIES "${LIBRARIES} optimized ${lib}")
SET(LIBRARIES "${LIBRARIES} debug ${lib}${POSTFIX}")
ENDFOREACH()
STRING(STRIP ${LIBRARIES} LIBRARIES) # leading and trailing whitespace cause confusion
SEPARATE_ARGUMENTS(LIBRARIES) # "optimized <lib> debug <lib>" needs to be a list instead of a string
SET(${NAME} ${LIBRARIES} PARENT_SCOPE)
ENDFUNCTION()
# Find Open CASCADE
IF("${OCC_INCLUDE_DIR}" STREQUAL "")
# 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")
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()
@@ -95,369 +22,209 @@ ELSE()
MESSAGE(FATAL_ERROR "Unable to find header files, aborting")
ENDIF()
SET(OPENCASCADE_LIBRARIES
TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO
TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset
)
IF(MSVC)
ADD_DEBUG_VARIANTS(OPENCASCADE_LIBRARIES "${OPENCASCADE_LIBRARIES}" "d")
ENDIF()
IF("${OCC_LIBRARY_DIR}" STREQUAL "")
# 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 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")
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} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64)
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()
IF(UNICODE_SUPPORT)
# Find ICU
IF("${ICU_INCLUDE_DIR}" STREQUAL "")
MESSAGE(STATUS "No ICU include directory specified")
ElSE()
SET(ICU_INCLUDE_DIR "${ICU_INCLUDE_DIR}" CACHE FILEPATH "ICU header files")
ENDIF()
IF("${ICU_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No ICU library directory specified")
ElSE()
SET(ICU_LIBRARY_DIR "${ICU_LIBRARY_DIR}" CACHE FILEPATH "ICU library files")
ENDIF()
FIND_LIBRARY(icu NAMES icuuc icuucd PATHS /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR})
IF(icu)
ADD_DEFINITIONS(-DHAVE_ICU)
MESSAGE(STATUS "ICU libraries found")
# NOTE icudata appears to be icudt on Windows/MSVC and icudata on others
# dl is included to resolve dlopen and friends symbols
IF(MSVC)
SET(ICU_LIBRARIES icuuc icudt)
ADD_DEBUG_VARIANTS(ICU_LIBRARIES "${ICU_LIBRARIES}" "d")
ADD_DEFINITIONS(-DU_STATIC_IMPLEMENTATION) # required for static ICU
ELSE()
SET(ICU_LIBRARIES icuuc icudata dl)
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR "UNICODE_SUPPORT enabled, but unable to find ICU. Disable UNICODE_SUPPORT or fix ICU paths to proceed.")
ENDIF()
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/local/include/opencollada" CACHE FILEPATH "OpenCOLLADA header files")
ElSE()
SET(OPENCOLLADA_INCLUDE_DIR "${OPENCOLLADA_INCLUDE_DIR}" CACHE FILEPATH "OpenCOLLADA header files")
ENDIF()
IF("${OPENCOLLADA_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No OpenCOLLADA library directory specified")
SET(OPENCOLLADA_LIBRARY_DIR "/usr/local/lib/opencollada" CACHE FILEPATH "OpenCOLLADA library files")
ElSE()
SET(OPENCOLLADA_LIBRARY_DIR "${OPENCOLLADA_LIBRARY_DIR}" CACHE FILEPATH "OpenCOLLADA library files")
ENDIF()
SET(OPENCOLLADA_INCLUDE_DIRS "${OPENCOLLADA_INCLUDE_DIR}/COLLADABaseUtils" "${OPENCOLLADA_INCLUDE_DIR}/COLLADAStreamWriter")
FIND_FILE(COLLADASWStreamWriter_h "COLLADASWStreamWriter.h" ${OPENCOLLADA_INCLUDE_DIRS})
IF(COLLADASWStreamWriter_h)
MESSAGE(STATUS "OpenCOLLADA header files found")
ADD_DEFINITIONS(-DWITH_OPENCOLLADA)
SET(OPENCOLLADA_LIBRARIES
GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader
OpenCOLLADAStreamWriter UTF buffer ftoa pcre
)
IF(NOT "${PCRE_LIBRARY_DIR}" STREQUAL "")
SET(OPENCOLLADA_LIBRARY_DIR ${OPENCOLLADA_LIBRARY_DIR} ${PCRE_LIBRARY_DIR})
ENDIF()
IF(MSVC)
ADD_DEBUG_VARIANTS(OPENCOLLADA_LIBRARIES "${OPENCOLLADA_LIBRARIES}" "d")
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find OpenCOLLADA. Disable COLLADA_SUPPORT or fix OpenCOLLADA paths to proceed.")
ENDIF()
IF("$ENV{ICU_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No ICU library directory specified")
ElSE()
SET(ICU_LIBRARY_DIR CACHE FILEPATH "ICU library files")
ENDIF()
if(HDF5_SUPPORT)
IF("${HDF5_INCLUDE_DIR}" STREQUAL "")
MESSAGE(STATUS "No HDF5 include directory specified")
ElSE()
SET(HDF5_INCLUDE_DIR "${HDF5_INCLUDE_DIR}" CACHE FILEPATH "HDF5 header files")
ENDIF()
IF("${HDF5_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No HDF5 library directory specified")
ElSE()
SET(HDF5_LIBRARY_DIR "${HDF5_LIBRARY_DIR}" CACHE FILEPATH "HDF5 library files")
ENDIF()
IF(WIN32)
# An additional lib- prefix is added by HDF5 to denote static libraries
SET(HDF5_LIBRARIES libhdf5_cpp libhdf5 libzlib)
ELSE()
SET(HDF5_LIBRARIES hdf5_cpp hdf5 z szip)
ENDIF()
endif()
FIND_LIBRARY(icu "icuuc" /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR})
# TODO Are these needed on other platforms still or can these be removed for good?
IF (NOT WIN32)
INCLUDE(CheckIncludeFileCXX)
MACRO(CHECK_ADD_OCE_OCC_DEF INCLUDE)
STRING(REPLACE . _ STR ${INCLUDE})
STRING(TOUPPER ${STR} STR)
CHECK_INCLUDE_FILE_CXX("${INCLUDE}" FOUND_${STR})
IF(FOUND_${STR})
ADD_DEFINITIONS(-DOCE_HAVE_${STR})
ADD_DEFINITIONS(-DHAVE_${STR})
ENDIF(FOUND_${STR})
ENDMACRO()
CHECK_ADD_OCE_OCC_DEF(limits)
CHECK_ADD_OCE_OCC_DEF(climits)
CHECK_ADD_OCE_OCC_DEF(limits.h)
CHECK_ADD_OCE_OCC_DEF(fstream)
CHECK_ADD_OCE_OCC_DEF(fstream.h)
CHECK_ADD_OCE_OCC_DEF(iomanip)
CHECK_ADD_OCE_OCC_DEF(iomanip.h)
CHECK_ADD_OCE_OCC_DEF(iostream)
CHECK_ADD_OCE_OCC_DEF(iostream.h)
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()
# NOTE: RelWithDebInfo and Release use O2 (= /Ox /Gl /Gy/ = Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy) by default,
# with the exception with RelWithDebInfo has /Ob1 instead. /Ob2 has been observed to improve the performance
# of IfcConvert significantly.
# TODO Setting of /GL and /LTCG don't seem to apply for static libraries (IfcGeom, IfcParse)
if(ENABLE_BUILD_OPTIMIZATIONS)
if(MSVC)
# C++
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /GL")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
# Linker
# /OPT:REF enables also /OPT:ICF and disables INCREMENTAL
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
# /OPT:NOICF is recommended when /DEBUG is used (http://msdn.microsoft.com/en-us/library/xe4t6fc1.aspx)
set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
else()
#TODO GCC (& Clang?) optimizations
message(STATUS "ENABLE_BUILD_OPTIMIZATIONS not implemented for GCC/non-MSVC compilers.)")
endif()
endif()
SET(CMAKE_BUILD_TYPE "Release")
ENDIF(NOT CMAKE_BUILD_TYPE)
IF(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
FOREACH(flag CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL
CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
IF(${flag} MATCHES "/MD")
STRING(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}")
ENDIF()
IF(${flag} MATCHES "/MDd")
STRING(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}")
ENDIF()
ENDFOREACH()
ElSE()
ADD_DEFINITIONS(-fPIC -Wno-non-virtual-dtor)
ENDIF()
ADD_DEFINITIONS(-D_UNICODE)
ElSE(MSVC)
ADD_DEFINITIONS(-fPIC -Wno-non-virtual-dtor)
ENDIF(MSVC)
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS}
${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${HDF5_INCLUDE_DIR}
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} /usr/inc /usr/local/inc /usr/local/include/oce ${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS})
ADD_LIBRARY(IfcParse STATIC
../src/ifcparse/Ifc2x3.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
)
if(NOT WIN32)
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} /usr/inc /usr/local/inc /usr/local/include/oce)
endif()
function(files_for_ifc_version IFC_VERSION RESULT_NAME)
set(IFC_PARSE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcparse)
set(${RESULT_NAME}
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.h
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}enum.h
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}-latebound.h
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.cpp
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}-latebound.cpp
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}-schema.cpp
PARENT_SCOPE
)
endfunction()
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()
# IfcParse
file(GLOB IFCPARSE_H_FILES ../src/ifcparse/*.h)
file(GLOB IFCPARSE_CPP_FILES ../src/ifcparse/*.cpp)
foreach(IFC_RELEASE ${IFC_RELEASE_NOT_USED})
files_for_ifc_version(${IFC_RELEASE} SOURCE_FILES_NOT_USED)
foreach(SOURCE_FILE ${SOURCE_FILES_NOT_USED})
list(REMOVE_ITEM IFCPARSE_CPP_FILES ${SOURCE_FILE})
list(REMOVE_ITEM IFCPARSE_H_FILES ${SOURCE_FILE})
endforeach()
endforeach()
set(IFCPARSE_FILES ${IFCPARSE_CPP_FILES} ${IFCPARSE_H_FILES})
ADD_LIBRARY(IfcParse STATIC ${IFCPARSE_FILES})
IF(UNICODE_SUPPORT)
TARGET_LINK_LIBRARIES(IfcParse ${ICU_LIBRARIES})
IF(icu)
TARGET_LINK_LIBRARIES(IfcParse icuuc)
ENDIF()
if(HDF5_SUPPORT)
TARGET_LINK_LIBRARIES(IfcParse ${HDF5_LIBRARIES})
endif()
# IfcGeom
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/*.h)
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp)
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES})
ADD_LIBRARY(IfcGeom STATIC ${IFCGEOM_FILES})
TARGET_LINK_LIBRARIES(IfcGeom IfcParse)
LINK_DIRECTORIES(${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} ${OPENCOLLADA_LIBRARY_DIR}
${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS} ${HDF5_LIBRARY_DIR}
LINK_DIRECTORIES (${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} ${OPENCOLLADA_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS})
ADD_EXECUTABLE(IfcConvert
../src/ifcconvert/ColladaSerializer.cpp
../src/ifcconvert/IfcConvert.cpp
../src/ifcconvert/OpenCascadeBasedSerializer.cpp
../src/ifcconvert/WavefrontObjSerializer.cpp
)
if(NOT WIN32)
LINK_DIRECTORIES(${LINK_DIRECTORIES} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64)
endif()
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})
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})
# Make sure cross-referenced symbols between static OCC libraries get
# resolved. Also add thread and rt libraries.
get_filename_component(libTKernelExt ${libTKernel} EXT)
if("${libTKernelExt}" STREQUAL ".a")
find_package(Threads)
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} rt dl)
endif()
ADD_EXECUTABLE(IfcGeomServer
../src/ifcgeomserver/IfcGeomServer.cpp
)
TARGET_LINK_LIBRARIES(IfcConvert IfcParse IfcGeom ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${ICU_LIBRARIES})
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)
# IfcGeomServer
file(GLOB CPP_FILES ../src/ifcgeomserver/*.cpp)
file(GLOB H_FILES ../src/ifcgeomserver/*.h)
set(SOURCE_FILES ${CPP_FILES} ${H_FILES})
ADD_EXECUTABLE(IfcGeomServer ${SOURCE_FILES})
# Build python wrapper using separate CMakeLists.txt
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
TARGET_LINK_LIBRARIES(IfcGeomServer IfcParse IfcGeom ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBRARIES})
# Build IfcParseExamples using separate CMakeLists.txt
ADD_SUBDIRECTORY(../src/examples examples)
IF(BUILD_IFCPYTHON)
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
ENDIF()
# ADD_SUBDIRECTORY(../src/qtviewer qtviewer)
IF(BUILD_EXAMPLES)
ADD_SUBDIRECTORY(../src/examples examples)
ENDIF()
IF(HDF5_SUPPORT)
ADD_SUBDIRECTORY(../src/hdf5_usecases hdf5_usecases)
ENDIF()
if(NOT MSVC)
add_definitions(-std=c++14)
endif()
# CMake installation targets
INSTALL(FILES ${IFCPARSE_H_FILES} DESTINATION include/ifcparse)
INSTALL(FILES ${IFCGEOM_H_FILES} DESTINATION include/ifcgeom)
INSTALL(TARGETS IfcConvert IfcGeomServer DESTINATION bin)
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
../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)
-372
View File
@@ -1,372 +0,0 @@
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
###############################################################################
# #
# This script builds IfcOpenShell and its dependencies #
# #
# Prerequisites for this script to function correctly: #
# * git * bzip2 * tar * c(++) compilers * yacc * autoconf #
# on debian 7.8 these can be obtained with: #
# $ apt-get install git bzip2 bizon autoconf gcc g++ #
# #
###############################################################################
set -e
PROJECT_NAME=IfcOpenShell
OCE_VERSION=0.16
PYTHON_VERSIONS=(2.7.9 3.3.6 3.4.2)
BOOST_VERSION=1.55.0
PCRE_VERSION=8.38
LIBXML_VERSION=2.9.3
CMAKE_VERSION=3.4.1
ICU_VERSION=56.1
# Helper function for coloured printing
BLACK_ON_WHITE="\033[0;30;107m"
RED="\033[31m"
GREEN="\033[32m"
YELLOW="\033[33m"
MAGENTA="\033[35m"
function cecho {
printf "$1$2\033[0m\n"
}
# Set defaults for missing empty environment variables
if [ -z "$IFCOS_NUM_BUILD_PROCS" ]; then
IFCOS_NUM_BUILD_PROCS=$(expr $(sysctl -n hw.ncpu 2> /dev/null || cat /proc/cpuinfo | grep processor | wc -l) + 1)
fi
if [ -z "$TARGET_ARCH" ]; then
TARGET_ARCH="$(uname -m)"
fi
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
CMAKE_DIR="$SCRIPT_DIR/../../cmake/"
if [ -z "$DEPS_DIR" ]; then
DEPS_DIR="$SCRIPT_DIR/../../build/$(uname)/"
[ -d $DEPS_DIR ] || mkdir -p $DEPS_DIR
DEPS_DIR=`readlink -f $DEPS_DIR`
fi
if [ -z "$BUILD_CFG" ]; then
BUILD_CFG="RelWithDebInfo"
fi
if [ -z "$BUILD_TYPE" ]; then
BUILD_TYPE=Build
fi
# Print build configuration information
cecho $BLACK_ON_WHITE "This script fetches and builds $PROJECT_NAME and its dependencies"
echo ""
cecho $GREEN "Script configuration:"
cecho $MAGENTA "* Target Architecture = $TARGET_ARCH"
echo " - Whether 32-bit (i686) or 64-bit (x86_64) will be built."
cecho $MAGENTA "* Dependency Directory = $DEPS_DIR"
echo " - The directory where $PROJECT_NAME dependencies are installed."
cecho $MAGENTA "* Build Config Type = $BUILD_CFG"
echo " - The used build configuration type for the dependencies."
echo " Defaults to RelWithDebInfo if not specified."
if [ "$BUILD_CFG" = "MinSizeRel" ]; then
cecho $RED " WARNING: MinSizeRel build can suffer from a significant performance loss."
fi
cecho $MAGENTA "* IFCOS_NUM_BUILD_PROCS = $IFCOS_NUM_BUILD_PROCS"
echo " - How many compiler processes may be run in parallel."
echo ""
# Check that required tools are in PATH
for cmd in git bunzip2 tar cc c++ autoconf yacc
do
which $cmd > /dev/null || { cecho $RED "Required tool '$cmd' not installed or not added to PATH" ; exit 1 ; }
done
which curl > /dev/null && DOWNLOAD="curl -sLO"
which wget > /dev/null && DOWNLOAD="wget -q --no-check-certificate"
if [ -z "$DOWNLOAD" ]; then
cecho $RED "No download application found, tried: curl, wget"
exit 1
fi
# Create log directory and file
mkdir -p $DEPS_DIR/logs
LOG_FILE=$DEPS_DIR/logs/`date +"%Y%m%d"`.log
BOOST_VERSION_UNDERSCORE=${BOOST_VERSION//./_}
ICU_VERSION_UNDERSCORE=${ICU_VERSION//./_}
CMAKE_VERSION_2=${CMAKE_VERSION:0:3}
OCE_LOCATION=https://github.com/tpaviot/oce/archive/OCE-$OCE_VERSION.tar.gz
BOOST_LOCATION=http://downloads.sourceforge.net/project/boost/boost/$BOOST_VERSION/boost_$BOOST_VERSION_UNDERSCORE.tar.bz2
OPENCOLLADA_LOCATION=https://github.com/KhronosGroup/OpenCOLLADA.git
OPENCOLLADA_COMMIT=f99d59e73e565a41715eaebc00c7664e1ee5e628
# Helper functions
function download {
[ -f $2 ] || $DOWNLOAD $1$2
}
function run_autoconf {
if [ ! -f configure ]; then
pushd . >>$LOG_FILE 2>&1
cd ..
./autogen.sh >>$LOG_FILE 2>&1
popd >>$LOG_FILE 2>&1
fi
../configure $2 --prefix=$DEPS_DIR/install/$1 >>$LOG_FILE 2>&1
}
function run_cmake {
if [ -z "$3" ]; then
P=..
else
P=$3
fi
$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake $P $2 -DCMAKE_BUILD_TYPE=$BUILD_TYPE >>$LOG_FILE 2>&1
}
function run_icu {
PLATFORM=`uname -s`
if [ $PLATFORM == "Darwin" ]; then
PLATFORM=MacOSX
fi
../source/runConfigureICU $PLATFORM $2 --prefix=$DEPS_DIR/install/$1 >>$LOG_FILE 2>&1
}
function git_clone {
[ -d $2 ] || git clone $1 >>$LOG_FILE 2>&1
if [ ! -z "$3" ]; then
cd $2
git checkout $3
cd ..
fi
}
function build_dependency {
if [ -e $DEPS_DIR/install/$1 ]; then
echo "Found existing $1"
return
fi
mkdir -p $DEPS_DIR/build/
cd $DEPS_DIR/build/
printf "\rFetching $1... "
$6 $4 $5 $7
if [ -d $5 ]; then
DEP_NAME=$5
else
DEP_NAME=`tar --exclude="*/*" -tf $5`
[ -z $DEP_NAME ] && DEP_NAME=`tar -tf $5 2> /dev/null | head -n 1 | cut -f1 -d /`
[ -d $DEP_NAME ] || tar -xf $5
fi
cd $DEP_NAME
if [ "$2" != "bjam" ]; then
[ -d build ] && rm -rf build
mkdir build
cd build
printf "\rConfiguring $1..."
run_$2 $1 "$3"
printf "\rBuilding $1... "
make -j$IFCOS_NUM_BUILD_PROCS >>$LOG_FILE 2>&1
printf "\rInstalling $1... "
make install >>$LOG_FILE 2>&1
printf "\rInstalled $1 \n"
else
printf "\rConfiguring $1..."
./bootstrap.sh >>$LOG_FILE 2>&1
printf "\rBuilding $1... "
./b2 $3 >>$LOG_FILE 2>&1
printf "\rInstalling $1... "
cp -R boost $DEPS_DIR/install/boost-$BOOST_VERSION/ >>$LOG_FILE 2>&1
printf "\rInstalled $1 \n"
fi
}
cecho $GREEN "Collecting dependencies:"
# Set compiler flags for 32bit builds on 64bit system
if [ "$TARGET_ARCH" == "i686" ] && [ "$(uname -m)" == "x86_64" ]; then
ADDITIONAL_ARGS="-m32 -arch i386"
fi
if [ "$(uname)" == "Darwin" ]; then
ADDITIONAL_ARGS="-macosx_version_min 10.6 $ADDITIONAL_ARGS"
fi
# If the linker supports GC sections, set it up to reduce binary file size
# -fPIC is required for the shared libraries to work
if man ld 2> /dev/null | grep gc-sections &> /dev/null; then
export CXXFLAGS="$CXXFLAGS -fPIC -fdata-sections -ffunction-sections -fvisibility=hidden -fvisibility-inlines-hidden $ADDITIONAL_ARGS"
export CFLAGS="$CFLAGS -fPIC -fdata-sections -ffunction-sections -fvisibility=hidden $ADDITIONAL_ARGS"
export LDFLAGS="$LDFLAGS -Wl,--gc-sections $ADDITIONAL_ARGS"
export CXXFLAGS_MINIMAL="$CXXFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
export CFLAGS_MINIMAL="$CFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
else
export CXXFLAGS="$CXXFLAGS -fPIC -fvisibility=hidden -fvisibility-inlines-hidden $ADDITIONAL_ARGS"
export CFLAGS="$CFLAGS -fPIC -fvisibility=hidden -fvisibility-inlines-hidden $ADDITIONAL_ARGS"
export LDFLAGS="$LDFLAGS -s -death_code $ADDITIONAL_ARGS"
export CXXFLAGS_MINIMAL="$CXXFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
export CFLAGS_MINIMAL="$CFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
fi
# Some dependencies need a more recent CMake version than most distros provide
build_dependency cmake-$CMAKE_VERSION autoconf "" https://cmake.org/files/v$CMAKE_VERSION_2/ cmake-$CMAKE_VERSION.tar.gz download
# Extract compiler flags from CMake to harmonize settings with other autoconf dependencies
CMAKE_FLAG_EXTRACT_DIR=ifcopenshell_cmake_test_`cat /dev/urandom | env LC_CTYPE=C tr -dc 'a-zA-Z0-9' | head -c 32`
[ -e $CMAKE_FLAG_EXTRACT_DIR ] && rm -rf $CMAKE_FLAG_EXTRACT_DIR
mkdir $CMAKE_FLAG_EXTRACT_DIR
cd $CMAKE_FLAG_EXTRACT_DIR
BUILD_CFG_UPPER=${BUILD_CFG^^}
for FL in C CXX LD; do
echo "
message(\"\${CMAKE_${FL}_FLAGS_${BUILD_CFG_UPPER}}\")
" > CMakeLists.txt
declare ${FL}FLAGS="`$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake . 2>&1 >/dev/null`"
declare ${FL}FLAGS_MINIMAL="`$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake . 2>&1 >/dev/null`"
done
cd ..
rm -rf $CMAKE_FLAG_EXTRACT_DIR
build_dependency pcre-$PCRE_VERSION autoconf "--disable-shared" ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ pcre-$PCRE_VERSION.tar.bz2 download
# An issue exists with swig-1.3 and python >= 3.2
# Therefore, build a recent copy from source
build_dependency swig autoconf "--with-pcre-prefix=$DEPS_DIR/install/pcre-$PCRE_VERSION" https://github.com/swig/swig.git swig git_clone rel-3.0.8
build_dependency oce-$OCE_VERSION cmake "-DOCE_DISABLE_TKSERVICE_FONT=ON -DOCE_TESTING=OFF -DOCE_BUILD_SHARED_LIB=OFF -DOCE_DISABLE_X11=ON -DOCE_VISUALISATION=OFF -DOCE_OCAF=OFF -DOCE_INSTALL_PREFIX=$DEPS_DIR/install/oce-$OCE_VERSION/" https://github.com/tpaviot/oce/archive/ OCE-$OCE_VERSION.tar.gz download
build_dependency libxml2-$LIBXML_VERSION autoconf "--without-python --disable-shared" ftp://xmlsoft.org/libxml2/ libxml2-$LIBXML_VERSION.tar.gz download
build_dependency OpenCOLLADA cmake "
-DLIBXML2_INCLUDE_DIR=$DEPS_DIR/install/libxml2-$LIBXML_VERSION/include/libxml2
-DLIBXML2_LIBRARIES=$DEPS_DIR/install/libxml2-$LIBXML_VERSION/lib/libxml2.a
-DPCRE_INCLUDE_DIR=$DEPS_DIR/install/pcre-$PCRE_VERSION/include
-DPCRE_PCREPOSIX_LIBRARY=$DEPS_DIR/install/pcre-$PCRE_VERSION/lib/libpcreposix.a
-DPCRE_PCRE_LIBRARY=$DEPS_DIR/install/pcre-$PCRE_VERSION/lib/libpcre.a
-DCMAKE_INSTALL_PREFIX=$DEPS_DIR/install/OpenCOLLADA/" https://github.com/KhronosGroup/OpenCOLLADA.git OpenCOLLADA git_clone
# Python should not be built with -fvisibility=hidden, from experience that introduces segfaults
OLD_CXX_FLAGS=$CXXFLAGS
OLD_C_FLAGS=$CFLAGS
OLD_LD_FLAGS=$LDFLAGS
export CXXFLAGS=$CXXFLAGS_MINIMAL
export CFLAGS=$CFLAGS_MINIMAL
export LDFLAGS=$LDFLAGS_MINIMAL
for PYTHON_VERSION in "${PYTHON_VERSIONS[@]}"; do
build_dependency python-$PYTHON_VERSION autoconf "" http://www.python.org/ftp/python/$PYTHON_VERSION/ Python-$PYTHON_VERSION.tgz download
done
export CXXFLAGS=$OLD_CXX_FLAGS
export CFLAGS=$OLD_C_FLAGS
export LDFLAGS=$OLD_LD_FLAGS
if [ "$(uname)" == "Darwin" ] && [ "$1" == "32" ]; then
BOOST_ADDRESS_MODEL="toolset=darwin architecture=x86 target-os=darwin address-model=32"
fi
build_dependency boost-$BOOST_VERSION bjam "--stagedir=$DEPS_DIR/install/boost-$BOOST_VERSION --with-program_options link=static $BOOST_ADDRESS_MODEL stage" http://downloads.sourceforge.net/project/boost/boost/$BOOST_VERSION/ boost_$BOOST_VERSION_UNDERSCORE.tar.bz2 download
build_dependency icu-$ICU_VERSION icu "--enable-static --disable-shared" http://download.icu-project.org/files/icu4c/$ICU_VERSION/ icu4c-${ICU_VERSION_UNDERSCORE}-src.tgz download
cecho $GREEN "Building IfcOpenShell:"
IFCOS_DIR=$DEPS_DIR/build/ifcopenshell
[ -d $IFCOS_DIR ] && rm -rf $IFCOS_DIR
mkdir -p $IFCOS_DIR
cd $IFCOS_DIR
mkdir -p executables
cd executables
printf "\rConfiguring executables..."
run_cmake "" "
-DBOOST_ROOT=$DEPS_DIR/install/boost-$BOOST_VERSION
-DOCC_INCLUDE_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/include/oce
-DOCC_LIBRARY_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/lib
-DOPENCOLLADA_INCLUDE_DIR=$DEPS_DIR/install/OpenCOLLADA/include/opencollada
-DOPENCOLLADA_LIBRARY_DIR=$DEPS_DIR/install/OpenCOLLADA/lib/opencollada
-DICU_INCLUDE_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/include
-DICU_LIBRARY_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/lib
-DPCRE_LIBRARY_DIR=$DEPS_DIR/install/pcre-$PCRE_VERSION/lib
-DBUILD_IFCPYTHON=OFF
" $CMAKE_DIR
printf "\rBuilding executables... "
make -j$IFCOS_NUM_BUILD_PROCS >>$LOG_FILE 2>&1
strip -s IfcConvert IfcGeomServer
cd ..
for PYTHON_VERSION in "${PYTHON_VERSIONS[@]}"; do
printf "\rConfiguring python $PYTHON_VERSION wrapper..."
mkdir -p python-$PYTHON_VERSION
cd python-$PYTHON_VERSION
PYTHON_LIBRARY=`ls $DEPS_DIR/install/python-$PYTHON_VERSION/lib/libpython*.a`
PYTHON_INCLUDE=`ls -d $DEPS_DIR/install/python-$PYTHON_VERSION/include/python*`
PYTHON_EXECUTABLE=$DEPS_DIR/install/python-$PYTHON_VERSION/bin/python
export PYTHON_LIBRARY_BASENAME=`basename $PYTHON_LIBRARY`
run_cmake "" "
-DBOOST_ROOT=$DEPS_DIR/install/boost-$BOOST_VERSION
-DOCC_INCLUDE_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/include/oce
-DOCC_LIBRARY_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/lib
-DOPENCOLLADA_INCLUDE_DIR=$DEPS_DIR/install/OpenCOLLADA/include/opencollada
-DOPENCOLLADA_LIBRARY_DIR=$DEPS_DIR/install/OpenCOLLADA/lib/opencollada
-DICU_INCLUDE_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/include
-DICU_LIBRARY_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/lib
-DPYTHON_LIBRARY=$PYTHON_LIBRARY
-DPYTHON_EXECUTABLE=$PYTHON_EXECUTABLE
-DPYTHON_INCLUDE_DIR=$PYTHON_INCLUDE
-DSWIG_EXECUTABLE=$DEPS_DIR/install/swig/bin/swig
" $CMAKE_DIR
# This still needs to be tested
# test "$(uname)" == "Darwin" && sed -i~ "s/-o/-flat_namespace -undefined suppress -o/" ifcwrap/CMakeFiles/_ifcopenshell_wrapper.dir/link.txt
printf "\rBuilding python $PYTHON_VERSION wrapper... "
make -j$IFCOS_NUM_BUILD_PROCS _ifcopenshell_wrapper >>$LOG_FILE 2>&1
strip -s \
-K PyInit__ifcopenshell_wrapper \
ifcwrap/_ifcopenshell_wrapper.so
done
printf "\rBuilt IfcOpenShell... \n\n"
+2 -21
View File
@@ -1,24 +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)
TARGET_LINK_LIBRARIES (IfcParseExamples IfcParse)
ADD_EXECUTABLE(IfcOpenHouse IfcOpenHouse.cpp)
TARGET_LINK_LIBRARIES(IfcOpenHouse IfcParse IfcGeom ${OPENCASCADE_LIBRARIES})
TARGET_LINK_LIBRARIES (IfcOpenHouse IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKOffset)
+99 -159
View File
@@ -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,31 +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);
IfcEntityList::ptr geometrical_entities(new IfcEntityList);
IfcEntities geometrical_entities(new IfcEntityList());
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::tesselate(shape, 100., geometrical_entities);
file.getSingle<IfcSchema::IfcSite>()->setRepresentation(ground_representation);
file.addEntities(geometrical_entities);
IfcSchema::IfcShapeRepresentation::list::ptr ground_reps = geometrical_entities->as<IfcSchema::IfcShapeRepresentation>();
for (IfcSchema::IfcShapeRepresentation::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);
@@ -295,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,
@@ -320,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.
@@ -342,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
@@ -353,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
@@ -373,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;
@@ -386,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
@@ -403,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;
@@ -450,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);
@@ -494,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.
@@ -539,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
}
+7 -10
View File
@@ -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();
+29 -29
View File
@@ -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);
+16 -16
View File
@@ -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);
+9 -9
View File
@@ -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);
+22 -22
View File
@@ -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);
}
-207
View File
@@ -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;
}
+19 -22
View File
@@ -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
-85
View File
@@ -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;
}
-24
View File
@@ -1,24 +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/>. #
# #
################################################################################
ADD_EXECUTABLE(hdf5_federate federate.cpp)
TARGET_LINK_LIBRARIES(hdf5_federate IfcParse ${ICU_LIBRARIES} ${Boost_LIBRARIES})
ADD_EXECUTABLE(hdf5_lod lod.cpp)
TARGET_LINK_LIBRARIES(hdf5_lod IfcParse IfcGeom ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBRARIES})
-361
View File
@@ -1,361 +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 "../../../src/ifcparse/IfcHdf5File.h"
#include "../../../src/ifcparse/IfcWritableEntity.h"
#include <boost/lexical_cast.hpp>
#include <set>
#include <algorithm>
#include "multifile_instance_locator.h"
#pragma warning(disable:4100)
// A comparison operator that is used to isolate the shared hierarchy
class ifc_inst_cmp {
public:
// For these we simply assume that only a single instance exists
bool operator()(IfcSchema::IfcSite* a, IfcSchema::IfcSite* b) const { return false; }
bool operator()(IfcSchema::IfcProject* a, IfcSchema::IfcProject* b) const { return false; }
bool operator()(IfcSchema::IfcBuilding* a, IfcSchema::IfcBuilding* b) const { return false; }
bool operator()(IfcSchema::IfcPostalAddress* a, IfcSchema::IfcPostalAddress* b) const { return false; }
bool operator()(IfcSchema::IfcUnitAssignment* a, IfcSchema::IfcUnitAssignment* b) const { return false; }
bool operator()(IfcSchema::IfcConversionBasedUnit* a, IfcSchema::IfcConversionBasedUnit* b) const {
return a->Name() < b->Name();
}
bool operator()(IfcSchema::IfcDimensionalExponents* a, IfcSchema::IfcDimensionalExponents* b) const {
// For every attribute (which are all integers) check equality
unsigned num_attrs = a->data().getArgumentCount();
for (unsigned i = 0; i < num_attrs; ++i) {
const int v1 = *a->data().getArgument(i);
const int v2 = *b->data().getArgument(i);
if (v1 != v2) {
return v1 < v2;
}
}
return false;
}
bool operator()(IfcSchema::IfcMeasureWithUnit* a, IfcSchema::IfcMeasureWithUnit* b) const {
// Assume the value component is enough to differentiate
double v1 = *a->ValueComponent()->data().getArgument(0);
double v2 = *b->ValueComponent()->data().getArgument(0);
return v1 < v2;
}
bool operator()(IfcSchema::IfcGeometricRepresentationSubContext* a, IfcSchema::IfcGeometricRepresentationSubContext* b) const {
return a->ContextType() < b->ContextType();
}
bool operator()(IfcSchema::IfcGeometricRepresentationContext* a, IfcSchema::IfcGeometricRepresentationContext* b) const {
return a->ContextType() < b->ContextType();
}
bool operator()(IfcSchema::IfcSIUnit* a, IfcSchema::IfcSIUnit* b) const {
// Assume same units accross files
return a->UnitType() < b->UnitType();
}
bool operator()(IfcSchema::IfcBuildingStorey* a, IfcSchema::IfcBuildingStorey* b) const {
return a->Name() < b->Name();
}
bool operator()(IfcSchema::IfcCartesianPoint* a, IfcSchema::IfcCartesianPoint* b) const {
return a->Coordinates() < b->Coordinates();
}
bool operator()(IfcSchema::IfcDirection* a, IfcSchema::IfcDirection* b) const {
return a->DirectionRatios() < b->DirectionRatios();
}
bool operator()(IfcSchema::IfcAxis2Placement3D* a, IfcSchema::IfcAxis2Placement3D* b) const {
if (a->Location()->Coordinates() != b->Location()->Coordinates()) {
return (*this)(a->Location(), b->Location());
}
if (b->hasAxis()) {
if (!a->hasAxis()) {
return true;
} else {
return (*this)(a->Axis(), b->Axis());
}
}
if (b->hasRefDirection()) {
if (!a->hasRefDirection()) {
return true;
} else {
return (*this)(a->RefDirection(), b->RefDirection());
}
}
return false;
}
bool operator()(IfcSchema::IfcLocalPlacement* a, IfcSchema::IfcLocalPlacement* b) const {
if (b->hasPlacementRelTo()) {
if (!a->hasPlacementRelTo()) {
return true;
} else {
return (*this)(a->PlacementRelTo(), b->PlacementRelTo());
}
}
return (*this)(a->RelativePlacement(), b->RelativePlacement());
}
bool operator()(IfcUtil::IfcBaseClass* a, IfcUtil::IfcBaseClass* b) const {
if (a->declaration().type() != b->declaration().type()) {
return a->declaration().type() < b->declaration().type();
// throw std::runtime_error("Types not matching");
}
if (a->declaration().type() == IfcSchema::Type::IfcSite) { return (*this)((IfcSchema::IfcSite*) a, (IfcSchema::IfcSite*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcConversionBasedUnit) { return (*this)((IfcSchema::IfcConversionBasedUnit*) a, (IfcSchema::IfcConversionBasedUnit*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcDimensionalExponents) { return (*this)((IfcSchema::IfcDimensionalExponents*) a, (IfcSchema::IfcDimensionalExponents*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcMeasureWithUnit) { return (*this)((IfcSchema::IfcMeasureWithUnit*) a, (IfcSchema::IfcMeasureWithUnit*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcProject) { return (*this)((IfcSchema::IfcProject*) a, (IfcSchema::IfcProject*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcBuilding) { return (*this)((IfcSchema::IfcBuilding*) a, (IfcSchema::IfcBuilding*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcPostalAddress) { return (*this)((IfcSchema::IfcPostalAddress*) a, (IfcSchema::IfcPostalAddress*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcUnitAssignment) { return (*this)((IfcSchema::IfcUnitAssignment*) a, (IfcSchema::IfcUnitAssignment*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcGeometricRepresentationSubContext) { return (*this)((IfcSchema::IfcGeometricRepresentationSubContext*) a, (IfcSchema::IfcGeometricRepresentationSubContext*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcGeometricRepresentationContext) { return (*this)((IfcSchema::IfcGeometricRepresentationContext*) a, (IfcSchema::IfcGeometricRepresentationContext*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcSIUnit) { return (*this)((IfcSchema::IfcSIUnit*) a, (IfcSchema::IfcSIUnit*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcBuildingStorey) { return (*this)((IfcSchema::IfcBuildingStorey*) a, (IfcSchema::IfcBuildingStorey*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcCartesianPoint) { return (*this)((IfcSchema::IfcCartesianPoint*) a, (IfcSchema::IfcCartesianPoint*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcDirection) { return (*this)((IfcSchema::IfcDirection*) a, (IfcSchema::IfcDirection*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcAxis2Placement3D) { return (*this)((IfcSchema::IfcAxis2Placement3D*) a, (IfcSchema::IfcAxis2Placement3D*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcLocalPlacement) { return (*this)((IfcSchema::IfcLocalPlacement*) a, (IfcSchema::IfcLocalPlacement*) b); }
// Should these be removed if an owner history is created manually?
if (a->declaration().type() == IfcSchema::Type::IfcPerson) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
if (a->declaration().type() == IfcSchema::Type::IfcOrganization) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
if (a->declaration().type() == IfcSchema::Type::IfcPersonAndOrganization) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
if (a->declaration().type() == IfcSchema::Type::IfcOwnerHistory) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
if (a->declaration().type() == IfcSchema::Type::IfcApplication) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
std::cerr << "Unexpected type: " + IfcSchema::Type::ToString(a->declaration().type()) << std::endl;
throw std::runtime_error("Unexpected type: " + IfcSchema::Type::ToString(a->declaration().type()));
}
};
// Usage: hdf5_federate Office_A_20110811_optimized.ifc Office_S_20110811_optimized.ifc Office_MEP_20110811_optimized.ifc
int main(int argc, char** argv) {
// A set of datatypes for the shared hierarchy
std::set<IfcSchema::Type::Enum> shared {
IfcSchema::Type::IfcSite,
IfcSchema::Type::IfcConversionBasedUnit,
IfcSchema::Type::IfcDimensionalExponents,
IfcSchema::Type::IfcMeasureWithUnit,
IfcSchema::Type::IfcProject,
IfcSchema::Type::IfcBuilding,
IfcSchema::Type::IfcPostalAddress,
IfcSchema::Type::IfcUnitAssignment,
IfcSchema::Type::IfcGeometricRepresentationSubContext,
IfcSchema::Type::IfcGeometricRepresentationContext,
IfcSchema::Type::IfcSIUnit,
IfcSchema::Type::IfcBuildingStorey
};
// Open the set of input files
std::vector<IfcParse::IfcFile*> files;
for (int i = 1; i < argc; ++i) {
files.push_back(new IfcParse::IfcFile());
files.back()->Init(argv[i]);
}
// Detect shared instances
std::set<IfcUtil::IfcBaseClass*> shared_instances;
for (auto& ty : shared) {
std::cout << IfcSchema::Type::ToString(ty) << std::endl;
for (auto& file : files) {
IfcEntityList::ptr insts = file->entitiesByType(ty);
std::vector<IfcUtil::IfcBaseClass*> no_subtypes;
std::copy_if(insts->begin(), insts->end(), std::back_inserter(no_subtypes), [ty](IfcUtil::IfcBaseClass* inst) {
return inst->declaration().type() == ty;
});
std::set<IfcUtil::IfcBaseClass*, ifc_inst_cmp> insts_unique(no_subtypes.begin(), no_subtypes.end());
if (insts_unique.size() != no_subtypes.size()) {
throw std::runtime_error("Non-unique instances encountered within file");
}
shared_instances.insert(insts_unique.begin(), insts_unique.end());
}
}
// Follow forward references for shared instances
std::set<IfcUtil::IfcBaseClass*> shared_instances_and_refs;
for (auto& inst : shared_instances) {
IfcEntityList::ptr insts = inst->data().file->traverse(inst);
// Filter out simple types
std::vector<IfcUtil::IfcBaseClass*> insts_without_types;
std::copy_if(insts->begin(), insts->end(), std::back_inserter(insts_without_types), [](IfcUtil::IfcBaseClass* inst) {
return inst->declaration().as_entity() != nullptr;
});
shared_instances_and_refs.insert(insts_without_types.begin(), insts_without_types.end());
}
time_t now_;
time(&now_);
int now = (int)now_;
// Create a novel ownerhistory for the shared hierarchy
IfcSchema::IfcPerson* person = new IfcSchema::IfcPerson(std::string("tfk"), std::string("Krijnen"), std::string("Thomas"), boost::none, boost::none, boost::none, boost::none, boost::none);
IfcSchema::IfcOrganization* org = new IfcSchema::IfcOrganization(std::string("TU/e"), "Eindhoven University of Technology", boost::none, boost::none, boost::none);
IfcSchema::IfcPersonAndOrganization* pando = new IfcSchema::IfcPersonAndOrganization(person, org, boost::none);
IfcSchema::IfcApplication* appl = new IfcSchema::IfcApplication(org, "v1", "IfcOpenShell-HDF5", "IfcOpenShell-HDF5");
IfcSchema::IfcOwnerHistory* owner_history = new IfcSchema::IfcOwnerHistory(pando, appl, IfcSchema::IfcStateEnum::IfcState_READONLY, IfcSchema::IfcChangeActionEnum::IfcChangeAction_ADDED, now, pando, appl, now);
std::vector<IfcUtil::IfcBaseClass*> replacements{ person, org, pando, appl, owner_history};
std::vector<IfcUtil::IfcBaseClass*> shared_instances_and_refs_vector(shared_instances_and_refs.begin(), shared_instances_and_refs.end());
IfcParse::IfcFile temp;
for (int i = 0; i < 0x1000001; ++i) temp.FreshId();
std::for_each(replacements.begin(), replacements.end(), [&shared_instances_and_refs_vector, &temp](IfcUtil::IfcBaseClass* new_inst) {
temp.addEntity(new_inst);
shared_instances_and_refs_vector.erase(
std::remove_if(shared_instances_and_refs_vector.begin(), shared_instances_and_refs_vector.end(), [new_inst](IfcUtil::IfcBaseClass* orig_inst) {
return orig_inst->declaration().type() == new_inst->declaration().type();
}),
shared_instances_and_refs_vector.end()
);
shared_instances_and_refs_vector.push_back(new_inst);
});
shared_instances_and_refs.clear();
shared_instances_and_refs.insert(shared_instances_and_refs_vector.begin(), shared_instances_and_refs_vector.end());
// Assign the new ownerhistory to rooted elements in the shared hierarchy
std::for_each(shared_instances_and_refs.begin(), shared_instances_and_refs.end(), [owner_history](IfcUtil::IfcBaseClass* inst) {
const IfcParse::entity* e = inst->declaration().as_entity();
if (e) {
auto attributes = e->all_attributes();
int index = 0;
std::for_each(attributes.begin(), attributes.end(), [&index, inst, owner_history](const IfcParse::entity::attribute* attr) {
const IfcParse::named_type* nt = attr->type_of_attribute()->as_named_type();
if (nt) {
const IfcParse::entity* e2 = nt->declared_type()->as_entity();
if (e2 && e2->type() == IfcSchema::Type::IfcOwnerHistory) {
IfcWrite::IfcWritableEntity* writable = new IfcWrite::IfcWritableEntity(&inst->data());
writable->setArgument(index, owner_history);
inst->data(writable);
}
}
index++;
});
}
});
std::set<IfcUtil::IfcBaseClass*, ifc_inst_cmp> shared_instances_and_refs_unique(shared_instances_and_refs.begin(), shared_instances_and_refs.end());
// Serialize models into different groups
IfcParse::Hdf5Settings settings;
settings.profile() = IfcParse::Hdf5Settings::standard_referenced;
settings.compress() = true;
settings.chunk_size() = 1024;
std::vector<std::string> names;
std::vector<std::pair<std::string::const_iterator, std::string::const_iterator>> fixes;
std::string common_prefix, common_postfix;
for (int i = 1; i < argc; ++i) {
names.push_back(argv[i]);
fixes.push_back({ names.back().begin(), names.back().end() - 1 });
}
while (true) {
std::vector<char> chars;
std::transform(fixes.begin(), fixes.end(), std::back_inserter(chars), [](auto& pair) {
if (pair.first == pair.second) return '\0';
return (*pair.first++);
});
auto pred = std::bind(std::equal_to<char>(), std::placeholders::_1, chars.front());
if (chars.front() != 0 && std::all_of(chars.begin()+1, chars.end(), pred)) {
common_prefix.push_back(chars.front());
} else {
break;
}
}
while (true) {
std::vector<char> chars;
std::transform(fixes.begin(), fixes.end(), std::back_inserter(chars), [](auto& pair) {
if (pair.first == pair.second) return '\0';
return (*pair.second--);
});
auto pred = std::bind(std::equal_to<char>(), std::placeholders::_1, chars.front());
if (chars.front() != 0 && std::all_of(chars.begin() + 1, chars.end(), pred)) {
common_postfix.insert(common_postfix.begin(), chars.front());
} else {
break;
}
}
H5::H5File file(common_prefix + common_postfix + ".hdf", H5F_ACC_TRUNC);
H5::Group group1 = file.createGroup("population");
IfcParse::IfcHdf5File ifc_hdf5(file, get_schema(), settings);
IfcParse::IfcSpfHeader header;
header.set_default();
IfcParse::instance_enumerator shared_insts_enum(&header, shared_instances_and_refs_unique.begin(), shared_instances_and_refs_unique.end());
multifile_instance_locator* locator = new multifile_instance_locator(file, group1, [&shared_instances_and_refs_unique](IfcUtil::IfcBaseClass* inst) {
auto it = shared_instances_and_refs_unique.find(inst);
if (it == shared_instances_and_refs_unique.end()) {
return inst;
} else {
return *it;
}
}, shared_instances_and_refs_unique.begin(), shared_instances_and_refs_unique.end());
ifc_hdf5.write_schema();
ifc_hdf5.write_population(group1, shared_insts_enum, locator);
int n = 0;
for (auto f : files) {
auto filename = argv[n++ + 1];
H5::Group discipline_group = file.createGroup(filename);
H5::Group child_group = discipline_group.createGroup("population");
locator->next(filename, child_group, f);
IfcParse::instance_enumerator inst_enum(&f->header(), locator->full_begin(), locator->full_end());
ifc_hdf5.write_population(child_group, inst_enum, locator);
}
return 0;
}
-472
View File
@@ -1,472 +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 "../../../src/ifcparse/IfcHdf5File.h"
#include "../../../src/ifcgeom/IfcGeom.h"
#include "../../../src/ifcparse/IfcWritableEntity.h"
#include <Bnd_Box.hxx>
#include <BRepBndLib.hxx>
#include <BRep_Builder.hxx>
#include <TopoDS_Compound.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepBuilderAPI_GTransform.hxx>
#include <algorithm>
#include "multifile_instance_locator.h"
void generate_bounding_boxes(IfcParse::IfcFile& f, const std::string& fn) {
IfcGeom::Kernel kernel;
auto unit_factor = kernel.initializeUnits(*f.entitiesByType<IfcSchema::IfcUnitAssignment>()->begin());
IfcGeom::IteratorSettings settings;
settings.convert_back_units() = true;
settings.disable_triangulation() = true;
settings.disable_opening_subtractions() = true;
IfcSchema::IfcProductDefinitionShape::list::ptr defs_ = f.entitiesByType<IfcSchema::IfcProductDefinitionShape>();
std::vector<IfcSchema::IfcProductDefinitionShape*> defs(defs_->begin(), defs_->end());
// Make sure to sort by id to have new definitions lining up in the same order
std::sort(defs.begin(), defs.end(), [](IfcSchema::IfcProductDefinitionShape* a, IfcSchema::IfcProductDefinitionShape* b) {
return a->data().id() < b->data().id();
});
std::ofstream str(fn.c_str(), std::ios_base::binary);
int N = defs.size(), n = 0;
std::cerr << "boxes:" << std::endl;
// In newer versions of IfcOpenShell this is a method Kernel::apply_transformation()
auto apply_transformation = [](const TopoDS_Shape& s, const gp_GTrsf& gt) {
if (gt.Form() == gp_Other) {
return BRepBuilderAPI_GTransform(s, gt, true).Shape();
}
gp_Trsf t = gt.Trsf();
if (t.Form() == gp_Identity) {
return s;
} else {
/// @todo set to 1. and exactly 1. or use epsilon?
if (t.ScaleFactor() != 1.) {
return BRepBuilderAPI_Transform(s, t, true).Shape();
} else {
return s.Moved(t);
}
}
};
// In newer versions of IfcOpenShell this is a method BRep::as_compound()
auto brep_as_compound = [&apply_transformation](const IfcGeom::Representation::BRep& brep) {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++it) {
const TopoDS_Shape& s = it->Shape();
gp_GTrsf trsf = it->Placement();
if (brep.settings().convert_back_units()) {
gp_Trsf scale;
scale.SetScaleFactor(1.0 / brep.settings().unit_magnitude());
trsf.PreMultiply(scale);
}
const TopoDS_Shape moved_shape = apply_transformation(s, trsf);
builder.Add(compound, moved_shape);
}
return compound;
};
// Generate non-aa bounding boxes in local coordinates as a tuple of six doubles from existing IfcProductDefinitionShape instances
std::for_each(defs.begin(), defs.end(), [&kernel, &brep_as_compound, &str, N, &n, &settings](IfcSchema::IfcProductDefinitionShape* def) {
Bnd_Box box;
auto prods = def->data().getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>();
if (prods->size() != 1) return;
IfcSchema::IfcProduct* prod = *prods->begin();
auto reps = def->Representations();
std::for_each(reps->begin(), reps->end(), [&kernel, &brep_as_compound, &settings, &box, prod](auto rep) {
if (rep->RepresentationIdentifier() == "Body") {
IfcGeom::BRepElement<double>* elem = kernel.create_brep_for_representation_and_product<double>(settings, rep, prod);
BRepBndLib::AddClose(brep_as_compound(elem->geometry()), box);
delete elem;
}
});
const size_t name = def->data().id();
double xyz[6];
box.Get(xyz[0], xyz[1], xyz[2], xyz[3], xyz[4], xyz[5]);
str.write((char*)&name, sizeof(size_t));
str.write((char*)xyz, sizeof(double) * 6);
if (n++ % 1000 == 0) {
std::cerr << "\r" << n * 100 / N << std::flush;
}
});
std::cerr << std::endl;
}
void find_geometric_types(IfcParse::IfcFile& f, const std::string& tfn) {
std::ofstream str(tfn.c_str(), std::ios_base::binary);
IfcSchema::IfcProductDefinitionShape::list::ptr defs_ = f.entitiesByType<IfcSchema::IfcProductDefinitionShape>();
std::vector<IfcSchema::IfcProductDefinitionShape*> defs(defs_->begin(), defs_->end());
// Make sure to sort by id to have new definitions lining up in the same order
std::sort(defs.begin(), defs.end(), [](IfcSchema::IfcProductDefinitionShape* a, IfcSchema::IfcProductDefinitionShape* b) {
return a->data().id() < b->data().id();
});
// Initial choice of geometric types
std::set<IfcSchema::Type::Enum> geometric_types{
IfcSchema::Type::IfcStyledItem, IfcSchema::Type::IfcMaterialDefinitionRepresentation, IfcSchema::Type::IfcStyledRepresentation,
IfcSchema::Type::IfcSurfaceStyleRendering, IfcSchema::Type::IfcSurfaceStyle, IfcSchema::Type::IfcPresentationLayerAssignment,
IfcSchema::Type::IfcPresentationStyleAssignment, IfcSchema::Type::IfcColourRgb
};
std::set<IfcSchema::Type::Enum> other_types;
// Find all instances
std::set<IfcUtil::IfcBaseClass*> geometric_instances;
for (auto ty : geometric_types) {
auto insts = f.entitiesByType(ty);
std::for_each(insts->begin(), insts->end(), [&geometric_instances](IfcUtil::IfcBaseClass* inst) {
geometric_instances.insert(inst);
});
}
int N, n;
// Not referenced. Revit generates unused IfcExtrudedAreaSolids some times.
auto repitems = f.entitiesByType(IfcSchema::Type::IfcRepresentationItem);
std::for_each(repitems->begin(), repitems->end(), [&f, &geometric_instances](IfcUtil::IfcBaseClass* inst) {
auto invs = f.getInverse(inst->data().id(), IfcSchema::Type::UNDEFINED, -1);
if (invs->size() == 0) {
auto refs = f.traverse(inst);
std::for_each(refs->begin(), refs->end(), [&geometric_instances](IfcUtil::IfcBaseClass* inst2) {
if (inst2->declaration().as_entity()) {
geometric_instances.insert(inst2);
}
});
}
});
// Recurse over forward attributes
auto vist_geometric = [&f, &geometric_types, &geometric_instances, &N, &n](IfcUtil::IfcBaseEntity* def) {
auto refs = f.traverse(def);
geometric_instances.insert(refs->begin(), refs->end());
std::for_each(refs->begin(), refs->end(), [&geometric_types](IfcUtil::IfcBaseClass* inst) {
if (inst->declaration().as_entity()) {
geometric_types.insert(inst->declaration().type());
}
});
if (n++ % 1000 == 0) {
std::cerr << "\r" << (n * 100 / N) << std::flush;
}
};
n = 0;
N = defs.size();
std::for_each(defs.begin(), defs.end(), vist_geometric);
// Include connection geometry (e.g space boundaries) as well
auto connection_geom = f.entitiesByType<IfcSchema::IfcConnectionGeometry>();
n = 0;
N = connection_geom->size();
std::for_each(connection_geom->begin(), connection_geom->end(), vist_geometric);
// Traverse again all instances, but now to detect which geometric types are fully and only shared by geometric instances
std::function<void(IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*)> fn;
fn = [&f, &geometric_instances, &other_types, &fn](IfcUtil::IfcBaseClass* root, IfcUtil::IfcBaseClass* inst) {
if (geometric_instances.find(inst) == geometric_instances.end()) {
auto ty = inst->declaration().type();
other_types.insert(ty);
auto refs = f.traverse(inst, 1);
std::for_each(refs->begin() + 1, refs->end(), [&fn, root](IfcUtil::IfcBaseClass* inst) {
if (inst->declaration().as_entity()) {
fn(root, inst);
}
});
}
};
N = std::distance(f.begin(), f.end());
n = 0;
std::for_each(f.begin(), f.end(), [&fn, N, &n](const auto& pair) {
fn(pair.second, pair.second);
if (n++ % 1000 == 0) {
std::cerr << "\r" << n * 100 / N << std::flush;
}
});
std::set<IfcSchema::Type::Enum> only_geometric;
std::set_difference(geometric_types.begin(), geometric_types.end(),
other_types.begin(), other_types.end(),
std::inserter(only_geometric, only_geometric.begin()));
only_geometric.erase(IfcSchema::Type::IfcGeometricRepresentationContext);
only_geometric.erase(IfcSchema::Type::IfcGeometricRepresentationSubContext);
std::cerr << "\nOnly geometric:" << std::endl;
for (auto ty : only_geometric) {
std::cerr << IfcSchema::Type::ToString(ty) << std::endl;
const size_t name = ty;
str.write((char*)&name, sizeof(size_t));
}
}
int main(int argc, char** argv) {
const std::string cache_fn = argv[1] + std::string(".boxes.bin");
const std::string types_fn = argv[1] + std::string(".types.bin");
if (argc == 2 && !ifstream(cache_fn).good()) {
std::string command = std::string("\"\"") + argv[0] + "\" \"" + argv[1] + "\" -b\"";
if (system(command.c_str()) != 0) {
return 1;
}
}
if (argc == 2 && !ifstream(types_fn).good()) {
std::string command = std::string("\"\"") + argv[0] + "\" \"" + argv[1] + "\" -t\"";
if (system(command.c_str()) != 0) {
return 1;
}
}
IfcParse::IfcFile f;
f.Init(argv[1]);
if (argc == 3 && std::string(argv[2]) == "-b") {
generate_bounding_boxes(f, cache_fn);
return 0;
}
if (argc == 3 && std::string(argv[2]) == "-t") {
find_geometric_types(f, types_fn);
return 0;
}
std::set<IfcSchema::Type::Enum> only_geometric;
{
std::ifstream str(types_fn.c_str(), std::ios_base::binary);
while (!str.eof()) {
size_t name;
str.read((char*)&name, sizeof(size_t));
only_geometric.insert((IfcSchema::Type::Enum) name);
}
}
std::set<IfcSchema::Type::Enum> property_types {
IfcSchema::Type::IfcRelDefines,
IfcSchema::Type::IfcPropertySetDefinition,
IfcSchema::Type::IfcTypeObject,
IfcSchema::Type::IfcProperty,
IfcSchema::Type::IfcPhysicalQuantity,
IfcSchema::Type::IfcRelAssociatesClassification,
IfcSchema::Type::IfcClassification,
IfcSchema::Type::IfcClassificationReference,
IfcSchema::Type::IfcRelAssociatesMaterial,
IfcSchema::Type::IfcMaterialList,
IfcSchema::Type::IfcMaterialLayerSetUsage,
IfcSchema::Type::IfcMaterialLayerSet,
IfcSchema::Type::IfcMaterialLayer,
IfcSchema::Type::IfcMaterial
};
std::vector<IfcUtil::IfcBaseClass*> new_defs, old_defs, old_prop_defs, old_geom_defs, old_box_defs, all_old_defs, all_defs;
std::for_each(only_geometric.begin(), only_geometric.end(), [&f, &old_geom_defs](IfcSchema::Type::Enum t) {
auto insts = f.entitiesByType(t);
std::for_each(insts->begin(), insts->end(), [t, &old_geom_defs](IfcUtil::IfcBaseClass* inst) {
if (inst->declaration().type() == t) {
old_geom_defs.push_back(inst);
}
});
});
std::for_each(f.begin(), f.end(), [&only_geometric, &old_defs, &old_prop_defs, &property_types](const auto& pair) {
IfcUtil::IfcBaseClass* inst = pair.second;
// This is checked the other way around to include subtypes
bool is_property = false;
for (auto pty : property_types) {
if (inst->declaration().is(pty)) {
is_property = true;
break;
}
}
auto ty = inst->declaration().type();
if (is_property) {
old_prop_defs.push_back(inst);
} else if (only_geometric.find(ty) == only_geometric.end()) {
old_defs.push_back(inst);
}
});
IfcSchema::IfcRepresentationContext* context = 0;
auto reps = (*f.entitiesByType<IfcSchema::IfcProductDefinitionShape>()->begin())->Representations();
std::for_each(reps->begin(), reps->end(), [&context](auto rep) {
IfcGeom::IfcRepresentationShapeItems items;
if (rep->RepresentationIdentifier() == "Body") {
context = rep->ContextOfItems();
}
});
auto id = f.FreshId();
int num_points_added = 0;
// Create bounding box representation from the 6-tuple definitions
{
std::ifstream str(cache_fn.c_str(), std::ios_base::binary);
while (!str.eof()) {
size_t name;
double xyz[6];
str.read((char*)&name, sizeof(size_t));
str.read((char*)xyz, sizeof(double) * 6);
IfcSchema::IfcCartesianPoint* corner = new IfcSchema::IfcCartesianPoint(std::vector<double>{xyz[0], xyz[1], xyz[2]});;
IfcSchema::IfcBoundingBox* bbox = new IfcSchema::IfcBoundingBox(corner, xyz[3] - xyz[0], xyz[4] - xyz[1], xyz[5] - xyz[2]);
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
items->push(bbox);
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(context, std::string("Body"), std::string("BoundingBox"), items);
IfcSchema::IfcRepresentation::list::ptr new_reps(new IfcSchema::IfcRepresentation::list);
new_reps->push(rep);
IfcSchema::IfcProductDefinitionShape* new_def = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, new_reps);
corner->data().isWritable()->setId(id++);
// NB: Corner is added to existing definitions
old_defs.push_back(corner); ++num_points_added;
new_defs.push_back(bbox);
new_defs.push_back(rep);
new_defs.push_back(new_def);
}
}
std::for_each(new_defs.begin(), new_defs.end(), [&id](auto new_def) {
new_def->data().isWritable()->setId(id++);
});
auto iden = [](IfcUtil::IfcBaseClass* inst) { return inst; };
std::set<IfcSchema::Type::Enum> old_new_geom_types;
std::vector<std::vector<IfcUtil::IfcBaseClass*>*> all_vectors = std::vector<std::vector<IfcUtil::IfcBaseClass*>*>{ &new_defs, &old_prop_defs, &old_defs, &old_geom_defs };
for (auto vec_ : all_vectors) {
auto& vec = *vec_;
for (auto& inst : vec) {
old_new_geom_types.insert(inst->declaration().type());
}
}
// Generate proper buckets of data and serialize
all_old_defs.insert(all_old_defs.end(), old_defs.begin(), old_defs.end());
all_old_defs.insert(all_old_defs.end(), old_prop_defs.begin(), old_prop_defs.end());
all_old_defs.insert(all_old_defs.end(), old_geom_defs.begin(), old_geom_defs.end());
all_defs.insert(all_defs.end(), all_old_defs.begin(), all_old_defs.end());
all_defs.insert(all_defs.end(), new_defs.begin(), new_defs.end());
old_box_defs.insert(old_box_defs.end(), old_defs.begin(), old_defs.end());
old_box_defs.insert(old_box_defs.end(), new_defs.begin(), new_defs.end());
auto contexts = f.entitiesByType<IfcSchema::IfcRepresentationContext>();
old_box_defs.insert(old_box_defs.end(), contexts->begin(), contexts->end());
{
int num_insts1 = std::distance(all_old_defs.begin(), all_old_defs.end());
int num_insts2 = std::distance(f.begin(), f.end());
if ((num_insts1 - num_points_added) != num_insts2) {
std::cerr << "Missign instances " << num_insts1 << " - " << num_points_added << " != " << num_insts2 << std::endl;
abort();
}
}
multifile_instance_locator* locator = new multifile_instance_locator(
old_new_geom_types.begin(), old_new_geom_types.end(),
all_old_defs.begin(), all_old_defs.end());
IfcParse::Hdf5Settings settings;
settings.profile() = IfcParse::Hdf5Settings::padded;
settings.compress() = true;
settings.chunk_size() = 1024;
H5::H5File hdf(argv[1] + std::string(".hdf"), H5F_ACC_TRUNC);
H5::H5File geom_hdf(argv[1] + std::string("-geometry.hdf"), H5F_ACC_TRUNC);
H5::H5File box_hdf(argv[1] + std::string("-bounding-boxes.hdf"), H5F_ACC_TRUNC);
H5::H5File prop_hdf(argv[1] + std::string("-properties.hdf"), H5F_ACC_TRUNC);
hdf.createGroup("geometry").close();
hdf.createGroup("bounding-boxes").close();
hdf.createGroup("properties").close();
hdf.mount("geometry", geom_hdf, H5::PropList::DEFAULT);
hdf.mount("bounding-boxes", box_hdf, H5::PropList::DEFAULT);
hdf.mount("properties", prop_hdf, H5::PropList::DEFAULT);
H5::Group main_population = hdf.createGroup("population");
H5::Group geom_population = hdf.createGroup("geometry/population");
H5::Group box_population = hdf.createGroup("bounding-boxes/population");
H5::Group prop_population = hdf.createGroup("properties/population");
{
IfcParse::IfcHdf5File ifc_hdf5(hdf, get_schema(), settings);
IfcParse::instance_categorizer categorizer(all_defs.begin(), all_defs.end());
ifc_hdf5.write_schema(&categorizer);
{
IfcParse::instance_enumerator enumerator(&f.header(), old_defs.begin(), old_defs.end());
ifc_hdf5.write_population(main_population, enumerator, locator);
}
{
IfcParse::instance_enumerator enumerator(&f.header(), old_geom_defs.begin(), old_geom_defs.end());
ifc_hdf5.write_population(geom_population, enumerator, locator);
}
{
IfcParse::instance_enumerator enumerator(&f.header(), old_prop_defs.begin(), old_prop_defs.end());
ifc_hdf5.write_population(prop_population, enumerator, locator);
}
{
// locator is setup with all_old_defs, need to switch to new_defs + old_defs for the cartesian points
// NB: also geom rep context
locator->next(box_population, old_box_defs.begin(), old_box_defs.end());
IfcParse::instance_enumerator enumerator(&f.header(), new_defs.begin(), new_defs.end());
ifc_hdf5.write_population(box_population, enumerator, locator);
}
}
}
@@ -1,275 +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 multifile_instance_locator : public IfcParse::abstract_instance_locator {
public:
typedef std::function<IfcUtil::IfcBaseClass*(IfcUtil::IfcBaseClass*)> mapping_t;
typedef std::pair<
std::vector<IfcSchema::Type::Enum>,
std::vector< std::vector<IfcUtil::IfcBaseEntity*> >
> population_t;
typedef std::vector<IfcUtil::IfcBaseClass*>::const_iterator full_const_iterator;
private:
H5::H5File* root_file_;
mapping_t mapping_;
std::set<IfcUtil::IfcBaseClass*> initial_population_set_;
std::set<IfcSchema::Type::Enum> initial_types_included_set_;
population_t initial_population_;
population_t subsequent_population_;
std::vector<IfcUtil::IfcBaseClass*> subsequent_minus_initial_;
H5::Group* initial_group_;
H5::Group* subsequent_group_;
H5::H5File* subsequent_file_;
std::string root_;
public:
template <typename ForwardIterator>
multifile_instance_locator(H5::H5File& root_file, H5::Group& group, mapping_t mapping, ForwardIterator b, ForwardIterator e)
: root_file_(&root_file)
, mapping_(mapping)
, initial_group_(&group)
, subsequent_group_(nullptr)
{
initial_population_set_.insert(b, e);
std::set<IfcSchema::Type::Enum> names_set;
std::for_each(b, e, [this, &names_set](IfcUtil::IfcBaseClass* inst) {
IfcSchema::Type::Enum ty = inst->declaration().type();
if (names_set.find(ty) == names_set.end()) {
initial_population_.first.push_back(ty);
names_set.insert(ty);
}
});
std::sort(initial_population_.first.begin(), initial_population_.first.end());
std::for_each(this->begin(), this->end(), [this, &b, &e](IfcSchema::Type::Enum t) {
std::vector<IfcUtil::IfcBaseEntity*> by_type;
std::for_each(b, e, [t,&by_type](IfcUtil::IfcBaseClass* inst) {
if (inst->declaration().type() == t && inst->declaration().as_entity()) {
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
}
});
std::sort(by_type.begin(), by_type.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
return i1->data().id() < i2->data().id();
});
initial_population_.second.emplace_back(by_type);
});
}
template <typename ForwardIteratorTypes, typename ForwardIteratorInsts>
multifile_instance_locator(ForwardIteratorTypes types_all_begin, ForwardIteratorTypes types_all_end, ForwardIteratorInsts insts_begin, ForwardIteratorInsts insts_end)
: subsequent_group_(nullptr)
{
initial_population_.first.assign(types_all_begin, types_all_end);
std::sort(initial_population_.first.begin(), initial_population_.first.end());
std::for_each(this->begin(), this->end(), [this, &insts_begin, &insts_end](IfcSchema::Type::Enum t) {
std::vector<IfcUtil::IfcBaseEntity*> by_type;
std::for_each(insts_begin, insts_end, [t, &by_type](IfcUtil::IfcBaseClass* inst) {
if (inst->declaration().type() == t && inst->declaration().as_entity()) {
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
}
});
std::sort(by_type.begin(), by_type.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
return i1->data().id() < i2->data().id();
});
initial_population_.second.emplace_back(by_type);
});
}
const_iterator begin() const {
if (subsequent_group_) {
return subsequent_population_.first.begin();
} else {
return initial_population_.first.begin();
}
}
const_iterator end() const {
if (subsequent_group_) {
return subsequent_population_.first.end();
} else {
return initial_population_.first.end();
}
}
full_const_iterator full_begin() const {
return subsequent_minus_initial_.begin();
}
full_const_iterator full_end() const {
return subsequent_minus_initial_.end();
}
const std::vector<IfcUtil::IfcBaseEntity*>& instances(IfcSchema::Type::Enum t) {
if (subsequent_group_) {
return subsequent_population_.second[std::lower_bound(begin(), end(), t) - begin()];
} else {
return initial_population_.second[std::lower_bound(begin(), end(), t) - begin()];
}
}
std::pair<int, int> operator()(IfcUtil::IfcBaseClass* v) {
if (IfcSchema::Type::IsSimple(v->declaration().type())) {
throw std::exception("Simple type not expected here");
}
IfcSchema::Type::Enum t = v->declaration().type();
// This remains constant for subsequent model serializations?
auto& dataset_names = initial_population_.first;
auto tt = std::lower_bound(dataset_names.begin(), dataset_names.end(), t);
int a = std::distance(dataset_names.begin(), tt);
int b;
const std::vector<IfcUtil::IfcBaseEntity*>& insts = instances(t);
auto it = std::lower_bound(insts.begin(), insts.end(), v, [](IfcUtil::IfcBaseClass* other, IfcUtil::IfcBaseClass* val) {
// An ordering based on ID is not equivalent to an ordering based on pointer address!
return other->data().id() < val->data().id();
});
if (it == insts.end()) {
throw std::runtime_error("Unable to find instance");
}
b = std::distance(insts.begin(), it);
return std::make_pair(a, b);
}
void make_reference(IfcUtil::IfcBaseClass* v, void*& ptr) {
v = mapping_(v);
IfcSchema::Type::Enum t = v->declaration().type();
population_t* pop;
H5::Group* group;
boost::optional<std::string> current_root;
if (initial_population_set_.find(v) != initial_population_set_.end()) {
pop = &initial_population_;
group = initial_group_;
current_root = boost::none;
} else {
pop = &subsequent_population_;
group = subsequent_group_;
current_root = root_;
}
int a = std::lower_bound(pop->first.begin(), pop->first.end(), t) - pop->first.begin();
auto& vec = pop->second[a];
hsize_t coord = std::lower_bound(vec.begin(), vec.end(), v, [](IfcUtil::IfcBaseClass* other, IfcUtil::IfcBaseClass* val) {
return other->data().id() < val->data().id();
}) - vec.begin();
hsize_t dims = instances(v->declaration().type()).size();
H5::DataSpace space(1, &dims);
space.selectElements(H5S_SELECT_SET, 1, &coord);
const std::string path = IfcSchema::Type::ToString(pop->first[a]);
std::string full_path = group->getObjName() + "/" + path + "_objects" + "/" + path + "_instances";
root_file_->reference(ptr, full_path, space);
ptr = static_cast<uint8_t*>(ptr) + sizeof(hdset_reg_ref_t);
}
template <typename ForwardIt>
void next(H5::Group& group, ForwardIt insts_begin, ForwardIt insts_end) {
subsequent_group_ = &group;
subsequent_population_.first = initial_population_.first;
subsequent_population_.second.clear();
std::for_each(this->begin(), this->end(), [this, &insts_begin, &insts_end](IfcSchema::Type::Enum t) {
std::vector<IfcUtil::IfcBaseEntity*> by_type;
std::for_each(insts_begin, insts_end, [t, &by_type](IfcUtil::IfcBaseClass* inst) {
if (inst->declaration().type() == t && inst->declaration().as_entity()) {
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
}
});
std::sort(by_type.begin(), by_type.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
return i1->data().id() < i2->data().id();
});
subsequent_population_.second.emplace_back(by_type);
});
}
void next(const std::string& name, H5::Group& group, IfcParse::IfcFile* f) {
subsequent_group_ = &group;
root_ = name;
subsequent_population_.first.clear();
subsequent_population_.second.clear();
subsequent_minus_initial_.clear();
auto f_begin = f->begin();
auto f_end = f->end();
std::set<IfcSchema::Type::Enum> names_set;
std::for_each(f_begin, f_end, [this, &names_set](auto& pair) {
IfcUtil::IfcBaseClass* inst = mapping_(pair.second);
if (initial_population_set_.find(inst) == initial_population_set_.end()) {
IfcSchema::Type::Enum ty = inst->declaration().type();
if (names_set.find(ty) == names_set.end()) {
subsequent_population_.first.push_back(ty);
names_set.insert(ty);
}
subsequent_minus_initial_.push_back(inst);
}
});
auto& names = subsequent_population_.first;
std::sort(names.begin(), names.end());
auto& vecs = subsequent_population_.second;
vecs.resize(names.size());
std::for_each(f_begin, f_end, [this, &names, &vecs](auto& pair) {
IfcUtil::IfcBaseClass* inst = mapping_(pair.second);
if (initial_population_set_.find(inst) == initial_population_set_.end() && inst->declaration().as_entity()) {
IfcSchema::Type::Enum ty = inst->declaration().type();
auto a = std::lower_bound(names.begin(), names.end(), ty) - names.begin();
auto& by_type = vecs[a];
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
}
});
std::for_each(vecs.begin(), vecs.end(), [](auto& vec) {
std::sort(vec.begin(), vec.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
return i1->data().id() < i2->data().id();
});
});
}
};
+81 -83
View 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'
)
+52 -63
View File
@@ -28,30 +28,30 @@ std::string collada_id(const std::string& s) {
id.reserve(s.size());
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
const std::string::value_type c = *it;
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_') || ( c == '-')) {
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<double>& 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);
source.setAccessorStride((unsigned long)strlen(coords));
source.setAccessorCount((unsigned long)floats.size() / 3);
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<double>::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<double>& positions, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials) {
void 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.
@@ -68,15 +68,19 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str
vertices.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::POSITION, "#" + mesh_id + COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX));
vertices.add();
std::vector<int>::const_iterator index_range_start = 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) {
const int current_material_id = *(material_it++);
const unsigned long num_triangles = (unsigned long)std::distance(index_range_start, it) / 3;
if ((previous_material_id != current_material_id && num_triangles > 0) || (it == faces.end())) {
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);
triangles.setMaterial(materials[previous_material_id].name());
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++ ) );
@@ -96,44 +100,11 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str
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);
lines.setMaterial(materials[it->first].name());
lines.setCount((unsigned long)it->second.size());
int offset = 0;
lines.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX, "#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++));
lines.prepareToAppendValues();
lines.appendValues(it->second);
lines.finish();
}
closeMesh();
closeGeometry();
}
@@ -142,7 +113,7 @@ 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<double>& 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;
@@ -184,7 +155,7 @@ void ColladaSerializer::ColladaExporter::ColladaScene::write() {
}
}
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeom::Material& material) {
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);
@@ -215,20 +186,20 @@ 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();
for (std::vector<IfcGeom::Material>::const_iterator it = materials.begin(); it != materials.end(); ++it) {
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 + "-fx");
@@ -247,16 +218,34 @@ void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_n
asset.add();
}
void ColladaSerializer::ColladaExporter::write(const std::string& unique_id, const std::string& type, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& _materials) {
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;
for (std::vector<IfcGeom::Material>::const_iterator it = _materials.begin(); it != _materials.end(); ++it) {
const IfcGeom::Material& material = *it;
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);
}
material_references.push_back(collada_id(material.name()));
}
deferreds.push_back(DeferredObject(unique_id, type, matrix, vertices, normals, faces, edges, material_ids, _materials, material_references));
deferreds.push_back(DeferredObject(guid, name, type, obj_id, matrix, vertices, normals, indices, material_ids, _materials, material_references));
}
const std::string ColladaSerializer::ColladaExporter::DeferredObject::Name() const {
std::stringstream ss;
if (!this->name.empty()) {
ss << this->obj_id << "_" << this->name;
} else {
ss << this->guid;
}
return collada_id(ss.str());
}
void ColladaSerializer::ColladaExporter::endDocument() {
@@ -264,13 +253,13 @@ void ColladaSerializer::ColladaExporter::endDocument() {
// only at this point all objects are written to the stream.
materials.write();
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
const std::string object_name = it->unique_id + "-representation";
geometries.write(object_name, it->type, it->vertices, it->normals, it->faces, it->edges, it->material_ids, it->materials);
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;
scene.add(object_name, object_name, object_name + "-representation", 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();
@@ -284,9 +273,9 @@ void ColladaSerializer::writeHeader() {
exporter.startDocument(unit_name, unit_magnitude);
}
void ColladaSerializer::write(const IfcGeom::TriangulationElement<double>* o) {
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
exporter.write(o->unique_id(), o->type(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.edges(), mesh.material_ids(), mesh.materials());
void ColladaSerializer::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() {
+26 -42
View File
@@ -22,10 +22,6 @@
#ifndef COLLADASERIALIZER_H
#define COLLADASERIALIZER_H
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4201 4512)
#endif
#include <COLLADASWStreamWriter.h>
#include <COLLADASWPrimitves.h>
#include <COLLADASWLibraryGeometries.h>
@@ -38,39 +34,30 @@
#include <COLLADASWLibraryMaterials.h>
#include <COLLADASWBaseInputElement.h>
#include <COLLADASWAsset.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#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)
: COLLADASW::LibraryGeometries(&stream)
{}
void addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<double>& floats, const char* coords = "XYZ");
void write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials);
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();
};
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:
@@ -79,61 +66,59 @@ private:
, scene_id(scene_id)
, 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<double>& 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();
};
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();
};
std::vector<IfcGeom::Material> materials;
std::vector<IfcGeomObjects::Material> materials;
ColladaEffects effects;
public:
explicit ColladaMaterials(COLLADASW::StreamWriter& stream)
: COLLADASW::LibraryMaterials(&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();
};
class DeferredObject {
public:
std::string unique_id, type;
std::vector<double> matrix;
std::vector<double> vertices;
std::vector<double> 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;
DeferredObject(const std::string& unique_id, const std::string& type, const std::vector<double>& matrix, const std::vector<double>& vertices,
const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int>& material_ids,
const std::vector<IfcGeom::Material>& materials, const std::vector<std::string>& material_references)
: unique_id(unique_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)
{}
const std::string Name() const;
};
COLLADABU::NativeString filename;
COLLADASW::StreamWriter stream;
@@ -151,7 +136,7 @@ private:
std::vector<DeferredObject> deferreds;
virtual ~ColladaExporter() {}
void startDocument(const std::string& unit_name, float unit_magnitude);
void write(const std::string& unique_id, const std::string& type, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& materials);
void 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;
@@ -164,15 +149,14 @@ public:
{}
bool ready();
void writeHeader();
void write(const IfcGeom::TriangulationElement<double>* o);
void write(const IfcGeom::BRepElement<double>* /*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
+8 -7
View File
@@ -20,16 +20,17 @@
#ifndef GEOMETRYSERIALIZER_H
#define GEOMETRYSERIALIZER_H
#include "../ifcconvert/Serializer.h"
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcgeom/IfcGeomObjects.h"
class GeometrySerializer : public Serializer {
class GeometrySerializer {
public:
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<double>* o) = 0;
virtual void write(const IfcGeom::BRepElement<double>* 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;
};
+87 -268
View File
@@ -26,37 +26,19 @@
* *
********************************************************************************/
#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
#define BOOST_MPL_LIMIT_LIST_SIZE 30
#include <fstream>
#include <sstream>
#include <set>
#include <time.h>
#include <boost/program_options.hpp>
#include <boost/algorithm/string.hpp>
#include "../ifcparse/Hdf5Settings.h"
#include "../ifcparse/IfcHdf5File.h"
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcgeom/IfcGeomObjects.h"
#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 <IGESControl_Controller.hxx>
#include <Standard_Version.hxx>
#if USE_VLD
#include <vld.h>
#endif
static std::string DEFAULT_EXTENSION = "obj";
void printVersion() {
std::cerr << "IfcOpenShell IfcConvert " << IFCOPENSHELL_VERSION << std::endl;
@@ -69,14 +51,10 @@ void printUsage(const boost::program_options::options_description& generic_optio
<< "Converts the geometry in an IFC file into one of the following formats:" << std::endl
<< " .obj WaveFront OBJ (a .mtl file is also created)" << std::endl;
#ifdef WITH_OPENCOLLADA
std::cerr << " .dae Collada Digital Asset Exchange" << std::endl;
std::cerr << " .dae Collada Digital Assets Exchange" << std::endl;
#endif
std::cerr << " .stp STEP Standard for the Exchange of Product Data" << std::endl
<< " .igs IGES Initial Graphics Exchange Specification" << std::endl
<< " .xml XML Property definitions and decomposition tree" << std::endl
<< " .svg SVG Scalable Vector Graphics (2d floor plan)" << std::endl
<< " .hdf HDF5 Efficient binary IFC serialization" << std::endl
<< " .ifc IFC-SPF Standard p21 IFC serialization" << std::endl
<< std::endl
<< "Command line options" << std::endl << generic_options << std::endl
<< "Advanced options" << std::endl << geom_options << std::endl;
@@ -106,77 +84,35 @@ int main(int argc, char** argv) {
("input-file", boost::program_options::value<std::string>(), "input IFC file")
("output-file", boost::program_options::value<std::string>(), "output geometry file");
std::string bounds, hdf5_profile;
uint32_t hdf5_chunk_size;
std::vector<std::string> entity_vector;
std::vector<std::string> hdf5_ref_attributes;
std::vector<std::string> hdf5_mount_points;
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.")
("bounds", boost::program_options::value<std::string>(&bounds),
"Specifies the bounding rectangle, for example 512x512, to which the "
"output will be scaled. Only used when converting to SVG.")
("hdf5-profile", boost::program_options::value<std::string>(&hdf5_profile), "")
("hdf5-compress", "")
("hdf5-fix-cartesian-point", "")
("hdf5-fix-global-id", "")
("hdf5-instantiate-inverse", "")
("hdf5-instantiate-select", "")
("hdf5-mount", boost::program_options::value< std::vector<std::string> >(&hdf5_mount_points)->multitoken(),
"")
("hdf5-chunk-size", boost::program_options::value(&hdf5_chunk_size), "")
("hdf5-ref-attributes", boost::program_options::value< std::vector<std::string> >(&hdf5_ref_attributes)->multitoken(),
"")
("include",
"Specifies that the entities listed after --entities are to be included")
("exclude",
"Specifies that the entities listed after --entities are to be excluded")
("entities", boost::program_options::value< std::vector<std::string> >(&entity_vector)->multitoken(),
"A list of entities that should be included in or excluded from the "
"geometrical output, depending on whether --ignore or --include is "
"specified. Defaults to IfcOpeningElement and IfcSpace to be excluded.");
("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);
@@ -192,19 +128,13 @@ int main(int argc, char** argv) {
} 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
} catch (...) {
// Catch other errors such as invalid command line syntax
}
boost::program_options::notify(vmap);
if (vmap.count("version")) {
printVersion();
return 0;
return 1;
} else if (vmap.count("help") || !vmap.count("input-file")) {
printUsage(generic_options, geom_options);
return vmap.count("help") ? 0 : 1;
} else if (vmap.count("include") && vmap.count("exclude")) {
std::cerr << "[Error] --include and --ignore can not be specified together" << std::endl;
printUsage(generic_options, geom_options);
return 1;
}
@@ -214,31 +144,23 @@ int main(int argc, char** argv) {
const bool use_world_coords = vmap.count("use-world-coords") != 0;
const bool convert_back_units = vmap.count("convert-back-units") != 0;
const bool sew_shells = vmap.count("sew-shells") != 0;
#if OCC_VERSION_HEX < 0x60900
const bool merge_boolean_operands = vmap.count("merge-boolean-operands") != 0;
#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;
bool include_entities = vmap.count("include") != 0;
const bool include_plan = vmap.count("plan") != 0;
const bool include_model = vmap.count("model") != 0 || (!include_plan);
boost::optional<int> bounding_width, bounding_height;
if (vmap.count("bounds") == 1) {
int w, h;
if (sscanf(bounds.c_str(), "%ux%u", &w, &h) == 2) {
bounding_width = w;
bounding_height = h;
} else {
std::cerr << "[Error] Invalid use of --bounds" << std::endl;
printUsage(generic_options, geom_options);
return 1;
}
}
// Gets the set ifc types to be ignored from the command line.
std::set<std::string> entities;
for (std::vector<std::string>::const_iterator it = entity_vector.begin(); it != entity_vector.end(); ++it) {
const std::string& mixed_case_type = *it;
entities.insert(boost::to_lower_copy(mixed_case_type));
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>();
@@ -246,117 +168,35 @@ int main(int argc, char** argv) {
// to maintain backwards compatibility with the obsolete IfcObj executable.
const std::string output_filename = vmap.count("output-file") == 1
? vmap["output-file"].as<std::string>()
: change_extension(input_filename, DEFAULT_EXTENSION);
: change_extension(input_filename, "obj");
if (output_filename.size() < 5) {
printUsage(generic_options, geom_options);
return 1;
}
std::string output_extension = output_filename.substr(output_filename.size()-4);
boost::to_lower(output_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);
// If no entities are specified these are the defaults to skip from output
if (entity_vector.empty()) {
if (output_extension == ".svg") {
entities.insert("ifcspace");
include_entities = true;
} else {
entities.insert("ifcopeningelement");
entities.insert("ifcspace");
}
std::string output_extension = output_filename.substr(output_filename.size()-4);
for (std::string::iterator c = output_extension.begin(); c != output_extension.end(); ++c) {
*c = tolower(*c);
}
Logger::SetOutput(&std::cout, &log_stream);
Logger::Verbosity(verbose ? Logger::LOG_NOTICE : Logger::LOG_ERROR);
if (output_extension == ".xml") {
int exit_code = 1;
try {
XmlSerializer s(output_filename);
IfcParse::IfcFile f;
if (!f.Init(input_filename)) {
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file");
} else {
s.setFile(&f);
s.finalize();
exit_code = 0;
}
} catch (...) {}
write_log();
return exit_code;
} else if (output_extension == ".hdf") {
int exit_code = 1;
// try {
IfcParse::IfcFile f;
if (!f.Init(input_filename)) {
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file");
} else {
IfcParse::Hdf5Settings settings;
settings.compress() = vmap.count("hdf5-compress") != 0;
settings.fix_cartesian_point() = vmap.count("hdf5-fix-cartesian-point") != 0;
settings.fix_global_id() = vmap.count("hdf5-fix-global-id") != 0;
settings.instantiate_inverse() = vmap.count("hdf5-instantiate-inverse") != 0;
settings.instantiate_select() = vmap.count("hdf5-instantiate-select") != 0;
std::sort(hdf5_ref_attributes.begin(), hdf5_ref_attributes.end());
settings.ref_attributes() = hdf5_ref_attributes;
if (vmap.count("hdf5-chunk-size") == 1) {
settings.chunk_size() = hdf5_chunk_size;
}
if (vmap.count("hdf5-profile") == 1) {
settings.profile() = IfcParse::Hdf5Settings::ProfileFromString(hdf5_profile);
}
f.write_hdf5(output_filename, settings);
exit_code = 0;
}
// } catch (...) {}
write_log();
// std::cin.get();
return exit_code;
} else if (output_extension == ".ifc") {
bool success = false;
const std::string input_extension = input_filename.substr(input_filename.size() - 4);
if (input_extension == ".ifc") {
IfcParse::IfcFile f;
if (f.Init(input_filename)) {
std::ofstream of(output_filename.c_str());
of << f;
success = true;
} else {
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file");
}
} else if (input_extension == ".hdf") {
std::ofstream fs(output_filename.c_str());
IfcParse::IfcHdf5File::convert_to_spf(input_filename, fs, hdf5_mount_points);
success = true;
} else {
Logger::Message(Logger::LOG_ERROR, "Unknown input extension");
}
write_log();
return success ? 0 : 1;
}
IfcGeom::IteratorSettings settings;
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);
GeometrySerializer* serializer;
if (output_extension == ".obj") {
const std::string mtl_filename = output_filename.substr(0,output_filename.size()-3) + "mtl";
if (!use_world_coords) {
Logger::Message(Logger::LOG_NOTICE, "Using world coords when writing WaveFront OBJ files");
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true);
IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS, true);
}
serializer = new WaveFrontOBJSerializer(output_filename, mtl_filename);
#ifdef WITH_OPENCOLLADA
@@ -370,15 +210,6 @@ int main(int argc, char** argv) {
// See: http://tracker.dev.opencascade.org/view.php?id=23679
IGESControl_Controller::Init();
serializer = new IgesSerializer(output_filename);
} else if (output_extension == ".svg") {
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
serializer = new SvgSerializer(output_filename);
if (bounding_width && bounding_height) {
((SvgSerializer*) serializer)->setBoundingRectangle(
static_cast<double>(*bounding_width),
static_cast<double>(*bounding_height)
);
}
} else {
Logger::Message(Logger::LOG_ERROR, "Unknown output filename extension");
write_log();
@@ -386,45 +217,30 @@ int main(int argc, char** argv) {
return 1;
}
if (!serializer->isTesselated()) {
if (weld_vertices) {
Logger::Message(Logger::LOG_NOTICE, "Weld vertices setting ignored when writing STEP or IGES files");
}
settings.disable_triangulation() = true;
}
IfcGeom::Iterator<double> context_iterator(settings, input_filename);
try {
if (include_entities) {
context_iterator.includeEntities(entities);
} else {
context_iterator.excludeEntities(entities);
}
} catch (const IfcParse::IfcException& e) {
std::cout << "[Error] " << e.what() << std::endl;
return 1;
}
if (!serializer->ready()) {
Logger::Message(Logger::LOG_ERROR, "Unable to open output file for writing");
write_log();
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);
if (!context_iterator.initialize()) {
// 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;
}
serializer->setFile(context_iterator.getFile());
if (convert_back_units) {
serializer->setUnitNameAndMagnitude(context_iterator.getUnitName(), static_cast<const float>(context_iterator.getUnitMagnitude()));
serializer->setUnitNameAndMagnitude(IfcGeomObjects::GetUnitName(), IfcGeomObjects::GetUnitMagnitude());
} else {
serializer->setUnitNameAndMagnitude("METER", 1.0f);
}
@@ -436,30 +252,35 @@ int main(int argc, char** argv) {
int old_progress = -1;
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
// true return value guarantees that a successfully processed product is
// available.
// 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 {
const IfcGeom::Element<double>* geom_object = context_iterator.get();
const IfcGeomObjects::IfcObject* geom_object;
if (serializer->isTesselated()) {
serializer->write(static_cast<const IfcGeom::TriangulationElement<double>*>(geom_object));
geom_object = IfcGeomObjects::Get();
} else {
serializer->write(static_cast<const IfcGeom::BRepElement<double>*>(geom_object));
geom_object = IfcGeomObjects::GetShapeModel();
}
const int progress = context_iterator.progress() / 2;
if (old_progress!= progress) Logger::ProgressBar(progress);
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;
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 (context_iterator.next());
} while ( IfcGeomObjects::Next() );
serializer->finalize();
delete serializer;
@@ -471,8 +292,6 @@ int main(int argc, char** argv) {
time(&end);
int dif = (int) difftime (end,start);
printf ("\nConversion took %d seconds\n", dif );
return 0;
}
void write_log() {
+3 -3
View File
@@ -20,10 +20,11 @@
#ifndef IGESSERIALIZER_H
#define IGESSERIALIZER_H
#include <IGESControl_Controller.hxx>
#include <IGESControl_Writer.hxx>
#include <Interface_Static.hxx>
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcgeom/IfcGeomObjects.h"
#include "../ifcconvert/OpenCascadeBasedSerializer.h"
@@ -42,10 +43,9 @@ 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);
}
}
+16 -19
View File
@@ -24,8 +24,6 @@
#include <BRepBuilderAPI_GTransform.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <Standard_Version.hxx>
#include "OpenCascadeBasedSerializer.h"
bool OpenCascadeBasedSerializer::ready() {
@@ -36,19 +34,18 @@ bool OpenCascadeBasedSerializer::ready() {
return succeeded;
}
void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement<double>* 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().convert_back_units()) {
gp_Trsf scale;
scale.SetScaleFactor(1.0 / o->geometry().settings().unit_magnitude());
gtrsf.PreMultiply(scale);
}
// 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;
@@ -67,18 +64,18 @@ void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement<double>* o) {
}
#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;
+5 -7
View File
@@ -20,15 +20,13 @@
#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)
@@ -37,12 +35,12 @@ public:
{}
virtual ~OpenCascadeBasedSerializer() {}
void writeHeader() {}
void writeMaterial(const IfcGeom::SurfaceStyle& style) {}
bool ready();
virtual void writeShape(const TopoDS_Shape& shape) = 0;
void write(const IfcGeom::TriangulationElement<double>* /*o*/) {}
void write(const IfcGeom::BRepElement<double>* o);
void writeTesselated(const IfcGeomObjects::IfcGeomObject* o) {}
void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o);
bool isTesselated() const { return false; }
void setFile(IfcParse::IfcFile*) {}
};
#endif
-35
View File
@@ -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
+3 -3
View File
@@ -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"
@@ -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);
}
}
+78
View File
@@ -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
-355
View File
@@ -1,355 +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 <BRepBuilderAPI_GTransform.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <TopExp_Explorer.hxx>
#include <BRep_Tool.hxx>
#include <BRepAlgo_Section.hxx>
#include <BRepTools.hxx>
#include <BRepAlgoAPI_Section.hxx>
#include <ShapeAnalysis_FreeBounds.hxx>
#include <TopTools_HSequenceOfShape.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Line.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Ellipse.hxx>
#include <gp_Ax22d.hxx>
#include <Standard_Version.hxx>
#include "../ifcparse/IfcGlobalId.h"
#include "SvgSerializer.h"
const double PI2 = M_PI * 2.;
bool SvgSerializer::ready() {
return true;
}
void SvgSerializer::write(path_object& p, const TopoDS_Wire& wire) {
/* ShapeFix_Wire fix;
Handle(ShapeExtend_WireData) data = new ShapeExtend_WireData;
for (TopExp_Explorer edges(result, TopAbs_EDGE); edges.More(); edges.Next()) {
data->Add(edges.Current());
}
fix.Load(data);
fix.FixReorder();
fix.FixConnected();
const TopoDS_Wire fixed_wire = fix.Wire(); */
bool first = true;
util::string_buffer path;
path.add(" <path style=\"stroke:black; fill:none;\" d=\"");
for (TopExp_Explorer edges(wire, TopAbs_EDGE); edges.More(); edges.Next()) {
const TopoDS_Edge& edge = TopoDS::Edge(edges.Current());
double u1, u2;
Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, u1, u2);
const bool reversed = edge.Orientation() == TopAbs_REVERSED;
gp_Pnt p1, p2;
curve->D0(u1, p1);
curve->D0(u2, p2);
if (reversed) {
std::swap(p1, p2);
}
if (first) {
path.add("M");
addXCoordinate(path.add(p1.X()));
path.add(",");
addYCoordinate(path.add(p1.Y()));
growBoundingBox(p1.X(), p1.Y());
}
growBoundingBox(p2.X(), p2.Y());
Handle(Standard_Type) ty = curve->DynamicType();
if (ty == STANDARD_TYPE(Geom_Circle) || ty == STANDARD_TYPE(Geom_Ellipse)) {
Handle(Geom_Conic) conic = Handle(Geom_Conic)::DownCast(curve);
const bool mirrored = conic->Position().Axis().Direction().Z() < 0;
double r1, r2;
bool larger_arc_segment = (fmod(u2 - u1 + PI2, PI2) > M_PI);
bool positive_direction = (u2 > u1);
if (mirrored != reversed) {
// In case the local coordinate system is mirrored
// the direction is reversed.
positive_direction = !positive_direction;
}
if (ty == STANDARD_TYPE(Geom_Circle)) {
Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(curve);
r1 = r2 = circle->Radius();
} else {
Handle(Geom_Ellipse) ellipse = Handle(Geom_Ellipse)::DownCast(curve);
r1 = ellipse->MajorRadius();
r2 = ellipse->MinorRadius();
}
// Calculate the angle between 2d vecs to have signed result
const gp_Dir& d = conic->Position().XDirection();
const gp_Dir2d d2(d.X(), d.Y());
const double ang = d2.Angle(gp::DX2d());
// Write radii
path.add(" A");
addSizeComponent(path.add(r1));
path.add(",");
addSizeComponent(path.add(r2));
// Write X-axis rotation
{ std::stringstream ss; ss << " " << ang << " ";
path.add(ss.str()); }
// Write large-arc-flag and sweep-flag
path.add(std::string(1, '0'+static_cast<int>(larger_arc_segment)));
path.add(",");
path.add(std::string(1, '0'+static_cast<int>(positive_direction)));
path.add(" ");
// Write arc end point
xcoords.push_back(path.add(p2.X()));
path.add(",");
ycoords.push_back(path.add(p2.Y()));
} else {
// Either a Geom_Line or something unimplemented,
// drawn as a straight line segment.
path.add(" L");
xcoords.push_back(path.add(p2.X()));
path.add(",");
ycoords.push_back(path.add(p2.Y()));
}
first = false;
}
path.add("\"/>\n");
p.second.push_back(path);
}
SvgSerializer::path_object& SvgSerializer::start_path(IfcSchema::IfcBuildingStorey* storey, const std::string& id) {
SvgSerializer::path_object& p = paths.insert(std::make_pair(storey, path_object()))->second;
p.first = id;
return p;
}
void SvgSerializer::write(const IfcGeom::BRepElement<double>* o) {
IfcSchema::IfcBuildingStorey* storey = 0;
IfcSchema::IfcObjectDefinition* obdef = static_cast<IfcSchema::IfcObjectDefinition*>(file->entityById(o->id()));
#ifndef USE_IFC4
typedef IfcSchema::IfcRelDecomposes decomposition_element;
#else
typedef IfcSchema::IfcRelAggregates decomposition_element;
#endif
for (;;) {
// Iterate over the decomposing element to find the parent IfcBuildingStorey
decomposition_element::list::ptr decomposes = obdef->Decomposes();
if (!decomposes->size()) {
if (obdef->declaration().is(IfcSchema::Type::IfcElement)) {
IfcSchema::IfcRelContainedInSpatialStructure::list::ptr containment = ((IfcSchema::IfcElement*)obdef)->ContainedInStructure();
if (!containment->size()) {
break;
}
for (IfcSchema::IfcRelContainedInSpatialStructure::list::it it = containment->begin(); it != containment->end(); ++it) {
IfcSchema::IfcRelContainedInSpatialStructure* container = *it;
if (container->RelatingStructure() != obdef) {
obdef = container->RelatingStructure();
}
}
} else {
break;
}
} else {
for (decomposition_element::list::it it = decomposes->begin(); it != decomposes->end(); ++it) {
decomposition_element* decompose = *it;
if (decompose->RelatingObject() != obdef) {
obdef = decompose->RelatingObject();
}
}
}
if (obdef->declaration().is(IfcSchema::Type::IfcBuildingStorey)) {
storey = static_cast<IfcSchema::IfcBuildingStorey*>(obdef);
break;
}
}
if (!storey) return;
path_object& p = start_path(storey, nameElement(o));
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) {
gp_GTrsf gtrsf = it->Placement();
const gp_Trsf& o_trsf = o->transformation().data();
gtrsf.PreMultiply(o_trsf);
const TopoDS_Shape& s = it->Shape();
bool trsf_valid = false;
gp_Trsf trsf;
try {
trsf = gtrsf.Trsf();
trsf_valid = true;
} catch (...) {}
const TopoDS_Shape moved_shape = trsf_valid
? BRepBuilderAPI_Transform(s, trsf, true).Shape()
: BRepBuilderAPI_GTransform(s, gtrsf, true).Shape();
const double inf = std::numeric_limits<double>::infinity();
double zmin = inf;
double zmax = -inf;
{TopExp_Explorer exp(moved_shape, TopAbs_VERTEX);
for (; exp.More(); exp.Next()) {
const TopoDS_Vertex& vertex = TopoDS::Vertex(exp.Current());
gp_Pnt pnt = BRep_Tool::Pnt(vertex);
if (pnt.Z() < zmin) { zmin = pnt.Z(); }
if (pnt.Z() > zmax) { zmax = pnt.Z(); }
}}
if (section_height) {
if (zmin > section_height || zmax < section_height) continue;
} else {
if (zmin == inf || (zmax - zmin) < 1.) continue;
}
const double cut_z = section_height.get_value_or(zmin + 1.);
// Create a horizontal cross section 1 meter above the bottom point of the shape
TopoDS_Shape result = BRepAlgoAPI_Section(moved_shape, gp_Pln(gp_Pnt(0, 0, cut_z), gp::DZ()));
Handle(TopTools_HSequenceOfShape) edges = new TopTools_HSequenceOfShape();
Handle(TopTools_HSequenceOfShape) wires = new TopTools_HSequenceOfShape();
{TopExp_Explorer exp(result, TopAbs_EDGE);
for (; exp.More(); exp.Next()) {
edges->Append(exp.Current());
}}
ShapeAnalysis_FreeBounds::ConnectEdgesToWires(edges, 1e-5, false, wires);
gp_Pnt prev;
for (int i = 1; i <= wires->Length(); ++i) {
const TopoDS_Wire& wire = TopoDS::Wire(wires->Value(i));
write(p, wire);
}
}
}
void SvgSerializer::setBoundingRectangle(double width, double height) {
this->width = width;
this->height = height;
this->rescale = true;
}
void SvgSerializer::finalize() {
if (rescale) {
// Scale the resulting image to a bounding rectangle specified by command line arguments
const double dx = xmax - xmin;
const double dy = ymax - ymin;
double sc = 1.;
if (dx / width > dy / height) {
sc = width / dx;
} else {
sc = height / dy;
}
const double cx = xmin * sc;
const double cy = ymin * sc;
{std::vector< boost::shared_ptr<util::string_buffer::float_item> >::const_iterator it;
for (it = xcoords.begin(); it != xcoords.end(); ++it) {
double& v = (*it)->value();
v = v * sc - cx;
}
for (it = ycoords.begin(); it != ycoords.end(); ++it) {
double& v = (*it)->value();
v = v * sc - cy;
}
for (it = radii.begin(); it != radii.end(); ++it) {
(*it)->value() *= sc;
}}
}
std::multimap<IfcSchema::IfcBuildingStorey*, path_object>::const_iterator it;
IfcSchema::IfcBuildingStorey* previous = 0;
bool first = true;
for (it = paths.begin(); it != paths.end(); ++it) {
if (it->first != previous || first) {
if (!first) {
svg_file << " </g>\n";
}
std::ostringstream oss;
svg_file << " <g " << nameElement(it->first) << ">\n";
}
svg_file << " <g " << it->second.first << ">\n";
std::vector<util::string_buffer>::const_iterator jt;
for (jt = it->second.second.begin(); jt != it->second.second.end(); ++jt) {
svg_file << jt->str();
}
svg_file << " </g>\n";
previous = it->first;
first = false;
}
svg_file << " </g>\n";
svg_file << "</svg>" << std::endl;
}
void SvgSerializer::writeHeader() {
svg_file << "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n";
}
std::string SvgSerializer::nameElement(const IfcGeom::Element<double>* elem) {
std::ostringstream oss;
const std::string type = "product";
oss << "id=\"" << type << "-" << elem->unique_id() << "\"";
return oss.str();
}
std::string SvgSerializer::nameElement(const IfcSchema::IfcProduct* elem) {
std::ostringstream oss;
const std::string type = elem->declaration().is(IfcSchema::Type::IfcBuildingStorey) ? "storey" : "product";
oss << "id=\"product-" << IfcParse::IfcGlobalId(elem->GlobalId()).formatted() << "\"";
return oss.str();
}
-79
View File
@@ -1,79 +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 <sstream>
#include <string>
#include <limits>
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcconvert/GeometrySerializer.h"
#include "../ifcconvert/util.h"
class SvgSerializer : public GeometrySerializer {
public:
typedef std::pair<std::string, std::vector<util::string_buffer> > path_object;
protected:
std::ofstream svg_file;
double xmin, ymin, xmax, ymax, width, height;
boost::optional<double> section_height;
bool rescale;
std::multimap<IfcSchema::IfcBuildingStorey*, path_object> paths;
std::vector< boost::shared_ptr<util::string_buffer::float_item> > xcoords;
std::vector< boost::shared_ptr<util::string_buffer::float_item> > ycoords;
std::vector< boost::shared_ptr<util::string_buffer::float_item> > radii;
IfcParse::IfcFile* file;
public:
explicit SvgSerializer(const std::string& out_filename)
: GeometrySerializer()
, svg_file(out_filename.c_str())
, xmin(+std::numeric_limits<double>::infinity())
, xmax(-std::numeric_limits<double>::infinity())
, ymin(+std::numeric_limits<double>::infinity())
, ymax(-std::numeric_limits<double>::infinity())
, rescale(false)
, file(0)
{}
virtual void addXCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { xcoords.push_back(fi); }
virtual void addYCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { ycoords.push_back(fi); }
virtual void addSizeComponent(const boost::shared_ptr<util::string_buffer::float_item>& fi) { radii.push_back(fi); }
virtual void growBoundingBox(double x, double y) { if (x < xmin) xmin = x; if (x > xmax) xmax = x; if (y < ymin) ymin = y; if (y > ymax) ymax = y; }
virtual ~SvgSerializer() {}
virtual void writeHeader();
virtual bool ready();
virtual void write(const IfcGeom::TriangulationElement<double>* /*o*/) {}
virtual void write(const IfcGeom::BRepElement<double>* o);
virtual void write(path_object& p, const TopoDS_Wire& wire);
virtual path_object& start_path(IfcSchema::IfcBuildingStorey* storey, const std::string& id);
virtual bool isTesselated() const { return false; }
virtual void finalize();
virtual void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
virtual void setFile(IfcParse::IfcFile* f) { file = f; }
virtual void setBoundingRectangle(double width, double height);
virtual void setSectionHeight(double h) { section_height = h; }
virtual std::string nameElement(const IfcGeom::Element<double>* elem);
virtual std::string nameElement(const IfcSchema::IfcProduct* elem);
};
#endif
+20 -47
View File
@@ -17,13 +17,12 @@
* *
********************************************************************************/
#include <limits>
#include <iomanip>
#include "../ifcgeom/IfcGeomRenderStyles.h"
#include "WavefrontObjSerializer.h"
#include <iomanip>
bool WaveFrontOBJSerializer::ready() {
return obj_stream.is_open() && mtl_stream.is_open();
}
@@ -44,7 +43,7 @@ void WaveFrontOBJSerializer::writeHeader() {
mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n";
}
void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style) {
void WaveFrontOBJSerializer::writeMaterial(const IfcGeomObjects::Material& style) {
mtl_stream << "newmtl " << style.name() << "\n";
if (style.hasDiffuse()) {
const double* diffuse = style.diffuse();
@@ -66,24 +65,25 @@ void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style) {
}
}
}
void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<double>* o) {
void WaveFrontOBJSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject* o) {
obj_stream << "g " << o->unique_id() << "\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";
obj_stream << std::setprecision(std::numeric_limits<double>::digits10);
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
const IfcGeomObjects::IfcRepresentationTriangulation& mesh = o->mesh();
const int vcount = (int)mesh.verts().size() / 3;
for ( std::vector<double>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) {
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<double>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) {
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++);
@@ -97,7 +97,12 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<double>*
const int material_id = *(material_it++);
if (material_id != previous_material_id) {
const IfcGeom::Material& material = mesh.materials()[material_id];
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()) {
@@ -111,38 +116,6 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<double>*
const int v2 = *(it++)+vcount_total;
const int v3 = *(it++)+vcount_total;
obj_stream << "f " << v1 << "//" << v1 << " " << v2 << "//" << v2 << " " << v3 << "//" << v3 << "\n";
}
std::set<int> faces_set (mesh.faces().begin(), mesh.faces().end());
const std::vector<int>& edges = mesh.edges();
for ( std::vector<int>::const_iterator it = edges.begin(); it != edges.end(); ) {
const int i1 = *(it++);
const int i2 = *(it++);
if (faces_set.find(i1) != faces_set.end() || faces_set.find(i2) != faces_set.end()) {
continue;
}
const int material_id = *(material_it++);
if (material_id != previous_material_id) {
const IfcGeom::Material& material = mesh.materials()[material_id];
const std::string material_name = material.name();
obj_stream << "usemtl " << material_name << "\n";
if (materials.find(material_name) == materials.end()) {
writeMaterial(material);
materials.insert(material_name);
}
previous_material_id = material_id;
}
const int v1 = i1 + vcount_total;
const int v2 = i2 + vcount_total;
obj_stream << "l " << v1 << " " << v2 << "\n";
}
vcount_total += vcount;
vcount_total += vcount;
}
+4 -5
View File
@@ -44,13 +44,12 @@ public:
virtual ~WaveFrontOBJSerializer() {}
bool ready();
void writeHeader();
void writeMaterial(const IfcGeom::Material& style);
void write(const IfcGeom::TriangulationElement<double>* o);
void write(const IfcGeom::BRepElement<double>* /*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
-293
View File
@@ -1,293 +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/foreach.hpp>
#include <boost/version.hpp>
#include "XmlSerializer.h"
#include <algorithm>
using boost::property_tree::ptree;
using namespace IfcSchema;
static 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) {
boost::optional<std::string> 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->declaration().type())) {
IfcUtil::IfcBaseType* f = (IfcUtil::IfcBaseType*) e;
value = format_attribute(f->data().getArgument(0), f->data().getArgument(0)->type());
} else if (e->declaration().is(IfcSchema::Type::IfcSIUnit) || e->declaration().is(IfcSchema::Type::IfcConversionBasedUnit)) {
// Some string concatenation to have a unit name as a XML attribute.
std::string unit_name;
if (e->declaration().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();
}
// TODO add toLower() and toUpper() string helper functions for the project
std::transform(unit_name.begin(), unit_name.end(), unit_name.begin(), ::tolower);
value = unit_name;
}
break; }
}
return value;
}
// 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;
const unsigned n = instance->data().getArgumentCount();
std::vector<const IfcParse::entity::attribute*> attributes = instance->declaration().all_attributes();
for (unsigned i = 0; i < n; ++i) {
const Argument* argument = instance->data().getArgument(i);
if (argument->isNull()) continue;
std::string argument_name = attributes[i]->name();
std::map<std::string, std::string>::const_iterator argument_name_it;
argument_name_it = argument_name_map.find(argument_name);
if (argument_name_it != argument_name_map.end()) {
argument_name = argument_name_it->second;
}
const IfcUtil::ArgumentType argument_type = instance->data().getArgument(i)->type();
boost::optional<std::string> value;
try {
value = format_attribute(argument, argument_type);
} 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->declaration().type()), child);
}
// A function to be called recursively. Template specialization is used
// to descend into decomposition, containment and property relationships.
template <typename A>
void descend(A* instance, ptree& tree) {
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 and IfcRelDefinesByProperties relations.
template <>
void descend(IfcProduct* product, ptree& tree) {
ptree& child = format_entity_instance(product, tree);
if (product->declaration().is(Type::IfcSpatialStructureElement)) {
IfcSpatialStructureElement* structure = (IfcSpatialStructureElement*) product;
IfcProduct::list::ptr elements = get_related
<IfcSpatialStructureElement, IfcRelContainedInSpatialStructure, IfcProduct>
(structure, &IfcSpatialStructureElement::ContainsElements, &IfcRelContainedInSpatialStructure::RelatedElements);
for (IfcProduct::list::it it = elements->begin(); it != elements->end(); ++it) {
descend(*it, child);
}
}
#ifdef USE_IFC2x3
IfcObjectDefinition::list::ptr structures = get_related
<IfcProduct, IfcRelDecomposes, IfcObjectDefinition>
(product, &IfcProduct::IsDecomposedBy, &IfcRelDecomposes::RelatedObjects);
#else
IfcObjectDefinition::list::ptr structures = get_related
<IfcProduct, IfcRelAggregates, IfcObjectDefinition>
(product, &IfcProduct::IsDecomposedBy, &IfcRelAggregates::RelatedObjects);
#endif
for (IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
IfcObjectDefinition* ob = *it;
if (ob->declaration().is(Type::IfcSpatialStructureElement)) {
descend((IfcProduct*)ob, child);
} else {
descend(ob, child);
}
}
IfcPropertySetDefinition::list::ptr property_sets = get_related
<IfcProduct, IfcRelDefinesByProperties, IfcPropertySetDefinition>
(product, &IfcProduct::IsDefinedBy, &IfcRelDefinesByProperties::RelatingPropertyDefinition);
for (IfcPropertySetDefinition::list::it it = property_sets->begin(); it != property_sets->end(); ++it) {
IfcPropertySetDefinition* pset = *it;
if (pset->declaration().is(Type::IfcPropertySet)) {
format_entity_instance(pset, child, true);
}
}
}
// Descends into the tree by recursing into IfcRelDecomposes relations.
template <>
void descend(IfcProject* project, ptree& tree) {
ptree& child = format_entity_instance(project, tree);
#ifdef USE_IFC2x3
IfcObjectDefinition::list::ptr structures = get_related
<IfcProject, IfcRelDecomposes, IfcObjectDefinition>
(project, &IfcProject::IsDecomposedBy, &IfcRelDecomposes::RelatedObjects);
#else
IfcObjectDefinition::list::ptr structures = get_related
<IfcProject, IfcRelAggregates, IfcObjectDefinition>
(project, &IfcProduct::IsDecomposedBy, &IfcRelAggregates::RelatedObjects);
#endif
for (IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
IfcObjectDefinition* ob = *it;
if (ob->declaration().is(Type::IfcSpatialStructureElement)) {
descend((IfcProduct*)ob, child);
} else {
descend(ob, 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->declaration().is(Type::IfcComplexProperty)) {
IfcComplexProperty* complex = (IfcComplexProperty*) p;
format_properties(complex->HasProperties(), node);
} else {
format_entity_instance(p, node);
}
}
}
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, decomposition, properties;
// Write the SPF header as XML nodes.
BOOST_FOREACH(const std::string& s, file->header().file_description().description()) {
header.add_child("file_description.description", ptree(s));
}
BOOST_FOREACH(const std::string& s, file->header().file_name().author()) {
header.add_child("file_name.author", ptree(s));
}
BOOST_FOREACH(const std::string& s, file->header().file_name().organization()) {
header.add_child("file_name.organization", ptree(s));
}
BOOST_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);
}
root.add_child("ifc.header", header);
root.add_child("ifc.properties", properties);
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);
}
-43
View File
@@ -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();
}
-64
View File
@@ -1,64 +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;
};
class string_item : public item {
std::string s;
public:
string_item(const std::string& s) : s(s) {}
void assign(const std::string& s) { this->s = s; }
const std::string& value() const { return s; }
std::string& value() { return s; }
std::string str() const { return s; }
};
class float_item : public item {
double d;
public:
float_item(const double& d) : d(d) {}
void assign(const double& d) { this->d = d; }
const double& value() const { return d; }
double& value() { return d; }
std::string str() const { std::stringstream ss; ss << d; return ss.str(); }
};
private:
std::vector< boost::shared_ptr<item> > items;
void clear();
void assign(const std::vector< boost::shared_ptr<item> >& other);
public:
boost::shared_ptr<string_item> add(const std::string& s);
boost::shared_ptr<float_item> add(const double& d);
std::string str() const;
};
}
#endif
+71
View File
@@ -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
+779
View File
@@ -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;
}
}
"""
+1 -3
View File
@@ -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
+23 -32
View File
@@ -115,7 +115,7 @@ actions = {
'general_aggregation_types' : "lambda t: AggregationType(t)",
'select_type' : "lambda t: SelectType(t)",
'binary_type' : "lambda t: BinaryType(t)",
'subtype_declaration' : "lambda t: SubTypeExpression(t)",
'subtype_declaration' : "lambda t: SubtypeExpression(t)",
'derive_clause' : "lambda t: AttributeList('derive', t)",
'derived_attr' : "lambda t: DerivedAttribute(t)",
'inverse_clause' : "lambda t: AttributeList('inverse', t)",
@@ -158,45 +158,36 @@ for id in to_emit:
stmt = "Suppress%s" % stmt
statements.append("%s << %s" % (id, stmt))
print ("""import os
import sys
import pickle
print ("""import sys
from pyparsing import *
from nodes import *
cache_file = sys.argv[1] + ".cache.dat"
if os.path.exists(cache_file):
with open(cache_file, "rb") as f:
mapping = pickle.load(f)
else:
from pyparsing import *
from nodes import *
import schema
import mapping
%s
syntax.ignore("--" + restOfLine)
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
ast = syntax.parseFile(sys.argv[1])
schema = schema.Schema(ast)
mapping = mapping.Mapping(schema)
%s
with open(cache_file, "wb") as f:
pickle.dump(mapping, f, protocol=0)
import schema
import mapping
import header
import enum_header
import implementation
import latebound_header
import latebound_implementation
import schema_class
import rt_header
import rt_implementation
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
ast = syntax.parseFile(sys.argv[1])
schema = schema.Schema(ast)
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()
schema_class.SchemaClass(mapping).emit()
rt_header.RuntimeTypingHeader(mapping).emit()
rt_implementation.RuntimeTypingImplementation(mapping).emit()
sys.stdout.write(mapping.schema.name)
"""%('\n '.join(statements)))
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)))
-35
View File
@@ -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()
+4 -11
View File
@@ -27,17 +27,11 @@
# #
###############################################################################
import re
import os
import re,csv
import csv
from builtins import open
try: from html.entities import entitydefs
except: from htmlentitydefs import entitydefs
make_absolute = lambda fn: os.path.join(os.path.dirname(os.path.realpath(__file__)), fn)
name_to_oid = {}
oid_to_desc = {}
oid_to_name = {}
@@ -45,19 +39,18 @@ 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, encoding='utf-8', errors='ignore') as f:
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(make_absolute('DocEntityAttributes.csv'), encoding='utf-8', errors='ignore') 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'), encoding='utf-8', errors='ignore') 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]
+6 -7
View File
@@ -18,11 +18,10 @@
###############################################################################
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()]), key=lambda s: s.lower())
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]))
self.str = templates.enum_header % {
'schema_name_upper' : mapping.schema.name.upper(),
@@ -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()
+28 -33
View File
@@ -17,40 +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 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 not in emitted_simpletypes:
continue
emitted_simpletypes.add(name)
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 = []
@@ -66,11 +65,11 @@ class Header(codegen.Base):
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.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]
@@ -96,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 ' 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 ' 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 ' 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))
@@ -124,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 -83
View File
@@ -17,10 +17,9 @@
# #
###############################################################################
import codegen
import templates
class Implementation(codegen.Base):
class Implementation:
def __init__(self, mapping):
enumeration_functions = []
entity_implementations = []
@@ -62,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 = '',
@@ -91,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,
@@ -129,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'] for a in mapping.get_assignable_arguments(related_entity, include_derived=True)].index(attr_name)
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,
@@ -156,10 +133,10 @@ class Implementation(codegen.Base):
)
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_entity_stmt%locals() for name, type in mapping.schema.simpletypes.items()]
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()]), key=lambda s: s.lower())
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]))
max_len = max(map(len, enumerable_types))
type_name_strings = catc(map(stringify, enumerable_types))
string_map_statements = [templates.string_map_statement % {
@@ -177,48 +154,6 @@ class Implementation(codegen.Base):
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 ),
('declaration', templates.const_function, 'const IfcParse::type_declaration&', (), templates.simpletype_impl_declaration ),
('', constructor, '', ('IfcAbstractEntity* e',), templates.simpletype_impl_explicit_constructor),
('', constructor, '', ("%s v" % type_str,), simpletype_impl_constructor ),
('', templates.cast_function, type_str, (), simpletype_impl_cast )
))))
simple_type_impl.append('')
external_definitions = ["extern entity* %s_type;" % n for n in mapping.schema.entities.keys() ] + \
["extern type_declaration* %s_type;" % n for n in mapping.schema.simpletypes.keys()]
self.str = templates.implementation % {
'schema_name_upper' : mapping.schema.name.upper(),
@@ -230,15 +165,14 @@ class Implementation(codegen.Base):
'string_map_statements' : catnl(string_map_statements),
'simple_type_statement' : simple_type_statements,
'parent_type_statements' : catnl(parent_type_statements),
'entity_implementations' : catnl(entity_implementations),
'simple_type_impl' : catnl(simple_type_impl),
'external_definitions' : catnl(external_definitions)
'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()
+42 -89
View File
@@ -17,9 +17,6 @@
# #
###############################################################################
from __future__ import print_function
import sys
import nodes
import templates
@@ -27,44 +24,24 @@ class Mapping:
express_to_cpp_typemapping = {
'boolean' : 'bool',
'logical' : 'boost::logic::tribool',
'logical' : 'bool',
'integer' : 'int',
'real' : 'double',
'number' : 'double',
'string' : 'std::string',
'binary' : 'boost::dynamic_bitset<>'
'string' : 'std::string'
}
supported_argument_types = set([
'INT', 'BOOL', 'TRIBOOL', 'DOUBLE', 'STRING', 'BINARY', 'ENUMERATION', 'ENTITY_INSTANCE',
'AGGREGATE_OF_INT', 'AGGREGATE_OF_BOOL', 'AGGREGATE_OF_TRIBOOL', 'AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_STRING', 'AGGREGATE_OF_BINARY', 'AGGREGATE_OF_ENTITY_INSTANCE',
'AGGREGATE_OF_AGGREGATE_OF_INT', 'AGGREGATE_OF_AGGREGATE_OF_BOOL', 'AGGREGATE_OF_AGGREGATE_OF_TRIBOOL', 'AGGREGATE_OF_AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE',
])
def __init__(self, schema):
self.schema = schema
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)):
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,73 +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"
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 (%s) mapped as 'unknown'" % (attr, ty), 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
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' : attr_type.bounds.lower,
'upper' : attr_type.bounds.upper
'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
@@ -161,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):
@@ -208,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)]
+7 -17
View File
@@ -44,17 +44,15 @@ class TypeDeclaration(Node):
class EntityDeclaration(Node):
name = property(lambda self: self.tokens[1])
attributes = property(lambda self: self.tokens_of_type(ExplicitAttribute))
abstract = property(lambda self: self.single_token_of_type(SuperTypeExpression) is not None and \
self.single_token_of_type(SuperTypeExpression).abstract)
def init(self):
assert self.tokens[0] == 'entity'
s = self.single_token_of_type(SubTypeExpression)
s = self.single_token_of_type(SubtypeExpression)
self.inverse = self.single_token_of_type(AttributeList, 'type', 'inverse')
self.derive = self.single_token_of_type(AttributeList, 'type', 'derive')
self.supertypes = s.types if s else []
def __repr__(self):
builder = ""
builder += "%sEntity(%s)" % ("Abstract " if self.abstract else "", self.name)
builder += "Entity(%s)" % (self.name)
if len(self.supertypes):
builder += "\n Supertypes: %s"%(",".join(self.supertypes))
if len(self.attributes):
@@ -108,20 +106,12 @@ class SelectType(Node):
class SubSuperTypeExpression(Node):
type = property(lambda self: self.tokens[0])
types = property(lambda self: self.tokens[3::2])
abstract = False
def init(self):
if self.tokens[0] == 'abstract':
self.tokens = self.tokens[1:]
self.abstract = True
assert self.type == self.type_relationship
assert self.type == self.class_type
class SubTypeExpression(SubSuperTypeExpression):
type_relationship = 'subtype'
class SuperTypeExpression(SubSuperTypeExpression):
type_relationship = 'supertype'
class SubtypeExpression(SubSuperTypeExpression):
class_type = 'subtype'
class AttributeList(Node):
@@ -137,7 +127,7 @@ class AttributeList(Node):
class InverseAttribute(Node):
name = property(lambda self: self.tokens[0])
type = property(lambda self: None if len(self.tokens) == 6 else self.tokens[2])
type = property(lambda self: self.tokens[2])
bounds = property(lambda self: None if len(self.tokens) == 6 else self.tokens[3])
entity = property(lambda self: self.tokens[-4])
attribute = property(lambda self: self.tokens[-2])
@@ -159,7 +149,7 @@ class BinaryType(Node):
def init(self):
pass
def __repr__(self):
return "binary"
return "BINARY"
class BoundSpecification(Node):
@@ -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()
@@ -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)
@@ -50,14 +49,12 @@ class LateBoundImplementation(codegen.Base):
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)
@@ -101,7 +98,7 @@ class LateBoundImplementation(codegen.Base):
'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()
+10 -15
View File
@@ -18,34 +18,29 @@
###############################################################################
import nodes
import platform
import collections
if tuple(map(int, platform.python_version_tuple())) < (2, 7):
import ordereddict
collections.OrderedDict = ordereddict.OrderedDict
class Schema:
def is_enumeration(self, v):
return 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: collections.OrderedDict(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)
self.simpletypes = of_type(str, nodes.AggregationType)
-215
View File
@@ -1,215 +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 operator
import nodes
import codegen
import templates
class SchemaClass(codegen.Base):
def __init__(self, mapping):
class UnmetDependenciesException(Exception): pass
schema_name = mapping.schema.name
declared_types = []
def get_declared_type(type, emitted_names=None):
if isinstance(type, nodes.AggregationType):
aggr_type = type.aggregate_type
make_bound = lambda b: -1 if b == '?' else int(b)
bound1, bound2 = map(make_bound, (type.bounds.lower, type.bounds.upper))
decl_type = get_declared_type(type.type, emitted_names)
return "new aggregation_type(aggregation_type::%(aggr_type)s_type, %(bound1)d, %(bound2)d, %(decl_type)s)" % locals()
elif isinstance(type, nodes.BinaryType):
return "new simple_type(simple_type::binary_type)"
elif isinstance(type, str):
if mapping.schema.is_type(type) or mapping.schema.is_entity(type):
if emitted_names is None or type in emitted_types:
return "new named_type(%s_type)" % type
else:
raise UnmetDependenciesException(type)
else:
return "new simple_type(simple_type::%s_type)" % type
def find_inverse_name_and_index(entity_name, attribute_name):
attributes_per_subtype = []
while True:
entity = mapping.schema.entities[entity_name]
attr_names = list(map(operator.attrgetter('name'), entity.attributes))
if len(attr_names):
attributes_per_subtype.append((entity_name, attr_names))
if len(entity.supertypes) != 1: break
entity_name = entity.supertypes[0]
index = 0
for et, attrs in attributes_per_subtype[::-1]:
try: return et, attrs.index(attribute_name)
except: pass
self.schema_name = mapping.schema.name.capitalize()
statements = ['',
'#include "../ifcparse/IfcSchema.h"',
'',
'using namespace IfcParse;'
'']
collections_by_type = (('entity', mapping.schema.entities ),
('type_declaration', mapping.schema.simpletypes ),
('select_type', mapping.schema.selects ),
('enumeration_type', mapping.schema.enumerations))
for cpp_type, collection in collections_by_type:
for name in collection.keys():
statements.append('%(cpp_type)s* %(name)s_type = 0;' % locals())
statements.append("""
#if defined(__clang__)
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC push_options
#pragma GCC optimize ("O0")
#elif defined(_MSC_VER)
#pragma optimize("", off)
#endif
""")
statements.append('schema_definition* populate_schema() {')
emitted_types = set()
# while len(emitted_types) < len(set(mapping.schema.simpletypes.keys()) - {"IfcPropertySetDefinitionSet"}):
while len(emitted_types) < len(set(mapping.schema.simpletypes.keys()) - {"IfcPropertySetDefinitionSet"}):
for name, type in mapping.schema.simpletypes.items():
if name in emitted_types: continue
# No support for types refering to entities :(
if name == "IfcPropertySetDefinitionSet": continue
try:
declared_type = get_declared_type(type, emitted_types)
except UnmetDependenciesException:
continue
statements.append(' %(name)s_type = new type_declaration(IfcSchema::Type::%(name)s, %(declared_type)s);' % locals())
emitted_types.add(name)
declared_types.append('%(name)s_type' % locals())
for name, enum in mapping.schema.enumerations.items():
statements.append(' {')
statements.append(' std::vector<std::string> items; items.reserve(%d);' % len(enum.values))
statements.extend(map(lambda v: ' items.push_back("%s");' % v, sorted(enum.values)))
statements.append(' %(name)s_type = new enumeration_type(IfcSchema::Type::%(name)s, items);' % locals())
statements.append(' }')
declared_types.append('%(name)s_type' % locals())
emitted_entities = set()
while len(emitted_entities) < len(mapping.schema.entities):
for name, type in mapping.schema.entities.items():
if name in emitted_entities: continue
if len(type.supertypes) == 0 or set(type.supertypes) < emitted_entities:
supertype = '0' if len(type.supertypes) == 0 else '%s_type' % type.supertypes[0]
statements.append(' %(name)s_type = new entity(IfcSchema::Type::%(name)s, %(supertype)s);' % locals())
emitted_entities.add(name)
declared_types.append('%(name)s_type' % locals())
emmited = emitted_types | emitted_entities | set(mapping.schema.enumerations.keys())
emitted_selects = set()
while len(emitted_selects) < len(mapping.schema.selects):
for name, type in mapping.schema.selects.items():
if name in emitted_selects: continue
type_values = sorted(set(type.values) - {"IfcPropertySetDefinitionSet"})
if set(type_values) < emmited:
statements.append(' {')
statements.append(' std::vector<const declaration*> items; items.reserve(%d);' % len(type_values))
statements.extend(map(lambda v: ' items.push_back(%s_type);' % v, sorted(type_values)))
statements.append(' %(name)s_type = new select_type(IfcSchema::Type::%(name)s, items);' % locals())
statements.append(' }')
emitted_selects.add(name)
emmited.add(name)
declared_types.append('%(name)s_type' % locals())
num_declarations = len(declared_types)
for name, type in mapping.schema.entities.items():
derived = set(mapping.derived_in_supertype(type))
attribute_names = list(map(operator.attrgetter('name'), mapping.arguments(type)))
statements.append(' {')
statements.append(' std::vector<const entity::attribute*> attributes; attributes.reserve(%d);' % len(type.attributes))
for attr in type.attributes:
attr_name, optional = attr.name, str(attr.optional).lower()
decl_type = get_declared_type(attr.type)
statements.append(' attributes.push_back(new entity::attribute("%(attr_name)s", %(decl_type)s, %(optional)s));' % locals())
statements.append(' std::vector<bool> derived; derived.reserve(%d);' % len(attribute_names))
statements.append(' ' + " ".join(map(lambda b: 'derived.push_back(%s);' % str(b in derived).lower(), attribute_names)))
statements.append(' %(name)s_type->set_attributes(attributes, derived);' % locals())
statements.append(' }')
for name, type in mapping.schema.entities.items():
if type.inverse:
statements.append(' {')
statements.append(' std::vector<const entity::inverse_attribute*> attributes; attributes.reserve(%d);' % len(type.inverse.elements))
for attr in type.inverse.elements:
if attr.bounds:
make_bound = lambda b: -1 if b == '?' else int(b)
bound1, bound2 = map(make_bound, (attr.bounds.lower, attr.bounds.upper))
else:
bound1, bound2 = -1, -1
attr_name, aggr_type, entity_ref = attr.name, attr.type, attr.entity
if aggr_type is None: aggr_type = 'unspecified'
attribute_entity, attribute_entity_index = find_inverse_name_and_index(entity_ref, attr.attribute)
statements.append(' attributes.push_back(new entity::inverse_attribute("%(attr_name)s", entity::inverse_attribute::%(aggr_type)s_type, %(bound1)d, %(bound2)d, %(entity_ref)s_type, %(attribute_entity)s_type->attributes()[%(attribute_entity_index)d]));' % locals())
statements.append(' %(name)s_type->set_inverse_attributes(attributes);' % locals())
statements.append(' }')
statements.append('')
statements.append(' std::vector<const declaration*> declarations; declarations.reserve(%(num_declarations)d);' % locals())
for type_name in declared_types:
statements.append(' declarations.push_back(%(type_name)s);' % locals())
statements.append(' return new schema_definition("%(schema_name)s", declarations, true);' % locals())
statements.extend(('}',''))
statements.append("""
#if defined(__clang__)
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC pop_options
#elif defined(_MSC_VER)
#pragma optimize("", on)
#endif
""")
statements.extend(('const schema_definition& get_schema() {',
'',
' static const schema_definition* s = populate_schema();',
' return *s;',
'}','',''))
self.str = "\n".join(statements)
self.file_name = '%s-schema.cpp'%self.schema_name
def __repr__(self):
return self.str
+82 -147
View File
@@ -23,27 +23,18 @@ header = """
#include <string>
#include <vector>
#include <map>
#include <boost/optional.hpp>
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcSchema.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/%(schema_name)senum.h"
const IfcParse::schema_definition& get_schema();
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4100)
#endif
#define IfcSchema %(schema_name)s
namespace %(schema_name)s {
const char* const Identifier = "%(schema_name_upper)s";
// Forward definitions
%(forward_definitions)s
@@ -51,13 +42,9 @@ 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);
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif
"""
@@ -71,7 +58,7 @@ namespace %(schema_name)s {
namespace Type {
typedef enum {
%(types)s, UNDEFINED
%(types)s, ALL
} Enum;
Enum Parent(Enum v);
Enum FromString(const std::string& s);
@@ -84,7 +71,7 @@ namespace Type {
#endif
"""
lb_header = """
rt_header = """
#ifndef %(schema_name_upper)sRT_H
#define %(schema_name_upper)sRT_H
@@ -99,13 +86,12 @@ namespace Type {
int GetAttributeCount(Enum t);
int GetAttributeIndex(Enum t, const std::string& a);
IfcUtil::ArgumentType GetAttributeType(Enum t, unsigned char a);
Enum GetAttributeEntity(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);
std::set<std::string> GetInverseAttributeNames(Enum t);
Enum GetAttributeEnumerationClass(Enum t, unsigned char a);
void PopulateDerivedFields(IfcWrite::IfcWritableEntity* e);
}}
@@ -114,21 +100,15 @@ namespace Type {
implementation= """
#include "../ifcparse/%(schema_name)s.h"
#include "../ifcparse/IfcSchema.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcWrite.h"
#include "../ifcparse/IfcWritableEntity.h"
#include <map>
using namespace %(schema_name)s;
using namespace IfcParse;
using namespace IfcWrite;
// External definitions
%(external_definitions)s
IfcUtil::IfcBaseClass* %(schema_name)s::SchemaEntity(IfcAbstractEntity* e) {
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;
@@ -165,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"
@@ -186,23 +183,10 @@ 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;
#if defined(__clang__)
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC push_options
#pragma GCC optimize ("O0")
#elif defined(_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;
@@ -221,13 +205,6 @@ void InitDerivedMap() {
%(derived_field_statements)s
}
#if defined(__clang__)
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC pop_options
#elif defined(_MSC_VER)
#pragma optimize("", on)
#endif
int Type::GetAttributeIndex(Enum t, const std::string& a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
@@ -249,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);
@@ -284,49 +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;
}
}
if ((t = Parent(t)) == -1) 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);
}
}
if ((t = Parent(t)) == -1) 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) {
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);
}
}
}
"""
@@ -334,8 +290,8 @@ 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
@@ -347,32 +303,11 @@ derived_field_statement = ' {std::set<int> idxs; %(statements)sderived_map[Ty
derived_field_statement_attrs = 'idxs.insert(%d); '
simpletype = """%(documentation)s
class %(name)s : public %(superclass)s {
public:
virtual const IfcParse::type_declaration& declaration() 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 data_->getArgument(i);"
simpletype_impl_is_with_supertype = "return v == Type::%(class_name)s || %(superclass)s::is(v);"
simpletype_impl_is_without_supertype = "return v == %(class_name)s::Class();"
simpletype_impl_type = "return Type::%(class_name)s;"
simpletype_impl_class = "return Type::%(class_name)s;"
simpletype_impl_explicit_constructor = "data_ = e;"
simpletype_impl_constructor = "IfcWritableEntity* e = new IfcWritableEntity(Type::%(class_name)s); e->setArgument(0, v); data_ = e;"
simpletype_impl_constructor_templated = "IfcWritableEntity* e = new IfcWritableEntity(Type::%(class_name)s); e->setArgument(0, v->generalize()); data_ = e;"
simpletype_impl_cast = "return *data_->getArgument(0);"
simpletype_impl_cast_templated = "IfcEntityList::ptr es = *data_->getArgument(0); return es->as<%(underlying_type)s>();"
simpletype_impl_declaration = "return *%(class_name)s_type;"
select = """%(documentation)s
typedef IfcUtil::IfcBaseClass %(name)s;
typedef IfcUtil::IfcSchemaEntity %(name)s;
"""
enumeration = """namespace %(name)s {
@@ -386,11 +321,18 @@ const char* ToString(%(name)s v);
entity = """%(documentation)s
class %(name)s %(superclass)s{
public:
%(attributes)s %(inverse)s virtual const IfcParse::entity& declaration() const;
%(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 const char* getArgumentName(unsigned int i) const {%(argument_name_function_body)s}
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;
};
"""
@@ -408,50 +350,43 @@ const char* %(name)s::ToString(%(name)s v) {
"""
entity_implementation = """// Function implementations for %(name)s
%(attributes)s
%(inverse)s
const IfcParse::entity& %(name)s::declaration() const { return *%(name)s_type; }
%(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"); data_ = e; }
%(name)s::%(name)s(%(constructor_arguments)s) : %(superclass)s { IfcWritableEntity* e = new IfcWritableEntity(Class());%(constructor_implementation)s data_ = e; EntityBuffer::Add(this); }
%(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; }'
parent_type_test = " || %s::is(v)"
optional_attr_stmt = "return !data_->getArgument(%(index)d)->isNull();"
optional_attr_stmt = "return !entity->getArgument(%(index)d)->isNull();"
get_attr_stmt = "return *data_->getArgument(%(index)d);"
get_attr_stmt_enum = "return %(type)s::FromString(*data_->getArgument(%(index)d));"
get_attr_stmt_entity = "return (%(type)s)((IfcUtil::IfcBaseClass*)(*data_->getArgument(%(index)d)));"
get_attr_stmt_array = "IfcEntityList::ptr es = *data_->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
get_attr_stmt_nested_array = "IfcEntityListList::ptr es = *data_->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
get_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::IfcSchemaEntity)(*entity->getArgument(%(index)d)));"
get_attr_stmt_array = "RETURN_AS_LIST(%(list_instance_type)s,%(index)d)"
get_inverse = "return data_->getInverse(Type::%(type)s, %(index)d)->as<%(type)s>();"
get_inverse = "RETURN_INVERSE(%(type)s)"
set_attr_stmt = "if ( ! data_->isWritable() ) { data_ = new IfcWritableEntity(data_); } ((IfcWritableEntity*)data_)->setArgument(%(index)d,v);"
set_attr_stmt_enum = "if ( ! data_->isWritable() ) { data_ = new IfcWritableEntity(data_); } ((IfcWritableEntity*)data_)->setArgument(%(index)d,v,%(type)s::ToString(v));"
set_attr_stmt_array = "if ( ! data_->isWritable() ) { data_ = new IfcWritableEntity(data_); } ((IfcWritableEntity*)data_)->setArgument(%(index)d,v->generalize());"
set_attr_stmt = "if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%(index)d,v);"
set_attr_stmt_enum = "if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%(index)d,v,%(type)s::ToString(v));"
set_attr_stmt_array = "if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%(index)d,v->generalize());"
constructor_stmt = " e->setArgument(%(index)d,(%(name)s));"
constructor_stmt_enum = " e->setArgument(%(index)d,%(name)s,%(type)s::ToString(%(name)s));"
@@ -459,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 ""
+22 -90
View File
@@ -36,33 +36,14 @@
#include <TopoDS_Face.hxx>
#include <Geom_Curve.hxx>
#include <gp_Pln.hxx>
#include <TColgp_SequenceOfPnt.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"
#define IN_CACHE(T,E,t,e) std::map<int,t>::const_iterator it = cache.T.find(E->data().id());\
if ( it != cache.T.end() ) { e = it->second; return true; }
#define CACHE(T,E,e) cache.T[E->data().id()] = e;
namespace IfcGeom {
class Cache {
public:
#include "IfcRegisterCreateCache.h"
std::map<int, SurfaceStyle> Style;
std::map<int, TopoDS_Shape> Shape;
};
class Kernel {
private:
Cache cache;
public:
// Tolerances and settings for various geometrical operations:
enum GeomValue {
// Specifies the deflection of the mesher
@@ -81,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
@@ -92,24 +76,25 @@ 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_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 is_compound(const TopoDS_Shape& shape);
bool is_convex(const TopoDS_Wire& wire);
@@ -121,72 +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);
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);
std::pair<std::string, double> initializeUnits(IfcSchema::IfcUnitAssignment*);
IfcSchema::IfcObjectDefinition* get_decomposing_entity(IfcSchema::IfcProduct*);
template <typename P>
IfcGeom::BRepElement<P>* create_brep_for_representation_and_product(const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*);
const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem* representation_item);
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) {
// For certain representation items, most notably boolean operands,
// a style definition might reside on one of its operands.
representation_item = find_item_carrying_style(representation_item);
IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem();
for (IfcSchema::IfcStyledItem::list::it jt = styled_items->begin(); jt != styled_items->end(); ++jt) {
#ifdef USE_IFC4
IfcEntityList::ptr style_assignments = (*jt)->Styles();
for (IfcEntityList::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
if (!(*kt)->declaration().is(IfcSchema::Type::IfcPresentationStyleAssignment)) {
continue;
}
IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt;
#else
IfcSchema::IfcPresentationStyleAssignment::list::ptr style_assignments = (*jt)->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->declaration().is(IfcSchema::Type::IfcSurfaceStyle)) {
IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style;
if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) {
IfcEntityList::ptr styles_elements = surface_style->Styles();
for (IfcEntityList::it mt = styles_elements->begin(); mt != styles_elements->end(); ++mt) {
if ((*mt)->declaration().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);
namespace Cache {
void Purge();
void PurgeShapeCache();
}
#include "IfcRegisterGeomHeader.h"
};
IfcSchema::IfcProductDefinitionShape* tesselate(TopoDS_Shape& shape, double deflection, IfcEntityList::ptr es);
}
#endif
+19 -58
View File
@@ -77,36 +77,32 @@
#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);
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
return false;
}
gp_Trsf trsf;
IfcSchema::IfcAxis2Placement* placement = l->Position();
if (placement->declaration().is(IfcSchema::Type::IfcAxis2Placement3D)) {
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
IfcSchema::IfcAxis2Placement placement = l->Position();
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
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);
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
return false;
}
// Open Cascade does not allow ellipses of which the minor radius
@@ -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();
if (placement->declaration().is(IfcSchema::Type::IfcAxis2Placement3D)) {
convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
IfcSchema::IfcAxis2Placement placement = l->Position();
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
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,46 +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 IfcSchema::IfcCartesianPoint::list::ptr cps = l->ControlPointsList();
const std::vector<int> mults = l->KnotMultiplicities();
const std::vector<double> knots = l->Knots();
TColgp_Array1OfPnt Poles(0, cps->size() - 1);
TColStd_Array1OfReal Knots(0, (int)knots.size() - 1);
TColStd_Array1OfInteger Mults(0, (int)mults.size() - 1);
Standard_Integer Degree = l->Degree();
Standard_Boolean Periodic = l->ClosedCurve();
int i = 0;
for (IfcSchema::IfcCartesianPoint::list::it it = cps->begin(); it != cps->end(); ++it, ++i) {
gp_Pnt pnt;
if (!convert(*it, pnt)) return false;
Poles(i) = pnt;
}
i = 0;
for (std::vector<int>::const_iterator it = mults.begin(); it != mults.end(); ++it, ++i) {
Mults(i) = *it;
}
i = 0;
for (std::vector<double>::const_iterator it = knots.begin(); it != knots.end(); ++it, ++i) {
Knots(i) = *it;
}
curve = new Geom_BSplineCurve(Poles, Knots, Mults, Degree, Periodic);
return true;
}
#endif
}
-162
View File
@@ -1,162 +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"
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.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;
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; }
Element(const ElementSettings& settings, int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const std::string& context, const gp_Trsf& trsf)
: _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _context(context), _transformation(settings, trsf)
{
std::ostringstream oss;
oss << "product-" << IfcParse::IfcGlobalId(guid).formatted();
if (!_context.empty()) {
std::string ctx = _context;
std::transform(ctx.begin(), ctx.end(), ctx.begin(), ::tolower);
std::replace(ctx.begin(), ctx.end(), ' ', '-');
oss << "-" << ctx;
}
_unique_id = oss.str();
}
virtual ~Element() {}
};
template <typename P>
class BRepElement : public Element<P> {
private:
Representation::BRep* _geometry;
public:
const Representation::BRep& geometry() const { return *_geometry; }
BRepElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const std::string& context, const gp_Trsf& trsf, Representation::BRep* geometry)
: Element<P>(geometry->settings(),id,parent_id,name,type,guid,context,trsf)
, _geometry(geometry)
{}
virtual ~BRepElement() {
delete _geometry;
}
private:
BRepElement(const BRepElement& other);
BRepElement& operator=(const BRepElement& other);
};
template <typename P>
class TriangulationElement : public Element<P> {
private:
Representation::Triangulation<P>* _geometry;
public:
const Representation::Triangulation<P>& geometry() const { return *_geometry; }
TriangulationElement(const BRepElement<P>& shape_model)
: Element<P>(shape_model)
, _geometry(new Representation::Triangulation<P>(shape_model.geometry()))
{}
virtual ~TriangulationElement() {
delete _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
+229 -419
View File
@@ -47,7 +47,6 @@
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <Geom_Line.hxx>
#include <Geom_Plane.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Ellipse.hxx>
#include <Geom_TrimmedCurve.hxx>
@@ -71,7 +70,6 @@
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS_Iterator.hxx>
#include <BRepAlgoAPI_Cut.hxx>
@@ -85,238 +83,134 @@
#include <Standard_Failure.hxx>
#include <BRep_Tool.hxx>
#include <BRepCheck_Face.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <Standard_Version.hxx>
#ifdef USE_IFC4
#include <Geom_BSplineSurface.hxx>
#include <TColgp_Array2OfPnt.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#endif
#include "../ifcgeom/IfcGeom.h"
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
Handle(Geom_Surface) face_surface;
const bool is_face_surface = l->declaration().is(IfcSchema::Type::IfcFaceSurface);
if (is_face_surface) {
IfcSchema::IfcFaceSurface* fs = (IfcSchema::IfcFaceSurface*) l;
fs->FaceSurface();
// FIXME: Surfaces are interpreted as a TopoDS_Shape
TopoDS_Shape surface_shape;
if (!convert_shape(fs->FaceSurface(), surface_shape)) return false;
// FIXME: Assert this obtaines the only face
TopExp_Explorer exp(surface_shape, TopAbs_FACE);
if (!exp.More()) return false;
TopoDS_Face surface = TopoDS::Face(exp.Current());
face_surface = BRep_Tool::Surface(surface);
bool IfcGeom::convert(const IfcSchema::IfcFace::ptr l, TopoDS_Shape& face) {
IfcSchema::IfcFaceBound::list bounds = l->Bounds();
IfcSchema::IfcFaceBound::it it = bounds->begin();
IfcSchema::IfcLoop::ptr loop = (*it)->Bound();
TopoDS_Wire outer_wire;
if ( ! IfcGeom::convert_wire(loop,outer_wire) ) return false;
BRepBuilderAPI_MakeFace mf (outer_wire);
BRepBuilderAPI_FaceError er = mf.Error();
if ( er == BRepBuilderAPI_NotPlanar ) {
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(outer_wire, 0.01, TopAbs_WIRE);
mf.~BRepBuilderAPI_MakeFace();
new (&mf) BRepBuilderAPI_MakeFace(outer_wire);
er = mf.Error();
}
const int num_bounds = bounds->size();
int num_outer_bounds = 0;
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
IfcSchema::IfcFaceBound* bound = *it;
if (bound->declaration().is(IfcSchema::Type::IfcFaceOuterBound)) num_outer_bounds ++;
}
// The number of outer bounds should be one according to the schema. Also Open Cascade
// expects this, but it is not strictly checked. Regardless, if the number is greater,
// the face will still be processed as long as there are no holes. A compound of faces
// is returned in that case.
if (num_bounds > 1 && num_outer_bounds > 1 && num_bounds != num_outer_bounds) {
Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l);
return false;
}
TopoDS_Compound compound;
BRep_Builder builder;
if (num_outer_bounds > 1) {
builder.MakeCompound(compound);
}
// The builder is initialized on the heap because of the various different moments
// of initialization depending on the configuration of surfaces and boundaries.
BRepBuilderAPI_MakeFace* mf = 0;
bool success = false;
int processed = 0;
for (int process_interior = 0; process_interior <= 1; ++process_interior) {
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
IfcSchema::IfcFaceBound* bound = *it;
IfcSchema::IfcLoop* loop = bound->Bound();
bool same_sense = bound->Orientation();
const bool is_interior =
!bound->declaration().is(IfcSchema::Type::IfcFaceOuterBound) &&
(num_bounds > 1) &&
(num_outer_bounds < num_bounds);
// The exterior face boundary is processed first
if (is_interior == !process_interior) continue;
if ( er != BRepBuilderAPI_FaceDone ) return false;
if ( bounds->Size() == 1 ) {
face = mf.Face();
} else {
for( ++it; it != bounds->end(); ++ it) {
IfcSchema::IfcLoop::ptr loop = (*it)->Bound();
TopoDS_Wire wire;
if (!convert_wire(loop, wire)) {
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop);
delete mf;
if ( ! IfcGeom::convert_wire(loop,wire) ) return false;
mf.Add(wire);
}
if ( mf.IsDone() ) {
ShapeFix_Shape sfs(mf.Face());
sfs.Perform();
TopoDS_Shape sfs_shape = sfs.Shape();
bool is_face = sfs_shape.ShapeType() == TopAbs_FACE;
if ( is_face ) {
face = TopoDS::Face(sfs_shape);
} else {
return false;
}
/*
The approach below does not result in a significant speed-up
if (loop->declaration().is(IfcSchema::Type::IfcPolyLoop) && processed == 0 && face_surface.IsNull()) {
IfcSchema::IfcPolyLoop* polyloop = (IfcSchema::IfcPolyLoop*) loop;
IfcSchema::IfcCartesianPoint::list::ptr points = polyloop->Polygon();
if (points->size() == 3) {
// Help Open Cascade by finding the plane more efficiently
IfcSchema::IfcCartesianPoint::list::it point_iterator = points->begin();
gp_Pnt a, b, c;
convert(*point_iterator++, a);
convert(*point_iterator++, b);
convert(*point_iterator++, c);
const gp_XYZ ab = (b.XYZ() - a.XYZ());
const gp_XYZ ac = (c.XYZ() - a.XYZ());
const gp_Vec cross = ab.Crossed(ac);
if (cross.SquareMagnitude() > ALMOST_ZERO) {
const gp_Dir n = cross;
face_surface = new Geom_Plane(a, n);
}
}
}
*/
if (!same_sense) {
wire.Reverse();
}
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(wire, getValue(GV_PRECISION), TopAbs_WIRE);
if (!mf) {
if (face_surface.IsNull()) {
mf = new BRepBuilderAPI_MakeFace(wire);
} else {
mf = new BRepBuilderAPI_MakeFace(face_surface, wire);
}
/* BRepBuilderAPI_FaceError er = mf->Error();
if (er == BRepBuilderAPI_NotPlanar) {
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(wire, getValue(GV_PRECISION), TopAbs_WIRE);
delete mf;
mf = new BRepBuilderAPI_MakeFace(wire);
} */
if (mf->IsDone()) {
TopoDS_Face outer_face_bound = mf->Face();
if (BRepCheck_Face(outer_face_bound).OrientationOfWires() == BRepCheck_BadOrientationOfSubshape) {
wire.Reverse();
same_sense = !same_sense;
delete mf;
if (face_surface.IsNull()) {
mf = new BRepBuilderAPI_MakeFace(wire);
} else {
mf = new BRepBuilderAPI_MakeFace(face_surface, wire);
}
ShapeFix_Face fix(mf->Face());
fix.FixOrientation();
fix.Perform();
outer_face_bound = fix.Face();
}
// If the wires are reversed the face needs to be reversed as well in order
// to maintain the counter-clock-wise ordering of the bounding wire's vertices.
bool all_reversed = true;
TopoDS_Iterator jt(outer_face_bound, false);
for (; jt.More(); jt.Next()) {
const TopoDS_Wire& w = TopoDS::Wire(jt.Value());
if ((w.Orientation() != TopAbs_REVERSED) == same_sense) {
all_reversed = false;
}
}
if (all_reversed) {
outer_face_bound.Reverse();
}
if (num_outer_bounds > 1) {
builder.Add(compound, outer_face_bound);
delete mf; mf = 0;
} else if (num_bounds > 1) {
// Reinitialize the builder to the outer face
// bound in order to add holes more robustly.
delete mf;
// TODO: What about the face_surface?
mf = new BRepBuilderAPI_MakeFace(outer_face_bound);
} else {
face = outer_face_bound;
success = true;
}
} else {
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary", bound);
delete mf;
return false;
}
} else {
mf->Add(wire);
}
processed ++;
} else {
return false;
}
}
if (!success) {
success = processed == num_bounds;
if (success) {
if (num_outer_bounds > 1) {
face = compound;
} else {
success = success && mf->IsDone();
if (success) {
face = mf->Face();
}
}
if ( IfcGeom::GetValue(GV_FORCE_CCW_FACE_ORIENTATION)>0 ) {
// Check the orientation of the face by comparing the
// normal of the topological surface to the Newell's Method's
// normal. Newell's Method is used for the normal calculation
// as a simple edge cross product can give opposite results
// for a concave face boundary.
// Reference: Graphics Gems III p. 231
BRepGProp_Face prop(TopoDS::Face(face));
gp_Vec normal_direction;
gp_Pnt center;
double u1,u2,v1,v2;
prop.Bounds(u1,u2,v1,v2);
prop.Normal((u1+u2)/2.0,(v1+v2)/2.0,center,normal_direction);
gp_Dir face_normal1 = gp_Dir(normal_direction.XYZ());
double x = 0, y = 0, z = 0;
gp_Pnt current, previous, first;
int n = 0;
// Iterate over the vertices of the outer wire (discarding
// any potential holes)
for ( TopExp_Explorer exp(outer_wire,TopAbs_VERTEX);; exp.Next()) {
unsigned has_more = exp.More();
if ( has_more ) {
const TopoDS_Vertex& v = TopoDS::Vertex(exp.Current());
current = BRep_Tool::Pnt(v);
} else {
current = first;
}
if ( n ) {
const double& xn = previous.X();
const double& yn = previous.Y();
const double& zn = previous.Z();
const double& xn1 = current.X();
const double& yn1 = current.Y();
const double& zn1 = current.Z();
x += (yn-yn1)*(zn+zn1);
y += (xn+xn1)*(zn-zn1);
z += (xn-xn1)*(yn+yn1);
} else {
first = current;
}
if ( !has_more ) {
break;
}
previous = current;
++n;
}
if (success) {
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(face, getValue(GV_PRECISION), TopAbs_FACE);
// If Newell's normal does not point in the same direction
// as the topological face normal the face orientation is
// reversed
gp_Vec face_normal2(x,y,z);
if ( face_normal1.Dot(face_normal2) < 0 ) {
TopAbs_Orientation o = face.Orientation();
face.Orientation(o == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD);
}
delete mf;
return success;
}
// It might be a good idea to globally discard faces
// smaller than a certain treshold value. But for now
// only when processing IfcConnectedFacesets the small
// faces are skipped.
// return face_area(face) > 0.0001;
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, TopoDS_Shape& face) {
bool IfcGeom::convert(const IfcSchema::IfcArbitraryClosedProfileDef::ptr l, TopoDS_Shape& face) {
TopoDS_Wire wire;
if ( ! convert_wire(l->OuterCurve(),wire) ) return false;
if ( ! IfcGeom::convert_wire(l->OuterCurve(),wire) ) return false;
TopoDS_Face f;
bool success = convert_wire_to_face(wire, f);
bool success = IfcGeom::convert_wire_to_face(wire, f);
if (success) face = f;
return success;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids* l, TopoDS_Shape& face) {
bool IfcGeom::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids::ptr l, TopoDS_Shape& face) {
TopoDS_Wire profile;
if ( ! convert_wire(l->OuterCurve(),profile) ) return false;
if ( ! IfcGeom::convert_wire(l->OuterCurve(),profile) ) return false;
BRepBuilderAPI_MakeFace mf(profile);
IfcSchema::IfcCurve::list::ptr voids = l->InnerCurves();
for( IfcSchema::IfcCurve::list::it it = voids->begin(); it != voids->end(); ++ it ) {
IfcSchema::IfcCurve::list voids = l->InnerCurves();
for( IfcSchema::IfcCurve::it it = voids->begin(); it != voids->end(); ++ it ) {
TopoDS_Wire hole;
if ( convert_wire(*it,hole) ) {
if ( IfcGeom::convert_wire(*it,hole) ) {
mf.Add(hole);
}
}
@@ -326,52 +220,52 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids*
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleProfileDef* l, TopoDS_Shape& face) {
const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
bool IfcGeom::convert(const IfcSchema::IfcRectangleProfileDef::ptr l, TopoDS_Shape& face) {
const double x = l->XDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
gp_Trsf2d trsf2d;
IfcGeom::Kernel::convert(l->Position(),trsf2d);
IfcGeom::convert(l->Position(),trsf2d);
double coords[8] = {-x,-y,x,-y,x,y,-x,y};
return profile_helper(4,coords,0,0,0,trsf2d,face);
return IfcGeom::profile_helper(4,coords,0,0,0,trsf2d,face);
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef* l, TopoDS_Shape& face) {
const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
const double r = l->RoundingRadius() * getValue(GV_LENGTH_UNIT);
bool IfcGeom::convert(const IfcSchema::IfcRoundedRectangleProfileDef::ptr l, TopoDS_Shape& face) {
const double x = l->XDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double r = l->RoundingRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || r < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
gp_Trsf2d trsf2d;
IfcGeom::Kernel::convert(l->Position(),trsf2d);
IfcGeom::convert(l->Position(),trsf2d);
double coords[8] = {-x,-y, x,-y, x,y, -x,y};
int fillets[4] = {0,1,2,3};
double radii[4] = {r,r,r,r};
return profile_helper(4,coords,4,fillets,radii,trsf2d,face);
return IfcGeom::profile_helper(4,coords,4,fillets,radii,trsf2d,face);
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l, TopoDS_Shape& face) {
const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d = l->WallThickness() * getValue(GV_LENGTH_UNIT);
bool IfcGeom::convert(const IfcSchema::IfcRectangleHollowProfileDef::ptr l, TopoDS_Shape& face) {
const double x = l->XDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d = l->WallThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const bool fr1 = l->hasOuterFilletRadius();
const bool fr1 = l->hasInnerFilletRadius();
const bool fr2 = l->hasInnerFilletRadius();
const double r1 = fr1 ? l->OuterFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.;
const double r2 = fr2 ? l->InnerFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.;
const double r1 = fr2 ? l->OuterFilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT) : 0.;
const double r2 = fr1 ? l->InnerFilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT) : 0.;
if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
@@ -379,15 +273,15 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l,
TopoDS_Face f2;
gp_Trsf2d trsf2d;
IfcGeom::Kernel::convert(l->Position(),trsf2d);
IfcGeom::convert(l->Position(),trsf2d);
double coords1[8] = {-x ,-y, x ,-y, x, y, -x, y };
double coords2[8] = {-x+d,-y+d, x-d,-y+d, x-d,y-d, -x+d,y-d};
double radii1[4] = {r1,r1,r1,r1};
double radii2[4] = {r2,r2,r2,r2};
int fillets[4] = {0,1,2,3};
bool s1 = profile_helper(4,coords1,fr1 ? 4 : 0,fillets,radii1,trsf2d,f1);
bool s2 = profile_helper(4,coords2,fr2 ? 4 : 0,fillets,radii2,trsf2d,f2);
bool s1 = IfcGeom::profile_helper(4,coords1,fr1 ? 4 : 0,fillets,radii1,trsf2d,f1);
bool s2 = IfcGeom::profile_helper(4,coords2,fr2 ? 4 : 0,fillets,radii2,trsf2d,f2);
if (!s1 || !s2) return false;
@@ -406,69 +300,53 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l,
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrapeziumProfileDef* l, TopoDS_Shape& face) {
const double x1 = l->BottomXDim() / 2.0f * getValue(GV_LENGTH_UNIT);
const double w = l->TopXDim() * getValue(GV_LENGTH_UNIT);
const double dx = l->TopXOffset() * getValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
bool IfcGeom::convert(const IfcSchema::IfcTrapeziumProfileDef::ptr l, TopoDS_Shape& face) {
const double x1 = l->BottomXDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double w = l->TopXDim() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double dx = l->TopXOffset() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
if ( x1 < ALMOST_ZERO || w < ALMOST_ZERO || y < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
gp_Trsf2d trsf2d;
IfcGeom::Kernel::convert(l->Position(),trsf2d);
IfcGeom::convert(l->Position(),trsf2d);
double coords[8] = {-x1,-y, x1,-y, dx+w-x1,y, dx-x1,y};
return profile_helper(4,coords,0,0,0,trsf2d,face);
return IfcGeom::profile_helper(4,coords,0,0,0,trsf2d,face);
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcIShapeProfileDef* l, TopoDS_Shape& face) {
const double x1 = l->OverallWidth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double y = l->OverallDepth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() / 2.0f * getValue(GV_LENGTH_UNIT);
const double dy1 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
bool doFillet1 = l->hasFilletRadius();
double f1 = 0.;
if ( doFillet1 ) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
bool IfcGeom::convert(const IfcSchema::IfcIShapeProfileDef::ptr l, TopoDS_Shape& face) {
const double x = l->OverallWidth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->OverallDepth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d2 = l->FlangeThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool doFillet = l->hasFilletRadius();
double f = 0.;
if ( doFillet ) {
f = l->FilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
}
bool doFillet2 = doFillet1;
double x2 = x1, dy2 = dy1, f2 = f1;
if (l->declaration().is(IfcSchema::Type::IfcAsymmetricIShapeProfileDef)) {
IfcSchema::IfcAsymmetricIShapeProfileDef* assym = (IfcSchema::IfcAsymmetricIShapeProfileDef*) l;
x2 = assym->TopFlangeWidth() / 2. * getValue(GV_LENGTH_UNIT);
doFillet2 = assym->hasTopFlangeFilletRadius();
if (doFillet2) {
f2 = assym->TopFlangeFilletRadius() * getValue(GV_LENGTH_UNIT);
}
if (assym->hasTopFlangeThickness()) {
dy2 = assym->TopFlangeThickness() * getValue(GV_LENGTH_UNIT);
}
}
if ( x1 < ALMOST_ZERO || x2 < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || dy1 < ALMOST_ZERO || dy2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
if ( x == 0.0f || y == 0.0f || d1 == 0.0f || d2 == 0.0f ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
gp_Trsf2d trsf2d;
convert(l->Position(),trsf2d);
IfcGeom::convert(l->Position(),trsf2d);
double coords[24] = {-x1,-y, x1,-y, x1,-y+dy1, d1,-y+dy1, d1,y-dy2, x2,y-dy2, x2,y, -x2,y, -x2,y-dy2, -d1,y-dy2, -d1,-y+dy1, -x1,-y+dy1};
double coords[24] = {-x,-y,x,-y,x,-y+d2,d1,-y+d2,d1,y-d2,x,y-d2,x,y,-x,y,-x,y-d2,-d1,y-d2,-d1,-y+d2,-x,-y+d2};
int fillets[4] = {3,4,9,10};
double radii[4] = {f1,f1,f2,f2};
return profile_helper(12,coords,(doFillet1||doFillet2) ? 4 : 0,fillets,radii,trsf2d,face);
double radii[4] = {f,f,f,f};
return IfcGeom::profile_helper(12,coords,doFillet ? 4 : 0,fillets,radii,trsf2d,face);
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcZShapeProfileDef* l, TopoDS_Shape& face) {
const double x = l->FlangeWidth() * getValue(GV_LENGTH_UNIT);
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double dx = l->WebThickness() / 2.0f * getValue(GV_LENGTH_UNIT);
const double dy = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
bool IfcGeom::convert(const IfcSchema::IfcZShapeProfileDef::ptr l, TopoDS_Shape& face) {
const double x = l->FlangeWidth() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->Depth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double dx = l->WebThickness() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double dy = l->FlangeThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool doFillet = l->hasFilletRadius();
bool doEdgeFillet = l->hasEdgeRadius();
@@ -477,74 +355,74 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcZShapeProfileDef* l, TopoDS_Sh
double f2 = 0.;
if ( doFillet ) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
f1 = l->FilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
}
if ( doEdgeFillet ) {
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
f2 = l->EdgeRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
}
if ( x == 0.0f || y == 0.0f || dx == 0.0f || dy == 0.0f ) {
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
gp_Trsf2d trsf2d;
IfcGeom::Kernel::convert(l->Position(),trsf2d);
IfcGeom::convert(l->Position(),trsf2d);
double coords[16] = {-dx,-y, x,-y, x,-y+dy, dx,-y+dy, dx,y, -x,y, -x,y-dy, -dx,y-dy};
int fillets[4] = {2,3,6,7};
double radii[4] = {f2,f1,f2,f1};
return profile_helper(8,coords,(doFillet || doEdgeFillet) ? 4 : 0,fillets,radii,trsf2d,face);
return IfcGeom::profile_helper(8,coords,(doFillet || doEdgeFillet) ? 4 : 0,fillets,radii,trsf2d,face);
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCShapeProfileDef* l, TopoDS_Shape& face) {
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double x = l->Width() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d1 = l->WallThickness() * getValue(GV_LENGTH_UNIT);
const double d2 = l->Girth() * getValue(GV_LENGTH_UNIT);
bool IfcGeom::convert(const IfcSchema::IfcCShapeProfileDef::ptr l, TopoDS_Shape& face) {
const double y = l->Depth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double x = l->Width() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d1 = l->WallThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d2 = l->Girth() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool doFillet = l->hasInternalFilletRadius();
double f1 = 0;
double f2 = 0;
if ( doFillet ) {
f1 = l->InternalFilletRadius() * getValue(GV_LENGTH_UNIT);
f1 = l->InternalFilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
f2 = f1 + d1;
}
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
gp_Trsf2d trsf2d;
IfcGeom::Kernel::convert(l->Position(),trsf2d);
IfcGeom::convert(l->Position(),trsf2d);
double coords[24] = {-x,-y,x,-y,x,-y+d2,x-d1,-y+d2,x-d1,-y+d1,-x+d1,-y+d1,-x+d1,y-d1,x-d1,y-d1,x-d1,y-d2,x,y-d2,x,y,-x,y};
int fillets[8] = {0,1,4,5,6,7,10,11};
double radii[8] = {f2,f2,f1,f1,f1,f1,f2,f2};
return profile_helper(12,coords,doFillet ? 8 : 0,fillets,radii,trsf2d,face);
return IfcGeom::profile_helper(12,coords,doFillet ? 8 : 0,fillets,radii,trsf2d,face);
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Shape& face) {
bool IfcGeom::convert(const IfcSchema::IfcLShapeProfileDef::ptr l, TopoDS_Shape& face) {
const bool hasSlope = l->hasLegSlope();
const bool doEdgeFillet = l->hasEdgeRadius();
const bool doFillet = l->hasFilletRadius();
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double x = (l->hasWidth() ? l->Width() : l->Depth()) / 2.0f * getValue(GV_LENGTH_UNIT);
const double d = l->Thickness() * getValue(GV_LENGTH_UNIT);
const double slope = hasSlope ? (l->LegSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
const double y = l->Depth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double x = (l->hasWidth() ? l->Width() : l->Depth()) / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d = l->Thickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double slope = hasSlope ? (l->LegSlope() * IfcGeom::GetValue(GV_PLANEANGLE_UNIT)) : 0.;
double f1 = 0.0f;
double f2 = 0.0f;
if (doFillet) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
f1 = l->FilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
}
if ( doEdgeFillet) {
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
f2 = l->EdgeRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
}
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
@@ -576,7 +454,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Sh
const double det = a1*b2 - a2*b1;
if (ALMOST_THE_SAME(det, 0.)) {
Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:", l);
Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:",l->entity);
return false;
}
@@ -585,24 +463,24 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Sh
}
gp_Trsf2d trsf2d;
convert(l->Position(),trsf2d);
IfcGeom::convert(l->Position(),trsf2d);
double coords[12] = {-x,-y, x,-y, x,-y+d-dy1, xx, xy, -x+d-dx1,y, -x,y};
int fillets[3] = {2,3,4};
double radii[3] = {f2,f1,f2};
return profile_helper(6,coords,doFillet ? 3 : 0,fillets,radii,trsf2d,face);
return IfcGeom::profile_helper(6,coords,doFillet ? 3 : 0,fillets,radii,trsf2d,face);
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcUShapeProfileDef* l, TopoDS_Shape& face) {
bool IfcGeom::convert(const IfcSchema::IfcUShapeProfileDef::ptr l, TopoDS_Shape& face) {
const bool doEdgeFillet = l->hasEdgeRadius();
const bool doFillet = l->hasFilletRadius();
const bool hasSlope = l->hasFlangeSlope();
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double x = l->FlangeWidth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() * getValue(GV_LENGTH_UNIT);
const double d2 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
const double slope = hasSlope ? (l->FlangeSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
const double y = l->Depth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double x = l->FlangeWidth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d2 = l->FlangeThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double slope = hasSlope ? (l->FlangeSlope() * IfcGeom::GetValue(GV_PLANEANGLE_UNIT)) : 0.;
double dy1 = 0.0f;
double dy2 = 0.0f;
@@ -610,10 +488,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcUShapeProfileDef* l, TopoDS_Sh
double f2 = 0.0f;
if (doFillet) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
f1 = l->FilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
}
if (doEdgeFillet) {
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
f2 = l->EdgeRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
}
if (hasSlope) {
@@ -622,35 +500,35 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcUShapeProfileDef* l, TopoDS_Sh
}
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
gp_Trsf2d trsf2d;
convert(l->Position(),trsf2d);
IfcGeom::convert(l->Position(),trsf2d);
double coords[16] = {-x,-y, x,-y, x,-y+d2-dy2, -x+d1,-y+d2+dy1, -x+d1,y-d2-dy1, x,y-d2+dy2, x,y, -x,y};
int fillets[4] = {2,3,4,5};
double radii[4] = {f2,f1,f1,f2};
return profile_helper(8, coords, (doFillet || doEdgeFillet) ? 4 : 0, fillets, radii, trsf2d, face);
return IfcGeom::profile_helper(8, coords, (doFillet || doEdgeFillet) ? 4 : 0, fillets, radii, trsf2d, face);
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Shape& face) {
bool IfcGeom::convert(const IfcSchema::IfcTShapeProfileDef::ptr l, TopoDS_Shape& face) {
const bool doFlangeEdgeFillet = l->hasFlangeEdgeRadius();
const bool doWebEdgeFillet = l->hasWebEdgeRadius();
const bool doFillet = l->hasFilletRadius();
const bool hasFlangeSlope = l->hasFlangeSlope();
const bool hasWebSlope = l->hasWebSlope();
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double x = l->FlangeWidth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() * getValue(GV_LENGTH_UNIT);
const double d2 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
const double flangeSlope = hasFlangeSlope ? (l->FlangeSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
const double webSlope = hasWebSlope ? (l->WebSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
const double y = l->Depth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double x = l->FlangeWidth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d2 = l->FlangeThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double flangeSlope = hasFlangeSlope ? (l->FlangeSlope() * IfcGeom::GetValue(GV_PLANEANGLE_UNIT)) : 0.;
const double webSlope = hasWebSlope ? (l->WebSlope() * IfcGeom::GetValue(GV_PLANEANGLE_UNIT)) : 0.;
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
@@ -663,13 +541,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
double f3 = 0.0f;
if (doFillet) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
f1 = l->FilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
}
if (doWebEdgeFillet) {
f2 = l->WebEdgeRadius() * getValue(GV_LENGTH_UNIT);
f2 = l->WebEdgeRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
}
if (doFlangeEdgeFillet) {
f3 = l->FlangeEdgeRadius() * getValue(GV_LENGTH_UNIT);
f3 = l->FlangeEdgeRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
}
double xx, xy;
@@ -698,7 +576,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
const double det = a1*b2 - a2*b1;
if (ALMOST_THE_SAME(det, 0.)) {
Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:", l);
Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:",l->entity);
return false;
}
@@ -710,23 +588,23 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
}
gp_Trsf2d trsf2d;
convert(l->Position(),trsf2d);
IfcGeom::convert(l->Position(),trsf2d);
double coords[16] = {d1/2.-dx2,-y, xx,xy, x,y-d2+dy2, x,y, -x,y, -x,y-d2+dy2, -xx,xy, -d1/2.+dx2,-y};
int fillets[6] = {0,1,2,5,6,7};
double radii[6] = {f2,f1,f3,f3,f1,f2};
return profile_helper(8, coords, (doFillet || doWebEdgeFillet || doFlangeEdgeFillet) ? 6 : 0, fillets, radii, trsf2d, face);
return IfcGeom::profile_helper(8, coords, (doFillet || doWebEdgeFillet || doFlangeEdgeFillet) ? 6 : 0, fillets, radii, trsf2d, face);
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleProfileDef* l, TopoDS_Shape& face) {
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
bool IfcGeom::convert(const IfcSchema::IfcCircleProfileDef::ptr l, TopoDS_Shape& face) {
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
if ( r == 0.0f ) {
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
gp_Trsf2d trsf;
convert(l->Position(),trsf);
IfcGeom::convert(l->Position(),trsf);
BRepBuilderAPI_MakeWire w;
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
@@ -735,22 +613,22 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleProfileDef* l, TopoDS_Sh
w.Add(edge);
TopoDS_Face f;
bool success = convert_wire_to_face(w, f);
bool success = IfcGeom::convert_wire_to_face(w, f);
if (success) face = f;
return success;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, TopoDS_Shape& face) {
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
const double t = l->WallThickness() * getValue(GV_LENGTH_UNIT);
bool IfcGeom::convert(const IfcSchema::IfcCircleHollowProfileDef::ptr l, TopoDS_Shape& face) {
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double t = l->WallThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
if ( r == 0.0f || t == 0.0f ) {
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
gp_Trsf2d trsf;
convert(l->Position(),trsf);
IfcGeom::convert(l->Position(),trsf);
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
BRepBuilderAPI_MakeWire outer;
@@ -769,18 +647,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, Top
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipseProfileDef* l, TopoDS_Shape& face) {
double rx = l->SemiAxis1() * getValue(GV_LENGTH_UNIT);
double ry = l->SemiAxis2() * getValue(GV_LENGTH_UNIT);
bool IfcGeom::convert(const IfcSchema::IfcEllipseProfileDef::ptr l, TopoDS_Shape& face) {
double rx = l->SemiAxis1() * IfcGeom::GetValue(GV_LENGTH_UNIT);
double ry = l->SemiAxis2() * IfcGeom::GetValue(GV_LENGTH_UNIT);
if ( rx < ALMOST_ZERO || ry < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
const bool rotated = ry > rx;
gp_Trsf2d trsf;
convert(l->Position(),trsf);
IfcGeom::convert(l->Position(),trsf);
gp_Ax2 ax = gp_Ax2();
if (rotated) {
@@ -795,16 +673,16 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipseProfileDef* l, TopoDS_S
w.Add(edge);
TopoDS_Face f;
bool success = convert_wire_to_face(w, f);
bool success = IfcGeom::convert_wire_to_face(w, f);
if (success) face = f;
return success;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCenterLineProfileDef* l, TopoDS_Shape& face) {
const double d = l->Thickness() * getValue(GV_LENGTH_UNIT) / 2.;
bool IfcGeom::convert(const IfcSchema::IfcCenterLineProfileDef::ptr l, TopoDS_Shape& face) {
const double d = l->Thickness() * IfcGeom::GetValue(GV_LENGTH_UNIT) / 2.;
TopoDS_Wire wire;
if (!convert_wire(l->Curve(), wire)) return false;
if (!IfcGeom::convert_wire(l->Curve(), wire)) return false;
// BRepOffsetAPI_MakeOffset insists on creating circular arc
// segments for joining the curves that constitute the center
@@ -849,18 +727,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCenterLineProfileDef* l, TopoD
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeProfileDef* l, TopoDS_Shape& face) {
bool IfcGeom::convert(const IfcSchema::IfcCompositeProfileDef::ptr l, TopoDS_Shape& face) {
// BRepBuilderAPI_MakeFace mf;
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
IfcSchema::IfcProfileDef::list::ptr profiles = l->Profiles();
//bool first = true;
for (IfcSchema::IfcProfileDef::list::it it = profiles->begin(); it != profiles->end(); ++it) {
IfcSchema::IfcProfileDef::list profiles = l->Profiles();
bool first = true;
for (IfcSchema::IfcProfileDef::it it = profiles->begin(); it != profiles->end(); ++it) {
TopoDS_Face f;
if (convert_face(*it, f)) {
if (IfcGeom::convert_face(*it, f)) {
builder.Add(compound, f);
/* TopExp_Explorer exp(f, TopAbs_WIRE);
for (; exp.More(); exp.Next()) {
@@ -879,10 +757,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeProfileDef* l, TopoDS
return !face.IsNull();
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcDerivedProfileDef* l, TopoDS_Shape& face) {
bool IfcGeom::convert(const IfcSchema::IfcDerivedProfileDef::ptr l, TopoDS_Shape& face) {
TopoDS_Face f;
gp_Trsf2d trsf2d;
if (convert_face(l->ParentProfile(), f) && IfcGeom::Kernel::convert(l->Operator(), trsf2d)) {
if (IfcGeom::convert_face(l->ParentProfile(), f) && IfcGeom::convert(l->Operator(), trsf2d)) {
gp_Trsf trsf = trsf2d;
face = TopoDS::Face(BRepBuilderAPI_Transform(f, trsf));
return true;
@@ -890,71 +768,3 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcDerivedProfileDef* l, TopoDS_S
return false;
}
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPlane* l, TopoDS_Shape& face) {
gp_Pln pln;
convert(l, pln);
Handle_Geom_Surface surf = new Geom_Plane(pln);
#if OCC_VERSION_HEX < 0x60502
face = BRepBuilderAPI_MakeFace(surf);
#else
face = BRepBuilderAPI_MakeFace(surf, getValue(GV_PRECISION));
#endif
return true;
}
#ifdef USE_IFC4
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineSurfaceWithKnots* l, TopoDS_Shape& face) {
boost::shared_ptr< IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint> > cps = l->ControlPointsList();
std::vector<double> uknots = l->UKnots();
std::vector<double> vknots = l->VKnots();
std::vector<int> umults = l->UMultiplicities();
std::vector<int> vmults = l->VMultiplicities();
TColgp_Array2OfPnt Poles (0, (int)cps->size() - 1, 0, (int)(*cps->begin()).size() - 1);
TColStd_Array1OfReal UKnots(0, (int)uknots.size() - 1);
TColStd_Array1OfReal VKnots(0, (int)vknots.size() - 1);
TColStd_Array1OfInteger UMults(0, (int)umults.size() - 1);
TColStd_Array1OfInteger VMults(0, (int)vmults.size() - 1);
Standard_Integer UDegree = l->UDegree();
Standard_Integer VDegree = l->VDegree();
int i = 0, j;
for (IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint>::outer_it it = cps->begin(); it != cps->end(); ++it, ++i) {
j = 0;
for (IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint>::inner_it jt = (*it).begin(); jt != (*it).end(); ++jt, ++j) {
IfcSchema::IfcCartesianPoint* p = *jt;
gp_Pnt pnt;
if (!convert(p, pnt)) return false;
Poles(i, j) = pnt;
}
}
i = 0;
for (std::vector<double>::const_iterator it = uknots.begin(); it != uknots.end(); ++it, ++i) {
UKnots(i) = *it;
}
i = 0;
for (std::vector<double>::const_iterator it = vknots.begin(); it != vknots.end(); ++it, ++i) {
VKnots(i) = *it;
}
i = 0;
for (std::vector<int>::const_iterator it = umults.begin(); it != umults.end(); ++it, ++i) {
UMults(i) = *it;
}
i = 0;
for (std::vector<int>::const_iterator it = vmults.begin(); it != vmults.end(); ++it, ++i) {
VMults(i) = *it;
}
Handle_Geom_Surface surf = new Geom_BSplineSurface(Poles, UKnots, VKnots, UMults, VMults, UDegree, VDegree);
#if OCC_VERSION_HEX < 0x60502
face = BRepBuilderAPI_MakeFace(surf);
#else
face = BRepBuilderAPI_MakeFace(surf, getValue(GV_PRECISION));
#endif
return true;
}
#endif
File diff suppressed because it is too large Load Diff
+71 -54
View File
@@ -77,19 +77,29 @@
#include "../ifcgeom/IfcGeom.h"
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianPoint* l, gp_Pnt& point) {
namespace IfcGeom {
namespace Cache {
#include "IfcRegisterCreateCache.h"
}
}
#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::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(
@@ -101,22 +111,22 @@ 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);
@@ -125,26 +135,27 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement3D* l, gp_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();
trsf.SetTransformation(ax3);
@@ -154,16 +165,16 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
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());
@@ -188,17 +199,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
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);
@@ -215,7 +227,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
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;
@@ -223,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());
@@ -251,14 +263,14 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
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);
@@ -267,12 +279,12 @@ 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);
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());
@@ -280,27 +292,32 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d
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->declaration().is(IfcSchema::Type::IfcLocalPlacement) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l);
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();
if ( relplacement->declaration().is(IfcSchema::Type::IfcAxis2Placement3D) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2);
IfcSchema::IfcAxis2Placement relplacement = current->RelativePlacement();
if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) {
IfcGeom::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2);
trsf.PreMultiply(trsf2);
}
if ( current->hasPlacementRelTo() ) {
IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo();
if ( relto->declaration().is(IfcSchema::Type::IfcLocalPlacement) )
current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo();
IfcSchema::IfcObjectPlacement::ptr relto = current->PlacementRelTo();
if ( relto->is(IfcSchema::Type::IfcLocalPlacement) )
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();
}
-513
View File
@@ -1,513 +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"
namespace IfcGeom {
template <typename P>
class Iterator {
private:
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?
P unit_magnitude;
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 = static_cast<P>(length_unit.second);
}
}
std::set<IfcSchema::Type::Enum> entities_to_include_or_exclude;
bool include_entities_in_processing;
void populate_set(const std::set<std::string>& include_or_ignore) {
entities_to_include_or_exclude.clear();
for (std::set<std::string>::const_iterator it = include_or_ignore.begin(); it != include_or_ignore.end(); ++it) {
const std::string uppercase_type = boost::to_upper_copy(*it);
IfcSchema::Type::Enum ty;
try {
ty = IfcSchema::Type::FromString(uppercase_type);
} catch (const IfcParse::IfcException&) {
std::stringstream ss;
ss << "'" << *it << "' does not name a valid IFC entity";
throw IfcParse::IfcException(ss.str());
}
entities_to_include_or_exclude.insert(ty);
// TODO: Add child classes so that containment in set can be in O(log n)
}
}
public:
bool initialize() {
try {
initUnits();
} catch (...) {}
std::set<std::string> context_types;
if (!settings.exclude_solids_and_surfaces()) {
// Really this should only be 'Model', as per
// the standard 'Design' is deprecated. So,
// just for backwards compatibility:
context_types.insert("model");
context_types.insert("design");
// DDS likes to output 'model view'
context_types.insert("model view");
}
if (settings.include_curves()) {
context_types.insert("plan");
}
double lowest_precision_encountered = std::numeric_limits<double>::infinity();
bool any_precision_encountered = false;
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->declaration().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 (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->declaration().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) return false;
representation_iterator = representations->begin();
ifcproducts.reset();
if (!create()) {
return false;
}
done = 0;
total = representations->size();
return true;
}
int progress() {
return 100 * done / total;
}
const std::string& getUnitName() {
return unit_name;
}
const P getUnitMagnitude() {
return unit_magnitude;
}
const std::string getLog() {
return Logger::GetLog();
}
IfcParse::IfcFile* getFile() {
return ifc_file;
}
void includeEntities(const std::set<std::string>& entities) {
populate_set(entities);
include_entities_in_processing = true;
}
void excludeEntities(const std::set<std::string>& entities) {
populate_set(entities);
include_entities_in_processing = false;
}
private:
// Move to the next IfcRepresentation
void _nextShape() {
ifcproducts.reset();
++ representation_iterator;
++ done;
}
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) {
IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation();
ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list);
IfcSchema::IfcProduct::list::ptr unfiltered_products(new IfcSchema::IfcProduct::list);
for ( IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it ) {
if ( (*it)->declaration().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)->data().getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>());
}
// Filter the products based on the set of entities being included or excluded for
// processing. The set is iterated over te able to filter on subtypes.
for ( IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin(); jt != unfiltered_products->end(); ++jt ) {
bool found = false;
for (std::set<IfcSchema::Type::Enum>::const_iterator kt = entities_to_include_or_exclude.begin(); kt != entities_to_include_or_exclude.end(); ++kt) {
if ((*jt)->declaration().is(*kt)) {
found = true;
break;
}
}
if (found == include_entities_in_processing) {
ifcproducts->push(*jt);
}
}
}
// Does this representation have any IfcProducts?
if (!ifcproducts->size()) {
_nextShape();
continue;
}
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;
BRepElement<P>* element = kernel.create_brep_for_representation_and_product<P>(settings, representation, product);
if ( !element ) {
_nextShape();
continue;
}
return element;
}
}
public:
bool next() {
// 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;
// Increment the iterator over the list of products using the current
// shape representation
if (ifcproducts) {
++ifcproduct_iterator;
}
return create();
}
Element<P>* get() {
// TODO: Test settings and throw
if (current_triangulation) return current_triangulation;
else if (current_serialization) return current_serialization;
else if (current_shape_model) return current_shape_model;
else return 0;
}
const Element<P>* getObject(int id) {
gp_Trsf trsf;
int parent_id = -1;
std::string instance_type, product_name, product_guid;
try {
const IfcUtil::IfcBaseClass* ifc_entity = ifc_file->entityById(id);
instance_type = IfcSchema::Type::ToString(ifc_entity->declaration().type());
if ( ifc_entity->declaration().is(IfcSchema::Type::IfcProduct) ) {
IfcSchema::IfcProduct* ifc_product = (IfcSchema::IfcProduct*)ifc_entity;
product_guid = ifc_product->GlobalId();
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->data().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);
return ifc_object;
}
bool create() {
try {
current_shape_model = create_shape_model_for_next_entity();
} catch (...) {}
if (!current_shape_model) return false;
if (settings.use_brep_data()) {
try {
current_serialization = new SerializedElement<P>(*current_shape_model);
} catch (...) {}
return !!current_serialization;
} else if (!settings.disable_triangulation()) {
try {
current_triangulation = new TriangulationElement<P>(*current_shape_model);
} catch (...) {}
return !!current_triangulation;
} else {
return true;
}
}
private:
void _initialize() {
current_triangulation = 0;
current_shape_model = 0;
current_serialization = 0;
// Upon initialisation, the (empty) set of entity names,
// should be excluded, or no products would be processed.
include_entities_in_processing = false;
unit_name = "METER";
unit_magnitude = 1.f;
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.sew_shells() ? 1000 : -1);
kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.include_curves() ? (settings.exclude_solids_and_surfaces() ? -1. : 0.) : +1.));
}
bool owns_ifc_file;
public:
Iterator(const IteratorSettings& settings, IfcParse::IfcFile* file)
: settings(settings)
, ifc_file(file)
, owns_ifc_file(false)
{
_initialize();
}
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;
}
delete current_triangulation;
current_triangulation = 0;
delete current_serialization;
current_serialization = 0;
delete current_shape_model;
current_shape_model = 0;
}
};
}
#endif
-179
View File
@@ -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/>. *
* *
********************************************************************************/
#ifndef IFCGEOMITERATORSETTINGS_H
#define IFCGEOMITERATORSETTINGS_H
#include <string>
#include "../ifcparse/IfcException.h"
namespace IfcGeom {
class IteratorSettings {
public:
// 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.
static 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.
static 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.
static 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.
static 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.
static const int SEW_SHELLS = 5;
// Specifies whether to compose IfcOpeningElements into a single compound
// in order to speed up the processing of opening subtractions.
static const int FASTER_BOOLEANS = 6;
// Disables the subtraction of IfcOpeningElement representations from
// the related building element representations.
static const int DISABLE_OPENING_SUBTRACTIONS = 8;
// Disables the triangulation of the topological representations. Useful if
// the client application understands Open Cascade's native format.
static const int DISABLE_TRIANGULATION = 9;
// Applies default materials to entity instances without a surface style.
static const int APPLY_DEFAULT_MATERIALS = 10;
// Specifies whether to include subtypes of IfcCurve.
static const int INCLUDE_CURVES = 11;
// Specifies whether to exclude subtypes of IfcSolidModel and IfcSurface.
static const int EXCLUDE_SOLIDS_AND_SURFACES = 12;
// End of settings enumeration.
private:
bool _weld_vertices, _use_world_coords, _convert_back_units, _use_brep_data, _sew_shells, _faster_booleans, _disable_opening_subtractions, _disable_triangulation, _apply_default_materials, _include_curves, _exclude_solids_and_surfaces;
double _deflection_tolerance;
public:
IteratorSettings()
: _weld_vertices(true)
, _use_world_coords(false)
, _convert_back_units(false)
, _use_brep_data(false)
, _sew_shells(false)
, _faster_booleans(false)
, _disable_opening_subtractions(false)
, _disable_triangulation(false)
, _apply_default_materials(false)
, _include_curves(false)
, _exclude_solids_and_surfaces(false)
// TODO: Make deflection tolerance into a command line argument
// For now, stick to one millimeter. Note that this is independent of the IFC length unit.
, _deflection_tolerance(1.e-3)
{}
const bool& weld_vertices() const { return _weld_vertices; }
bool& weld_vertices() { return _weld_vertices; }
const bool& use_world_coords() const { return _use_world_coords; }
bool& use_world_coords() { return _use_world_coords; }
const bool& convert_back_units() const { return _convert_back_units; }
bool& convert_back_units() { return _convert_back_units; }
const bool& use_brep_data() const { return _use_brep_data; }
bool& use_brep_data() { return _use_brep_data; }
const bool& sew_shells() const { return _sew_shells; }
bool& sew_shells() { return _sew_shells; }
const bool& faster_booleans() const { return _faster_booleans; }
bool& faster_booleans() { return _faster_booleans; }
const bool& disable_opening_subtractions() const { return _disable_opening_subtractions; }
bool& disable_opening_subtractions() { return _disable_opening_subtractions; }
const bool& disable_triangulation() const { return _disable_triangulation; }
bool& disable_triangulation() { return _disable_triangulation; }
const bool& apply_default_materials() const { return _apply_default_materials; }
bool& apply_default_materials() { return _apply_default_materials; }
const bool& include_curves() const { return _include_curves; }
bool& include_curves() { return _include_curves; }
const bool& exclude_solids_and_surfaces() const { return _exclude_solids_and_surfaces; }
bool& exclude_solids_and_surfaces() { return _exclude_solids_and_surfaces; }
const double& deflection_tolerance() const { return _deflection_tolerance; }
double& deflection_tolerance() { return _deflection_tolerance; }
void set(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:
_faster_booleans = value;
break;
case SEW_SHELLS:
_sew_shells = value;
break;
case DISABLE_OPENING_SUBTRACTIONS:
_disable_opening_subtractions = value;
break;
case DISABLE_TRIANGULATION:
_disable_triangulation = value;
break;
case APPLY_DEFAULT_MATERIALS:
_apply_default_materials = value;
break;
case INCLUDE_CURVES:
_include_curves = value;
break;
case EXCLUDE_SOLIDS_AND_SURFACES:
_exclude_solids_and_surfaces = value;
break;
default: throw IfcParse::IfcException("Invalid IteratorSetting");
}
}
};
class ElementSettings : public IteratorSettings {
private:
double _unit_magnitude;
std::string _element_type;
public:
ElementSettings(const IteratorSettings& settings,
double unit_magnitude,
const std::string& element_type)
: IteratorSettings(settings)
, _unit_magnitude(unit_magnitude)
, _element_type(element_type)
{}
const double& unit_magnitude() const { return _unit_magnitude; }
const std::string& element_type() const { return _element_type; }
};
}
#endif
-34
View File
@@ -1,34 +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(); }
bool IfcGeom::Material::operator==(const IfcGeom::Material& other) const { return style == other.style; }
-50
View File
@@ -1,50 +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 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;
bool operator==(const Material& other) const;
};
}
#endif
+727
View File
@@ -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; }
+286
View File
@@ -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
+29 -30
View File
@@ -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,34 +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->declaration().is(IfcSchema::Type::IfcColourRgb)) {
} 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->declaration().is(IfcSchema::Type::IfcNormalisedRatioMeasure)) {
return process_colour(static_cast<IfcSchema::IfcNormalisedRatioMeasure*>(colour_or_factor), rgb);
} else if (colour_or_factor->is(IfcSchema::Type::IfcNormalisedRatioMeasure)) {
return process_colour(static_cast<IfcUtil::IfcBaseEntity*>(colour_or_factor), rgb);
} else {
return false;
}
}
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepresentationItem* item) {
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->data().id();
std::map<int,SurfaceStyle>::const_iterator it = cache.Style.find(surface_style_id);
if (it != cache.Style.end()) {
int surface_style_id = shading_styles.first->entity->id();
std::map<int,SurfaceStyle>::const_iterator it = Cache::Style.find(surface_style_id);
if (it != Cache::Style.end()) {
return &(it->second);
}
SurfaceStyle surface_style;
@@ -66,11 +75,11 @@ const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepr
} 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]));
}
if (shading_styles.second->declaration().is(IfcSchema::Type::IfcSurfaceStyleRendering)) {
if (shading_styles.second->is(IfcSchema::Type::IfcSurfaceStyleRendering)) {
IfcSchema::IfcSurfaceStyleRendering* rendering_style = static_cast<IfcSchema::IfcSurfaceStyleRendering*>(shading_styles.second);
if (rendering_style->hasDiffuseColour() && process_colour(rendering_style->DiffuseColour(), rgb)) {
SurfaceStyle::ColorComponent diffuse = surface_style.Diffuse().get_value_or(SurfaceStyle::ColorComponent(1,1,1));
@@ -86,15 +95,7 @@ const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepr
surface_style.Specular().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
}
if (rendering_style->hasSpecularHighlight()) {
IfcSchema::IfcSpecularHighlightSelect* highlight = rendering_style->SpecularHighlight();
if (highlight->declaration().is(IfcSchema::Type::IfcSpecularRoughness)) {
double roughness = *((IfcSchema::IfcSpecularRoughness*)highlight);
if (roughness >= 1e-9) {
surface_style.Specularity().reset(1.0 / roughness);
}
} else if (highlight->declaration().is(IfcSchema::Type::IfcSpecularExponent)) {
surface_style.Specularity().reset(*((IfcSchema::IfcSpecularExponent*)highlight));
}
// Not supported
}
if (rendering_style->hasTransmissionColour()) {
// Not supported
@@ -104,7 +105,7 @@ const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepr
surface_style.Transparency().reset(d);
}
}
return &(cache.Style[surface_style_id] = surface_style);
return &(Cache::Style[surface_style_id] = surface_style);
}
static std::map<std::string, IfcGeom::SurfaceStyle> default_materials;
@@ -152,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;
}
+70 -18
View File
@@ -20,6 +20,12 @@
#ifndef IFCGEOMRENDERSTYLES_H
#define IFCGEOMRENDERSTYLES_H
#ifdef __GNUC__
#include <tr1/array>
#else
#include <array>
#endif
#ifdef USE_IFC4
#include "../ifcparse/Ifc4.h"
#else
@@ -31,7 +37,7 @@ namespace IfcGeom {
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;
@@ -50,23 +56,10 @@ namespace IfcGeom {
boost::optional<double> transparency;
boost::optional<double> specularity;
public:
SurfaceStyle() {
this->name = "surface-style";
}
SurfaceStyle(int id) : id(id) {
std::stringstream sstr;
sstr << "surface-style-" << id;
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) {
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(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
@@ -82,7 +75,21 @@ namespace IfcGeom {
}
}
const std::string& Name() const { return *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; }
@@ -94,7 +101,52 @@ namespace IfcGeom {
boost::optional<double>& Specularity() { return specularity; }
};
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
-59
View File
@@ -1,59 +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 <BRepBuilderAPI_GTransform.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 (settings().convert_back_units()) {
gp_Trsf scale;
scale.SetScaleFactor(1.0 / settings().unit_magnitude());
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();
}
-309
View File
@@ -1,309 +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 <BRepAdaptor_Curve.hxx>
#include <GCPnts_QuasiUniformDeflection.hxx>
#include "../ifcgeom/IfcGeomIteratorSettings.h"
#include "../ifcgeom/IfcGeomMaterial.h"
#include "../ifcgeom/IfcRepresentationShapeItem.h"
namespace IfcGeom {
namespace Representation {
class 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 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 Serialization : public Representation {
private:
int _id;
std::string _brep_data;
public:
int id() const { return _id; }
const std::string& brep_data() const { return _brep_data; }
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<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<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().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");
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
const bool calculate_normals = !settings().weld_vertices();
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);
}
_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 (num_faces == 0) {
// Edges are only emitted if there are no faces. A mixed representation of faces
// and loose edges is discouraged by the standard. An alternative would be to use
// TopExp::MapShapesAndAncestors() to find edges that do not belong to any face.
for (TopExp_Explorer texp(s, TopAbs_EDGE); texp.More(); texp.Next()) {
BRepAdaptor_Curve crv(TopoDS::Edge(texp.Current()));
GCPnts_QuasiUniformDeflection tessellater(crv, settings().deflection_tolerance());
int n = tessellater.NbPoints();
int start = (int)_verts.size() / 3;
for (int i = 1; i <= n; ++i) {
gp_XYZ p = tessellater.Value(i).XYZ();
trsf.Transforms(p);
_material_ids.push_back(surface_style_id);
_verts.push_back(static_cast<P>(p.X()));
_verts.push_back(static_cast<P>(p.Y()));
_verts.push_back(static_cast<P>(p.Z()));
if (i > 1) {
_edges.push_back(start + i - 2);
_edges.push_back(start + i - 1);
}
}
}
}
}
}
virtual ~Triangulation() {}
private:
// Welds vertices that belong to different faces
int addVertex(int material_index, const gp_XYZ& p) {
const P X = static_cast<P>(settings().convert_back_units() ? (p.X() / settings().unit_magnitude()) : p.X());
const P Y = static_cast<P>(settings().convert_back_units() ? (p.Y() / settings().unit_magnitude()) : p.Y());
const P Z = static_cast<P>(settings().convert_back_units() ? (p.Z() / settings().unit_magnitude()) : p.Z());
int i = (int) _verts.size() / 3;
if (settings().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
-38
View File
@@ -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
+181 -451
View File
@@ -65,8 +65,6 @@
#include <TopoDS.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_CompSolid.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepPrimAPI_MakePrism.hxx>
@@ -76,7 +74,6 @@
#include <BRepPrimAPI_MakeCylinder.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <BRepPrimAPI_MakeWedge.hxx>
#include <BRepBuilderAPI_MakePolygon.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepBuilderAPI_MakeShell.hxx>
@@ -94,71 +91,35 @@
#include <TopLoc_Location.hxx>
#include <BRepCheck_Analyzer.hxx>
#include <BRepClass3d_SolidClassifier.hxx>
#include <Standard_Version.hxx>
#include "../ifcgeom/IfcGeom.h"
bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_Shape& shape) {
const double height = l->Depth() * getValue(GV_LENGTH_UNIT);
if (height < getValue(GV_PRECISION)) {
Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l);
return false;
}
TopoDS_Shape face;
if ( !convert_face(l->SweptArea(),face) ) return false;
bool IfcGeom::convert(const IfcSchema::IfcExtrudedAreaSolid::ptr l, TopoDS_Shape& shape) {
TopoDS_Face face;
if ( ! IfcGeom::convert_face(l->SweptArea(),face) ) return false;
const double height = l->Depth() * IfcGeom::GetValue(GV_LENGTH_UNIT);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
IfcGeom::convert(l->Position(),trsf);
gp_Dir dir;
convert(l->ExtrudedDirection(),dir);
shape.Nullify();
if (face.ShapeType() == TopAbs_COMPOUND) {
// For compounds (most likely the result of a IfcCompositeProfileDef)
// create a compound solid shape.
TopExp_Explorer exp(face, TopAbs_FACE);
TopoDS_CompSolid compound;
BRep_Builder builder;
builder.MakeCompSolid(compound);
int num_faces_extruded = 0;
for (; exp.More(); exp.Next(), ++num_faces_extruded) {
builder.Add(compound, BRepPrimAPI_MakePrism(exp.Current(), height*dir));
}
if (num_faces_extruded) {
shape = compound;
}
}
if (shape.IsNull()) {
shape = BRepPrimAPI_MakePrism(face, height*dir);
}
shape = BRepPrimAPI_MakePrism(face,height*dir);
shape.Move(trsf);
return ! shape.IsNull();
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion* l, TopoDS_Shape& shape) {
bool IfcGeom::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion::ptr l, TopoDS_Shape& shape) {
TopoDS_Wire wire;
if ( !convert_wire(l->SweptCurve(), wire) ) {
if ( !IfcGeom::convert_wire(l->SweptCurve(), wire) ) {
TopoDS_Face face;
if ( !convert_face(l->SweptCurve(),face) ) return false;
if ( !IfcGeom::convert_face(l->SweptCurve(),face) ) return false;
TopExp_Explorer exp(face, TopAbs_WIRE);
wire = TopoDS::Wire(exp.Current());
}
const double height = l->Depth() * getValue(GV_LENGTH_UNIT);
const double height = l->Depth() * IfcGeom::GetValue(GV_LENGTH_UNIT);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
IfcGeom::convert(l->Position(),trsf);
gp_Dir dir;
convert(l->ExtrudedDirection(),dir);
@@ -168,20 +129,20 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion* l, T
return !shape.IsNull();
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfRevolution* l, TopoDS_Shape& shape) {
bool IfcGeom::convert(const IfcSchema::IfcSurfaceOfRevolution::ptr l, TopoDS_Shape& shape) {
TopoDS_Wire wire;
if ( !convert_wire(l->SweptCurve(), wire) ) {
if ( !IfcGeom::convert_wire(l->SweptCurve(), wire) ) {
TopoDS_Face face;
if ( !convert_face(l->SweptCurve(),face) ) return false;
if ( !IfcGeom::convert_face(l->SweptCurve(),face) ) return false;
TopExp_Explorer exp(face, TopAbs_WIRE);
wire = TopoDS::Wire(exp.Current());
}
gp_Ax1 ax1;
IfcGeom::Kernel::convert(l->AxisPosition(), ax1);
IfcGeom::convert(l->AxisPosition(), ax1);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
IfcGeom::convert(l->Position(),trsf);
shape = BRepPrimAPI_MakeRevol(wire, ax1);
@@ -189,17 +150,17 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfRevolution* l, TopoDS
return !shape.IsNull();
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRevolvedAreaSolid* l, TopoDS_Shape& shape) {
const double ang = l->Angle() * getValue(GV_PLANEANGLE_UNIT);
bool IfcGeom::convert(const IfcSchema::IfcRevolvedAreaSolid::ptr l, TopoDS_Shape& shape) {
const double ang = l->Angle() * IfcGeom::GetValue(GV_PLANEANGLE_UNIT);
TopoDS_Face face;
if ( ! convert_face(l->SweptArea(),face) ) return false;
if ( ! IfcGeom::convert_face(l->SweptArea(),face) ) return false;
gp_Ax1 ax1;
IfcGeom::Kernel::convert(l->Axis(), ax1);
IfcGeom::convert(l->Axis(), ax1);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
IfcGeom::convert(l->Position(),trsf);
if (ang >= M_PI * 2. - ALMOST_ZERO) {
shape = BRepPrimAPI_MakeRevol(face, ax1);
@@ -211,10 +172,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRevolvedAreaSolid* l, TopoDS_S
return !shape.IsNull();
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFacetedBrep* l, IfcRepresentationShapeItems& shape) {
bool IfcGeom::convert(const IfcSchema::IfcFacetedBrep::ptr l, IfcRepresentationShapeItems& shape) {
TopoDS_Shape s;
const SurfaceStyle* collective_style = get_style(l);
if (convert_shape(l->Outer(),s) ) {
if (IfcGeom::convert_shape(l->Outer(),s) ) {
const SurfaceStyle* indiv_style = get_style(l->Outer());
shape.push_back(IfcRepresentationShapeItem(s, indiv_style ? indiv_style : collective_style));
return true;
@@ -222,49 +183,39 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFacetedBrep* l, IfcRepresentat
return false;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFaceBasedSurfaceModel* l, IfcRepresentationShapeItems& shapes) {
IfcSchema::IfcConnectedFaceSet::list::ptr facesets = l->FbsmFaces();
bool IfcGeom::convert(const IfcSchema::IfcFaceBasedSurfaceModel::ptr l, IfcRepresentationShapeItems& shapes) {
IfcSchema::IfcConnectedFaceSet::list facesets = l->FbsmFaces();
const SurfaceStyle* collective_style = get_style(l);
for( IfcSchema::IfcConnectedFaceSet::list::it it = facesets->begin(); it != facesets->end(); ++ it ) {
for( IfcSchema::IfcConnectedFaceSet::it it = facesets->begin(); it != facesets->end(); ++ it ) {
TopoDS_Shape s;
const SurfaceStyle* shell_style = get_style(*it);
if (convert_shape(*it,s)) {
if (IfcGeom::convert_shape(*it,s)) {
shapes.push_back(IfcRepresentationShapeItem(s, shell_style ? shell_style : collective_style));
}
}
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, TopoDS_Shape& shape) {
IfcSchema::IfcSurface* surface = l->BaseSurface();
if ( ! surface->declaration().is(IfcSchema::Type::IfcPlane) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface);
bool IfcGeom::convert(const IfcSchema::IfcHalfSpaceSolid::ptr l, TopoDS_Shape& shape) {
IfcSchema::IfcSurface::ptr surface = l->BaseSurface();
if ( ! surface->is(IfcSchema::Type::IfcPlane) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface->entity);
return false;
}
gp_Pln pln;
IfcGeom::Kernel::convert((IfcSchema::IfcPlane*)surface,pln);
IfcGeom::convert(reinterpret_pointer_cast<IfcSchema::IfcSurface,IfcSchema::IfcPlane>(surface),pln);
const gp_Pnt pnt = pln.Location().Translated( l->AgreementFlag() ? -pln.Axis().Direction() : pln.Axis().Direction());
shape = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln),pnt).Solid();
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l, TopoDS_Shape& shape) {
bool IfcGeom::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace::ptr l, TopoDS_Shape& shape) {
TopoDS_Shape halfspace;
if ( ! IfcGeom::Kernel::convert((IfcSchema::IfcHalfSpaceSolid*)l,halfspace) ) return false;
if ( ! IfcGeom::convert(reinterpret_pointer_cast<IfcSchema::IfcPolygonalBoundedHalfSpace,IfcSchema::IfcHalfSpaceSolid>(l),halfspace) ) return false;
TopoDS_Wire wire;
if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false;
if ( ! IfcGeom::convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false;
gp_Trsf trsf;
if ( ! convert(l->Position(),trsf) ) return false;
TColgp_SequenceOfPnt points;
if (wire_to_sequence_of_point(wire, points)) {
remove_duplicate_points_from_loop(points, wire.Closed()); // Note: wire always closed, as per if statement above
remove_collinear_points_from_loop(points, wire.Closed());
sequence_of_point_to_wire(points, wire, wire.Closed());
}
convert(l->Position(),trsf);
TopoDS_Shape prism = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,200));
gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-100.0));
prism.Move(trsf*down);
@@ -272,117 +223,60 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l,
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, IfcRepresentationShapeItems& shapes) {
IfcEntityList::ptr shells = l->SbsmBoundary();
bool IfcGeom::convert(const IfcSchema::IfcShellBasedSurfaceModel::ptr l, IfcRepresentationShapeItems& shapes) {
IfcUtil::IfcAbstractSelect::list shells = l->SbsmBoundary();
const SurfaceStyle* collective_style = get_style(l);
for( IfcEntityList::it it = shells->begin(); it != shells->end(); ++ it ) {
for( IfcUtil::IfcAbstractSelect::it it = shells->begin(); it != shells->end(); ++ it ) {
TopoDS_Shape s;
const SurfaceStyle* shell_style = 0;
if ((*it)->declaration().is(IfcSchema::Type::IfcRepresentationItem)) {
if ((*it)->is(IfcSchema::Type::IfcRepresentationItem)) {
shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it);
}
if (convert_shape(*it,s)) {
if (IfcGeom::convert_shape(*it,s)) {
shapes.push_back(IfcRepresentationShapeItem(s, shell_style ? shell_style : collective_style));
}
}
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) {
bool IfcGeom::convert(const IfcSchema::IfcBooleanResult::ptr l, TopoDS_Shape& shape) {
TopoDS_Shape s1, s2;
IfcRepresentationShapeItems items1, items2;
TopoDS_Wire boundary_wire;
IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand();
IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand();
bool is_halfspace = operand2->declaration().is(IfcSchema::Type::IfcHalfSpaceSolid);
IfcSchema::IfcBooleanOperand operand1 = l->FirstOperand();
IfcSchema::IfcBooleanOperand operand2 = l->SecondOperand();
bool is_halfspace = operand2->is(IfcSchema::Type::IfcHalfSpaceSolid);
if ( shape_type(operand1) == ST_SHAPELIST ) {
if (!(convert_shapes(operand1, items1) && flatten_shape_list(items1, s1, true))) {
return false;
}
} else if ( shape_type(operand1) == ST_SHAPE ) {
if ( ! convert_shape(operand1, s1) ) {
return false;
}
{ TopoDS_Solid temp_solid;
s1 = ensure_fit_for_subtraction(s1, temp_solid); }
} else {
Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", operand1);
if ( ! IfcGeom::convert_shape(operand1,s1) )
return false;
}
const double first_operand_volume = shape_volume(s1);
if ( first_operand_volume <= ALMOST_ZERO )
Logger::Message(Logger::LOG_WARNING, "Empty solid for:", l->FirstOperand());
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand()->entity);
bool shape2_processed = false;
if ( shape_type(operand2) == ST_SHAPELIST ) {
shape2_processed = convert_shapes(operand2, items2) && flatten_shape_list(items2, s2, true);
} else if ( shape_type(operand2) == ST_SHAPE ) {
shape2_processed = convert_shape(operand2,s2);
if (shape2_processed && !is_halfspace) {
TopoDS_Solid temp_solid;
s2 = ensure_fit_for_subtraction(s2, temp_solid);
}
} else {
Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", operand2);
}
if (!shape2_processed) {
if ( !IfcGeom::convert_shape(l->SecondOperand(),s2) ) {
shape = s1;
Logger::Message(Logger::LOG_ERROR, "Failed to convert SecondOperand of:", l);
Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l->entity);
return true;
}
if (!is_halfspace) {
if ( ! is_halfspace ) {
const double second_operand_volume = shape_volume(s2);
if ( second_operand_volume <= ALMOST_ZERO )
Logger::Message(Logger::LOG_WARNING, "Empty solid for:", operand2);
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2->entity);
}
const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator();
/*
// TK: A little debugging trick to output both operands for visual inspection
BRep_Builder builder;
TopoDS_Compound compound;
builder.MakeCompound(compound);
builder.Add(compound, s1);
builder.Add(compound, s2);
shape = compound;
return true;
*/
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
bool valid_cut = false;
#if OCC_VERSION_HEX < 0x60900
BRepAlgoAPI_Cut brep_cut(s1, s2);
#else
BRepAlgoAPI_Cut brep_cut;
TopTools_ListOfShape s1s;
s1s.Append(s1);
TopTools_ListOfShape s2s;
s2s.Append(s2);
brep_cut.SetFuzzyValue(getValue(GV_PRECISION));
brep_cut.SetArguments(s1s);
brep_cut.SetTools(s2s);
brep_cut.Build();
#endif
BRepAlgoAPI_Cut brep_cut(s1,s2);
if ( brep_cut.IsDone() ) {
TopoDS_Shape result = brep_cut;
ShapeFix_Shape fix(result);
try {
fix.Perform();
result = fix.Shape();
} catch (...) {
Logger::Message(Logger::LOG_WARNING, "Shape healing failed on boolean result", l);
}
fix.Perform();
result = fix.Shape();
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if ( is_valid ) {
@@ -394,9 +288,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
if ( valid_cut ) {
const double volume_after_subtraction = shape_volume(shape);
if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) )
Logger::Message(Logger::LOG_WARNING, "Subtraction yields unchanged volume:", l);
Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",l->entity);
} else {
Logger::Message(Logger::LOG_ERROR, "Failed to process subtraction:", l);
Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",l->entity);
shape = s1;
}
@@ -415,9 +309,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if ( is_valid ) {
shape = result;
return true;
}
}
}
return true;
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) {
@@ -432,74 +327,53 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if ( is_valid ) {
shape = result;
return true;
}
}
return true;
} else {
return false;
}
return false;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Shape& shape) {
IfcSchema::IfcFace::list::ptr faces = l->CfsFaces();
bool IfcGeom::convert(const IfcSchema::IfcConnectedFaceSet::ptr l, TopoDS_Shape& shape) {
IfcSchema::IfcFace::list faces = l->CfsFaces();
bool facesAdded = false;
const unsigned int num_faces = (unsigned)faces->size();
bool valid_shell = false;
if ( num_faces < getValue(GV_MAX_FACES_TO_SEW) ) {
const unsigned int num_faces = faces->Size();
if ( num_faces < GetValue(GV_MAX_FACES_TO_SEW) ) {
BRepOffsetAPI_Sewing builder;
builder.SetTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMaxTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMinTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
for( IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++ it ) {
builder.SetTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMaxTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMinTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
for( IfcSchema::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) {
TopoDS_Face face;
bool converted_face = false;
try {
converted_face = convert_face(*it,face);
} catch (...) {}
if ( converted_face && face_area(face) > getValue(GV_MINIMAL_FACE_AREA) ) {
if ( IfcGeom::convert_face(*it,face) && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) {
builder.Add(face);
facesAdded = true;
} else {
Logger::Message(Logger::LOG_WARNING, "Invalid face:", *it);
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
}
}
if ( ! facesAdded ) return false;
builder.Perform();
shape = builder.SewedShape();
try {
builder.Perform();
shape = builder.SewedShape();
valid_shell = BRepCheck_Analyzer(shape).IsValid();
ShapeFix_Solid solid;
solid.LimitTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
shape = solid.SolidFromShell(TopoDS::Shell(shape));
} catch(...) {}
if (valid_shell) {
try {
ShapeFix_Solid solid;
solid.LimitTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
TopoDS_Solid solid_shape = solid.SolidFromShell(TopoDS::Shell(shape));
if (!solid_shape.IsNull()) {
try {
BRepClass3d_SolidClassifier classifier(solid_shape);
shape = solid_shape;
} catch (...) {}
}
} catch(...) {}
} else {
Logger::Message(Logger::LOG_WARNING, "Failed to sew faceset:", l);
}
}
if (!valid_shell) {
} else {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
for( IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++ it ) {
for( IfcSchema::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) {
TopoDS_Face face;
bool converted_face = false;
try {
converted_face = convert_face(*it,face);
} catch (...) {}
if ( converted_face && face_area(face) > getValue(GV_MINIMAL_FACE_AREA) ) {
if ( IfcGeom::convert_face(*it,face) && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) {
builder.Add(compound,face);
facesAdded = true;
} else {
Logger::Message(Logger::LOG_WARNING, "Invalid face:", *it);
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
}
}
if ( ! facesAdded ) return false;
@@ -508,185 +382,162 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Sh
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentationShapeItems& shapes) {
bool IfcGeom::convert(const IfcSchema::IfcMappedItem::ptr l, IfcRepresentationShapeItems& shapes) {
gp_GTrsf gtrsf;
IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget();
if ( transform->declaration().is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf);
} else if ( transform->declaration().is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform);
IfcSchema::IfcCartesianTransformationOperator::ptr transform = l->MappingTarget();
if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) {
IfcGeom::convert(reinterpret_pointer_cast<IfcSchema::IfcCartesianTransformationOperator,
IfcSchema::IfcCartesianTransformationOperator3DnonUniform>(transform),gtrsf);
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity);
return false;
} else if ( transform->declaration().is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) {
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) {
gp_Trsf trsf;
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf);
IfcGeom::convert(reinterpret_pointer_cast<IfcSchema::IfcCartesianTransformationOperator,
IfcSchema::IfcCartesianTransformationOperator3D>(transform),trsf);
gtrsf = trsf;
} else if ( transform->declaration().is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) {
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) {
gp_Trsf2d trsf_2d;
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,trsf_2d);
IfcGeom::convert(reinterpret_pointer_cast<IfcSchema::IfcCartesianTransformationOperator,
IfcSchema::IfcCartesianTransformationOperator2D>(transform),trsf_2d);
gtrsf = (gp_Trsf) trsf_2d;
}
IfcSchema::IfcRepresentationMap* map = l->MappingSource();
IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin();
IfcSchema::IfcRepresentationMap::ptr map = l->MappingSource();
IfcSchema::IfcAxis2Placement placement = map->MappingOrigin();
gp_Trsf trsf;
if (placement->declaration().is(IfcSchema::Type::IfcAxis2Placement3D)) {
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
IfcGeom::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
} else {
gp_Trsf2d trsf_2d;
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf_2d);
IfcGeom::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf_2d);
trsf = trsf_2d;
}
gtrsf.Multiply(trsf);
const IfcGeom::SurfaceStyle* mapped_item_style = get_style(l);
const unsigned int previous_size = (const unsigned int) shapes.size();
bool b = convert_shapes(map->MappedRepresentation(), shapes);
bool b = IfcGeom::convert_shapes(map->MappedRepresentation(),shapes);
for ( unsigned int i = previous_size; i < shapes.size(); ++ i ) {
shapes[i].append(gtrsf);
// Apply styles assigned to the mapped item only if on
// a more granular level no styles have been applied
if (!shapes[i].hasStyle()) {
shapes[i].setStyle(mapped_item_style);
}
}
return b;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRepresentation* l, IfcRepresentationShapeItems& shapes) {
IfcSchema::IfcRepresentationItem::list::ptr items = l->Items();
bool part_succes = false;
if ( items->size() ) {
for ( IfcSchema::IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++ it ) {
IfcSchema::IfcRepresentationItem* representation_item = *it;
if ( shape_type(representation_item) == ST_SHAPELIST ) {
part_succes |= convert_shapes(*it, shapes);
} else {
TopoDS_Shape s;
if (convert_shape(representation_item,s)) {
shapes.push_back(IfcRepresentationShapeItem(s, get_style(representation_item)));
part_succes |= true;
}
bool IfcGeom::convert(const IfcSchema::IfcShapeRepresentation::ptr l, IfcRepresentationShapeItems& shapes) {
IfcSchema::IfcRepresentationItem::list items = l->Items();
if ( ! items->Size() ) return false;
for ( IfcSchema::IfcRepresentationItem::it it = items->begin(); it != items->end(); ++ it ) {
IfcSchema::IfcRepresentationItem* representation_item = *it;
if ( IfcGeom::is_shape_collection(representation_item) ) IfcGeom::convert_shapes(*it,shapes);
else {
TopoDS_Shape s;
if (IfcGeom::convert_shape(representation_item,s)) {
shapes.push_back(IfcRepresentationShapeItem(s, get_style(representation_item)));
}
}
}
return part_succes;
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcGeometricSet* l, IfcRepresentationShapeItems& shapes) {
IfcEntityList::ptr elements = l->Elements();
if ( !elements->size() ) return false;
bool part_succes = false;
bool IfcGeom::convert(const IfcSchema::IfcGeometricSet::ptr l, IfcRepresentationShapeItems& shapes) {
IfcUtil::IfcAbstractSelect::list elements = l->Elements();
if ( !elements->Size() ) return false;
const IfcGeom::SurfaceStyle* parent_style = get_style(l);
for ( IfcEntityList::it it = elements->begin(); it != elements->end(); ++ it ) {
IfcSchema::IfcGeometricSetSelect* element = *it;
TopoDS_Shape s;
if (convert_shape(element, s)) {
part_succes = true;
const IfcGeom::SurfaceStyle* style = 0;
if (element->declaration().is(IfcSchema::Type::IfcPoint)) {
style = get_style((IfcSchema::IfcPoint*) element);
} else if (element->declaration().is(IfcSchema::Type::IfcCurve)) {
style = get_style((IfcSchema::IfcCurve*) element);
} else if (element->declaration().is(IfcSchema::Type::IfcSurface)) {
style = get_style((IfcSchema::IfcSurface*) element);
for ( IfcUtil::IfcAbstractSelect::it it = elements->begin(); it != elements->end(); ++ it ) {
IfcSchema::IfcGeometricSetSelect element = *it;
if (element->is(IfcSchema::Type::IfcSurface)) {
IfcSchema::IfcSurface* surface = (IfcSchema::IfcSurface*) element;
TopoDS_Shape s;
if (IfcGeom::convert_shape(surface, s)) {
const IfcGeom::SurfaceStyle* style = get_style(surface);
shapes.push_back(IfcRepresentationShapeItem(s, style ? style : parent_style));
}
shapes.push_back(IfcRepresentationShapeItem(s, style ? style : parent_style));
}
}
return part_succes;
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBlock* l, TopoDS_Shape& shape) {
const double dx = l->XLength() * getValue(GV_LENGTH_UNIT);
const double dy = l->YLength() * getValue(GV_LENGTH_UNIT);
const double dz = l->ZLength() * getValue(GV_LENGTH_UNIT);
bool IfcGeom::convert(const IfcSchema::IfcBlock::ptr l, TopoDS_Shape& shape) {
const double dx = l->XLength() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double dy = l->YLength() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double dz = l->ZLength() * IfcGeom::GetValue(GV_LENGTH_UNIT);
BRepPrimAPI_MakeBox builder(dx, dy, dz);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
IfcGeom::convert(l->Position(),trsf);
shape = builder.Solid().Moved(trsf);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularPyramid* l, TopoDS_Shape& shape) {
const double dx = l->XLength() * getValue(GV_LENGTH_UNIT);
const double dy = l->YLength() * getValue(GV_LENGTH_UNIT);
const double dz = l->Height() * getValue(GV_LENGTH_UNIT);
bool IfcGeom::convert(const IfcSchema::IfcRectangularPyramid::ptr l, TopoDS_Shape& shape) {
const double dx = l->XLength() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double dy = l->YLength() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double dz = l->Height() * IfcGeom::GetValue(GV_LENGTH_UNIT);
BRepPrimAPI_MakeWedge builder(dx, dz, dy, dx / 2., dy / 2., dx / 2., dy / 2.);
gp_Trsf trsf1, trsf2;
trsf2.SetValues(
1, 0, 0, 0,
0, 0, 1, 0,
0, 1, 0, 0
#if OCC_VERSION_HEX < 0x60800
, Precision::Angular(), Precision::Confusion()
#endif
);
trsf2.SetValues(1, 0, 0, 0,
0, 0, 1, 0,
0, 1, 0, 0, Precision::Confusion(), Precision::Confusion());
IfcGeom::Kernel::convert(l->Position(), trsf1);
IfcGeom::convert(l->Position(), trsf1);
shape = BRepBuilderAPI_Transform(builder.Solid(), trsf1 * trsf2);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRightCircularCylinder* l, TopoDS_Shape& shape) {
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
const double h = l->Height() * getValue(GV_LENGTH_UNIT);
bool IfcGeom::convert(const IfcSchema::IfcRightCircularCylinder::ptr l, TopoDS_Shape& shape) {
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double h = l->Height() * IfcGeom::GetValue(GV_LENGTH_UNIT);
BRepPrimAPI_MakeCylinder builder(r, h);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
IfcGeom::convert(l->Position(),trsf);
shape = builder.Solid().Moved(trsf);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRightCircularCone* l, TopoDS_Shape& shape) {
const double r = l->BottomRadius() * getValue(GV_LENGTH_UNIT);
const double h = l->Height() * getValue(GV_LENGTH_UNIT);
bool IfcGeom::convert(const IfcSchema::IfcRightCircularCone::ptr l, TopoDS_Shape& shape) {
const double r = l->BottomRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double h = l->Height() * IfcGeom::GetValue(GV_LENGTH_UNIT);
BRepPrimAPI_MakeCone builder(r, 0., h);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
IfcGeom::convert(l->Position(),trsf);
shape = builder.Solid().Moved(trsf);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSphere* l, TopoDS_Shape& shape) {
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
bool IfcGeom::convert(const IfcSchema::IfcSphere::ptr l, TopoDS_Shape& shape) {
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
BRepPrimAPI_MakeSphere builder(r);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
IfcGeom::convert(l->Position(),trsf);
shape = builder.Solid().Moved(trsf);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCsgSolid* l, TopoDS_Shape& shape) {
return convert_shape(l->TreeRootExpression(), shape);
bool IfcGeom::convert(const IfcSchema::IfcCsgSolid::ptr l, TopoDS_Shape& shape) {
return IfcGeom::convert_shape(l->TreeRootExpression(), shape);
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_Shape& face) {
bool IfcGeom::convert(const IfcSchema::IfcCurveBoundedPlane::ptr l, TopoDS_Shape& face) {
gp_Pln pln;
IfcGeom::Kernel::convert(l->BasisSurface(), pln);
IfcGeom::convert(l->BasisSurface(), pln);
gp_Trsf trsf;
trsf.SetTransformation(pln.Position(), gp::XOY());
trsf.SetTransformation(pln.Position());
TopoDS_Wire outer;
convert_wire(l->OuterBoundary(), outer);
IfcGeom::convert_wire(l->OuterBoundary(), outer);
BRepBuilderAPI_MakeFace mf (outer);
mf.Add(outer);
IfcSchema::IfcCurve::list::ptr boundaries = l->InnerBoundaries();
IfcSchema::IfcCurve::list inner = l->InnerBoundaries();
for (IfcSchema::IfcCurve::list::it it = boundaries->begin(); it != boundaries->end(); ++it) {
for (IfcSchema::IfcCurve::it it = inner->begin(); it != inner->end(); ++it) {
TopoDS_Wire inner;
convert_wire(*it, inner);
IfcGeom::convert_wire(*it, inner);
mf.Add(inner);
}
@@ -698,13 +549,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_S
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularTrimmedSurface* l, TopoDS_Shape& face) {
if (!l->BasisSurface()->declaration().is(IfcSchema::Type::IfcPlane)) {
Logger::Message(Logger::LOG_ERROR, "Unsupported BasisSurface:", l->BasisSurface());
bool IfcGeom::convert(const IfcSchema::IfcRectangularTrimmedSurface::ptr l, TopoDS_Shape& face) {
if (!l->BasisSurface()->is(IfcSchema::Type::IfcPlane)) {
Logger::Message(Logger::LOG_ERROR, "Unsupported BasisSurface:", l->BasisSurface()->entity);
return false;
}
gp_Pln pln;
IfcGeom::Kernel::convert((IfcSchema::IfcPlane*) l->BasisSurface(), pln);
IfcGeom::convert((IfcSchema::IfcPlane*) l->BasisSurface(), pln);
BRepBuilderAPI_MakeFace mf(pln, l->U1(), l->U2(), l->V1(), l->V2());
@@ -713,19 +564,19 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularTrimmedSurface* l,
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, TopoDS_Shape& shape) {
bool IfcGeom::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid::ptr l, TopoDS_Shape& shape) {
gp_Trsf directrix, position;
TopoDS_Shape face;
TopoDS_Wire wire, section;
if (!l->ReferenceSurface()->declaration().is(IfcSchema::Type::IfcPlane)) {
Logger::Message(Logger::LOG_WARNING, "Reference surface not supported", l->ReferenceSurface());
if (!l->ReferenceSurface()->is(IfcSchema::Type::IfcPlane)) {
Logger::Message(Logger::LOG_WARNING, "Reference surface not supported", l->ReferenceSurface()->entity);
return false;
}
if (!IfcGeom::Kernel::convert(l->Position(), position) ||
!convert_face(l->SweptArea(), face) ||
!convert_wire(l->Directrix(), wire) ) {
if (!IfcGeom::convert(l->Position(), position) ||
!IfcGeom::convert_face(l->SweptArea(), face) ||
!IfcGeom::convert_wire(l->Directrix(), wire) ) {
return false;
}
@@ -733,7 +584,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l,
gp_Pnt directrix_origin;
gp_Vec directrix_tangent;
bool directrix_on_plane = true;
IfcGeom::Kernel::convert((IfcSchema::IfcPlane*) l->ReferenceSurface(), pln);
IfcGeom::convert((IfcSchema::IfcPlane*) l->ReferenceSurface(), pln);
// As per Informal propositions 2: The Directrix shall lie on the ReferenceSurface.
// This is not always the case with the test files in the repository. I am not sure
@@ -744,7 +595,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l,
for (TopExp_Explorer exp(wire, TopAbs_VERTEX); exp.More(); exp.Next()) {
if (pln.Distance(BRep_Tool::Pnt(TopoDS::Vertex(exp.Current()))) > ALMOST_ZERO) {
directrix_on_plane = false;
Logger::Message(Logger::LOG_WARNING, "The Directrix does not lie on the ReferenceSurface", l);
Logger::Message(Logger::LOG_WARNING, "The Directrix does not lie on the ReferenceSurface", l->entity);
break;
}
}
@@ -786,12 +637,12 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l,
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shape& shape) {
bool IfcGeom::convert(const IfcSchema::IfcSweptDiskSolid::ptr l, TopoDS_Shape& shape) {
TopoDS_Wire wire, section1, section2;
bool hasInnerRadius = l->hasInnerRadius();
const bool hasInnerRadius = l->hasInnerRadius();
if (!convert_wire(l->Directrix(), wire)) {
if (!IfcGeom::convert_wire(l->Directrix(), wire)) {
return false;
}
@@ -807,19 +658,14 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shap
directrix = gp_Ax2(directrix_origin, directrix_tangent);
}
const double r1 = l->Radius() * getValue(GV_LENGTH_UNIT);
const double r1 = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
Handle(Geom_Circle) circle = new Geom_Circle(directrix, r1);
section1 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle));
if (hasInnerRadius) {
const double r2 = l->InnerRadius() * getValue(GV_LENGTH_UNIT);
if (r2 < getValue(GV_PRECISION)) {
// Subtraction of pipes with small radii is unstable.
hasInnerRadius = false;
} else {
Handle(Geom_Circle) circle2 = new Geom_Circle(directrix, r2);
section2 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle2));
}
const double r2 = l->InnerRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
Handle(Geom_Circle) circle = new Geom_Circle(directrix, r2);
section2 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle));
}
// NB: Note that StartParam and EndParam param are ignored and the assumption is
@@ -859,7 +705,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shap
}
if (!is_valid) {
Logger::Message(Logger::LOG_WARNING, "Failed to subtract inner radius void for:", l);
Logger::Message(Logger::LOG_WARNING, "Failed to subtract inner radius void for:", l->entity);
}
}
@@ -868,128 +714,12 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shap
#ifdef USE_IFC4
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCylindricalSurface* l, TopoDS_Shape& face) {
bool IfcGeom::convert(const IfcSchema::IfcCylindricalSurface::ptr l, TopoDS_Shape& face) {
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
IfcGeom::convert(l->Position(),trsf);
#if OCC_VERSION_HEX < 0x60502
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius())).Face().Moved(trsf);
#else
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius()), getValue(GV_PRECISION)).Face().Moved(trsf);
#endif
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius()), GetValue(GV_PRECISION)).Face().Moved(trsf);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAdvancedBrep* l, TopoDS_Shape& shape) {
return convert(l->Outer(), shape);
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, TopoDS_Shape& shape) {
IfcSchema::IfcCartesianPointList3D* point_list = l->Coordinates();
const std::vector< std::vector<double> > coordinates = point_list->CoordList();
std::vector<gp_Pnt> points;
points.reserve(coordinates.size());
for (std::vector< std::vector<double> >::const_iterator it = coordinates.begin(); it != coordinates.end(); ++it) {
const std::vector<double>& coords = *it;
if (coords.size() != 3) {
Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on Coordinates", l);
return false;
}
points.push_back(gp_Pnt(coords[0] * getValue(GV_LENGTH_UNIT),
coords[1] * getValue(GV_LENGTH_UNIT),
coords[2] * getValue(GV_LENGTH_UNIT)));
}
std::vector< std::vector<int> > indices = l->CoordIndex();
std::vector<TopoDS_Face> faces;
faces.reserve(indices.size());
for(std::vector< std::vector<int> >::const_iterator it = indices.begin(); it != indices.end(); ++ it) {
const std::vector<int>& tri = *it;
if (tri.size() != 3) {
Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on CoordIndex", l);
return false;
}
const int min_index = *std::min_element(tri.begin(), tri.end());
const int max_index = *std::max_element(tri.begin(), tri.end());
if (min_index < 1 || max_index > points.size()) {
Logger::Message(Logger::LOG_ERROR, "Contents of CoordIndex out of bounds", l);
return false;
}
const gp_Pnt& a = points[tri[0] - 1]; // account for zero- vs
const gp_Pnt& b = points[tri[1] - 1]; // one-based indices in
const gp_Pnt& c = points[tri[2] - 1]; // c++ and express
TopoDS_Wire wire = BRepBuilderAPI_MakePolygon(a, b, c, true).Wire();
TopoDS_Face face = BRepBuilderAPI_MakeFace(wire).Face();
TopoDS_Iterator face_it(face, false);
const TopoDS_Wire& w = TopoDS::Wire(face_it.Value());
const bool reversed = w.Orientation() == TopAbs_REVERSED;
if (reversed) {
face.Reverse();
}
if (face_area(face) > getValue(GV_MINIMAL_FACE_AREA)) {
faces.push_back(face);
}
}
if (faces.empty()) return false;
const unsigned int num_faces = (unsigned)indices.size();
bool valid_shell = false;
if (faces.size() < getValue(GV_MAX_FACES_TO_SEW)) {
BRepOffsetAPI_Sewing builder;
builder.SetTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMaxTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMinTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
for (std::vector<TopoDS_Face>::const_iterator it = faces.begin(); it != faces.end(); ++it) {
builder.Add(*it);
}
try {
builder.Perform();
shape = builder.SewedShape();
valid_shell = BRepCheck_Analyzer(shape).IsValid();
} catch(...) {}
if (valid_shell) {
try {
ShapeFix_Solid solid;
solid.LimitTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
TopoDS_Solid solid_shape = solid.SolidFromShell(TopoDS::Shell(shape));
if (!solid_shape.IsNull()) {
try {
BRepClass3d_SolidClassifier classifier(solid_shape);
shape = solid_shape;
} catch (...) {}
}
} catch(...) {}
} else {
Logger::Message(Logger::LOG_WARNING, "Failed to sew faceset:", l);
}
}
if (!valid_shell) {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
for (std::vector<TopoDS_Face>::const_iterator it = faces.begin(); it != faces.end(); ++it) {
builder.Add(compound, *it);
}
shape = compound;
}
return true;
}
#endif
#endif
+84 -274
View File
@@ -47,50 +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 <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 ) {
Logger::Message(Logger::LOG_WARNING, "Creating a composite curve without unit information:", l);
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;
@@ -100,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;
@@ -141,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) ) {
Logger::Message(Logger::LOG_ERROR, "Failed to convert curve:", curve);
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());
@@ -167,66 +164,48 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
w.Add(wire2);
//last_vertex = w.Vertex();
if ( w.Error() != BRepBuilderAPI_WireDone ) {
Logger::Message(Logger::LOG_ERROR, "Failed to join curve segments:", l);
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);
}
Logger::Message(Logger::LOG_ERROR,"Failed to join curve segments:",l->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 isConic = basis_curve->declaration().is(IfcSchema::Type::IfcConic);
double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT);
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 ? IfcGeom::GetValue(GV_PLANEANGLE_UNIT) : IfcGeom::GetValue(GV_LENGTH_UNIT);
Handle(Geom_Curve) curve;
if ( !convert_curve(basis_curve,curve) ) return false;
if ( ! IfcGeom::convert_curve(basis_curve,curve) ) return false;
bool trim_cartesian = l->MasterRepresentation() == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN;
IfcEntityList::ptr trims1 = l->Trim1();
IfcEntityList::ptr trims2 = l->Trim2();
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;
if ( i->declaration().is(IfcSchema::Type::IfcCartesianPoint) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] );
for ( IfcUtil::IfcAbstractSelect::it it = trims1->begin(); it != trims1->end(); it ++ ) {
const IfcUtil::IfcAbstractSelect::ptr i = *it;
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
IfcGeom::convert(reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,IfcSchema::IfcCartesianPoint>(i), pnts[sense_agreement] );
has_pnts[sense_agreement] = true;
} else if ( i->declaration().is(IfcSchema::Type::IfcParameterValue) ) {
const double value = *((IfcSchema::IfcParameterValue*)i);
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
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;
if ( i->declaration().is(IfcSchema::Type::IfcCartesianPoint) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] );
for ( IfcUtil::IfcAbstractSelect::it it = trims2->begin(); it != trims2->end(); it ++ ) {
const IfcUtil::IfcAbstractSelect::ptr i = *it;
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
IfcGeom::convert(reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,IfcSchema::IfcCartesianPoint>(i), pnts[1-sense_agreement] );
has_pnts[1-sense_agreement] = true;
} else if ( i->declaration().is(IfcSchema::Type::IfcParameterValue) ) {
const double value = *((IfcSchema::IfcParameterValue*)i);
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
const double value = *((IfcUtil::IfcBaseEntity*)i)->entity->getArgument(0);
flts[1-sense_agreement] = value * parameterFactor;
has_flts[1-sense_agreement] = true;
}
@@ -234,20 +213,20 @@ 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) ) {
Logger::Message(Logger::LOG_WARNING, "Skipping segment with length below tolerance level:", l);
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();
if ( err == BRepBuilderAPI_PointProjectionFailed ) {
Logger::Message(Logger::LOG_WARNING, "Point projection failed for:", l);
Logger::Message(Logger::LOG_WARNING,"Point projection failed for:",l->entity);
trim_cartesian_failed = true;
}
} else {
@@ -259,22 +238,22 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
// is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because
// the vector is normalised when passed to Geom_Line constructor the magnitude
// needs to be factored in with the IfcParameterValue here.
if ( basis_curve->declaration().is(IfcSchema::Type::IfcLine) ) {
if ( basis_curve->is(IfcSchema::Type::IfcLine) ) {
IfcSchema::IfcLine* line = static_cast<IfcSchema::IfcLine*>(basis_curve);
const double magnitude = line->Dir()->Magnitude();
flts[0] *= magnitude; flts[1] *= magnitude;
}
if ( basis_curve->declaration().is(IfcSchema::Type::IfcEllipse) ) {
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]);
@@ -290,213 +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);
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);
}
if (count < 3) {
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l);
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->declaration().is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->declaration().is(IfcSchema::Type::IfcCartesianPoint)) {
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l);
return false;
}
gp_Pnt p1, p2;
if (!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()->declaration().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()) std::swap(pnt1, pnt2);
TopExp_Explorer exp(result, TopAbs_EDGE);
bool first = true;
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();
first = false;
if (first && last) {
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, p1, p2));
} else if (first) {
gp_Pnt pu;
ecrv->D0(u2, pu);
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, p1, pu));
} else if (last) {
gp_Pnt pu;
ecrv->D0(u1, pu);
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, pu, p2));
} else {
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, u1, u2));
}
}
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)) {
if (!(*it)->Orientation()) w.Reverse();
TopoDS_Iterator topoit(w, false);
for (; topoit.More(); topoit.Next()) {
const TopoDS_Edge& e = TopoDS::Edge(topoit.Value());
mw.Add(e);
}
// mw.Add(w);
}
}
result = mw;
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdge* l, TopoDS_Wire& result) {
if (!l->EdgeStart()->declaration().is(IfcSchema::Type::IfcVertexPoint) || !l->EdgeEnd()->declaration().is(IfcSchema::Type::IfcVertexPoint)) {
Logger::Message(Logger::LOG_ERROR, "Only IfcVertexPoints are supported for EdgeStart and -End", l);
return false;
}
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry();
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry();
if (!pnt1->declaration().is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->declaration().is(IfcSchema::Type::IfcCartesianPoint)) {
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l);
return false;
}
gp_Pnt p1, p2;
if (!convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
!convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
{
return false;
}
BRepBuilderAPI_MakeWire mw;
mw.Add(BRepBuilderAPI_MakeEdge(p1, p2));
result = mw.Wire();
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcOrientedEdge* l, TopoDS_Wire& result) {
if (convert_wire(l->EdgeElement(), result)) {
if (!l->Orientation()) {
result.Reverse();
}
return true;
} else {
return false;
}
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSubedge* l, TopoDS_Wire& result) {
TopoDS_Wire temp;
if (convert_wire(l->ParentEdge(), result) && convert((IfcSchema::IfcEdge*) l, temp)) {
TopExp_Explorer exp(result, TopAbs_EDGE);
TopoDS_Edge edge = TopoDS::Edge(exp.Current());
Standard_Real u1, u2;
Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u1, u2);
TopoDS_Vertex v1, v2;
TopExp::Vertices(temp, v1, v2);
BRepBuilderAPI_MakeWire mw;
mw.Add(BRepBuilderAPI_MakeEdge(crv, v1, v2));
result = mw.Wire();
return true;
} else {
return false;
}
}
+32 -73
View File
@@ -18,101 +18,60 @@
********************************************************************************/
#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);
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) {
const unsigned int id = l->data().id();
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;
std::map<int,TopoDS_Shape>::const_iterator it = cache.Shape.find(id);
if ( it != cache.Shape.end() ) { r = it->second; return true; }
const bool include_curves = getValue(GV_DIMENSIONALITY) != +1;
const bool include_solids_and_surfaces = getValue(GV_DIMENSIONALITY) != -1;
IfcGeom::ShapeType st = shape_type(l);
ignored = (!include_solids_and_surfaces && (st == ST_SHAPE || st == ST_FACE)) || (!include_curves && (st == ST_WIRE || st == ST_CURVE));
if (st == ST_SHAPELIST) {
processed = true;
IfcRepresentationShapeItems items;
success = convert_shapes(l, items) && flatten_shape_list(items, r, false);
} else if (st == ST_SHAPE && include_solids_and_surfaces) {
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);
cache.Shape[id] = r;
} else if (!ignored) {
const char* const msg = processed
? "Failed to convert:"
: "No operation defined for:";
Logger::Message(Logger::LOG_ERROR, msg, l);
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);
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);
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);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
return false;
}
+6 -21
View File
@@ -41,28 +41,21 @@
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcParse.h"
using namespace IfcSchema;
SHAPES(IfcShellBasedSurfaceModel);
SHAPES(IfcFaceBasedSurfaceModel);
SHAPES(IfcRepresentation);
SHAPES(IfcShapeRepresentation);
SHAPES(IfcMappedItem);
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);
#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);
@@ -75,6 +68,9 @@ SHAPE(IfcCurveBoundedPlane);
SHAPE(IfcRectangularTrimmedSurface);
SHAPE(IfcSurfaceCurveSweptAreaSolid);
SHAPE(IfcSweptDiskSolid);
#ifdef USE_IFC4
SHAPE(IfcCylindricalSurface);
#endif
FACE(IfcArbitraryProfileDefWithVoids);
FACE(IfcArbitraryClosedProfileDef);
@@ -83,7 +79,6 @@ FACE(IfcRectangleHollowProfileDef);
FACE(IfcRectangleProfileDef);
FACE(IfcTrapeziumProfileDef)
FACE(IfcCShapeProfileDef);
// IfcAsymmetricIShapeProfileDef included
FACE(IfcIShapeProfileDef);
FACE(IfcLShapeProfileDef);
FACE(IfcTShapeProfileDef);
@@ -95,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);
@@ -113,9 +101,6 @@ WIRE(IfcArbitraryOpenProfileDef);
CURVE(IfcCircle);
CURVE(IfcEllipse);
CURVE(IfcLine);
#ifdef USE_IFC4
CURVE(IfcBSplineCurveWithKnots);
#endif
CLASS(IfcCartesianPoint,gp_Pnt);
CLASS(IfcDirection,gp_Dir);
+1 -1
View File
@@ -1,6 +1,6 @@
#include "IfcRegisterUndef.h"
#define CURVE(T) \
if ( l->declaration().is(T::Class()) ) return convert(l->as<T>(), r);
if ( l->is(T::Class()) ) return convert((T*)l,r);
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
+1 -1
View File
@@ -1,6 +1,6 @@
#include "IfcRegisterUndef.h"
#define FACE(T) \
if ( l->declaration().is(T::Class()) ) return convert(l->as<T>(), r);
if ( l->is(T::Class()) ) return convert((T*)l,r);
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
+3 -3
View File
@@ -1,14 +1,14 @@
#include "IfcRegisterUndef.h"
#define SHAPE(T) \
if ( !processed && l->declaration().is(T::Class()) ) { \
if ( !processed && l->is(T::Class()) ) { \
processed = true; \
try { \
if ( convert(l->as<T>(), r) ) { \
if ( convert((T*)l,r) ) { \
success = true; \
} \
} catch(...) { } \
if ( !success) { \
Logger::Message(Logger::LOG_ERROR, "Failed to convert:", l); \
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
return false; \
} \
}
+3 -3
View File
@@ -1,10 +1,10 @@
#include "IfcRegisterUndef.h"
#define SHAPES(T) \
if ( l->declaration().is(T::Class()) ) { \
if ( l->is(T::Class()) ) { \
try { \
return convert(l->as<T>(), r); \
return IfcGeom::convert((T*)l,r); \
} catch (...) { } \
Logger::Message(Logger::LOG_ERROR, "Failed to convert:", l); \
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
return false; \
}
#include "IfcRegisterDef.h"
+1 -1
View File
@@ -1,6 +1,6 @@
#include "IfcRegisterUndef.h"
#define WIRE(T) \
if ( l->declaration().is(T::Class()) ) return convert((T*)l,r);
if ( l->is(T::Class()) ) return convert((T*)l,r);
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
+1 -1
View File
@@ -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"
-14
View File
@@ -1,14 +0,0 @@
#include "IfcRegisterUndef.h"
#define SHAPES(T) \
if ( l->declaration().is(T::Class()) ) return ST_SHAPELIST;
#define SHAPE(T) \
if ( l->declaration().is(T::Class()) ) return ST_SHAPE;
#define WIRE(T) \
if ( l->declaration().is(T::Class()) ) return ST_WIRE;
#define FACE(T) \
if ( l->declaration().is(T::Class()) ) return ST_FACE;
#define CURVE(T) \
if ( l->declaration().is(T::Class()) ) return ST_CURVE;
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
-1
View File
@@ -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,13 +17,14 @@
* *
********************************************************************************/
#ifndef IFCSIPREFIX
#define IFCSIPREFIX
#ifndef IFCSHAPELIST_H
#define IFCSHAPELIST_H
#include "../ifcparse/IfcParse.h"
#include <gp_GTrsf.hxx>
#include <TopoDS_Shape.hxx>
namespace IfcParse {
double IfcSIPrefixToValue(IfcSchema::IfcSIPrefix::IfcSIPrefix v);
namespace IfcGeom {
typedef std::pair<gp_GTrsf*,const TopoDS_Shape*> LocationShape;
typedef std::vector<LocationShape> ShapeList;
}
#endif
#endif
+44 -75
View File
@@ -35,11 +35,7 @@
#include <fcntl.h>
#endif
#include "../ifcgeom/IfcGeomIterator.h"
#if USE_VLD
#include <vld.h>
#endif
#include "../ifcgeom/IfcGeomObjects.h"
using namespace boost;
@@ -73,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);
@@ -160,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) {};
};
@@ -190,17 +186,16 @@ public:
class Entity : public Command {
private:
const IfcGeom::TriangulationElement<float>* geom;
bool append_line_data;
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],
@@ -208,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 = indices.begin(); it != indices.end(); ++it) {
indices.push_back(*it);
}
swrite(s, std::string((char*) indices.data(), indices.size() * sizeof(int32_t)));
if (append_line_data) {
std::vector<int32_t> lines;
std::set<int32_t> faces_set (indices.begin(), indices.end());
const std::vector<int>& edges = geom->geometry().edges();
for ( std::vector<int>::const_iterator it = edges.begin(); it != edges.end(); ) {
const int32_t i1 = *(it++);
const int32_t i2 = *(it++);
if (faces_set.find(i1) != faces_set.end() || faces_set.find(i2) != faces_set.end()) {
continue;
}
lines.push_back(i1);
lines.push_back(i2);
}
swrite(s, std::string((char*) lines.data(), lines.size() * sizeof(int32_t)));
}
}
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]));
@@ -253,40 +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))); }
}
public:
Entity(const IfcGeom::TriangulationElement<float>* geom) : Command(ENTITY), geom(geom), append_line_data(true) {};
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) {};
};
int main () {
int main (int argc, char** argv) {
if (sizeof(float) != 4 || sizeof(int32_t) != 4) {
return 1;
}
// Redirect stdout to this stream, so that involuntary
// writes to stdout do not interfere with our protocol.
std::ostringstream oss;
@@ -303,12 +278,10 @@ int main () {
bool has_more = false;
IfcGeom::Iterator<float>* iterator = 0;
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: {
@@ -317,15 +290,12 @@ int main () {
char* data = new char[len];
memcpy(data, m.string().c_str(), len);
IfcGeom::IteratorSettings settings;
settings.use_world_coords() = false;
settings.weld_vertices() = false;
settings.convert_back_units() = true;
settings.include_curves() = true;
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;
}
@@ -335,23 +305,22 @@ int main () {
exit_code = 1;
break;
}
const IfcGeom::TriangulationElement<float>* geom = static_cast<const IfcGeom::TriangulationElement<float>*>(iterator->get());
const IfcGeomObjects::IfcGeomObject* geom = IfcGeomObjects::Get();
Entity(geom).write(std::cout);
continue;
}
case NEXT: {
Next n; n.read(std::cin);
has_more = iterator->next();
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: {
+24 -54
View File
@@ -17,15 +17,12 @@
* *
********************************************************************************/
#include <map>
#include <set>
#include <Max.h>
#include <stdmat.h>
#include <istdplug.h>
#include "../ifcmax/IfcMax.h"
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcgeom/IfcGeomObjects.h"
static const int NUM_MATERIAL_SLOTS = 24;
@@ -122,7 +119,7 @@ Mtl* FindMaterialByName(MtlBaseLib* library, const std::string& material_name) {
return m;
}
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();
@@ -151,7 +148,7 @@ Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& sl
return m;
}
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) {
@@ -203,10 +200,9 @@ Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi_mats,
int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, BOOL suppressPrompts) {
IfcGeom::IteratorSettings settings;
settings.use_world_coords() = false;
settings.weld_vertices() = true;
settings.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);
@@ -216,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);
if (!iterator.initialize()) return false;
if ( ! IfcGeomObjects::Init(fn_mb,0,0) ) return false;
itfc->ProgressStart(_T("Importing file..."), TRUE, fn, NULL);
@@ -228,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 = 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 = 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 = 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);
}
@@ -298,14 +267,15 @@ 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();
+48
View File
@@ -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;
}
+127
View File
@@ -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 );
}
+5
View File
@@ -0,0 +1,5 @@
#include "../IfcObj/Materials.h"
void InitMaterials() {
materials["IFCSITE"] = ObjMaterial("IFCSITE",0.7f,0.8f,0.5f);
}
+64
View File
@@ -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,149 +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 os
import sys
import numbers
import platform
import functools
import itertools
from functools import reduce
from . import guid
python_distribution = os.path.join(platform.system().lower(),
platform.architecture()[0],
'python%s.%s' % platform.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:
raise ImportError("IfcOpenShell not built for '%s'" % python_distribution)
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 __dir__(self):
return sorted(set(itertools.chain(
dir(type(self)),
self.wrapped_data.get_attribute_names(),
self.wrapped_data.get_inverse_attribute_names()
)))
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):
return [entity_instance(e) for e in self.wrapped_data.traverse(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())
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()
@@ -1,88 +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 os
import sys
from .. import ifcopenshell_wrapper
def has_occ():
try: import OCC.BRepTools
except: return False
return True
has_occ = has_occ()
wrap_shape_creation = lambda settings, shape: shape
if has_occ:
from . import occ_utils as utils
wrap_shape_creation = lambda settings, shape: utils.create_shape_from_serialization(shape) if getattr(settings, 'use_python_opencascade', False) else shape
# Subclass the settings module to provide an additional
# setting to enable pythonOCC when available
class settings(ifcopenshell_wrapper.settings):
if has_occ:
USE_PYTHON_OPENCASCADE = -1
def set(self, *args):
setting, value = args
if setting == settings.USE_PYTHON_OPENCASCADE:
self.set(settings.USE_BREP_DATA, value)
self.set(settings.USE_WORLD_COORDS, value)
self.set(settings.DISABLE_TRIANGULATION, value)
self.use_python_opencascade = value
else:
ifcopenshell_wrapper.settings.set(self, *args)
# Hide templating precision to the user by choosing based on Python's
# internal float type. This is probably always going to be a double.
for ty in (ifcopenshell_wrapper.iterator_single_precision, ifcopenshell_wrapper.iterator_double_precision):
if ty.mantissa_size() == sys.float_info.mant_dig:
_iterator = ty
# Make sure people are able to use python's platform agnostic paths
class iterator(_iterator):
def __init__(self, settings, filename):
self.settings = settings
_iterator.__init__(self, settings, os.path.abspath(filename))
if has_occ:
def get(self):
return wrap_shape_creation(self.settings, _iterator.get(self))
def create_shape(settings, inst, repr=None):
return wrap_shape_creation(
settings,
ifcopenshell_wrapper.create_shape(
settings,
inst.wrapped_data,
repr.wrapped_data if repr is not None else None
))
def iterate(settings, filename):
it = iterator(settings, filename)
if it.initialize():
while True:
yield it.get()
if not it.next(): break
@@ -1,94 +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 random
from collections import namedtuple
import OCC.gp
import OCC.V3d
import OCC.Quantity
import OCC.BRepTools
import OCC.Display.SimpleGui
tuple = namedtuple('shape', ('data', 'geometry'))
handle, main_loop, add_menu, add_function_to_menu = None, None, None, None
def initialize_display():
global handle, main_loop, add_menu, add_function_to_menu
handle, main_loop, add_menu, add_function_to_menu = OCC.Display.SimpleGui.init_display()
def setup():
viewer_handle = handle.GetViewer()
viewer = viewer_handle.GetObject()
while True:
viewer.InitActiveLights()
try: active_light = viewer.ActiveLight()
except: break
viewer.DelLight(active_light)
viewer.NextActiveLights()
for dir in [(1,2,-3), (-2,-1,1)]:
light = OCC.V3d.V3d_DirectionalLight(viewer_handle)
light.SetDirection(*dir)
viewer.SetLightOn(light.GetHandle())
setup()
return handle
def display_shape(shape, clr=None):
if not clr:
r = lambda: random.random() * 0.3 + 0.7
clr = OCC.Quantity.Quantity_Color(r(), r(), r(), OCC.Quantity.Quantity_TOC_RGB)
return handle.DisplayShape(shape, color=clr, update=True)
def set_shape_transparency(ais, t):
handle.Context.SetTransparency(ais, t)
def get_bounding_box_center(bbox):
bbmin = [0.]*3; bbmax = [0.]*3
bbmin[0], bbmin[1], bbmin[2], bbmax[0], bbmax[1], bbmax[2] = bbox.Get()
return OCC.gp.gp_Pnt(*map(lambda xy: (xy[0]+xy[1])/2., zip(bbmin, bbmax)))
def create_shape_from_serialization(brep_object):
brep_data, occ_shape = None, None
is_product_shape = True
try:
brep_data = brep_object.geometry.brep_data
except:
try:
brep_data = brep_object.brep_data
is_product_shape = False
except: pass
if not brep_data: return tuple(brep_object, None)
try:
ss = OCC.BRepTools.BRepTools_ShapeSet()
ss.ReadFromString(brep_data)
occ_shape = ss.Shape(ss.NbShapes())
except: pass
if is_product_shape:
return tuple(brep_object, occ_shape)
else:
return occ_shape
@@ -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/>. #
# #
###############################################################################
import string
from functools import reduce
chars = string.digits + string.ascii_uppercase + string.ascii_lowercase + '_$'
def compress(g):
bs = [int(g[i:i+2], 16) for i in range(0, len(g), 2)]
def b64(v, l=4):
return ''.join([chars[(v // (64**i))%64] for i in range(l)][::-1])
return ''.join([b64(bs[0], 2)] + [b64((bs[i] << 16) + (bs[i+1] << 8) + bs[i+2]) for i in range(1,16,3)])
def expand(g):
def b64(v):
return reduce(lambda a, b: a * 64 + b, map(lambda c: chars.index(c), v))
bs = [b64(g[0:2])]
for i in range(5):
d = b64(g[2+4*i:6+4*i])
bs += [(d >> (8*(2-j)))%256 for j in range(3)]
return ''.join(['%02x'%b for b in bs])
def split(g):
return '{%s-%s-%s-%s-%s}'%(g[:8], g[8:12], g[12:16], g[16:20], g[20:])
-89
View File
@@ -1,89 +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 HDF5SETTINGS_H
#define HDF5SETTINGS_H
#include <string>
#include <vector>
#include <stdexcept>
namespace IfcParse {
struct Hdf5Settings {
private:
bool compress_, fix_cartesian_point_, fix_global_id_, instantiate_select_, instantiate_inverse_;
unsigned int chunk_size_;
std::vector<std::string> ref_attributes_;
public:
enum Profile {
standard,
padded,
standard_referenced,
padded_referenced
};
static Profile ProfileFromString(const std::string& s) {
if (s == "standard") return standard;
if (s == "padded") return padded;
if (s == "referenced") return standard_referenced;
if (s == "padded-referenced") return padded_referenced;
throw std::runtime_error("Unrecognized profile");
}
private:
Profile profile_;
public:
Hdf5Settings()
: compress_(false)
, fix_cartesian_point_(false)
, fix_global_id_(false)
, instantiate_select_(false)
, instantiate_inverse_(false)
, chunk_size_(false)
, profile_(standard)
{}
bool compress() const { return compress_; }
bool fix_cartesian_point() const { return fix_cartesian_point_; }
bool fix_global_id() const { return fix_global_id_; }
bool instantiate_select() const { return instantiate_select_; }
bool instantiate_inverse() const { return instantiate_inverse_; }
bool& compress() { return compress_; }
bool& fix_cartesian_point() { return fix_cartesian_point_; }
bool& fix_global_id() { return fix_global_id_; }
bool& instantiate_select() { return instantiate_select_; }
bool& instantiate_inverse() { return instantiate_inverse_; }
unsigned int chunk_size() const { return chunk_size_; }
unsigned int& chunk_size() { return chunk_size_; }
Profile profile() const { return profile_; }
Profile& profile() { return profile_; }
const std::vector<std::string>& ref_attributes() const { return ref_attributes_; }
std::vector<std::string>& ref_attributes() { return ref_attributes_; }
};
}
#endif
File diff suppressed because it is too large Load Diff
@@ -23,9 +23,7 @@
* but instead modify the python script that has been used to generate this. *
* *
********************************************************************************/
#ifndef USE_IFC4
#ifndef IFC2X3RT_H
#define IFC2X3RT_H
@@ -40,15 +38,13 @@ namespace Type {
int GetAttributeCount(Enum t);
int GetAttributeIndex(Enum t, const std::string& a);
IfcUtil::ArgumentType GetAttributeType(Enum t, unsigned char a);
Enum GetAttributeEntity(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);
std::set<std::string> GetInverseAttributeNames(Enum t);
Enum GetAttributeEnumerationClass(Enum t, unsigned char a);
void PopulateDerivedFields(IfcWrite::IfcWritableEntity* e);
}}
#endif
#endif
File diff suppressed because it is too large Load Diff
+6113 -8368
View File
File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More