mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-07 00:11:36 +00:00
Compare commits
425 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 16f2b0a0d2 | |||
| 6dd22fda82 | |||
| 1e772a7ea9 | |||
| 7e14d4389e | |||
| 852e3e28ee | |||
| e962872549 | |||
| f16b2e59ae | |||
| 844428fefd | |||
| a53ffd2662 | |||
| fd02665e5e | |||
| fa3fdcd273 | |||
| e6499ef3b1 | |||
| cf1de365e7 | |||
| 3bdf429c30 | |||
| 1bef19a87a | |||
| e07189e6b1 | |||
| f851a7188f | |||
| d8d82eb6ec | |||
| 89e97e5d7c | |||
| 388c717317 | |||
| 20eb913b65 | |||
| 6ca5c90517 | |||
| 5e2d5129bb | |||
| 226a02adfc | |||
| 03a82fe301 | |||
| b40a21743b | |||
| 2562d6c208 | |||
| cab7716bdf | |||
| 83af36dc60 | |||
| 34fd334fcb | |||
| 839dd9aed6 | |||
| 0f0d060177 | |||
| 6dc9ff6fa3 | |||
| c2da3b9e82 | |||
| 621859453a | |||
| 01ab21a69a | |||
| 9c81735cbd | |||
| 659f05bda3 | |||
| 59020a22ee | |||
| 693444d4d2 | |||
| 93a33a8507 | |||
| e1b1940d83 | |||
| 9a2e5d698a | |||
| 71dcc96ac2 | |||
| 2422da4048 | |||
| f6403c81e1 | |||
| de78c6c5dc | |||
| f24c996bc1 | |||
| 3dbb52a4f3 | |||
| d9c4920d37 | |||
| dcf331a78d | |||
| 09679050c2 | |||
| d13a7b613b | |||
| 61fba3f406 | |||
| b8001ea05d | |||
| 4163f817a6 | |||
| 2a0471ec27 | |||
| 418b78cdd5 | |||
| c1c738390f | |||
| 766d45e0cb | |||
| df88474bc5 | |||
| 481515f5ae | |||
| a33f5b6e17 | |||
| 10bec3eee0 | |||
| da0af77570 | |||
| a6094f50b9 | |||
| c3f1b41860 | |||
| 4122759f1a | |||
| a583339492 | |||
| f12e980bfe | |||
| 4979deb111 | |||
| c575352d20 | |||
| 2f8fa3282b | |||
| 993e322a8e | |||
| 61ccd8a7cf | |||
| 450baf224f | |||
| 7b2197fa37 | |||
| cde1c5f2ee | |||
| 33772a4710 | |||
| 178c34fb22 | |||
| 17ecc43f78 | |||
| 72999e04d9 | |||
| f191b1fdd2 | |||
| d095bfecde | |||
| 2e1699beea | |||
| 5c07c8dc95 | |||
| 0fa05faee8 | |||
| 21e8a1e8e6 | |||
| 2e6601b3e7 | |||
| 634932e6e7 | |||
| a041d289c6 | |||
| 01f8882311 | |||
| f2bdfbd049 | |||
| c7bf03e8f8 | |||
| 18e451b874 | |||
| f4d58b3969 | |||
| 76a3146b70 | |||
| fe70acb541 | |||
| a52901344c | |||
| d0e26f07fc | |||
| 5270710fc2 | |||
| ed8cc620ea | |||
| 9b13ed3f38 | |||
| 801c7da40f | |||
| 4be7da1a43 | |||
| a0db3a3406 | |||
| 18f8d7b3a3 | |||
| 010e05308d | |||
| 973fa9ccb5 | |||
| 0d42a293ad | |||
| 6716423a68 | |||
| a02a06a0e3 | |||
| d3438335a2 | |||
| a0bb589ed3 | |||
| 056bcd12d0 | |||
| fe699e0a81 | |||
| 4eee9a1936 | |||
| 8c1710cae1 | |||
| e2d3b3734f | |||
| b243572d23 | |||
| 3224a2cf83 | |||
| a2d91f9331 | |||
| 0301e2fb1b | |||
| 0036bd2dc2 | |||
| 0877bb0ac3 | |||
| e62ce005dc | |||
| b6e2d78bfa | |||
| bf292cccd0 | |||
| 83c4b6a642 | |||
| 2dc5cd44b7 | |||
| fcbe93c4c2 | |||
| 89b3b96f1e | |||
| 16a82f035f | |||
| b562508f5b | |||
| a13042f227 | |||
| 3cbb47a831 | |||
| 7d806296c1 | |||
| d6bd0c861b | |||
| 8164c90ba0 | |||
| fff6f97651 | |||
| 6a5d5dcb12 | |||
| bb3dc351b8 | |||
| 90946e0877 | |||
| 7895835ca3 | |||
| 7caa4e3e1d | |||
| d721dabf3b | |||
| ac8cf298fa | |||
| 9087bc65a7 | |||
| ccf4e84e18 | |||
| 0f1db1267b | |||
| 431e993ba3 | |||
| d912e73282 | |||
| 106da12444 | |||
| 579d3713fd | |||
| 89a015724b | |||
| 8b63959509 | |||
| 0a8791e04e | |||
| 318779196b | |||
| d076fa588b | |||
| 6190771817 | |||
| 206a9cf5d0 | |||
| d4b51a82e7 | |||
| a749775045 | |||
| 26ed16ba52 | |||
| 7b4d8734ed | |||
| 455d382a9e | |||
| c9313c8e02 | |||
| b44a88d203 | |||
| 921c3eb2d3 | |||
| d5efe45b0b | |||
| b8a7b5426d | |||
| 89bea19b75 | |||
| 5c0eb05482 | |||
| c9ff455812 | |||
| fdf1b29682 | |||
| f3af39546b | |||
| 44ddc5e6dc | |||
| c7ddc0643e | |||
| 3a9e90f94f | |||
| db6630c1f8 | |||
| c20afd24a5 | |||
| 7b82bfb477 | |||
| 3e00139a87 | |||
| 23beb5691c | |||
| c6a265adf8 | |||
| 94d214808e | |||
| a58b2ede63 | |||
| e5c20a009d | |||
| b590747db9 | |||
| 2532ba30e4 | |||
| 9096895bdb | |||
| 82143f226e | |||
| 22a8d9a17b | |||
| 4385f3b14d | |||
| 3cba242295 | |||
| 822fa91f4d | |||
| 266d6f4c97 | |||
| 8406c5243c | |||
| 810d3eab1e | |||
| 17f6e67706 | |||
| f5c32adff1 | |||
| bb43dec90f | |||
| 0e5edbcd84 | |||
| 68fc361d96 | |||
| 06b4fcb066 | |||
| 85d5d86c84 | |||
| 78f4d7d592 | |||
| 92bc7b13cb | |||
| e518146bd6 | |||
| e9eb7db620 | |||
| 1068070037 | |||
| 3d302619c5 | |||
| 48febb7eff | |||
| feaa13a809 | |||
| 76cbb79c75 | |||
| 6aabbd4a55 | |||
| 48676a733f | |||
| f8c45b2a99 | |||
| 1ec14118fe | |||
| 381f711103 | |||
| b748c0a573 | |||
| c4e8a409de | |||
| 28863f90b9 | |||
| 4f60c7d48c | |||
| f70b37137d | |||
| 49d491704e | |||
| a3f17cd4e7 | |||
| b96cf38e17 | |||
| 5a994ebe28 | |||
| ffc008228d | |||
| 77ba3f5a80 | |||
| 04d4095ffe | |||
| 569fa49796 | |||
| 7abe2df066 | |||
| 9b64c6f4b9 | |||
| 771f78a671 | |||
| 3d6b330366 | |||
| 37d4e9bcbd | |||
| 7390faa654 | |||
| b7d4eb62d5 | |||
| 40a60386c8 | |||
| 9bf9f82b3b | |||
| b37a684eb9 | |||
| c97cf661a2 | |||
| 53f625346f | |||
| 608c7d9841 | |||
| 955190b517 | |||
| 462425f61d | |||
| 0a0f44b674 | |||
| 9f9a0ea3dc | |||
| a28b5517e8 | |||
| df1805921b | |||
| 5ea13970c8 | |||
| aad6c77d00 | |||
| 9bbbc6e7d9 | |||
| d41dbc386e | |||
| 9cd0a76f84 | |||
| dada40735b | |||
| 2ce89c8b22 | |||
| 0552c336df | |||
| 349e7ddaa7 | |||
| f20ae8e25e | |||
| 8f853ac5af | |||
| 6822e84849 | |||
| 73266ea216 | |||
| b0ccf69870 | |||
| 573655e5ef | |||
| 2a7135f347 | |||
| a57a305e9d | |||
| e6ff1126ad | |||
| 6c8a60db6e | |||
| b5c9de8d64 | |||
| 5fe4cfab63 | |||
| b3e5264aa9 | |||
| e3d5b6220d | |||
| 846e881cf4 | |||
| ee87466521 | |||
| def1328a91 | |||
| a7c0c08725 | |||
| 63e9b706c1 | |||
| 16d400e192 | |||
| 3801e52bff | |||
| c597404dfe | |||
| 47b9ed4482 | |||
| d23dee551c | |||
| 79817341e0 | |||
| 0124034803 | |||
| 2da6f5428d | |||
| 5f677baf63 | |||
| b5f055e54b | |||
| 4c79f713ed | |||
| b789839e4a | |||
| 23d5827229 | |||
| f0425b16d1 | |||
| e1edda588e | |||
| 6c7c88d7a5 | |||
| 3503c8c933 | |||
| e37b062757 | |||
| 97b6f444d1 | |||
| 418dabaff2 | |||
| 7b17c2dccd | |||
| f6f541ee3b | |||
| 09168d8910 | |||
| e57f20f5f2 | |||
| 511e83c2c6 | |||
| 8581fed39b | |||
| 1d319f7ac4 | |||
| 9780c047e9 | |||
| 1c757c351b | |||
| f3c26c372d | |||
| 4d5d749255 | |||
| 8872affe54 | |||
| 3236218aba | |||
| 2a403e240d | |||
| 3f285ea639 | |||
| 4c976c8b70 | |||
| d88d4d5951 | |||
| eb815120dc | |||
| 7f8d84a1af | |||
| 24044fb92a | |||
| cd366bf8c2 | |||
| 96ce5f6b25 | |||
| 120de2f601 | |||
| 872dd4e831 | |||
| 6e44683b5d | |||
| e77216d41c | |||
| cf2e82e8f5 | |||
| 9a1c7af953 | |||
| 5648b8d8bc | |||
| 1837b79ac3 | |||
| e6aa449ef8 | |||
| aa1ff90241 | |||
| 1c39eba3f7 | |||
| 92c5bb637b | |||
| d45056f9c5 | |||
| 83b6ce9083 | |||
| 81292f1adc | |||
| 49e4ff31ca | |||
| 7066337449 | |||
| 948d7675f0 | |||
| 1b54ba039d | |||
| e87b8988cd | |||
| bd83259d2b | |||
| 604d6b032d | |||
| b30fbf73ae | |||
| ed1db3dc68 | |||
| 68740367a5 | |||
| 365b5f5d48 | |||
| b406d1c100 | |||
| 95a1332228 | |||
| a0d74bdf83 | |||
| 24279776ab | |||
| aebb9469a9 | |||
| 0ecaf28e3e | |||
| 3e7c0cfd55 | |||
| aae576aae2 | |||
| 1aab95459b | |||
| 80b39c0d22 | |||
| bc801d00ba | |||
| 54ecdb8295 | |||
| 71ea636206 | |||
| 2f16bb42ed | |||
| 268109875f | |||
| dab6e1d220 | |||
| 220b36b09c | |||
| 4c17d153f4 | |||
| 7597f25db0 | |||
| ec2ed06272 | |||
| 05c98de100 | |||
| 17f873b486 | |||
| 87259c0cab | |||
| 5615c70952 | |||
| 11b877f925 | |||
| 60963acd3f | |||
| 7748a6ef0f | |||
| c47a43caf7 | |||
| 3fa934a056 | |||
| 2bd37fd088 | |||
| 6b2dc3683a | |||
| 8653e59403 | |||
| 586ad14013 | |||
| 3c2cf1bb08 | |||
| 71b173a494 | |||
| 06958a02a4 | |||
| 30804b4232 | |||
| 0f088f02b3 | |||
| 9577778573 | |||
| bffb19a92f | |||
| 0f53a877c7 | |||
| bbf80bedaa | |||
| eb433ff8e2 | |||
| 03beb42d2e | |||
| 714bf5eb8d | |||
| b4059cc340 | |||
| 27962701b9 | |||
| 14a3f80c59 | |||
| 063f498066 | |||
| 2e0e5862f6 | |||
| d6693ff931 | |||
| 17ebefa158 | |||
| 12a0571bf4 | |||
| 1d1fd49608 | |||
| 259cfa895e | |||
| 3f048efc79 | |||
| dccbccfa06 | |||
| 80bc1b5dab | |||
| 5d4ff0b54a | |||
| 852cb7d8c4 | |||
| 24b03330ef | |||
| e4749147d6 | |||
| 4f26622e03 | |||
| 71b5cd12a8 | |||
| 6064ab0fa4 | |||
| 48e61cdcea | |||
| a33fc19ed6 | |||
| 578dce4a47 | |||
| f1322996f0 | |||
| 2353c25fb8 | |||
| e56281a72e | |||
| db98906643 | |||
| e729795da2 | |||
| 8b11a1baf7 | |||
| 2f500aa098 | |||
| 0814c16f06 | |||
| cb6884b48e |
+10
@@ -0,0 +1,10 @@
|
||||
# Dependency and build folders created by the build scripts
|
||||
/deps*/
|
||||
/build*/
|
||||
/install*/
|
||||
/win/BuildDepsCache*.txt
|
||||
# IfcExpressParser residue
|
||||
/src/ifcexpressparser/__pycache__
|
||||
/src/ifcexpressparser/express_parser.py
|
||||
# Python test residue
|
||||
/test/__pycache__
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
@@ -1,26 +1,126 @@
|
||||
IfcOpenShell
|
||||
============
|
||||
open source (LGPL) software library for working with the IFC file format
|
||||
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)
|
||||
|
||||
|
||||
http://IfcOpenShell.org
|
||||
Prerequisites
|
||||
=============
|
||||
* Git, CMake (2.6 or newer), Visual Studio 2008 or newer with C++ toolset (Windows), or GCC (*nix, Clang untested).
|
||||
|
||||
About this repository
|
||||
=====================
|
||||
|
||||
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.
|
||||
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
|
||||
|
||||
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
|
||||
>>> wall.GlobalId
|
||||
>>>
|
||||
>>> # Accessing EXPRESS attributes by name:
|
||||
>>> wall.GlobalId
|
||||
'2O2Fr$t4X7Zf8NOew3FL9r'
|
||||
>>> wall.Name = "My wall"
|
||||
>>> wall.NonExistingAttr
|
||||
@@ -42,8 +142,11 @@ The following interactive session illustrates its use:
|
||||
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'
|
||||
@@ -52,81 +155,16 @@ The following interactive session illustrates its use:
|
||||
>>> 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")
|
||||
|
||||
|
||||
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.
|
||||
|
||||
[win/readme.md]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/win/readme.md "win/readme.md"
|
||||
[IFC2x3 TC1]: http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc2x3-tc1-release "IFC2x3 TC1"
|
||||
[IFC4]: http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc4-release "IFC4"
|
||||
+406
-173
@@ -1,17 +1,90 @@
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
cmake_minimum_required (VERSION 2.8.5)
|
||||
|
||||
project (IfcOpenShell)
|
||||
|
||||
OPTION(UNICODE_SUPPORT "Build IfcOpenShell with Unicode support (requires ICU)." ON)
|
||||
OPTION(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON)
|
||||
OPTION(HDF5_SUPPORT "Enable HDF5 support (requires HDF5, zlib)" ON)
|
||||
OPTION(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF)
|
||||
#TODO OPTION(IFCCONVERT_DOUBLE_PRECISION "IfcConvert: Use double precision floating-point numbers." OFF)
|
||||
OPTION(USE_IFC4 "Use IFC 4 instead of IFC 2x3 (full rebuild recommended when switching this)" OFF)
|
||||
OPTION(BUILD_IFCPYTHON "Build IfcPython." ON)
|
||||
OPTION(BUILD_EXAMPLES "Build example applications." ON)
|
||||
OPTION(USE_VLD "Use Visual Leak Detector for debugging memory leaks, MSVC-only." OFF)
|
||||
# TODO QtViewer is deprecated ATM as it uses the 0.4 API
|
||||
# OPTION(BUILD_QTVIEWER "Build IfcOpenShell Qt GUI Viewer (requires Qt 4 framework)." OFF)
|
||||
|
||||
|
||||
# Create cache entries if absent for environment variables
|
||||
MACRO(UNIFY_ENVVARS_AND_CACHE VAR)
|
||||
IF ((NOT DEFINED ${VAR}) AND (NOT "$ENV{${VAR}}" STREQUAL ""))
|
||||
SET(${VAR} "$ENV{${VAR}}" CACHE STRING "${VAR}" FORCE)
|
||||
ENDIF()
|
||||
ENDMACRO()
|
||||
|
||||
UNIFY_ENVVARS_AND_CACHE(OCC_INCLUDE_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(OCC_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(ICU_INCLUDE_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(ICU_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_INCLUDE_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(HDF5_INCLUDE_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(HDF5_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(PCRE_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE)
|
||||
|
||||
# Find Boost
|
||||
IF(MSVC)
|
||||
SET(Boost_USE_STATIC_LIBS ON)
|
||||
SET(Boost_USE_STATIC_RUNTIME ON)
|
||||
SET(Boost_USE_MULTITHREADED ON)
|
||||
ENDIF()
|
||||
FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options)
|
||||
MESSAGE(STATUS "Boost include files found in ${Boost_INCLUDE_DIRS}")
|
||||
MESSAGE(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}")
|
||||
|
||||
# Find Open CASCADE header files
|
||||
IF("$ENV{OCC_INCLUDE_DIR}" STREQUAL "")
|
||||
# Usage:
|
||||
# SET(SOME_LIRARIES foo bar)
|
||||
# ADD_DEBUG_VARIANTS(SOME_LIRARIES "${SOME_LIRARIES}" "d")
|
||||
# "foo bar" -> "optimized foo debug food optimized bar debug bard"
|
||||
FUNCTION(ADD_DEBUG_VARIANTS NAME LIBRARIES POSTFIX)
|
||||
SET(LIBRARIES_STR "${LIBRARIES}")
|
||||
SET(LIBRARIES "")
|
||||
FOREACH(lib ${LIBRARIES_STR})
|
||||
SET(LIBRARIES "${LIBRARIES} optimized ${lib}")
|
||||
SET(LIBRARIES "${LIBRARIES} debug ${lib}${POSTFIX}")
|
||||
ENDFOREACH()
|
||||
STRING(STRIP ${LIBRARIES} LIBRARIES) # leading and trailing whitespace cause confusion
|
||||
SEPARATE_ARGUMENTS(LIBRARIES) # "optimized <lib> debug <lib>" needs to be a list instead of a string
|
||||
SET(${NAME} ${LIBRARIES} PARENT_SCOPE)
|
||||
ENDFUNCTION()
|
||||
|
||||
# Find Open CASCADE
|
||||
IF("${OCC_INCLUDE_DIR}" STREQUAL "")
|
||||
SET(OCC_INCLUDE_DIR "/usr/include/opencascade/" CACHE FILEPATH "Open CASCADE header files")
|
||||
MESSAGE(STATUS "Looking for opencascade include files in: ${OCC_INCLUDE_DIR}")
|
||||
MESSAGE(STATUS "Use OCC_INCLUDE_DIR to specify another directory")
|
||||
ELSE()
|
||||
SET(OCC_INCLUDE_DIR $ENV{OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files")
|
||||
SET(OCC_INCLUDE_DIR ${OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files")
|
||||
MESSAGE(STATUS "Looking for opencascade include files in: ${OCC_INCLUDE_DIR}")
|
||||
ENDIF()
|
||||
|
||||
@@ -22,209 +95,369 @@ ELSE()
|
||||
MESSAGE(FATAL_ERROR "Unable to find header files, aborting")
|
||||
ENDIF()
|
||||
|
||||
# Find Open CASCADE library files
|
||||
IF("$ENV{OCC_LIBRARY_DIR}" STREQUAL "")
|
||||
SET(OPENCASCADE_LIBRARIES
|
||||
TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO
|
||||
TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset
|
||||
)
|
||||
|
||||
IF(MSVC)
|
||||
ADD_DEBUG_VARIANTS(OPENCASCADE_LIBRARIES "${OPENCASCADE_LIBRARIES}" "d")
|
||||
ENDIF()
|
||||
|
||||
IF("${OCC_LIBRARY_DIR}" STREQUAL "")
|
||||
SET(OCC_LIBRARY_DIR "/usr/lib/" CACHE FILEPATH "Open CASCADE library files")
|
||||
MESSAGE(STATUS "Looking for opencascade library files in: ${OCC_LIBRARY_DIR}")
|
||||
MESSAGE(STATUS "Use OCC_LIBRARY_DIR to specify another directory")
|
||||
ELSE()
|
||||
SET(OCC_LIBRARY_DIR $ENV{OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files")
|
||||
SET(OCC_LIBRARY_DIR ${OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files")
|
||||
MESSAGE(STATUS "Looking for opencascade library files in: ${OCC_LIBRARY_DIR}")
|
||||
ENDIF()
|
||||
|
||||
FIND_LIBRARY(libTKernel "TKernel" ${OCC_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64)
|
||||
FIND_LIBRARY(libTKernel NAMES TKernel TKerneld PATHS ${OCC_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64)
|
||||
IF(libTKernel)
|
||||
MESSAGE(STATUS "Library files found")
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "Unable to find library files, aborting")
|
||||
ENDIF()
|
||||
|
||||
IF("$ENV{ICU_INCLUDE_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No ICU include directory specified")
|
||||
ElSE()
|
||||
SET(ICU_INCLUDE_DIR CACHE FILEPATH "ICU header files")
|
||||
IF(UNICODE_SUPPORT)
|
||||
# Find ICU
|
||||
IF("${ICU_INCLUDE_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No ICU include directory specified")
|
||||
ElSE()
|
||||
SET(ICU_INCLUDE_DIR "${ICU_INCLUDE_DIR}" CACHE FILEPATH "ICU header files")
|
||||
ENDIF()
|
||||
|
||||
IF("${ICU_LIBRARY_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No ICU library directory specified")
|
||||
ElSE()
|
||||
SET(ICU_LIBRARY_DIR "${ICU_LIBRARY_DIR}" CACHE FILEPATH "ICU library files")
|
||||
ENDIF()
|
||||
|
||||
FIND_LIBRARY(icu NAMES icuuc icuucd PATHS /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR})
|
||||
|
||||
IF(icu)
|
||||
ADD_DEFINITIONS(-DHAVE_ICU)
|
||||
MESSAGE(STATUS "ICU libraries found")
|
||||
# NOTE icudata appears to be icudt on Windows/MSVC and icudata on others
|
||||
# dl is included to resolve dlopen and friends symbols
|
||||
IF(MSVC)
|
||||
SET(ICU_LIBRARIES icuuc icudt)
|
||||
ADD_DEBUG_VARIANTS(ICU_LIBRARIES "${ICU_LIBRARIES}" "d")
|
||||
ADD_DEFINITIONS(-DU_STATIC_IMPLEMENTATION) # required for static ICU
|
||||
ELSE()
|
||||
SET(ICU_LIBRARIES icuuc icudata dl)
|
||||
ENDIF()
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "UNICODE_SUPPORT enabled, but unable to find ICU. Disable UNICODE_SUPPORT or fix ICU paths to proceed.")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF("$ENV{ICU_LIBRARY_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No ICU library directory specified")
|
||||
ElSE()
|
||||
SET(ICU_LIBRARY_DIR CACHE FILEPATH "ICU library files")
|
||||
IF(COLLADA_SUPPORT)
|
||||
# Find OpenCOLLADA
|
||||
IF("${OPENCOLLADA_INCLUDE_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No OpenCOLLADA include directory specified")
|
||||
SET(OPENCOLLADA_INCLUDE_DIR "/usr/local/include/opencollada" CACHE FILEPATH "OpenCOLLADA header files")
|
||||
ElSE()
|
||||
SET(OPENCOLLADA_INCLUDE_DIR "${OPENCOLLADA_INCLUDE_DIR}" CACHE FILEPATH "OpenCOLLADA header files")
|
||||
ENDIF()
|
||||
|
||||
IF("${OPENCOLLADA_LIBRARY_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No OpenCOLLADA library directory specified")
|
||||
SET(OPENCOLLADA_LIBRARY_DIR "/usr/local/lib/opencollada" CACHE FILEPATH "OpenCOLLADA library files")
|
||||
ElSE()
|
||||
SET(OPENCOLLADA_LIBRARY_DIR "${OPENCOLLADA_LIBRARY_DIR}" CACHE FILEPATH "OpenCOLLADA library files")
|
||||
ENDIF()
|
||||
|
||||
SET(OPENCOLLADA_INCLUDE_DIRS "${OPENCOLLADA_INCLUDE_DIR}/COLLADABaseUtils" "${OPENCOLLADA_INCLUDE_DIR}/COLLADAStreamWriter")
|
||||
|
||||
FIND_FILE(COLLADASWStreamWriter_h "COLLADASWStreamWriter.h" ${OPENCOLLADA_INCLUDE_DIRS})
|
||||
IF(COLLADASWStreamWriter_h)
|
||||
MESSAGE(STATUS "OpenCOLLADA header files found")
|
||||
ADD_DEFINITIONS(-DWITH_OPENCOLLADA)
|
||||
SET(OPENCOLLADA_LIBRARIES
|
||||
GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader
|
||||
OpenCOLLADAStreamWriter UTF buffer ftoa pcre
|
||||
)
|
||||
IF(NOT "${PCRE_LIBRARY_DIR}" STREQUAL "")
|
||||
SET(OPENCOLLADA_LIBRARY_DIR ${OPENCOLLADA_LIBRARY_DIR} ${PCRE_LIBRARY_DIR})
|
||||
ENDIF()
|
||||
IF(MSVC)
|
||||
ADD_DEBUG_VARIANTS(OPENCOLLADA_LIBRARIES "${OPENCOLLADA_LIBRARIES}" "d")
|
||||
ENDIF()
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find OpenCOLLADA. Disable COLLADA_SUPPORT or fix OpenCOLLADA paths to proceed.")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
FIND_LIBRARY(icu "icuuc" /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR})
|
||||
if(HDF5_SUPPORT)
|
||||
IF("${HDF5_INCLUDE_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No HDF5 include directory specified")
|
||||
ElSE()
|
||||
SET(HDF5_INCLUDE_DIR "${HDF5_INCLUDE_DIR}" CACHE FILEPATH "HDF5 header files")
|
||||
ENDIF()
|
||||
|
||||
IF("${HDF5_LIBRARY_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No HDF5 library directory specified")
|
||||
ElSE()
|
||||
SET(HDF5_LIBRARY_DIR "${HDF5_LIBRARY_DIR}" CACHE FILEPATH "HDF5 library files")
|
||||
ENDIF()
|
||||
|
||||
IF(WIN32)
|
||||
# An additional lib- prefix is added by HDF5 to denote static libraries
|
||||
SET(HDF5_LIBRARIES libhdf5_cpp libhdf5 libzlib)
|
||||
ELSE()
|
||||
SET(HDF5_LIBRARIES hdf5_cpp hdf5 z szip)
|
||||
ENDIF()
|
||||
endif()
|
||||
|
||||
IF(icu)
|
||||
MESSAGE(STATUS "ICU libraries found")
|
||||
ADD_DEFINITIONS(-DHAVE_ICU)
|
||||
ELSE()
|
||||
MESSAGE(STATUS "Unable to find ICU library files, continuing")
|
||||
# TODO Are these needed on other platforms still or can these be removed for good?
|
||||
IF (NOT WIN32)
|
||||
INCLUDE(CheckIncludeFileCXX)
|
||||
|
||||
MACRO(CHECK_ADD_OCE_OCC_DEF INCLUDE)
|
||||
STRING(REPLACE . _ STR ${INCLUDE})
|
||||
STRING(TOUPPER ${STR} STR)
|
||||
CHECK_INCLUDE_FILE_CXX("${INCLUDE}" FOUND_${STR})
|
||||
IF(FOUND_${STR})
|
||||
ADD_DEFINITIONS(-DOCE_HAVE_${STR})
|
||||
ADD_DEFINITIONS(-DHAVE_${STR})
|
||||
ENDIF(FOUND_${STR})
|
||||
ENDMACRO()
|
||||
|
||||
CHECK_ADD_OCE_OCC_DEF(limits)
|
||||
CHECK_ADD_OCE_OCC_DEF(climits)
|
||||
CHECK_ADD_OCE_OCC_DEF(limits.h)
|
||||
CHECK_ADD_OCE_OCC_DEF(fstream)
|
||||
CHECK_ADD_OCE_OCC_DEF(fstream.h)
|
||||
CHECK_ADD_OCE_OCC_DEF(iomanip)
|
||||
CHECK_ADD_OCE_OCC_DEF(iomanip.h)
|
||||
CHECK_ADD_OCE_OCC_DEF(iostream)
|
||||
CHECK_ADD_OCE_OCC_DEF(iostream.h)
|
||||
ENDIF()
|
||||
|
||||
IF("$ENV{OPENCOLLADA_INCLUDE_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No OpenCOLLADA include directory specified")
|
||||
SET(OPENCOLLADA_INCLUDE_DIR "/usr/local/include/opencollada" CACHE FILEPATH "OpenCOLLADA header files")
|
||||
ElSE()
|
||||
SET(OPENCOLLADA_INCLUDE_DIR "$ENV{OPENCOLLADA_INCLUDE_DIR}" CACHE FILEPATH "OpenCOLLADA header files")
|
||||
ENDIF()
|
||||
|
||||
IF("$ENV{OPENCOLLADA_LIBRARY_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No OpenCOLLADA library directory specified")
|
||||
SET(OPENCOLLADA_LIBRARY_DIR "/usr/local/lib/opencollada" CACHE FILEPATH "OpenCOLLADA library files")
|
||||
ElSE()
|
||||
SET(OPENCOLLADA_LIBRARY_DIR "$ENV{OPENCOLLADA_LIBRARY_DIR}" CACHE FILEPATH "OpenCOLLADA library files")
|
||||
ENDIF()
|
||||
|
||||
SET(OPENCOLLADA_INCLUDE_DIRS "${OPENCOLLADA_INCLUDE_DIR}/COLLADABaseUtils" "${OPENCOLLADA_INCLUDE_DIR}/COLLADAStreamWriter")
|
||||
|
||||
FIND_FILE(COLLADASWStreamWriter_h "COLLADASWStreamWriter.h" ${OPENCOLLADA_INCLUDE_DIRS})
|
||||
IF(COLLADASWStreamWriter_h)
|
||||
MESSAGE(STATUS "OpenCOLLADA header files found")
|
||||
ADD_DEFINITIONS(-DWITH_OPENCOLLADA)
|
||||
SET(OPENCOLLADA_LIBRARIES
|
||||
GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils
|
||||
OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader
|
||||
OpenCOLLADAStreamWriter UTF buffer ftoa pcre
|
||||
)
|
||||
ELSE()
|
||||
MESSAGE(STATUS "OpenCOLLADA header files not found, continuing without COLLADA support")
|
||||
ENDIF()
|
||||
|
||||
INCLUDE(CheckIncludeFileCXX)
|
||||
|
||||
MACRO(CHECK_ADD_OCE_OCC_DEF INCLUDE)
|
||||
STRING(REPLACE . _ STR ${INCLUDE})
|
||||
STRING(TOUPPER ${STR} STR)
|
||||
CHECK_INCLUDE_FILE_CXX("${INCLUDE}" FOUND_${STR})
|
||||
IF(FOUND_${STR})
|
||||
ADD_DEFINITIONS(-DOCE_HAVE_${STR})
|
||||
ADD_DEFINITIONS(-DHAVE_${STR})
|
||||
ENDIF(FOUND_${STR})
|
||||
ENDMACRO(CHECK_ADD_OCE_OCC_DEF)
|
||||
|
||||
CHECK_ADD_OCE_OCC_DEF(limits)
|
||||
CHECK_ADD_OCE_OCC_DEF(climits)
|
||||
CHECK_ADD_OCE_OCC_DEF(limits.h)
|
||||
CHECK_ADD_OCE_OCC_DEF(fstream)
|
||||
CHECK_ADD_OCE_OCC_DEF(fstream.h)
|
||||
CHECK_ADD_OCE_OCC_DEF(iomanip)
|
||||
CHECK_ADD_OCE_OCC_DEF(iomanip.h)
|
||||
CHECK_ADD_OCE_OCC_DEF(iostream)
|
||||
CHECK_ADD_OCE_OCC_DEF(iostream.h)
|
||||
|
||||
IF(NOT CMAKE_BUILD_TYPE)
|
||||
SET(CMAKE_BUILD_TYPE "Release")
|
||||
ENDIF(NOT CMAKE_BUILD_TYPE)
|
||||
SET(CMAKE_BUILD_TYPE "Release")
|
||||
ENDIF()
|
||||
|
||||
# NOTE: RelWithDebInfo and Release use O2 (= /Ox /Gl /Gy/ = Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy) by default,
|
||||
# with the exception with RelWithDebInfo has /Ob1 instead. /Ob2 has been observed to improve the performance
|
||||
# of IfcConvert significantly.
|
||||
# TODO Setting of /GL and /LTCG don't seem to apply for static libraries (IfcGeom, IfcParse)
|
||||
if(ENABLE_BUILD_OPTIMIZATIONS)
|
||||
if(MSVC)
|
||||
# C++
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /GL")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
|
||||
# Linker
|
||||
# /OPT:REF enables also /OPT:ICF and disables INCREMENTAL
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
|
||||
# /OPT:NOICF is recommended when /DEBUG is used (http://msdn.microsoft.com/en-us/library/xe4t6fc1.aspx)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
|
||||
else()
|
||||
#TODO GCC (& Clang?) optimizations
|
||||
message(STATUS "ENABLE_BUILD_OPTIMIZATIONS not implemented for GCC/non-MSVC compilers.)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
IF(MSVC)
|
||||
ADD_DEFINITIONS(-D_UNICODE)
|
||||
ElSE(MSVC)
|
||||
ADD_DEFINITIONS(-fPIC -Wno-non-virtual-dtor)
|
||||
ENDIF(MSVC)
|
||||
|
||||
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} /usr/inc /usr/local/inc /usr/local/include/oce ${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS})
|
||||
|
||||
ADD_LIBRARY(IfcParse STATIC
|
||||
../src/ifcparse/Ifc2x3.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
|
||||
)
|
||||
|
||||
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(icu)
|
||||
TARGET_LINK_LIBRARIES(IfcParse icuuc)
|
||||
IF(USE_VLD)
|
||||
ADD_DEFINITIONS(-DUSE_VLD)
|
||||
ENDIF()
|
||||
# Enforce Unicode for CRT and Win32 API calls
|
||||
ADD_DEFINITIONS(-D_UNICODE -DUNICODE)
|
||||
# Disable warnings about unsafe C functions; we could use the safe C99 & C11 versions if we have no need for supporting old compilers.
|
||||
ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS)
|
||||
ADD_DEFINITIONS(-bigobj) # required for building the big ifcXXX.objs, https://msdn.microsoft.com/en-us/library/ms173499.aspx
|
||||
# Bump up the warning level from the default 3 to 4.
|
||||
ADD_DEFINITIONS(-W4)
|
||||
IF(MSVC_VERSION GREATER 1800) # > 2013
|
||||
# Disable overeager and false positives causing C4458 ("declaration of 'indentifier' hides class member"), at least for now.
|
||||
ADD_DEFINITIONS(-wd4458)
|
||||
ENDIF()
|
||||
# Link against the static VC runtime
|
||||
FOREACH(flag CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL
|
||||
CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
|
||||
IF(${flag} MATCHES "/MD")
|
||||
STRING(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}")
|
||||
ENDIF()
|
||||
IF(${flag} MATCHES "/MDd")
|
||||
STRING(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}")
|
||||
ENDIF()
|
||||
ENDFOREACH()
|
||||
ElSE()
|
||||
ADD_DEFINITIONS(-fPIC -Wno-non-virtual-dtor)
|
||||
ENDIF()
|
||||
|
||||
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS}
|
||||
${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${HDF5_INCLUDE_DIR}
|
||||
)
|
||||
if(NOT WIN32)
|
||||
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} /usr/inc /usr/local/inc /usr/local/include/oce)
|
||||
endif()
|
||||
|
||||
function(files_for_ifc_version IFC_VERSION RESULT_NAME)
|
||||
set(IFC_PARSE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcparse)
|
||||
set(${RESULT_NAME}
|
||||
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.h
|
||||
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}enum.h
|
||||
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}-latebound.h
|
||||
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.cpp
|
||||
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}-latebound.cpp
|
||||
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}-schema.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endfunction()
|
||||
|
||||
if(COMPILE_SCHEMA)
|
||||
find_package(PythonInterp)
|
||||
|
||||
IF(NOT PYTHONINTERP_FOUND)
|
||||
MESSAGE(FATAL_ERROR "A Python interpreter is necessary when COMPILE_SCHEMA is enabled. Disable COMPILE_SCHEMA or fix Python paths to proceed.")
|
||||
ENDIF()
|
||||
|
||||
set(IFC_RELEASE_NOT_USED "2x3" "4")
|
||||
|
||||
# Install pyparsing if necessary
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST)
|
||||
if ("${PYTHON_PACKAGE_LIST}" STREQUAL "")
|
||||
execute_process(COMMAND pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST)
|
||||
if ("${PYTHON_PACKAGE_LIST}" STREQUAL "")
|
||||
message(WARNING "Failed to find pip. Pip is required to automatically install pyparsing")
|
||||
endif()
|
||||
endif()
|
||||
string(FIND "${PYTHON_PACKAGE_LIST}" pyparsing PYPARSING_FOUND)
|
||||
if ("${PYPARSING_FOUND}" STREQUAL "-1")
|
||||
message(STATUS "Installing pyparsing")
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip "install" --user pyparsing RESULT_VARIABLE SUCCESS)
|
||||
if (NOT "${SUCCESS}" STREQUAL "0")
|
||||
execute_process(COMMAND pip "install" --user pyparsing RESULT_VARIABLE SUCCESS)
|
||||
if (NOT "${SUCCESS}" STREQUAL "0")
|
||||
message(WARNING "Failed to automatically install pyparsing. Please install manually")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Python interpreter with pyparsing found")
|
||||
endif()
|
||||
|
||||
# Bootstrap the parser
|
||||
message(STATUS "Compiling schema, this will take a while...")
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} bootstrap.py express.bnf
|
||||
WORKING_DIRECTORY ../src/ifcexpressparser
|
||||
OUTPUT_FILE express_parser.py
|
||||
RESULT_VARIABLE SUCCESS)
|
||||
|
||||
if (NOT "${SUCCESS}" STREQUAL "0")
|
||||
MESSAGE(FATAL_ERROR "Failed to bootstrap parser. Make sure pyparsing is installed")
|
||||
endif()
|
||||
|
||||
# Generate code
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} ../ifcexpressparser/express_parser.py ../../${COMPILE_SCHEMA}
|
||||
WORKING_DIRECTORY ../src/ifcparse
|
||||
OUTPUT_VARIABLE COMPILED_SCHEMA_NAME)
|
||||
|
||||
# Prevent the schema that had just been compiled from being excluded
|
||||
if("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC2X3")
|
||||
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "2x3")
|
||||
add_definitions(-DUSE_IFC2x3)
|
||||
elseif("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC4")
|
||||
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "4")
|
||||
add_definitions(-DUSE_IFC4)
|
||||
endif()
|
||||
else()
|
||||
if(USE_IFC4)
|
||||
add_definitions(-DUSE_IFC4)
|
||||
set(IFC_RELEASE_NOT_USED "2x3")
|
||||
else()
|
||||
add_definitions(-DUSE_IFC2x3) # TODO Make all caps? i.e. USE_IFC2X3
|
||||
set(IFC_RELEASE_NOT_USED "4")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# IfcParse
|
||||
file(GLOB IFCPARSE_H_FILES ../src/ifcparse/*.h)
|
||||
file(GLOB IFCPARSE_CPP_FILES ../src/ifcparse/*.cpp)
|
||||
|
||||
foreach(IFC_RELEASE ${IFC_RELEASE_NOT_USED})
|
||||
files_for_ifc_version(${IFC_RELEASE} SOURCE_FILES_NOT_USED)
|
||||
foreach(SOURCE_FILE ${SOURCE_FILES_NOT_USED})
|
||||
list(REMOVE_ITEM IFCPARSE_CPP_FILES ${SOURCE_FILE})
|
||||
list(REMOVE_ITEM IFCPARSE_H_FILES ${SOURCE_FILE})
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
set(IFCPARSE_FILES ${IFCPARSE_CPP_FILES} ${IFCPARSE_H_FILES})
|
||||
|
||||
ADD_LIBRARY(IfcParse STATIC ${IFCPARSE_FILES})
|
||||
|
||||
IF(UNICODE_SUPPORT)
|
||||
TARGET_LINK_LIBRARIES(IfcParse ${ICU_LIBRARIES})
|
||||
ENDIF()
|
||||
|
||||
if(HDF5_SUPPORT)
|
||||
TARGET_LINK_LIBRARIES(IfcParse ${HDF5_LIBRARIES})
|
||||
endif()
|
||||
|
||||
# IfcGeom
|
||||
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/*.h)
|
||||
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp)
|
||||
|
||||
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES})
|
||||
ADD_LIBRARY(IfcGeom STATIC ${IFCGEOM_FILES})
|
||||
|
||||
TARGET_LINK_LIBRARIES(IfcGeom IfcParse)
|
||||
|
||||
LINK_DIRECTORIES (${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} ${OPENCOLLADA_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS})
|
||||
|
||||
ADD_EXECUTABLE(IfcConvert
|
||||
../src/ifcconvert/ColladaSerializer.cpp
|
||||
../src/ifcconvert/IfcConvert.cpp
|
||||
../src/ifcconvert/OpenCascadeBasedSerializer.cpp
|
||||
../src/ifcconvert/WavefrontObjSerializer.cpp
|
||||
LINK_DIRECTORIES(${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} ${OPENCOLLADA_LIBRARY_DIR}
|
||||
${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS} ${HDF5_LIBRARY_DIR}
|
||||
)
|
||||
if(NOT WIN32)
|
||||
LINK_DIRECTORIES(${LINK_DIRECTORIES} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64)
|
||||
endif()
|
||||
|
||||
TARGET_LINK_LIBRARIES (IfcConvert IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES})
|
||||
file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp)
|
||||
file(GLOB IFCCONVERT_H_FILES ../src/ifcconvert/*.h)
|
||||
set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES})
|
||||
ADD_EXECUTABLE(IfcConvert ${IFCCONVERT_FILES})
|
||||
|
||||
ADD_EXECUTABLE(IfcGeomServer
|
||||
../src/ifcgeomserver/IfcGeomServer.cpp
|
||||
)
|
||||
# Make sure cross-referenced symbols between static OCC libraries get
|
||||
# resolved. Also add thread and rt libraries.
|
||||
get_filename_component(libTKernelExt ${libTKernel} EXT)
|
||||
if("${libTKernelExt}" STREQUAL ".a")
|
||||
find_package(Threads)
|
||||
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} rt dl)
|
||||
endif()
|
||||
|
||||
TARGET_LINK_LIBRARIES (IfcGeomServer IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset)
|
||||
TARGET_LINK_LIBRARIES(IfcConvert IfcParse IfcGeom ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${ICU_LIBRARIES})
|
||||
|
||||
# Build python wrapper using separate CMakeLists.txt
|
||||
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
|
||||
# IfcGeomServer
|
||||
file(GLOB CPP_FILES ../src/ifcgeomserver/*.cpp)
|
||||
file(GLOB H_FILES ../src/ifcgeomserver/*.h)
|
||||
set(SOURCE_FILES ${CPP_FILES} ${H_FILES})
|
||||
ADD_EXECUTABLE(IfcGeomServer ${SOURCE_FILES})
|
||||
|
||||
# Build IfcParseExamples using separate CMakeLists.txt
|
||||
ADD_SUBDIRECTORY(../src/examples examples)
|
||||
TARGET_LINK_LIBRARIES(IfcGeomServer IfcParse IfcGeom ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBRARIES})
|
||||
|
||||
# ADD_SUBDIRECTORY(../src/qtviewer qtviewer)
|
||||
IF(BUILD_IFCPYTHON)
|
||||
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
|
||||
ENDIF()
|
||||
|
||||
# CMake installation targets
|
||||
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
|
||||
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()
|
||||
|
||||
../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)
|
||||
# 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)
|
||||
INSTALL(TARGETS IfcParse IfcGeom DESTINATION lib)
|
||||
|
||||
Executable
+372
@@ -0,0 +1,372 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
###############################################################################
|
||||
# #
|
||||
# This script builds IfcOpenShell and its dependencies #
|
||||
# #
|
||||
# Prerequisites for this script to function correctly: #
|
||||
# * git * bzip2 * tar * c(++) compilers * yacc * autoconf #
|
||||
# on debian 7.8 these can be obtained with: #
|
||||
# $ apt-get install git bzip2 bizon autoconf gcc g++ #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
set -e
|
||||
|
||||
PROJECT_NAME=IfcOpenShell
|
||||
OCE_VERSION=0.16
|
||||
PYTHON_VERSIONS=(2.7.9 3.3.6 3.4.2)
|
||||
BOOST_VERSION=1.55.0
|
||||
PCRE_VERSION=8.38
|
||||
LIBXML_VERSION=2.9.3
|
||||
CMAKE_VERSION=3.4.1
|
||||
ICU_VERSION=56.1
|
||||
|
||||
# Helper function for coloured printing
|
||||
|
||||
BLACK_ON_WHITE="\033[0;30;107m"
|
||||
RED="\033[31m"
|
||||
GREEN="\033[32m"
|
||||
YELLOW="\033[33m"
|
||||
MAGENTA="\033[35m"
|
||||
function cecho {
|
||||
printf "$1$2\033[0m\n"
|
||||
}
|
||||
|
||||
# Set defaults for missing empty environment variables
|
||||
|
||||
if [ -z "$IFCOS_NUM_BUILD_PROCS" ]; then
|
||||
IFCOS_NUM_BUILD_PROCS=$(expr $(sysctl -n hw.ncpu 2> /dev/null || cat /proc/cpuinfo | grep processor | wc -l) + 1)
|
||||
fi
|
||||
|
||||
if [ -z "$TARGET_ARCH" ]; then
|
||||
TARGET_ARCH="$(uname -m)"
|
||||
fi
|
||||
|
||||
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||
CMAKE_DIR="$SCRIPT_DIR/../../cmake/"
|
||||
|
||||
if [ -z "$DEPS_DIR" ]; then
|
||||
DEPS_DIR="$SCRIPT_DIR/../../build/$(uname)/"
|
||||
[ -d $DEPS_DIR ] || mkdir -p $DEPS_DIR
|
||||
DEPS_DIR=`readlink -f $DEPS_DIR`
|
||||
fi
|
||||
|
||||
if [ -z "$BUILD_CFG" ]; then
|
||||
BUILD_CFG="RelWithDebInfo"
|
||||
fi
|
||||
|
||||
if [ -z "$BUILD_TYPE" ]; then
|
||||
BUILD_TYPE=Build
|
||||
fi
|
||||
|
||||
# Print build configuration information
|
||||
|
||||
cecho $BLACK_ON_WHITE "This script fetches and builds $PROJECT_NAME and its dependencies"
|
||||
echo ""
|
||||
cecho $GREEN "Script configuration:"
|
||||
|
||||
cecho $MAGENTA "* Target Architecture = $TARGET_ARCH"
|
||||
echo " - Whether 32-bit (i686) or 64-bit (x86_64) will be built."
|
||||
cecho $MAGENTA "* Dependency Directory = $DEPS_DIR"
|
||||
echo " - The directory where $PROJECT_NAME dependencies are installed."
|
||||
cecho $MAGENTA "* Build Config Type = $BUILD_CFG"
|
||||
echo " - The used build configuration type for the dependencies."
|
||||
echo " Defaults to RelWithDebInfo if not specified."
|
||||
|
||||
if [ "$BUILD_CFG" = "MinSizeRel" ]; then
|
||||
cecho $RED " WARNING: MinSizeRel build can suffer from a significant performance loss."
|
||||
fi
|
||||
|
||||
cecho $MAGENTA "* IFCOS_NUM_BUILD_PROCS = $IFCOS_NUM_BUILD_PROCS"
|
||||
echo " - How many compiler processes may be run in parallel."
|
||||
|
||||
echo ""
|
||||
|
||||
# Check that required tools are in PATH
|
||||
|
||||
for cmd in git bunzip2 tar cc c++ autoconf yacc
|
||||
do
|
||||
which $cmd > /dev/null || { cecho $RED "Required tool '$cmd' not installed or not added to PATH" ; exit 1 ; }
|
||||
done
|
||||
|
||||
which curl > /dev/null && DOWNLOAD="curl -sLO"
|
||||
which wget > /dev/null && DOWNLOAD="wget -q --no-check-certificate"
|
||||
|
||||
if [ -z "$DOWNLOAD" ]; then
|
||||
cecho $RED "No download application found, tried: curl, wget"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create log directory and file
|
||||
|
||||
mkdir -p $DEPS_DIR/logs
|
||||
LOG_FILE=$DEPS_DIR/logs/`date +"%Y%m%d"`.log
|
||||
|
||||
BOOST_VERSION_UNDERSCORE=${BOOST_VERSION//./_}
|
||||
ICU_VERSION_UNDERSCORE=${ICU_VERSION//./_}
|
||||
CMAKE_VERSION_2=${CMAKE_VERSION:0:3}
|
||||
|
||||
OCE_LOCATION=https://github.com/tpaviot/oce/archive/OCE-$OCE_VERSION.tar.gz
|
||||
BOOST_LOCATION=http://downloads.sourceforge.net/project/boost/boost/$BOOST_VERSION/boost_$BOOST_VERSION_UNDERSCORE.tar.bz2
|
||||
OPENCOLLADA_LOCATION=https://github.com/KhronosGroup/OpenCOLLADA.git
|
||||
OPENCOLLADA_COMMIT=f99d59e73e565a41715eaebc00c7664e1ee5e628
|
||||
|
||||
# Helper functions
|
||||
|
||||
function download {
|
||||
[ -f $2 ] || $DOWNLOAD $1$2
|
||||
}
|
||||
|
||||
function run_autoconf {
|
||||
if [ ! -f configure ]; then
|
||||
pushd . >>$LOG_FILE 2>&1
|
||||
cd ..
|
||||
./autogen.sh >>$LOG_FILE 2>&1
|
||||
popd >>$LOG_FILE 2>&1
|
||||
fi
|
||||
../configure $2 --prefix=$DEPS_DIR/install/$1 >>$LOG_FILE 2>&1
|
||||
}
|
||||
|
||||
function run_cmake {
|
||||
if [ -z "$3" ]; then
|
||||
P=..
|
||||
else
|
||||
P=$3
|
||||
fi
|
||||
$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake $P $2 -DCMAKE_BUILD_TYPE=$BUILD_TYPE >>$LOG_FILE 2>&1
|
||||
}
|
||||
|
||||
function run_icu {
|
||||
PLATFORM=`uname -s`
|
||||
if [ $PLATFORM == "Darwin" ]; then
|
||||
PLATFORM=MacOSX
|
||||
fi
|
||||
../source/runConfigureICU $PLATFORM $2 --prefix=$DEPS_DIR/install/$1 >>$LOG_FILE 2>&1
|
||||
}
|
||||
|
||||
function git_clone {
|
||||
[ -d $2 ] || git clone $1 >>$LOG_FILE 2>&1
|
||||
if [ ! -z "$3" ]; then
|
||||
cd $2
|
||||
git checkout $3
|
||||
cd ..
|
||||
fi
|
||||
}
|
||||
|
||||
function build_dependency {
|
||||
if [ -e $DEPS_DIR/install/$1 ]; then
|
||||
echo "Found existing $1"
|
||||
return
|
||||
fi
|
||||
mkdir -p $DEPS_DIR/build/
|
||||
cd $DEPS_DIR/build/
|
||||
printf "\rFetching $1... "
|
||||
$6 $4 $5 $7
|
||||
if [ -d $5 ]; then
|
||||
DEP_NAME=$5
|
||||
else
|
||||
DEP_NAME=`tar --exclude="*/*" -tf $5`
|
||||
[ -z $DEP_NAME ] && DEP_NAME=`tar -tf $5 2> /dev/null | head -n 1 | cut -f1 -d /`
|
||||
[ -d $DEP_NAME ] || tar -xf $5
|
||||
fi
|
||||
cd $DEP_NAME
|
||||
if [ "$2" != "bjam" ]; then
|
||||
[ -d build ] && rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
printf "\rConfiguring $1..."
|
||||
run_$2 $1 "$3"
|
||||
printf "\rBuilding $1... "
|
||||
make -j$IFCOS_NUM_BUILD_PROCS >>$LOG_FILE 2>&1
|
||||
printf "\rInstalling $1... "
|
||||
make install >>$LOG_FILE 2>&1
|
||||
printf "\rInstalled $1 \n"
|
||||
else
|
||||
printf "\rConfiguring $1..."
|
||||
./bootstrap.sh >>$LOG_FILE 2>&1
|
||||
printf "\rBuilding $1... "
|
||||
./b2 $3 >>$LOG_FILE 2>&1
|
||||
printf "\rInstalling $1... "
|
||||
cp -R boost $DEPS_DIR/install/boost-$BOOST_VERSION/ >>$LOG_FILE 2>&1
|
||||
printf "\rInstalled $1 \n"
|
||||
fi
|
||||
}
|
||||
|
||||
cecho $GREEN "Collecting dependencies:"
|
||||
|
||||
# Set compiler flags for 32bit builds on 64bit system
|
||||
|
||||
if [ "$TARGET_ARCH" == "i686" ] && [ "$(uname -m)" == "x86_64" ]; then
|
||||
ADDITIONAL_ARGS="-m32 -arch i386"
|
||||
fi
|
||||
|
||||
if [ "$(uname)" == "Darwin" ]; then
|
||||
ADDITIONAL_ARGS="-macosx_version_min 10.6 $ADDITIONAL_ARGS"
|
||||
fi
|
||||
|
||||
# If the linker supports GC sections, set it up to reduce binary file size
|
||||
# -fPIC is required for the shared libraries to work
|
||||
|
||||
if man ld 2> /dev/null | grep gc-sections &> /dev/null; then
|
||||
export CXXFLAGS="$CXXFLAGS -fPIC -fdata-sections -ffunction-sections -fvisibility=hidden -fvisibility-inlines-hidden $ADDITIONAL_ARGS"
|
||||
export CFLAGS="$CFLAGS -fPIC -fdata-sections -ffunction-sections -fvisibility=hidden $ADDITIONAL_ARGS"
|
||||
export LDFLAGS="$LDFLAGS -Wl,--gc-sections $ADDITIONAL_ARGS"
|
||||
export CXXFLAGS_MINIMAL="$CXXFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
|
||||
export CFLAGS_MINIMAL="$CFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
|
||||
else
|
||||
export CXXFLAGS="$CXXFLAGS -fPIC -fvisibility=hidden -fvisibility-inlines-hidden $ADDITIONAL_ARGS"
|
||||
export CFLAGS="$CFLAGS -fPIC -fvisibility=hidden -fvisibility-inlines-hidden $ADDITIONAL_ARGS"
|
||||
export LDFLAGS="$LDFLAGS -s -death_code $ADDITIONAL_ARGS"
|
||||
export CXXFLAGS_MINIMAL="$CXXFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
|
||||
export CFLAGS_MINIMAL="$CFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
|
||||
fi
|
||||
|
||||
# Some dependencies need a more recent CMake version than most distros provide
|
||||
build_dependency cmake-$CMAKE_VERSION autoconf "" https://cmake.org/files/v$CMAKE_VERSION_2/ cmake-$CMAKE_VERSION.tar.gz download
|
||||
|
||||
# Extract compiler flags from CMake to harmonize settings with other autoconf dependencies
|
||||
CMAKE_FLAG_EXTRACT_DIR=ifcopenshell_cmake_test_`cat /dev/urandom | env LC_CTYPE=C tr -dc 'a-zA-Z0-9' | head -c 32`
|
||||
[ -e $CMAKE_FLAG_EXTRACT_DIR ] && rm -rf $CMAKE_FLAG_EXTRACT_DIR
|
||||
mkdir $CMAKE_FLAG_EXTRACT_DIR
|
||||
cd $CMAKE_FLAG_EXTRACT_DIR
|
||||
BUILD_CFG_UPPER=${BUILD_CFG^^}
|
||||
for FL in C CXX LD; do
|
||||
echo "
|
||||
message(\"\${CMAKE_${FL}_FLAGS_${BUILD_CFG_UPPER}}\")
|
||||
" > CMakeLists.txt
|
||||
declare ${FL}FLAGS="`$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake . 2>&1 >/dev/null`"
|
||||
declare ${FL}FLAGS_MINIMAL="`$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake . 2>&1 >/dev/null`"
|
||||
done
|
||||
cd ..
|
||||
rm -rf $CMAKE_FLAG_EXTRACT_DIR
|
||||
|
||||
build_dependency pcre-$PCRE_VERSION autoconf "--disable-shared" ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ pcre-$PCRE_VERSION.tar.bz2 download
|
||||
|
||||
# An issue exists with swig-1.3 and python >= 3.2
|
||||
# Therefore, build a recent copy from source
|
||||
build_dependency swig autoconf "--with-pcre-prefix=$DEPS_DIR/install/pcre-$PCRE_VERSION" https://github.com/swig/swig.git swig git_clone rel-3.0.8
|
||||
|
||||
build_dependency oce-$OCE_VERSION cmake "-DOCE_DISABLE_TKSERVICE_FONT=ON -DOCE_TESTING=OFF -DOCE_BUILD_SHARED_LIB=OFF -DOCE_DISABLE_X11=ON -DOCE_VISUALISATION=OFF -DOCE_OCAF=OFF -DOCE_INSTALL_PREFIX=$DEPS_DIR/install/oce-$OCE_VERSION/" https://github.com/tpaviot/oce/archive/ OCE-$OCE_VERSION.tar.gz download
|
||||
build_dependency libxml2-$LIBXML_VERSION autoconf "--without-python --disable-shared" ftp://xmlsoft.org/libxml2/ libxml2-$LIBXML_VERSION.tar.gz download
|
||||
build_dependency OpenCOLLADA cmake "
|
||||
-DLIBXML2_INCLUDE_DIR=$DEPS_DIR/install/libxml2-$LIBXML_VERSION/include/libxml2
|
||||
-DLIBXML2_LIBRARIES=$DEPS_DIR/install/libxml2-$LIBXML_VERSION/lib/libxml2.a
|
||||
-DPCRE_INCLUDE_DIR=$DEPS_DIR/install/pcre-$PCRE_VERSION/include
|
||||
-DPCRE_PCREPOSIX_LIBRARY=$DEPS_DIR/install/pcre-$PCRE_VERSION/lib/libpcreposix.a
|
||||
-DPCRE_PCRE_LIBRARY=$DEPS_DIR/install/pcre-$PCRE_VERSION/lib/libpcre.a
|
||||
-DCMAKE_INSTALL_PREFIX=$DEPS_DIR/install/OpenCOLLADA/" https://github.com/KhronosGroup/OpenCOLLADA.git OpenCOLLADA git_clone
|
||||
|
||||
# Python should not be built with -fvisibility=hidden, from experience that introduces segfaults
|
||||
|
||||
OLD_CXX_FLAGS=$CXXFLAGS
|
||||
OLD_C_FLAGS=$CFLAGS
|
||||
OLD_LD_FLAGS=$LDFLAGS
|
||||
export CXXFLAGS=$CXXFLAGS_MINIMAL
|
||||
export CFLAGS=$CFLAGS_MINIMAL
|
||||
export LDFLAGS=$LDFLAGS_MINIMAL
|
||||
|
||||
for PYTHON_VERSION in "${PYTHON_VERSIONS[@]}"; do
|
||||
build_dependency python-$PYTHON_VERSION autoconf "" http://www.python.org/ftp/python/$PYTHON_VERSION/ Python-$PYTHON_VERSION.tgz download
|
||||
done
|
||||
|
||||
export CXXFLAGS=$OLD_CXX_FLAGS
|
||||
export CFLAGS=$OLD_C_FLAGS
|
||||
export LDFLAGS=$OLD_LD_FLAGS
|
||||
|
||||
if [ "$(uname)" == "Darwin" ] && [ "$1" == "32" ]; then
|
||||
BOOST_ADDRESS_MODEL="toolset=darwin architecture=x86 target-os=darwin address-model=32"
|
||||
fi
|
||||
build_dependency boost-$BOOST_VERSION bjam "--stagedir=$DEPS_DIR/install/boost-$BOOST_VERSION --with-program_options link=static $BOOST_ADDRESS_MODEL stage" http://downloads.sourceforge.net/project/boost/boost/$BOOST_VERSION/ boost_$BOOST_VERSION_UNDERSCORE.tar.bz2 download
|
||||
|
||||
build_dependency icu-$ICU_VERSION icu "--enable-static --disable-shared" http://download.icu-project.org/files/icu4c/$ICU_VERSION/ icu4c-${ICU_VERSION_UNDERSCORE}-src.tgz download
|
||||
|
||||
cecho $GREEN "Building IfcOpenShell:"
|
||||
|
||||
IFCOS_DIR=$DEPS_DIR/build/ifcopenshell
|
||||
[ -d $IFCOS_DIR ] && rm -rf $IFCOS_DIR
|
||||
mkdir -p $IFCOS_DIR
|
||||
cd $IFCOS_DIR
|
||||
|
||||
mkdir -p executables
|
||||
cd executables
|
||||
|
||||
printf "\rConfiguring executables..."
|
||||
|
||||
run_cmake "" "
|
||||
-DBOOST_ROOT=$DEPS_DIR/install/boost-$BOOST_VERSION
|
||||
-DOCC_INCLUDE_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/include/oce
|
||||
-DOCC_LIBRARY_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/lib
|
||||
-DOPENCOLLADA_INCLUDE_DIR=$DEPS_DIR/install/OpenCOLLADA/include/opencollada
|
||||
-DOPENCOLLADA_LIBRARY_DIR=$DEPS_DIR/install/OpenCOLLADA/lib/opencollada
|
||||
-DICU_INCLUDE_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/include
|
||||
-DICU_LIBRARY_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/lib
|
||||
-DPCRE_LIBRARY_DIR=$DEPS_DIR/install/pcre-$PCRE_VERSION/lib
|
||||
-DBUILD_IFCPYTHON=OFF
|
||||
" $CMAKE_DIR
|
||||
|
||||
printf "\rBuilding executables... "
|
||||
|
||||
make -j$IFCOS_NUM_BUILD_PROCS >>$LOG_FILE 2>&1
|
||||
|
||||
strip -s IfcConvert IfcGeomServer
|
||||
|
||||
cd ..
|
||||
|
||||
for PYTHON_VERSION in "${PYTHON_VERSIONS[@]}"; do
|
||||
|
||||
printf "\rConfiguring python $PYTHON_VERSION wrapper..."
|
||||
|
||||
mkdir -p python-$PYTHON_VERSION
|
||||
cd python-$PYTHON_VERSION
|
||||
|
||||
PYTHON_LIBRARY=`ls $DEPS_DIR/install/python-$PYTHON_VERSION/lib/libpython*.a`
|
||||
PYTHON_INCLUDE=`ls -d $DEPS_DIR/install/python-$PYTHON_VERSION/include/python*`
|
||||
PYTHON_EXECUTABLE=$DEPS_DIR/install/python-$PYTHON_VERSION/bin/python
|
||||
export PYTHON_LIBRARY_BASENAME=`basename $PYTHON_LIBRARY`
|
||||
|
||||
run_cmake "" "
|
||||
-DBOOST_ROOT=$DEPS_DIR/install/boost-$BOOST_VERSION
|
||||
-DOCC_INCLUDE_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/include/oce
|
||||
-DOCC_LIBRARY_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/lib
|
||||
-DOPENCOLLADA_INCLUDE_DIR=$DEPS_DIR/install/OpenCOLLADA/include/opencollada
|
||||
-DOPENCOLLADA_LIBRARY_DIR=$DEPS_DIR/install/OpenCOLLADA/lib/opencollada
|
||||
-DICU_INCLUDE_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/include
|
||||
-DICU_LIBRARY_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/lib
|
||||
-DPYTHON_LIBRARY=$PYTHON_LIBRARY
|
||||
-DPYTHON_EXECUTABLE=$PYTHON_EXECUTABLE
|
||||
-DPYTHON_INCLUDE_DIR=$PYTHON_INCLUDE
|
||||
-DSWIG_EXECUTABLE=$DEPS_DIR/install/swig/bin/swig
|
||||
" $CMAKE_DIR
|
||||
|
||||
# This still needs to be tested
|
||||
# test "$(uname)" == "Darwin" && sed -i~ "s/-o/-flat_namespace -undefined suppress -o/" ifcwrap/CMakeFiles/_ifcopenshell_wrapper.dir/link.txt
|
||||
|
||||
printf "\rBuilding python $PYTHON_VERSION wrapper... "
|
||||
|
||||
make -j$IFCOS_NUM_BUILD_PROCS _ifcopenshell_wrapper >>$LOG_FILE 2>&1
|
||||
|
||||
strip -s \
|
||||
-K PyInit__ifcopenshell_wrapper \
|
||||
ifcwrap/_ifcopenshell_wrapper.so
|
||||
|
||||
done
|
||||
|
||||
printf "\rBuilt IfcOpenShell... \n\n"
|
||||
@@ -1,5 +1,24 @@
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
ADD_EXECUTABLE(IfcParseExamples IfcParseExamples.cpp)
|
||||
TARGET_LINK_LIBRARIES (IfcParseExamples IfcParse)
|
||||
TARGET_LINK_LIBRARIES(IfcParseExamples IfcParse)
|
||||
|
||||
ADD_EXECUTABLE(IfcOpenHouse IfcOpenHouse.cpp)
|
||||
TARGET_LINK_LIBRARIES (IfcOpenHouse IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKOffset)
|
||||
TARGET_LINK_LIBRARIES(IfcOpenHouse IfcParse IfcGeom ${OPENCASCADE_LIBRARIES})
|
||||
|
||||
+160
-100
@@ -41,21 +41,25 @@
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
#endif
|
||||
|
||||
// Some convenience typedefs and definitions.
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
typedef std::pair<double, double> XY;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
// The creation of Nurbs-surface for the IfcSite mesh, to be implemented lateron
|
||||
void createGroundShape(TopoDS_Shape& shape);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int main() {
|
||||
|
||||
// The IfcHierarchyHelper is a subclass of the regular IfcFile that provides several
|
||||
// convenience functions for working with geometry in IFC files.
|
||||
IfcHierarchyHelper file;
|
||||
file.filename("IfcOpenHouse.ifc");
|
||||
file.header().file_name().name("IfcOpenHouse.ifc");
|
||||
|
||||
// Start by adding a wall to the file, initially leaving most attributes blank.
|
||||
IfcSchema::IfcWallStandardCase* south_wall = new IfcSchema::IfcWallStandardCase(
|
||||
@@ -83,17 +87,23 @@ int main(int argc, char** argv) {
|
||||
// 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.
|
||||
IfcSchema::IfcProductDefinitionShape* south_wall_shape = file.addBox(10000, 360, 3000);
|
||||
// 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 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());
|
||||
south_wall->setObjectPlacement(file.addLocalPlacement(storey_placement));
|
||||
|
||||
// A pale white colour is assigned to the wall.
|
||||
IfcSchema::IfcPresentationStyleAssignment* wall_colour = file.setSurfaceColour(
|
||||
south_wall->Representation(), 0.75, 0.73, 0.68);
|
||||
south_wall_shape, 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>(),
|
||||
@@ -104,90 +114,125 @@ int main(int argc, char** argv) {
|
||||
// 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, 0, 0, 0, file.getSingle<IfcSchema::IfcRepresentationContext>()));
|
||||
footing->setObjectPlacement(file.addLocalPlacement(0, 2500, -2000));
|
||||
footing->setRepresentation(file.addBox(10100, 5460, 2000));
|
||||
footing->setObjectPlacement(file.addLocalPlacement(storey_placement, 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(-2500, 0, 400),
|
||||
file.addBox(6000, 3630, 1600, 0, 0, 0, file.getSingle<IfcSchema::IfcRepresentationContext>()), null
|
||||
null, null, null, file.addLocalPlacement(south_wall->ObjectPlacement(), -2500, 0, 400),
|
||||
file.addBox(6000, 3630, 1600), 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(3000, 0, 400),
|
||||
file.addBox(1860, 3000, 1600, 0, 0, 0, file.getSingle<IfcSchema::IfcRepresentationContext>()), null
|
||||
null, null, null, file.addLocalPlacement(storey_placement, 3000, 0, 400),
|
||||
file.addBox(1860, 3000, 1600), 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);
|
||||
|
||||
// The roof geometry is slanted 45 degrees by specifying a direction for the box extrusion
|
||||
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);
|
||||
// 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)));
|
||||
|
||||
// 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::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);
|
||||
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);
|
||||
|
||||
// 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);
|
||||
file.addBuildingProduct(south_roof_part);
|
||||
file.addBuildingProduct(north_roof_part);
|
||||
file.addBuildingProduct(roof);
|
||||
|
||||
file.setSurfaceColour(roof_rep, 0.24, 0.08, 0.04);
|
||||
|
||||
// Copy the south wall to the north
|
||||
file.addBuildingProduct(new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("North wall"),
|
||||
null, null, file.addLocalPlacement(0, 5000, 0), south_wall->Representation(), null
|
||||
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
|
||||
#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(4820, 2500, 0, 0, 0, 1, 0, 1, 0), file.addBox(5000, 360, 6000), null
|
||||
S("East wall"), null, null, file.addLocalPlacement(storey_placement, 4820, 2500, 0, 0, 0, 1, 0, 1, 0), clipped_wall_body_reps[0], null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
|
||||
#endif
|
||||
);
|
||||
file.addBuildingProduct(east_wall);
|
||||
|
||||
// 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(-4820, 2500, 0, 0, 0, 1, 0, -1, 0), east_wall->Representation(), null
|
||||
S("West wall"), null, null, file.addLocalPlacement(storey_placement, -4820, 2500, 0, 0, 0, 1, 0, -1, 0), clipped_wall_body_reps[1], null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
|
||||
#endif
|
||||
@@ -199,27 +244,31 @@ int main(int argc, char** argv) {
|
||||
// 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, west_opening->ObjectPlacement(), west_opening->Representation(), null
|
||||
null, null, null, file.addLocalPlacement(west_wall->ObjectPlacement(), 2500, -2500+4820, 400, 0, 0, 1, 0, 1, 0),
|
||||
file.addBox(6000, 3630, 1600), 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);
|
||||
IfcEntities geometrical_entities(new IfcEntityList());
|
||||
IfcEntityList::ptr 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 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.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.setSurfaceColour(ground_representation, 0.15, 0.25, 0.05);
|
||||
|
||||
@@ -246,7 +295,7 @@ int main(int argc, char** argv) {
|
||||
, null
|
||||
#endif
|
||||
);
|
||||
IfcSchema::IfcMaterialLayer::list layers (new IfcTemplatedEntityList<IfcSchema::IfcMaterialLayer>());
|
||||
IfcSchema::IfcMaterialLayer::list::ptr layers (new IfcTemplatedEntityList<IfcSchema::IfcMaterialLayer>());
|
||||
layers->push(layer);
|
||||
IfcSchema::IfcMaterialLayerSet* layer_set = new IfcSchema::IfcMaterialLayerSet(
|
||||
layers,
|
||||
@@ -271,17 +320,17 @@ int main(int argc, char** argv) {
|
||||
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.
|
||||
@@ -293,7 +342,7 @@ int main(int argc, char** argv) {
|
||||
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(5050, 1000, 0, 0, 1, 0, 1, 0, 0),
|
||||
null, null, null, file.addLocalPlacement(storey_placement, 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
|
||||
@@ -304,19 +353,19 @@ int main(int argc, char** argv) {
|
||||
file.setSurfaceColour(stair->Representation(), footing_colour);
|
||||
|
||||
IfcSchema::IfcOpeningElement* door_opening = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, file.addLocalPlacement(5000-180, 2500-900, 0), file.addBox(1000, 1000, 2200), null
|
||||
null, null, null, file.addLocalPlacement(storey_placement, 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(4800, 1600, 0, 0, 0, 1, 0, 1, 0), 0, null, 2200, 1000
|
||||
file.addLocalPlacement(storey_placement, 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
|
||||
@@ -324,9 +373,9 @@ int main(int argc, char** argv) {
|
||||
#endif
|
||||
);
|
||||
door->setRepresentation(file.addBox(80, 80, 2120, 0, file.addPlacement3d(460, 0, 0)));
|
||||
IfcSchema::IfcRepresentation::list door_representations = door->Representation()->Representations();
|
||||
IfcSchema::IfcRepresentation::list::ptr door_representations = door->Representation()->Representations();
|
||||
IfcSchema::IfcShapeRepresentation* door_body = 0;
|
||||
for (IfcSchema::IfcRepresentation::it i = door_representations->begin(); i != door_representations->end(); ++i) {
|
||||
for (IfcSchema::IfcRepresentation::list::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;
|
||||
@@ -337,7 +386,11 @@ int main(int argc, char** argv) {
|
||||
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));
|
||||
file.addEntity(new IfcSchema::IfcRelFillsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, door_opening, door));
|
||||
|
||||
IfcSchema::IfcDoorStyle* door_style = new IfcSchema::IfcDoorStyle(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("Door type"), null, null, null, null, null,
|
||||
IfcSchema::IfcDoorStyleOperationEnum::IfcDoorStyleOperation_SINGLE_SWING_LEFT, IfcSchema::IfcDoorStyleConstructionEnum::IfcDoorStyleConstruction_WOOD, false, false);
|
||||
file.addRelatedObject<IfcSchema::IfcRelDefinesByType>(door_style, door);
|
||||
|
||||
// Surface styles are assigned to representation items, hence there is no real limitation to
|
||||
// assign different colours within the same representation. However, some viewers have
|
||||
@@ -350,32 +403,39 @@ int main(int argc, char** argv) {
|
||||
// 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::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
|
||||
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
|
||||
|
||||
// The beams all have the same surface style assigned
|
||||
IfcSchema::IfcPresentationStyleAssignment* frame_style = 0;
|
||||
for (IfcSchema::IfcProductDefinitionShape::it i = frame_representations->begin(); i != frame_representations->end(); ++i) {
|
||||
for (IfcSchema::IfcShapeRepresentation::list::it i = frame_representations->begin(); i != frame_representations->end(); i += 2) {
|
||||
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 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));
|
||||
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));
|
||||
|
||||
for (IfcSchema::IfcLocalPlacement::it it = window_placements->begin(); it != window_placements->end(); ++it) {
|
||||
for (IfcSchema::IfcLocalPlacement::list::it it = window_placements->begin(); it != window_placements->end(); ++it) {
|
||||
|
||||
// Create the window at the current location
|
||||
IfcSchema::IfcLocalPlacement* place = *it;
|
||||
@@ -390,42 +450,42 @@ int main(int argc, char** argv) {
|
||||
file.addBuildingProduct(window);
|
||||
|
||||
// Initalize a list of parts for the window to be composed of
|
||||
IfcSchema::IfcObjectDefinition::list window_parts(new IfcTemplatedEntityList<IfcSchema::IfcObjectDefinition>());
|
||||
IfcSchema::IfcObjectDefinition::list::ptr 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 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));
|
||||
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));
|
||||
|
||||
// Now iterate over the placements and representations of the beam and add them to list of parts
|
||||
IfcSchema::IfcLocalPlacement::it frame_placement;
|
||||
IfcSchema::IfcProductDefinitionShape::it frame_representation;
|
||||
IfcSchema::IfcLocalPlacement::list::it frame_placement;
|
||||
IfcSchema::IfcShapeRepresentation::list::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, *frame_representation, null
|
||||
null, null, null, *frame_placement, file.addMappedItem(*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(930, 45, 90), file.addBox(1680, 10, 1420), null
|
||||
null, null, file.addLocalPlacement(storey_placement, 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);
|
||||
@@ -434,7 +494,7 @@ int main(int argc, char** argv) {
|
||||
// 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.
|
||||
@@ -479,6 +539,6 @@ void createGroundShape(TopoDS_Shape& shape) {
|
||||
#if OCC_VERSION_HEX < 0x60502
|
||||
shape = BRepBuilderAPI_MakeFace(surf);
|
||||
#else
|
||||
shape = BRepBuilderAPI_MakeFace(surf, 1);
|
||||
shape = BRepBuilderAPI_MakeFace(surf, Precision::Confusion());
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -17,9 +17,12 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../ifcparse/IfcParse.h"
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
#endif
|
||||
|
||||
using namespace IfcSchema;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
@@ -41,7 +44,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,
|
||||
@@ -55,17 +58,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 elements = file.EntitiesByType<IfcBuildingElement>();
|
||||
IfcBuildingElement::list::ptr 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::it it = elements->begin(); it != elements->end(); ++ it ) {
|
||||
for ( IfcBuildingElement::list::it it = elements->begin(); it != elements->end(); ++ it ) {
|
||||
|
||||
const IfcBuildingElement::ptr element = *it;
|
||||
const IfcBuildingElement* element = *it;
|
||||
std::cout << element->entity->toString() << std::endl;
|
||||
|
||||
if ( element->is(IfcWindow::Class()) ) {
|
||||
const IfcWindow::ptr window = reinterpret_pointer_cast<IfcBuildingElement,IfcWindow>(element);
|
||||
const IfcWindow* window = (IfcWindow*)element;
|
||||
|
||||
if ( window->hasOverallWidth() && window->hasOverallHeight() ) {
|
||||
const double area = window->OverallWidth()*window->OverallHeight();
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
static int i = 0;
|
||||
|
||||
void create_product_from_item(IfcHierarchyHelper& file, IfcSchema::IfcRepresentationItem* item, const std::string& s) {
|
||||
@@ -43,16 +43,16 @@ void create_product_from_item(IfcHierarchyHelper& file, IfcSchema::IfcRepresenta
|
||||
file.addBuildingProduct(product);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement(120 * i++));
|
||||
product->setObjectPlacement(file.addLocalPlacement(0, 120 * i++));
|
||||
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
items->push(item);
|
||||
|
||||
if (s == "GeometricSet") {
|
||||
IfcSchema::IfcGeometricSet* set = new IfcSchema::IfcGeometricSet(items->generalize());
|
||||
file.AddEntity(set);
|
||||
items = IfcSchema::IfcRepresentationItem::list(new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
file.addEntity(set);
|
||||
items = IfcSchema::IfcRepresentationItem::list::ptr(new IfcSchema::IfcRepresentationItem::list());
|
||||
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(0, 0, reps);
|
||||
file.AddEntity(rep);
|
||||
file.AddEntity(shape);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, 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.filename(filename);
|
||||
file.header().file_name().name(filename);
|
||||
|
||||
double coords1[] = {-50.0, 0.0};
|
||||
double coords2[] = { 50.0, 0.0};
|
||||
IfcSchema::IfcCartesianPoint::list points (new IfcTemplatedEntityList<IfcSchema::IfcCartesianPoint>());
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list());
|
||||
points->push(new IfcSchema::IfcCartesianPoint(std::vector<double>(coords1, coords1+2)));
|
||||
points->push(new IfcSchema::IfcCartesianPoint(std::vector<double>(coords2, coords2+2)));
|
||||
file.AddEntities(points->generalize());
|
||||
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);
|
||||
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));
|
||||
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.));
|
||||
IfcSchema::IfcTrimmedCurve* trim = new IfcSchema::IfcTrimmedCurve(ellipse, trim1, trim2, true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
file.AddEntity(trim);
|
||||
file.addEntity(trim);
|
||||
|
||||
create_products_from_curve(file, trim);
|
||||
|
||||
|
||||
@@ -32,19 +32,19 @@
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "IfcCompositeProfileDef.ifc";
|
||||
IfcHierarchyHelper file;
|
||||
file.filename(filename);
|
||||
file.header().file_name().name(filename);
|
||||
|
||||
double coords1[] = {100.0, 0.0};
|
||||
double coords2[] = {200.0, 0.0};
|
||||
double coords3[] = {300.0, 0.0};
|
||||
|
||||
IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list());
|
||||
|
||||
IfcSchema::IfcCartesianTransformationOperator2D* transform1 = new IfcSchema::IfcCartesianTransformationOperator2D(file.addDoublet<IfcSchema::IfcDirection>(1, 0), file.addDoublet<IfcSchema::IfcDirection>(0, -1), file.addDoublet<IfcSchema::IfcCartesianPoint>(40, 0), null);
|
||||
IfcSchema::IfcCartesianTransformationOperator2D* transform2 = new IfcSchema::IfcCartesianTransformationOperator2D(file.addDoublet<IfcSchema::IfcDirection>(0, -1), file.addDoublet<IfcSchema::IfcDirection>(1, 0), file.addDoublet<IfcSchema::IfcCartesianPoint>(40, 0), 0.3);
|
||||
@@ -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 reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
|
||||
items->push(solid);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("SweptSolid"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
file.AddEntity(rep);
|
||||
file.AddEntity(shape);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
class Node {
|
||||
private:
|
||||
@@ -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.filename(filename);
|
||||
file.header().file_name().name(filename);
|
||||
|
||||
IfcSchema::IfcRepresentationItem* csg1 = Node::Box(8000.,6000.,3000.).subtract(
|
||||
Node::Box(7600.,5600.,2800.).move(200.,200.,200.)
|
||||
@@ -171,8 +171,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement());
|
||||
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
|
||||
items->push(csg1);
|
||||
items->push(csg2);
|
||||
@@ -180,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(0, 0, reps);
|
||||
file.AddEntity(rep);
|
||||
file.AddEntity(shape);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
typedef struct {
|
||||
double r1;
|
||||
@@ -58,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 points(new IfcTemplatedEntityList<Ifc2x3::IfcCartesianPoint>());
|
||||
Ifc2x3::IfcCartesianPoint::list::ptr points(new Ifc2x3::IfcCartesianPoint::list());
|
||||
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);
|
||||
IfcEntities trim1(new IfcEntityList());
|
||||
IfcEntities trim2(new IfcEntityList());
|
||||
file.addEntity(ellipse);
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
if (pref == Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER) {
|
||||
trim1->push(new IfcWrite::IfcSelectHelper(pie.t1, Ifc2x3::Type::IfcParameterValue));
|
||||
trim2->push(new IfcWrite::IfcSelectHelper(pie.t2, Ifc2x3::Type::IfcParameterValue));
|
||||
trim1->push(new Ifc2x3::IfcParameterValue(pie.t1));
|
||||
trim2->push(new Ifc2x3::IfcParameterValue(pie.t2));
|
||||
} else {
|
||||
trim1->push(p2);
|
||||
trim2->push(p3);
|
||||
}
|
||||
Ifc2x3::IfcTrimmedCurve* trim = new Ifc2x3::IfcTrimmedCurve(ellipse, trim1, trim2, true, pref);
|
||||
file.AddEntity(trim);
|
||||
file.addEntity(trim);
|
||||
|
||||
Ifc2x3::IfcCompositeCurveSegment::list segments(new IfcTemplatedEntityList<Ifc2x3::IfcCompositeCurveSegment>());
|
||||
Ifc2x3::IfcCompositeCurveSegment::list::ptr segments(new Ifc2x3::IfcCompositeCurveSegment::list());
|
||||
Ifc2x3::IfcCompositeCurveSegment* s2 = new Ifc2x3::IfcCompositeCurveSegment(Ifc2x3::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, trim);
|
||||
|
||||
Ifc2x3::IfcPolyline* poly = new Ifc2x3::IfcPolyline(points);
|
||||
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(200 * i++));
|
||||
product->setObjectPlacement(file.addLocalPlacement(0, 200 * i++));
|
||||
|
||||
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(profile,
|
||||
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
|
||||
|
||||
file.AddEntity(solid);
|
||||
file.addEntity(solid);
|
||||
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
|
||||
items->push(solid);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("SweptSolid"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
file.AddEntity(rep);
|
||||
file.AddEntity(shape);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Example that generates various forms of IfcFace *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
static int x = 0;
|
||||
|
||||
void create_testcase(IfcHierarchyHelper& file, IfcSchema::IfcFace* face, const std::string& name) {
|
||||
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
|
||||
faces->push(face);
|
||||
IfcSchema::IfcOpenShell* shell = new IfcSchema::IfcOpenShell(faces);
|
||||
|
||||
IfcSchema::IfcConnectedFaceSet::list::ptr shells(new IfcSchema::IfcConnectedFaceSet::list);
|
||||
shells->push(shell);
|
||||
IfcSchema::IfcFaceBasedSurfaceModel* model = new IfcSchema::IfcFaceBasedSurfaceModel(shells);
|
||||
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, name, null, null, 0, 0, null, null);
|
||||
file.addBuildingProduct(product);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement(0, 1000 * x++, 0));
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
|
||||
|
||||
items->push(model);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getRepresentationContext("Model"), S("Body"), S("SurfaceModel"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
file.addEntity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
IfcHierarchyHelper file;
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "polyloop");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint* point1 = file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, 0., 0.);
|
||||
IfcSchema::IfcCartesianPoint* point2 = file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, 0., 0.);
|
||||
IfcSchema::IfcVertexPoint* vertex1 = new IfcSchema::IfcVertexPoint(point1);
|
||||
IfcSchema::IfcVertexPoint* vertex2 = new IfcSchema::IfcVertexPoint(point2);
|
||||
IfcSchema::IfcCircle* circle = new IfcSchema::IfcCircle(file.addPlacement2d(), 400.);
|
||||
IfcSchema::IfcEdgeCurve* edge1 = new IfcSchema::IfcEdgeCurve(vertex1, vertex2, circle, true);
|
||||
IfcSchema::IfcEdgeCurve* edge2 = new IfcSchema::IfcEdgeCurve(vertex2, vertex1, circle, true);
|
||||
IfcSchema::IfcOrientedEdge* oriented_edge1 = new IfcSchema::IfcOrientedEdge(edge1, true);
|
||||
IfcSchema::IfcOrientedEdge* oriented_edge2 = new IfcSchema::IfcOrientedEdge(edge2, true);
|
||||
IfcSchema::IfcOrientedEdge::list::ptr edges(new IfcSchema::IfcOrientedEdge::list);
|
||||
edges->push(oriented_edge1);
|
||||
edges->push(oriented_edge2);
|
||||
IfcSchema::IfcEdgeLoop* loop = new IfcSchema::IfcEdgeLoop(edges);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "circle");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* outer_bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points2 (new IfcSchema::IfcCartesianPoint::list);
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-300, -300, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, -300, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, +300, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-300, +300, 0));
|
||||
IfcSchema::IfcPolyLoop* loop2 = new IfcSchema::IfcPolyLoop(points2);
|
||||
IfcSchema::IfcFaceBound* inner_bound1 = new IfcSchema::IfcFaceBound(loop2, false);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points3 (new IfcSchema::IfcCartesianPoint::list);
|
||||
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, +300, 0));
|
||||
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+300, +300, 0));
|
||||
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+300, -300, 0));
|
||||
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, -300, 0));
|
||||
IfcSchema::IfcPolyLoop* loop3 = new IfcSchema::IfcPolyLoop(points3);
|
||||
IfcSchema::IfcFaceBound* inner_bound2 = new IfcSchema::IfcFaceBound(loop3, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(inner_bound1);
|
||||
bounds->push(outer_bound);
|
||||
bounds->push(inner_bound2);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "polyloop with holes");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, +400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* bound1 = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points2 (new IfcSchema::IfcCartesianPoint::list);
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, +400, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, -400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop2 = new IfcSchema::IfcPolyLoop(points2);
|
||||
IfcSchema::IfcFaceOuterBound* bound2 = new IfcSchema::IfcFaceOuterBound(loop2, false);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound1);
|
||||
bounds->push(bound2);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "multiple outer boundaries (invalid)");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 1e-6));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "imprecise polyloop");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint* point1 = file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, 0., 0.);
|
||||
IfcSchema::IfcCartesianPoint* point2 = file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, 0., 0.);
|
||||
IfcSchema::IfcVertexPoint* vertex1 = new IfcSchema::IfcVertexPoint(point1);
|
||||
IfcSchema::IfcVertexPoint* vertex2 = new IfcSchema::IfcVertexPoint(point2);
|
||||
IfcSchema::IfcCircle* circle = new IfcSchema::IfcCircle(file.addPlacement2d(), 400.);
|
||||
IfcSchema::IfcEdgeCurve* edge1 = new IfcSchema::IfcEdgeCurve(vertex1, vertex2, circle, true);
|
||||
IfcSchema::IfcEdgeCurve* edge2 = new IfcSchema::IfcEdgeCurve(vertex2, vertex1, circle, true);
|
||||
IfcSchema::IfcOrientedEdge* oriented_edge1 = new IfcSchema::IfcOrientedEdge(edge1, true);
|
||||
IfcSchema::IfcOrientedEdge* oriented_edge2 = new IfcSchema::IfcOrientedEdge(edge2, true);
|
||||
IfcSchema::IfcOrientedEdge::list::ptr edges(new IfcSchema::IfcOrientedEdge::list);
|
||||
edges->push(oriented_edge1);
|
||||
edges->push(oriented_edge2);
|
||||
IfcSchema::IfcEdgeLoop* loop = new IfcSchema::IfcEdgeLoop(edges);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr trim1(new IfcSchema::IfcCartesianPoint::list);
|
||||
IfcSchema::IfcCartesianPoint::list::ptr trim2(new IfcSchema::IfcCartesianPoint::list);
|
||||
trim1->push(point1);
|
||||
trim2->push(point2);
|
||||
IfcSchema::IfcTrimmedCurve* trimmed_curve = new IfcSchema::IfcTrimmedCurve(circle, trim1->generalize(), trim2->generalize(), true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);
|
||||
IfcSchema::IfcArbitraryOpenProfileDef* profile = new IfcSchema::IfcArbitraryOpenProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_CURVE, boost::none, trimmed_curve);
|
||||
IfcSchema::IfcAxis1Placement* place = new IfcSchema::IfcAxis1Placement(file.addTriplet<IfcSchema::IfcCartesianPoint>(0., 0., 0.), file.addTriplet<IfcSchema::IfcDirection>(1., 0., 0.));
|
||||
IfcSchema::IfcSurfaceOfRevolution* surface = new IfcSchema::IfcSurfaceOfRevolution(profile, file.addPlacement3d(), place);
|
||||
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFaceSurface(bounds, surface, true);
|
||||
create_testcase(file, face, "face surface");
|
||||
}
|
||||
const std::string filename = "faces.ifc";
|
||||
file.header().file_name().name(filename);
|
||||
std::ofstream f(filename.c_str());
|
||||
f << file;
|
||||
}
|
||||
+22
-19
@@ -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 profiles) {
|
||||
void create_testcase_for(IfcSchema::IfcProfileDef::list::ptr 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 profiles) {
|
||||
file.filename(filename);
|
||||
|
||||
int i = 0;
|
||||
for (IfcSchema::IfcProfileDef::it it = profiles->begin(); it != profiles->end(); ++it, ++i) {
|
||||
for (IfcSchema::IfcProfileDef::list::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 profiles) {
|
||||
file.getSingle<IfcSchema::IfcProject>()->setName(profile_type);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement(100 * i));
|
||||
product->setObjectPlacement(file.addLocalPlacement(0, 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 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 reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
|
||||
|
||||
items->push(solid);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
@@ -73,8 +73,8 @@ void create_testcase_for(IfcSchema::IfcProfileDef::list 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 profiles) {
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
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 profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
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 profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
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 profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcEllipseProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0, 15.0));
|
||||
@@ -132,16 +132,19 @@ int main(int argc, char** argv) {
|
||||
null, 0, 15.0, 25.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
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 profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcLShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, null, null, null, null, null));
|
||||
@@ -156,7 +159,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 profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcCShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 10.0, null, null));
|
||||
@@ -165,7 +168,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 profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcCircleProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0));
|
||||
@@ -174,7 +177,7 @@ int main(int argc, char** argv) {
|
||||
null, 0, 25.0, 5.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcRectangleProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0));
|
||||
@@ -189,7 +192,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 profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
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
@@ -0,0 +1,85 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Example that generates an IfcTriangulatedFaceSet *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../ifcparse/Ifc4.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
#include "suzanne_geometry.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
template <typename T>
|
||||
std::vector< std::vector<T> > create_vector_from_array(const T* arr, unsigned size) {
|
||||
std::vector< std::vector<T> > result;
|
||||
result.reserve(size);
|
||||
|
||||
for (unsigned i = 0; i < size; ) {
|
||||
std::vector<T> ts; ts.reserve(3);
|
||||
for (unsigned j = 0; j < 3; ++i, ++j) {
|
||||
ts.push_back(arr[i]);
|
||||
}
|
||||
result.push_back(ts);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
IfcHierarchyHelper file;
|
||||
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, S("Blender's Suzanne"), null, null, 0, 0, null, null);
|
||||
file.addBuildingProduct(product);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement());
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
|
||||
|
||||
std::vector< std::vector< double > > vertices_vector = create_vector_from_array(vertices, sizeof(vertices) / sizeof(vertices[0]));
|
||||
std::vector< std::vector< int > > indices_vector = create_vector_from_array(indices, sizeof(indices) / sizeof(indices[0]));
|
||||
|
||||
IfcSchema::IfcCartesianPointList3D* coordinates = new IfcSchema::IfcCartesianPointList3D(vertices_vector);
|
||||
IfcSchema::IfcTriangulatedFaceSet* faceset = new IfcSchema::IfcTriangulatedFaceSet(coordinates, null, null, indices_vector, null);
|
||||
|
||||
items->push(faceset);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getRepresentationContext("Model"), S("Body"), S("SurfaceModel"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
file.addEntity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
|
||||
const std::string filename = "tesselated_faceset.ifc";
|
||||
file.header().file_name().name(filename);
|
||||
std::ofstream f(filename.c_str());
|
||||
f << file;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
ADD_EXECUTABLE(hdf5_federate federate.cpp)
|
||||
TARGET_LINK_LIBRARIES(hdf5_federate IfcParse ${ICU_LIBRARIES} ${Boost_LIBRARIES})
|
||||
|
||||
ADD_EXECUTABLE(hdf5_lod lod.cpp)
|
||||
TARGET_LINK_LIBRARIES(hdf5_lod IfcParse IfcGeom ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBRARIES})
|
||||
@@ -0,0 +1,361 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../../../src/ifcparse/IfcHdf5File.h"
|
||||
#include "../../../src/ifcparse/IfcWritableEntity.h"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
#include "multifile_instance_locator.h"
|
||||
|
||||
#pragma warning(disable:4100)
|
||||
|
||||
// A comparison operator that is used to isolate the shared hierarchy
|
||||
class ifc_inst_cmp {
|
||||
public:
|
||||
|
||||
// For these we simply assume that only a single instance exists
|
||||
bool operator()(IfcSchema::IfcSite* a, IfcSchema::IfcSite* b) const { return false; }
|
||||
bool operator()(IfcSchema::IfcProject* a, IfcSchema::IfcProject* b) const { return false; }
|
||||
bool operator()(IfcSchema::IfcBuilding* a, IfcSchema::IfcBuilding* b) const { return false; }
|
||||
bool operator()(IfcSchema::IfcPostalAddress* a, IfcSchema::IfcPostalAddress* b) const { return false; }
|
||||
bool operator()(IfcSchema::IfcUnitAssignment* a, IfcSchema::IfcUnitAssignment* b) const { return false; }
|
||||
|
||||
bool operator()(IfcSchema::IfcConversionBasedUnit* a, IfcSchema::IfcConversionBasedUnit* b) const {
|
||||
return a->Name() < b->Name();
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcDimensionalExponents* a, IfcSchema::IfcDimensionalExponents* b) const {
|
||||
// For every attribute (which are all integers) check equality
|
||||
|
||||
unsigned num_attrs = a->data().getArgumentCount();
|
||||
for (unsigned i = 0; i < num_attrs; ++i) {
|
||||
const int v1 = *a->data().getArgument(i);
|
||||
const int v2 = *b->data().getArgument(i);
|
||||
if (v1 != v2) {
|
||||
return v1 < v2;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcMeasureWithUnit* a, IfcSchema::IfcMeasureWithUnit* b) const {
|
||||
// Assume the value component is enough to differentiate
|
||||
|
||||
double v1 = *a->ValueComponent()->data().getArgument(0);
|
||||
double v2 = *b->ValueComponent()->data().getArgument(0);
|
||||
return v1 < v2;
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcGeometricRepresentationSubContext* a, IfcSchema::IfcGeometricRepresentationSubContext* b) const {
|
||||
return a->ContextType() < b->ContextType();
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcGeometricRepresentationContext* a, IfcSchema::IfcGeometricRepresentationContext* b) const {
|
||||
return a->ContextType() < b->ContextType();
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcSIUnit* a, IfcSchema::IfcSIUnit* b) const {
|
||||
// Assume same units accross files
|
||||
|
||||
return a->UnitType() < b->UnitType();
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcBuildingStorey* a, IfcSchema::IfcBuildingStorey* b) const {
|
||||
return a->Name() < b->Name();
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcCartesianPoint* a, IfcSchema::IfcCartesianPoint* b) const {
|
||||
return a->Coordinates() < b->Coordinates();
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcDirection* a, IfcSchema::IfcDirection* b) const {
|
||||
return a->DirectionRatios() < b->DirectionRatios();
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcAxis2Placement3D* a, IfcSchema::IfcAxis2Placement3D* b) const {
|
||||
if (a->Location()->Coordinates() != b->Location()->Coordinates()) {
|
||||
return (*this)(a->Location(), b->Location());
|
||||
}
|
||||
if (b->hasAxis()) {
|
||||
if (!a->hasAxis()) {
|
||||
return true;
|
||||
} else {
|
||||
return (*this)(a->Axis(), b->Axis());
|
||||
}
|
||||
}
|
||||
if (b->hasRefDirection()) {
|
||||
if (!a->hasRefDirection()) {
|
||||
return true;
|
||||
} else {
|
||||
return (*this)(a->RefDirection(), b->RefDirection());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator()(IfcSchema::IfcLocalPlacement* a, IfcSchema::IfcLocalPlacement* b) const {
|
||||
if (b->hasPlacementRelTo()) {
|
||||
if (!a->hasPlacementRelTo()) {
|
||||
return true;
|
||||
} else {
|
||||
return (*this)(a->PlacementRelTo(), b->PlacementRelTo());
|
||||
}
|
||||
}
|
||||
return (*this)(a->RelativePlacement(), b->RelativePlacement());
|
||||
}
|
||||
|
||||
bool operator()(IfcUtil::IfcBaseClass* a, IfcUtil::IfcBaseClass* b) const {
|
||||
if (a->declaration().type() != b->declaration().type()) {
|
||||
return a->declaration().type() < b->declaration().type();
|
||||
// throw std::runtime_error("Types not matching");
|
||||
}
|
||||
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcSite) { return (*this)((IfcSchema::IfcSite*) a, (IfcSchema::IfcSite*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcConversionBasedUnit) { return (*this)((IfcSchema::IfcConversionBasedUnit*) a, (IfcSchema::IfcConversionBasedUnit*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcDimensionalExponents) { return (*this)((IfcSchema::IfcDimensionalExponents*) a, (IfcSchema::IfcDimensionalExponents*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcMeasureWithUnit) { return (*this)((IfcSchema::IfcMeasureWithUnit*) a, (IfcSchema::IfcMeasureWithUnit*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcProject) { return (*this)((IfcSchema::IfcProject*) a, (IfcSchema::IfcProject*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcBuilding) { return (*this)((IfcSchema::IfcBuilding*) a, (IfcSchema::IfcBuilding*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcPostalAddress) { return (*this)((IfcSchema::IfcPostalAddress*) a, (IfcSchema::IfcPostalAddress*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcUnitAssignment) { return (*this)((IfcSchema::IfcUnitAssignment*) a, (IfcSchema::IfcUnitAssignment*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcGeometricRepresentationSubContext) { return (*this)((IfcSchema::IfcGeometricRepresentationSubContext*) a, (IfcSchema::IfcGeometricRepresentationSubContext*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcGeometricRepresentationContext) { return (*this)((IfcSchema::IfcGeometricRepresentationContext*) a, (IfcSchema::IfcGeometricRepresentationContext*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcSIUnit) { return (*this)((IfcSchema::IfcSIUnit*) a, (IfcSchema::IfcSIUnit*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcBuildingStorey) { return (*this)((IfcSchema::IfcBuildingStorey*) a, (IfcSchema::IfcBuildingStorey*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcCartesianPoint) { return (*this)((IfcSchema::IfcCartesianPoint*) a, (IfcSchema::IfcCartesianPoint*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcDirection) { return (*this)((IfcSchema::IfcDirection*) a, (IfcSchema::IfcDirection*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcAxis2Placement3D) { return (*this)((IfcSchema::IfcAxis2Placement3D*) a, (IfcSchema::IfcAxis2Placement3D*) b); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcLocalPlacement) { return (*this)((IfcSchema::IfcLocalPlacement*) a, (IfcSchema::IfcLocalPlacement*) b); }
|
||||
|
||||
// Should these be removed if an owner history is created manually?
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcPerson) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcOrganization) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcPersonAndOrganization) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcOwnerHistory) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
|
||||
if (a->declaration().type() == IfcSchema::Type::IfcApplication) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
|
||||
|
||||
std::cerr << "Unexpected type: " + IfcSchema::Type::ToString(a->declaration().type()) << std::endl;
|
||||
throw std::runtime_error("Unexpected type: " + IfcSchema::Type::ToString(a->declaration().type()));
|
||||
}
|
||||
};
|
||||
|
||||
// Usage: hdf5_federate Office_A_20110811_optimized.ifc Office_S_20110811_optimized.ifc Office_MEP_20110811_optimized.ifc
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
// A set of datatypes for the shared hierarchy
|
||||
std::set<IfcSchema::Type::Enum> shared {
|
||||
IfcSchema::Type::IfcSite,
|
||||
IfcSchema::Type::IfcConversionBasedUnit,
|
||||
IfcSchema::Type::IfcDimensionalExponents,
|
||||
IfcSchema::Type::IfcMeasureWithUnit,
|
||||
IfcSchema::Type::IfcProject,
|
||||
IfcSchema::Type::IfcBuilding,
|
||||
IfcSchema::Type::IfcPostalAddress,
|
||||
IfcSchema::Type::IfcUnitAssignment,
|
||||
IfcSchema::Type::IfcGeometricRepresentationSubContext,
|
||||
IfcSchema::Type::IfcGeometricRepresentationContext,
|
||||
IfcSchema::Type::IfcSIUnit,
|
||||
IfcSchema::Type::IfcBuildingStorey
|
||||
};
|
||||
|
||||
// Open the set of input files
|
||||
std::vector<IfcParse::IfcFile*> files;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
files.push_back(new IfcParse::IfcFile());
|
||||
files.back()->Init(argv[i]);
|
||||
}
|
||||
|
||||
// Detect shared instances
|
||||
std::set<IfcUtil::IfcBaseClass*> shared_instances;
|
||||
|
||||
for (auto& ty : shared) {
|
||||
std::cout << IfcSchema::Type::ToString(ty) << std::endl;
|
||||
|
||||
for (auto& file : files) {
|
||||
IfcEntityList::ptr insts = file->entitiesByType(ty);
|
||||
std::vector<IfcUtil::IfcBaseClass*> no_subtypes;
|
||||
std::copy_if(insts->begin(), insts->end(), std::back_inserter(no_subtypes), [ty](IfcUtil::IfcBaseClass* inst) {
|
||||
return inst->declaration().type() == ty;
|
||||
});
|
||||
|
||||
std::set<IfcUtil::IfcBaseClass*, ifc_inst_cmp> insts_unique(no_subtypes.begin(), no_subtypes.end());
|
||||
|
||||
if (insts_unique.size() != no_subtypes.size()) {
|
||||
throw std::runtime_error("Non-unique instances encountered within file");
|
||||
}
|
||||
|
||||
shared_instances.insert(insts_unique.begin(), insts_unique.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Follow forward references for shared instances
|
||||
std::set<IfcUtil::IfcBaseClass*> shared_instances_and_refs;
|
||||
|
||||
for (auto& inst : shared_instances) {
|
||||
IfcEntityList::ptr insts = inst->data().file->traverse(inst);
|
||||
|
||||
// Filter out simple types
|
||||
std::vector<IfcUtil::IfcBaseClass*> insts_without_types;
|
||||
std::copy_if(insts->begin(), insts->end(), std::back_inserter(insts_without_types), [](IfcUtil::IfcBaseClass* inst) {
|
||||
return inst->declaration().as_entity() != nullptr;
|
||||
});
|
||||
|
||||
shared_instances_and_refs.insert(insts_without_types.begin(), insts_without_types.end());
|
||||
}
|
||||
|
||||
time_t now_;
|
||||
time(&now_);
|
||||
int now = (int)now_;
|
||||
|
||||
// Create a novel ownerhistory for the shared hierarchy
|
||||
IfcSchema::IfcPerson* person = new IfcSchema::IfcPerson(std::string("tfk"), std::string("Krijnen"), std::string("Thomas"), boost::none, boost::none, boost::none, boost::none, boost::none);
|
||||
IfcSchema::IfcOrganization* org = new IfcSchema::IfcOrganization(std::string("TU/e"), "Eindhoven University of Technology", boost::none, boost::none, boost::none);
|
||||
IfcSchema::IfcPersonAndOrganization* pando = new IfcSchema::IfcPersonAndOrganization(person, org, boost::none);
|
||||
IfcSchema::IfcApplication* appl = new IfcSchema::IfcApplication(org, "v1", "IfcOpenShell-HDF5", "IfcOpenShell-HDF5");
|
||||
IfcSchema::IfcOwnerHistory* owner_history = new IfcSchema::IfcOwnerHistory(pando, appl, IfcSchema::IfcStateEnum::IfcState_READONLY, IfcSchema::IfcChangeActionEnum::IfcChangeAction_ADDED, now, pando, appl, now);
|
||||
|
||||
std::vector<IfcUtil::IfcBaseClass*> replacements{ person, org, pando, appl, owner_history};
|
||||
|
||||
std::vector<IfcUtil::IfcBaseClass*> shared_instances_and_refs_vector(shared_instances_and_refs.begin(), shared_instances_and_refs.end());
|
||||
|
||||
IfcParse::IfcFile temp;
|
||||
for (int i = 0; i < 0x1000001; ++i) temp.FreshId();
|
||||
|
||||
std::for_each(replacements.begin(), replacements.end(), [&shared_instances_and_refs_vector, &temp](IfcUtil::IfcBaseClass* new_inst) {
|
||||
temp.addEntity(new_inst);
|
||||
|
||||
shared_instances_and_refs_vector.erase(
|
||||
std::remove_if(shared_instances_and_refs_vector.begin(), shared_instances_and_refs_vector.end(), [new_inst](IfcUtil::IfcBaseClass* orig_inst) {
|
||||
return orig_inst->declaration().type() == new_inst->declaration().type();
|
||||
}),
|
||||
shared_instances_and_refs_vector.end()
|
||||
);
|
||||
|
||||
shared_instances_and_refs_vector.push_back(new_inst);
|
||||
});
|
||||
|
||||
shared_instances_and_refs.clear();
|
||||
shared_instances_and_refs.insert(shared_instances_and_refs_vector.begin(), shared_instances_and_refs_vector.end());
|
||||
|
||||
// Assign the new ownerhistory to rooted elements in the shared hierarchy
|
||||
std::for_each(shared_instances_and_refs.begin(), shared_instances_and_refs.end(), [owner_history](IfcUtil::IfcBaseClass* inst) {
|
||||
const IfcParse::entity* e = inst->declaration().as_entity();
|
||||
if (e) {
|
||||
auto attributes = e->all_attributes();
|
||||
int index = 0;
|
||||
std::for_each(attributes.begin(), attributes.end(), [&index, inst, owner_history](const IfcParse::entity::attribute* attr) {
|
||||
const IfcParse::named_type* nt = attr->type_of_attribute()->as_named_type();
|
||||
if (nt) {
|
||||
const IfcParse::entity* e2 = nt->declared_type()->as_entity();
|
||||
if (e2 && e2->type() == IfcSchema::Type::IfcOwnerHistory) {
|
||||
IfcWrite::IfcWritableEntity* writable = new IfcWrite::IfcWritableEntity(&inst->data());
|
||||
writable->setArgument(index, owner_history);
|
||||
inst->data(writable);
|
||||
}
|
||||
}
|
||||
index++;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
std::set<IfcUtil::IfcBaseClass*, ifc_inst_cmp> shared_instances_and_refs_unique(shared_instances_and_refs.begin(), shared_instances_and_refs.end());
|
||||
|
||||
// Serialize models into different groups
|
||||
|
||||
IfcParse::Hdf5Settings settings;
|
||||
settings.profile() = IfcParse::Hdf5Settings::standard_referenced;
|
||||
settings.compress() = true;
|
||||
settings.chunk_size() = 1024;
|
||||
|
||||
std::vector<std::string> names;
|
||||
std::vector<std::pair<std::string::const_iterator, std::string::const_iterator>> fixes;
|
||||
std::string common_prefix, common_postfix;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
names.push_back(argv[i]);
|
||||
fixes.push_back({ names.back().begin(), names.back().end() - 1 });
|
||||
}
|
||||
|
||||
while (true) {
|
||||
std::vector<char> chars;
|
||||
std::transform(fixes.begin(), fixes.end(), std::back_inserter(chars), [](auto& pair) {
|
||||
if (pair.first == pair.second) return '\0';
|
||||
return (*pair.first++);
|
||||
});
|
||||
auto pred = std::bind(std::equal_to<char>(), std::placeholders::_1, chars.front());
|
||||
if (chars.front() != 0 && std::all_of(chars.begin()+1, chars.end(), pred)) {
|
||||
common_prefix.push_back(chars.front());
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
std::vector<char> chars;
|
||||
std::transform(fixes.begin(), fixes.end(), std::back_inserter(chars), [](auto& pair) {
|
||||
if (pair.first == pair.second) return '\0';
|
||||
return (*pair.second--);
|
||||
});
|
||||
auto pred = std::bind(std::equal_to<char>(), std::placeholders::_1, chars.front());
|
||||
if (chars.front() != 0 && std::all_of(chars.begin() + 1, chars.end(), pred)) {
|
||||
common_postfix.insert(common_postfix.begin(), chars.front());
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
H5::H5File file(common_prefix + common_postfix + ".hdf", H5F_ACC_TRUNC);
|
||||
H5::Group group1 = file.createGroup("population");
|
||||
|
||||
IfcParse::IfcHdf5File ifc_hdf5(file, get_schema(), settings);
|
||||
IfcParse::IfcSpfHeader header;
|
||||
header.set_default();
|
||||
|
||||
IfcParse::instance_enumerator shared_insts_enum(&header, shared_instances_and_refs_unique.begin(), shared_instances_and_refs_unique.end());
|
||||
|
||||
multifile_instance_locator* locator = new multifile_instance_locator(file, group1, [&shared_instances_and_refs_unique](IfcUtil::IfcBaseClass* inst) {
|
||||
auto it = shared_instances_and_refs_unique.find(inst);
|
||||
if (it == shared_instances_and_refs_unique.end()) {
|
||||
return inst;
|
||||
} else {
|
||||
return *it;
|
||||
}
|
||||
}, shared_instances_and_refs_unique.begin(), shared_instances_and_refs_unique.end());
|
||||
|
||||
ifc_hdf5.write_schema();
|
||||
ifc_hdf5.write_population(group1, shared_insts_enum, locator);
|
||||
|
||||
int n = 0;
|
||||
for (auto f : files) {
|
||||
auto filename = argv[n++ + 1];
|
||||
H5::Group discipline_group = file.createGroup(filename);
|
||||
H5::Group child_group = discipline_group.createGroup("population");
|
||||
|
||||
locator->next(filename, child_group, f);
|
||||
IfcParse::instance_enumerator inst_enum(&f->header(), locator->full_begin(), locator->full_end());
|
||||
|
||||
ifc_hdf5.write_population(child_group, inst_enum, locator);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,472 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../../../src/ifcparse/IfcHdf5File.h"
|
||||
#include "../../../src/ifcgeom/IfcGeom.h"
|
||||
#include "../../../src/ifcparse/IfcWritableEntity.h"
|
||||
|
||||
#include <Bnd_Box.hxx>
|
||||
#include <BRepBndLib.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <TopoDS_Compound.hxx>
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
#include <BRepBuilderAPI_GTransform.hxx>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "multifile_instance_locator.h"
|
||||
|
||||
void generate_bounding_boxes(IfcParse::IfcFile& f, const std::string& fn) {
|
||||
IfcGeom::Kernel kernel;
|
||||
auto unit_factor = kernel.initializeUnits(*f.entitiesByType<IfcSchema::IfcUnitAssignment>()->begin());
|
||||
|
||||
IfcGeom::IteratorSettings settings;
|
||||
settings.convert_back_units() = true;
|
||||
settings.disable_triangulation() = true;
|
||||
settings.disable_opening_subtractions() = true;
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape::list::ptr defs_ = f.entitiesByType<IfcSchema::IfcProductDefinitionShape>();
|
||||
std::vector<IfcSchema::IfcProductDefinitionShape*> defs(defs_->begin(), defs_->end());
|
||||
// Make sure to sort by id to have new definitions lining up in the same order
|
||||
std::sort(defs.begin(), defs.end(), [](IfcSchema::IfcProductDefinitionShape* a, IfcSchema::IfcProductDefinitionShape* b) {
|
||||
return a->data().id() < b->data().id();
|
||||
});
|
||||
|
||||
std::ofstream str(fn.c_str(), std::ios_base::binary);
|
||||
|
||||
int N = defs.size(), n = 0;
|
||||
|
||||
std::cerr << "boxes:" << std::endl;
|
||||
|
||||
// In newer versions of IfcOpenShell this is a method Kernel::apply_transformation()
|
||||
auto apply_transformation = [](const TopoDS_Shape& s, const gp_GTrsf& gt) {
|
||||
if (gt.Form() == gp_Other) {
|
||||
return BRepBuilderAPI_GTransform(s, gt, true).Shape();
|
||||
}
|
||||
gp_Trsf t = gt.Trsf();
|
||||
if (t.Form() == gp_Identity) {
|
||||
return s;
|
||||
} else {
|
||||
/// @todo set to 1. and exactly 1. or use epsilon?
|
||||
if (t.ScaleFactor() != 1.) {
|
||||
return BRepBuilderAPI_Transform(s, t, true).Shape();
|
||||
} else {
|
||||
return s.Moved(t);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// In newer versions of IfcOpenShell this is a method BRep::as_compound()
|
||||
auto brep_as_compound = [&apply_transformation](const IfcGeom::Representation::BRep& brep) {
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++it) {
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
gp_GTrsf trsf = it->Placement();
|
||||
|
||||
if (brep.settings().convert_back_units()) {
|
||||
gp_Trsf scale;
|
||||
scale.SetScaleFactor(1.0 / brep.settings().unit_magnitude());
|
||||
trsf.PreMultiply(scale);
|
||||
}
|
||||
|
||||
const TopoDS_Shape moved_shape = apply_transformation(s, trsf);
|
||||
builder.Add(compound, moved_shape);
|
||||
}
|
||||
return compound;
|
||||
};
|
||||
|
||||
// Generate non-aa bounding boxes in local coordinates as a tuple of six doubles from existing IfcProductDefinitionShape instances
|
||||
std::for_each(defs.begin(), defs.end(), [&kernel, &brep_as_compound, &str, N, &n, &settings](IfcSchema::IfcProductDefinitionShape* def) {
|
||||
Bnd_Box box;
|
||||
|
||||
auto prods = def->data().getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>();
|
||||
if (prods->size() != 1) return;
|
||||
|
||||
IfcSchema::IfcProduct* prod = *prods->begin();
|
||||
|
||||
auto reps = def->Representations();
|
||||
|
||||
std::for_each(reps->begin(), reps->end(), [&kernel, &brep_as_compound, &settings, &box, prod](auto rep) {
|
||||
if (rep->RepresentationIdentifier() == "Body") {
|
||||
IfcGeom::BRepElement<double>* elem = kernel.create_brep_for_representation_and_product<double>(settings, rep, prod);
|
||||
BRepBndLib::AddClose(brep_as_compound(elem->geometry()), box);
|
||||
delete elem;
|
||||
}
|
||||
});
|
||||
|
||||
const size_t name = def->data().id();
|
||||
|
||||
double xyz[6];
|
||||
box.Get(xyz[0], xyz[1], xyz[2], xyz[3], xyz[4], xyz[5]);
|
||||
|
||||
str.write((char*)&name, sizeof(size_t));
|
||||
str.write((char*)xyz, sizeof(double) * 6);
|
||||
|
||||
if (n++ % 1000 == 0) {
|
||||
std::cerr << "\r" << n * 100 / N << std::flush;
|
||||
}
|
||||
});
|
||||
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void find_geometric_types(IfcParse::IfcFile& f, const std::string& tfn) {
|
||||
std::ofstream str(tfn.c_str(), std::ios_base::binary);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape::list::ptr defs_ = f.entitiesByType<IfcSchema::IfcProductDefinitionShape>();
|
||||
std::vector<IfcSchema::IfcProductDefinitionShape*> defs(defs_->begin(), defs_->end());
|
||||
// Make sure to sort by id to have new definitions lining up in the same order
|
||||
std::sort(defs.begin(), defs.end(), [](IfcSchema::IfcProductDefinitionShape* a, IfcSchema::IfcProductDefinitionShape* b) {
|
||||
return a->data().id() < b->data().id();
|
||||
});
|
||||
|
||||
// Initial choice of geometric types
|
||||
std::set<IfcSchema::Type::Enum> geometric_types{
|
||||
IfcSchema::Type::IfcStyledItem, IfcSchema::Type::IfcMaterialDefinitionRepresentation, IfcSchema::Type::IfcStyledRepresentation,
|
||||
IfcSchema::Type::IfcSurfaceStyleRendering, IfcSchema::Type::IfcSurfaceStyle, IfcSchema::Type::IfcPresentationLayerAssignment,
|
||||
IfcSchema::Type::IfcPresentationStyleAssignment, IfcSchema::Type::IfcColourRgb
|
||||
};
|
||||
std::set<IfcSchema::Type::Enum> other_types;
|
||||
|
||||
// Find all instances
|
||||
std::set<IfcUtil::IfcBaseClass*> geometric_instances;
|
||||
|
||||
for (auto ty : geometric_types) {
|
||||
auto insts = f.entitiesByType(ty);
|
||||
std::for_each(insts->begin(), insts->end(), [&geometric_instances](IfcUtil::IfcBaseClass* inst) {
|
||||
geometric_instances.insert(inst);
|
||||
});
|
||||
}
|
||||
|
||||
int N, n;
|
||||
|
||||
// Not referenced. Revit generates unused IfcExtrudedAreaSolids some times.
|
||||
auto repitems = f.entitiesByType(IfcSchema::Type::IfcRepresentationItem);
|
||||
std::for_each(repitems->begin(), repitems->end(), [&f, &geometric_instances](IfcUtil::IfcBaseClass* inst) {
|
||||
auto invs = f.getInverse(inst->data().id(), IfcSchema::Type::UNDEFINED, -1);
|
||||
if (invs->size() == 0) {
|
||||
auto refs = f.traverse(inst);
|
||||
std::for_each(refs->begin(), refs->end(), [&geometric_instances](IfcUtil::IfcBaseClass* inst2) {
|
||||
if (inst2->declaration().as_entity()) {
|
||||
geometric_instances.insert(inst2);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Recurse over forward attributes
|
||||
auto vist_geometric = [&f, &geometric_types, &geometric_instances, &N, &n](IfcUtil::IfcBaseEntity* def) {
|
||||
auto refs = f.traverse(def);
|
||||
geometric_instances.insert(refs->begin(), refs->end());
|
||||
std::for_each(refs->begin(), refs->end(), [&geometric_types](IfcUtil::IfcBaseClass* inst) {
|
||||
if (inst->declaration().as_entity()) {
|
||||
geometric_types.insert(inst->declaration().type());
|
||||
}
|
||||
});
|
||||
if (n++ % 1000 == 0) {
|
||||
std::cerr << "\r" << (n * 100 / N) << std::flush;
|
||||
}
|
||||
};
|
||||
|
||||
n = 0;
|
||||
N = defs.size();
|
||||
|
||||
std::for_each(defs.begin(), defs.end(), vist_geometric);
|
||||
|
||||
// Include connection geometry (e.g space boundaries) as well
|
||||
auto connection_geom = f.entitiesByType<IfcSchema::IfcConnectionGeometry>();
|
||||
|
||||
n = 0;
|
||||
N = connection_geom->size();
|
||||
|
||||
std::for_each(connection_geom->begin(), connection_geom->end(), vist_geometric);
|
||||
|
||||
// Traverse again all instances, but now to detect which geometric types are fully and only shared by geometric instances
|
||||
std::function<void(IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*)> fn;
|
||||
fn = [&f, &geometric_instances, &other_types, &fn](IfcUtil::IfcBaseClass* root, IfcUtil::IfcBaseClass* inst) {
|
||||
if (geometric_instances.find(inst) == geometric_instances.end()) {
|
||||
auto ty = inst->declaration().type();
|
||||
|
||||
other_types.insert(ty);
|
||||
auto refs = f.traverse(inst, 1);
|
||||
std::for_each(refs->begin() + 1, refs->end(), [&fn, root](IfcUtil::IfcBaseClass* inst) {
|
||||
if (inst->declaration().as_entity()) {
|
||||
fn(root, inst);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
N = std::distance(f.begin(), f.end());
|
||||
n = 0;
|
||||
|
||||
std::for_each(f.begin(), f.end(), [&fn, N, &n](const auto& pair) {
|
||||
fn(pair.second, pair.second);
|
||||
if (n++ % 1000 == 0) {
|
||||
std::cerr << "\r" << n * 100 / N << std::flush;
|
||||
}
|
||||
});
|
||||
|
||||
std::set<IfcSchema::Type::Enum> only_geometric;
|
||||
std::set_difference(geometric_types.begin(), geometric_types.end(),
|
||||
other_types.begin(), other_types.end(),
|
||||
std::inserter(only_geometric, only_geometric.begin()));
|
||||
|
||||
only_geometric.erase(IfcSchema::Type::IfcGeometricRepresentationContext);
|
||||
only_geometric.erase(IfcSchema::Type::IfcGeometricRepresentationSubContext);
|
||||
|
||||
std::cerr << "\nOnly geometric:" << std::endl;
|
||||
|
||||
for (auto ty : only_geometric) {
|
||||
std::cerr << IfcSchema::Type::ToString(ty) << std::endl;
|
||||
const size_t name = ty;
|
||||
str.write((char*)&name, sizeof(size_t));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const std::string cache_fn = argv[1] + std::string(".boxes.bin");
|
||||
const std::string types_fn = argv[1] + std::string(".types.bin");
|
||||
|
||||
if (argc == 2 && !ifstream(cache_fn).good()) {
|
||||
std::string command = std::string("\"\"") + argv[0] + "\" \"" + argv[1] + "\" -b\"";
|
||||
if (system(command.c_str()) != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc == 2 && !ifstream(types_fn).good()) {
|
||||
std::string command = std::string("\"\"") + argv[0] + "\" \"" + argv[1] + "\" -t\"";
|
||||
if (system(command.c_str()) != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
IfcParse::IfcFile f;
|
||||
f.Init(argv[1]);
|
||||
|
||||
if (argc == 3 && std::string(argv[2]) == "-b") {
|
||||
generate_bounding_boxes(f, cache_fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc == 3 && std::string(argv[2]) == "-t") {
|
||||
find_geometric_types(f, types_fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::set<IfcSchema::Type::Enum> only_geometric;
|
||||
{
|
||||
std::ifstream str(types_fn.c_str(), std::ios_base::binary);
|
||||
while (!str.eof()) {
|
||||
size_t name;
|
||||
str.read((char*)&name, sizeof(size_t));
|
||||
only_geometric.insert((IfcSchema::Type::Enum) name);
|
||||
}
|
||||
}
|
||||
|
||||
std::set<IfcSchema::Type::Enum> property_types {
|
||||
IfcSchema::Type::IfcRelDefines,
|
||||
IfcSchema::Type::IfcPropertySetDefinition,
|
||||
IfcSchema::Type::IfcTypeObject,
|
||||
IfcSchema::Type::IfcProperty,
|
||||
IfcSchema::Type::IfcPhysicalQuantity,
|
||||
IfcSchema::Type::IfcRelAssociatesClassification,
|
||||
IfcSchema::Type::IfcClassification,
|
||||
IfcSchema::Type::IfcClassificationReference,
|
||||
IfcSchema::Type::IfcRelAssociatesMaterial,
|
||||
IfcSchema::Type::IfcMaterialList,
|
||||
IfcSchema::Type::IfcMaterialLayerSetUsage,
|
||||
IfcSchema::Type::IfcMaterialLayerSet,
|
||||
IfcSchema::Type::IfcMaterialLayer,
|
||||
IfcSchema::Type::IfcMaterial
|
||||
};
|
||||
|
||||
std::vector<IfcUtil::IfcBaseClass*> new_defs, old_defs, old_prop_defs, old_geom_defs, old_box_defs, all_old_defs, all_defs;
|
||||
|
||||
std::for_each(only_geometric.begin(), only_geometric.end(), [&f, &old_geom_defs](IfcSchema::Type::Enum t) {
|
||||
auto insts = f.entitiesByType(t);
|
||||
std::for_each(insts->begin(), insts->end(), [t, &old_geom_defs](IfcUtil::IfcBaseClass* inst) {
|
||||
if (inst->declaration().type() == t) {
|
||||
old_geom_defs.push_back(inst);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
std::for_each(f.begin(), f.end(), [&only_geometric, &old_defs, &old_prop_defs, &property_types](const auto& pair) {
|
||||
IfcUtil::IfcBaseClass* inst = pair.second;
|
||||
|
||||
// This is checked the other way around to include subtypes
|
||||
bool is_property = false;
|
||||
for (auto pty : property_types) {
|
||||
if (inst->declaration().is(pty)) {
|
||||
is_property = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto ty = inst->declaration().type();
|
||||
|
||||
if (is_property) {
|
||||
old_prop_defs.push_back(inst);
|
||||
} else if (only_geometric.find(ty) == only_geometric.end()) {
|
||||
old_defs.push_back(inst);
|
||||
}
|
||||
});
|
||||
|
||||
IfcSchema::IfcRepresentationContext* context = 0;
|
||||
auto reps = (*f.entitiesByType<IfcSchema::IfcProductDefinitionShape>()->begin())->Representations();
|
||||
std::for_each(reps->begin(), reps->end(), [&context](auto rep) {
|
||||
IfcGeom::IfcRepresentationShapeItems items;
|
||||
if (rep->RepresentationIdentifier() == "Body") {
|
||||
context = rep->ContextOfItems();
|
||||
}
|
||||
});
|
||||
|
||||
auto id = f.FreshId();
|
||||
int num_points_added = 0;
|
||||
|
||||
// Create bounding box representation from the 6-tuple definitions
|
||||
{
|
||||
std::ifstream str(cache_fn.c_str(), std::ios_base::binary);
|
||||
while (!str.eof()) {
|
||||
size_t name;
|
||||
double xyz[6];
|
||||
|
||||
str.read((char*)&name, sizeof(size_t));
|
||||
str.read((char*)xyz, sizeof(double) * 6);
|
||||
|
||||
IfcSchema::IfcCartesianPoint* corner = new IfcSchema::IfcCartesianPoint(std::vector<double>{xyz[0], xyz[1], xyz[2]});;
|
||||
IfcSchema::IfcBoundingBox* bbox = new IfcSchema::IfcBoundingBox(corner, xyz[3] - xyz[0], xyz[4] - xyz[1], xyz[5] - xyz[2]);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
|
||||
items->push(bbox);
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(context, std::string("Body"), std::string("BoundingBox"), items);
|
||||
IfcSchema::IfcRepresentation::list::ptr new_reps(new IfcSchema::IfcRepresentation::list);
|
||||
new_reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* new_def = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, new_reps);
|
||||
|
||||
corner->data().isWritable()->setId(id++);
|
||||
|
||||
// NB: Corner is added to existing definitions
|
||||
old_defs.push_back(corner); ++num_points_added;
|
||||
new_defs.push_back(bbox);
|
||||
new_defs.push_back(rep);
|
||||
new_defs.push_back(new_def);
|
||||
}
|
||||
}
|
||||
|
||||
std::for_each(new_defs.begin(), new_defs.end(), [&id](auto new_def) {
|
||||
new_def->data().isWritable()->setId(id++);
|
||||
});
|
||||
|
||||
auto iden = [](IfcUtil::IfcBaseClass* inst) { return inst; };
|
||||
|
||||
std::set<IfcSchema::Type::Enum> old_new_geom_types;
|
||||
|
||||
std::vector<std::vector<IfcUtil::IfcBaseClass*>*> all_vectors = std::vector<std::vector<IfcUtil::IfcBaseClass*>*>{ &new_defs, &old_prop_defs, &old_defs, &old_geom_defs };
|
||||
for (auto vec_ : all_vectors) {
|
||||
auto& vec = *vec_;
|
||||
for (auto& inst : vec) {
|
||||
old_new_geom_types.insert(inst->declaration().type());
|
||||
}
|
||||
}
|
||||
|
||||
// Generate proper buckets of data and serialize
|
||||
|
||||
all_old_defs.insert(all_old_defs.end(), old_defs.begin(), old_defs.end());
|
||||
all_old_defs.insert(all_old_defs.end(), old_prop_defs.begin(), old_prop_defs.end());
|
||||
all_old_defs.insert(all_old_defs.end(), old_geom_defs.begin(), old_geom_defs.end());
|
||||
all_defs.insert(all_defs.end(), all_old_defs.begin(), all_old_defs.end());
|
||||
all_defs.insert(all_defs.end(), new_defs.begin(), new_defs.end());
|
||||
old_box_defs.insert(old_box_defs.end(), old_defs.begin(), old_defs.end());
|
||||
old_box_defs.insert(old_box_defs.end(), new_defs.begin(), new_defs.end());
|
||||
auto contexts = f.entitiesByType<IfcSchema::IfcRepresentationContext>();
|
||||
old_box_defs.insert(old_box_defs.end(), contexts->begin(), contexts->end());
|
||||
|
||||
{
|
||||
int num_insts1 = std::distance(all_old_defs.begin(), all_old_defs.end());
|
||||
int num_insts2 = std::distance(f.begin(), f.end());
|
||||
if ((num_insts1 - num_points_added) != num_insts2) {
|
||||
std::cerr << "Missign instances " << num_insts1 << " - " << num_points_added << " != " << num_insts2 << std::endl;
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
multifile_instance_locator* locator = new multifile_instance_locator(
|
||||
old_new_geom_types.begin(), old_new_geom_types.end(),
|
||||
all_old_defs.begin(), all_old_defs.end());
|
||||
|
||||
IfcParse::Hdf5Settings settings;
|
||||
settings.profile() = IfcParse::Hdf5Settings::padded;
|
||||
settings.compress() = true;
|
||||
settings.chunk_size() = 1024;
|
||||
|
||||
H5::H5File hdf(argv[1] + std::string(".hdf"), H5F_ACC_TRUNC);
|
||||
H5::H5File geom_hdf(argv[1] + std::string("-geometry.hdf"), H5F_ACC_TRUNC);
|
||||
H5::H5File box_hdf(argv[1] + std::string("-bounding-boxes.hdf"), H5F_ACC_TRUNC);
|
||||
H5::H5File prop_hdf(argv[1] + std::string("-properties.hdf"), H5F_ACC_TRUNC);
|
||||
|
||||
hdf.createGroup("geometry").close();
|
||||
hdf.createGroup("bounding-boxes").close();
|
||||
hdf.createGroup("properties").close();
|
||||
|
||||
hdf.mount("geometry", geom_hdf, H5::PropList::DEFAULT);
|
||||
hdf.mount("bounding-boxes", box_hdf, H5::PropList::DEFAULT);
|
||||
hdf.mount("properties", prop_hdf, H5::PropList::DEFAULT);
|
||||
|
||||
H5::Group main_population = hdf.createGroup("population");
|
||||
H5::Group geom_population = hdf.createGroup("geometry/population");
|
||||
H5::Group box_population = hdf.createGroup("bounding-boxes/population");
|
||||
H5::Group prop_population = hdf.createGroup("properties/population");
|
||||
|
||||
{
|
||||
IfcParse::IfcHdf5File ifc_hdf5(hdf, get_schema(), settings);
|
||||
IfcParse::instance_categorizer categorizer(all_defs.begin(), all_defs.end());
|
||||
ifc_hdf5.write_schema(&categorizer);
|
||||
|
||||
{
|
||||
IfcParse::instance_enumerator enumerator(&f.header(), old_defs.begin(), old_defs.end());
|
||||
ifc_hdf5.write_population(main_population, enumerator, locator);
|
||||
}
|
||||
|
||||
{
|
||||
IfcParse::instance_enumerator enumerator(&f.header(), old_geom_defs.begin(), old_geom_defs.end());
|
||||
ifc_hdf5.write_population(geom_population, enumerator, locator);
|
||||
}
|
||||
|
||||
{
|
||||
IfcParse::instance_enumerator enumerator(&f.header(), old_prop_defs.begin(), old_prop_defs.end());
|
||||
ifc_hdf5.write_population(prop_population, enumerator, locator);
|
||||
}
|
||||
|
||||
{
|
||||
// locator is setup with all_old_defs, need to switch to new_defs + old_defs for the cartesian points
|
||||
// NB: also geom rep context
|
||||
locator->next(box_population, old_box_defs.begin(), old_box_defs.end());
|
||||
|
||||
IfcParse::instance_enumerator enumerator(&f.header(), new_defs.begin(), new_defs.end());
|
||||
ifc_hdf5.write_population(box_population, enumerator, locator);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
class multifile_instance_locator : public IfcParse::abstract_instance_locator {
|
||||
public:
|
||||
typedef std::function<IfcUtil::IfcBaseClass*(IfcUtil::IfcBaseClass*)> mapping_t;
|
||||
typedef std::pair<
|
||||
std::vector<IfcSchema::Type::Enum>,
|
||||
std::vector< std::vector<IfcUtil::IfcBaseEntity*> >
|
||||
> population_t;
|
||||
typedef std::vector<IfcUtil::IfcBaseClass*>::const_iterator full_const_iterator;
|
||||
|
||||
private:
|
||||
H5::H5File* root_file_;
|
||||
|
||||
mapping_t mapping_;
|
||||
std::set<IfcUtil::IfcBaseClass*> initial_population_set_;
|
||||
std::set<IfcSchema::Type::Enum> initial_types_included_set_;
|
||||
|
||||
population_t initial_population_;
|
||||
population_t subsequent_population_;
|
||||
std::vector<IfcUtil::IfcBaseClass*> subsequent_minus_initial_;
|
||||
|
||||
H5::Group* initial_group_;
|
||||
H5::Group* subsequent_group_;
|
||||
H5::H5File* subsequent_file_;
|
||||
std::string root_;
|
||||
|
||||
public:
|
||||
|
||||
template <typename ForwardIterator>
|
||||
multifile_instance_locator(H5::H5File& root_file, H5::Group& group, mapping_t mapping, ForwardIterator b, ForwardIterator e)
|
||||
: root_file_(&root_file)
|
||||
, mapping_(mapping)
|
||||
, initial_group_(&group)
|
||||
, subsequent_group_(nullptr)
|
||||
{
|
||||
initial_population_set_.insert(b, e);
|
||||
|
||||
std::set<IfcSchema::Type::Enum> names_set;
|
||||
std::for_each(b, e, [this, &names_set](IfcUtil::IfcBaseClass* inst) {
|
||||
IfcSchema::Type::Enum ty = inst->declaration().type();
|
||||
if (names_set.find(ty) == names_set.end()) {
|
||||
initial_population_.first.push_back(ty);
|
||||
names_set.insert(ty);
|
||||
}
|
||||
});
|
||||
|
||||
std::sort(initial_population_.first.begin(), initial_population_.first.end());
|
||||
|
||||
std::for_each(this->begin(), this->end(), [this, &b, &e](IfcSchema::Type::Enum t) {
|
||||
std::vector<IfcUtil::IfcBaseEntity*> by_type;
|
||||
|
||||
std::for_each(b, e, [t,&by_type](IfcUtil::IfcBaseClass* inst) {
|
||||
if (inst->declaration().type() == t && inst->declaration().as_entity()) {
|
||||
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
|
||||
}
|
||||
});
|
||||
|
||||
std::sort(by_type.begin(), by_type.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
|
||||
return i1->data().id() < i2->data().id();
|
||||
});
|
||||
|
||||
initial_population_.second.emplace_back(by_type);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename ForwardIteratorTypes, typename ForwardIteratorInsts>
|
||||
multifile_instance_locator(ForwardIteratorTypes types_all_begin, ForwardIteratorTypes types_all_end, ForwardIteratorInsts insts_begin, ForwardIteratorInsts insts_end)
|
||||
: subsequent_group_(nullptr)
|
||||
{
|
||||
initial_population_.first.assign(types_all_begin, types_all_end);
|
||||
std::sort(initial_population_.first.begin(), initial_population_.first.end());
|
||||
|
||||
std::for_each(this->begin(), this->end(), [this, &insts_begin, &insts_end](IfcSchema::Type::Enum t) {
|
||||
std::vector<IfcUtil::IfcBaseEntity*> by_type;
|
||||
|
||||
std::for_each(insts_begin, insts_end, [t, &by_type](IfcUtil::IfcBaseClass* inst) {
|
||||
if (inst->declaration().type() == t && inst->declaration().as_entity()) {
|
||||
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
|
||||
}
|
||||
});
|
||||
|
||||
std::sort(by_type.begin(), by_type.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
|
||||
return i1->data().id() < i2->data().id();
|
||||
});
|
||||
|
||||
initial_population_.second.emplace_back(by_type);
|
||||
});
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
if (subsequent_group_) {
|
||||
return subsequent_population_.first.begin();
|
||||
} else {
|
||||
return initial_population_.first.begin();
|
||||
}
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
if (subsequent_group_) {
|
||||
return subsequent_population_.first.end();
|
||||
} else {
|
||||
return initial_population_.first.end();
|
||||
}
|
||||
}
|
||||
|
||||
full_const_iterator full_begin() const {
|
||||
return subsequent_minus_initial_.begin();
|
||||
}
|
||||
|
||||
full_const_iterator full_end() const {
|
||||
return subsequent_minus_initial_.end();
|
||||
}
|
||||
|
||||
const std::vector<IfcUtil::IfcBaseEntity*>& instances(IfcSchema::Type::Enum t) {
|
||||
if (subsequent_group_) {
|
||||
return subsequent_population_.second[std::lower_bound(begin(), end(), t) - begin()];
|
||||
} else {
|
||||
return initial_population_.second[std::lower_bound(begin(), end(), t) - begin()];
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<int, int> operator()(IfcUtil::IfcBaseClass* v) {
|
||||
if (IfcSchema::Type::IsSimple(v->declaration().type())) {
|
||||
throw std::exception("Simple type not expected here");
|
||||
}
|
||||
|
||||
IfcSchema::Type::Enum t = v->declaration().type();
|
||||
|
||||
// This remains constant for subsequent model serializations?
|
||||
auto& dataset_names = initial_population_.first;
|
||||
auto tt = std::lower_bound(dataset_names.begin(), dataset_names.end(), t);
|
||||
int a = std::distance(dataset_names.begin(), tt);
|
||||
int b;
|
||||
|
||||
const std::vector<IfcUtil::IfcBaseEntity*>& insts = instances(t);
|
||||
|
||||
auto it = std::lower_bound(insts.begin(), insts.end(), v, [](IfcUtil::IfcBaseClass* other, IfcUtil::IfcBaseClass* val) {
|
||||
// An ordering based on ID is not equivalent to an ordering based on pointer address!
|
||||
return other->data().id() < val->data().id();
|
||||
});
|
||||
|
||||
if (it == insts.end()) {
|
||||
throw std::runtime_error("Unable to find instance");
|
||||
}
|
||||
|
||||
b = std::distance(insts.begin(), it);
|
||||
|
||||
return std::make_pair(a, b);
|
||||
}
|
||||
|
||||
void make_reference(IfcUtil::IfcBaseClass* v, void*& ptr) {
|
||||
v = mapping_(v);
|
||||
IfcSchema::Type::Enum t = v->declaration().type();
|
||||
|
||||
population_t* pop;
|
||||
H5::Group* group;
|
||||
boost::optional<std::string> current_root;
|
||||
|
||||
if (initial_population_set_.find(v) != initial_population_set_.end()) {
|
||||
pop = &initial_population_;
|
||||
group = initial_group_;
|
||||
current_root = boost::none;
|
||||
} else {
|
||||
pop = &subsequent_population_;
|
||||
group = subsequent_group_;
|
||||
current_root = root_;
|
||||
}
|
||||
|
||||
int a = std::lower_bound(pop->first.begin(), pop->first.end(), t) - pop->first.begin();
|
||||
auto& vec = pop->second[a];
|
||||
|
||||
hsize_t coord = std::lower_bound(vec.begin(), vec.end(), v, [](IfcUtil::IfcBaseClass* other, IfcUtil::IfcBaseClass* val) {
|
||||
return other->data().id() < val->data().id();
|
||||
}) - vec.begin();
|
||||
|
||||
hsize_t dims = instances(v->declaration().type()).size();
|
||||
H5::DataSpace space(1, &dims);
|
||||
space.selectElements(H5S_SELECT_SET, 1, &coord);
|
||||
const std::string path = IfcSchema::Type::ToString(pop->first[a]);
|
||||
|
||||
std::string full_path = group->getObjName() + "/" + path + "_objects" + "/" + path + "_instances";
|
||||
|
||||
root_file_->reference(ptr, full_path, space);
|
||||
ptr = static_cast<uint8_t*>(ptr) + sizeof(hdset_reg_ref_t);
|
||||
}
|
||||
|
||||
template <typename ForwardIt>
|
||||
void next(H5::Group& group, ForwardIt insts_begin, ForwardIt insts_end) {
|
||||
subsequent_group_ = &group;
|
||||
|
||||
subsequent_population_.first = initial_population_.first;
|
||||
subsequent_population_.second.clear();
|
||||
|
||||
std::for_each(this->begin(), this->end(), [this, &insts_begin, &insts_end](IfcSchema::Type::Enum t) {
|
||||
std::vector<IfcUtil::IfcBaseEntity*> by_type;
|
||||
|
||||
std::for_each(insts_begin, insts_end, [t, &by_type](IfcUtil::IfcBaseClass* inst) {
|
||||
if (inst->declaration().type() == t && inst->declaration().as_entity()) {
|
||||
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
|
||||
}
|
||||
});
|
||||
|
||||
std::sort(by_type.begin(), by_type.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
|
||||
return i1->data().id() < i2->data().id();
|
||||
});
|
||||
|
||||
subsequent_population_.second.emplace_back(by_type);
|
||||
});
|
||||
}
|
||||
|
||||
void next(const std::string& name, H5::Group& group, IfcParse::IfcFile* f) {
|
||||
subsequent_group_ = &group;
|
||||
root_ = name;
|
||||
|
||||
subsequent_population_.first.clear();
|
||||
subsequent_population_.second.clear();
|
||||
subsequent_minus_initial_.clear();
|
||||
|
||||
auto f_begin = f->begin();
|
||||
auto f_end = f->end();
|
||||
|
||||
std::set<IfcSchema::Type::Enum> names_set;
|
||||
std::for_each(f_begin, f_end, [this, &names_set](auto& pair) {
|
||||
IfcUtil::IfcBaseClass* inst = mapping_(pair.second);
|
||||
if (initial_population_set_.find(inst) == initial_population_set_.end()) {
|
||||
IfcSchema::Type::Enum ty = inst->declaration().type();
|
||||
if (names_set.find(ty) == names_set.end()) {
|
||||
subsequent_population_.first.push_back(ty);
|
||||
names_set.insert(ty);
|
||||
}
|
||||
subsequent_minus_initial_.push_back(inst);
|
||||
}
|
||||
});
|
||||
|
||||
auto& names = subsequent_population_.first;
|
||||
std::sort(names.begin(), names.end());
|
||||
|
||||
auto& vecs = subsequent_population_.second;
|
||||
vecs.resize(names.size());
|
||||
|
||||
std::for_each(f_begin, f_end, [this, &names, &vecs](auto& pair) {
|
||||
IfcUtil::IfcBaseClass* inst = mapping_(pair.second);
|
||||
if (initial_population_set_.find(inst) == initial_population_set_.end() && inst->declaration().as_entity()) {
|
||||
IfcSchema::Type::Enum ty = inst->declaration().type();
|
||||
auto a = std::lower_bound(names.begin(), names.end(), ty) - names.begin();
|
||||
auto& by_type = vecs[a];
|
||||
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
|
||||
}
|
||||
});
|
||||
|
||||
std::for_each(vecs.begin(), vecs.end(), [](auto& vec) {
|
||||
std::sort(vec.begin(), vec.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
|
||||
return i1->data().id() < i2->data().id();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -30,27 +30,16 @@ bl_info = {
|
||||
"description": "Import files in the "\
|
||||
"Industry Foundation Classes (.ifc) file format",
|
||||
"author": "Thomas Krijnen, IfcOpenShell",
|
||||
"blender": (2, 5, 8),
|
||||
"api": 37702,
|
||||
"blender": (2, 73, 0),
|
||||
"location": "File > Import",
|
||||
"warning": "",
|
||||
"wiki_url": "http://sourceforge.net/apps/"\
|
||||
"mediawiki/ifcopenshell/index.php",
|
||||
"tracker_url": "http://sourceforge.net/tracker/?group_id=543113",
|
||||
"tracker_url": "https://sourceforge.net/p/ifcopenshell/"\
|
||||
"_list/tickets?source=navbar",
|
||||
"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 "IfcImport" in locals():
|
||||
imp.reload(IfcImport)
|
||||
if "ifcopenshell" in locals():
|
||||
imp.reload(ifcopenshell)
|
||||
|
||||
import bpy
|
||||
import mathutils
|
||||
@@ -70,54 +59,64 @@ bpy.types.Object.ifc_type = StringProperty(name="IFC Entity Type",
|
||||
description="The STEP Datatype keyword")
|
||||
|
||||
|
||||
def import_ifc(filename, use_names, process_relations):
|
||||
global wrong_unicode
|
||||
from . import IfcImport
|
||||
def import_ifc(filename, use_names, process_relations, blender_booleans):
|
||||
from . import ifcopenshell
|
||||
from .ifcopenshell import geom as ifcopenshell_geom
|
||||
print("Reading %s..."%bpy.path.basename(filename))
|
||||
if wrong_unicode:
|
||||
valid_file = IfcImport.InitUCS2(
|
||||
''.join(['\0']+['\0%s'%s for s in filename]+['\0\0'])
|
||||
)
|
||||
else:
|
||||
valid_file = IfcImport.Init(filename)
|
||||
settings = ifcopenshell_geom.settings()
|
||||
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, blender_booleans)
|
||||
iterator = ifcopenshell_geom.iterator(settings, filename)
|
||||
valid_file = iterator.initialize()
|
||||
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 = 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
|
||||
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
|
||||
|
||||
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.mesh.id)
|
||||
me = bpy.data.meshes.new('mesh%d' % ob.geometry.id)
|
||||
me.from_pydata(verts, [], faces)
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
bob = bpy.data.objects.new(nm, me)
|
||||
mat = mathutils.Matrix(([m[0], m[1], m[2], 0],
|
||||
@@ -138,10 +137,12 @@ def import_ifc(filename, use_names, process_relations):
|
||||
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
|
||||
|
||||
bob.hide = ob_type == 'IfcSpace' or ob_type == 'IfcOpeningElement'
|
||||
bob.hide_render = bob.hide
|
||||
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'
|
||||
|
||||
if ob.id not in id_to_object: id_to_object[ob.id] = []
|
||||
id_to_object[ob.id].append(bob)
|
||||
@@ -149,11 +150,19 @@ def import_ifc(filename, use_names, process_relations):
|
||||
if ob.parent_id > 0:
|
||||
id_to_parent[ob.id] = ob.parent_id
|
||||
|
||||
progress = IfcImport.Progress() // 2
|
||||
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
|
||||
if progress > old_progress:
|
||||
print("\r[" + "#" * progress + " " * (50 - progress) + "]", end="")
|
||||
old_progress = progress
|
||||
if not IfcImport.Next():
|
||||
if not iterator.next():
|
||||
break
|
||||
|
||||
print("\rDone creating geometry" + " " * 30)
|
||||
@@ -169,24 +178,13 @@ def import_ifc(filename, use_names, process_relations):
|
||||
if parent_id in id_to_object:
|
||||
bob = id_to_object[parent_id][0]
|
||||
else:
|
||||
parent_ob = IfcImport.GetObject(parent_id)
|
||||
parent_ob = iterator.getObject(parent_id)
|
||||
if parent_ob.id == -1:
|
||||
bob = None
|
||||
else:
|
||||
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
|
||||
m = parent_ob.transformation.matrix.data
|
||||
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((
|
||||
@@ -201,7 +199,7 @@ def import_ifc(filename, use_names, process_relations):
|
||||
|
||||
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
|
||||
@@ -226,13 +224,19 @@ def import_ifc(filename, use_names, process_relations):
|
||||
|
||||
if process_relations:
|
||||
print("Done processing relations")
|
||||
|
||||
if not wrong_unicode:
|
||||
txt = bpy.data.texts.new("%s.log"%bpy.path.basename(filename))
|
||||
txt.from_string(IfcImport.GetLog())
|
||||
|
||||
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())
|
||||
|
||||
IfcImport.CleanUp()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@@ -251,15 +255,13 @@ 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):
|
||||
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):
|
||||
if not import_ifc(self.filepath, self.use_names, self.process_relations, self.blender_booleans):
|
||||
self.report({'ERROR'},
|
||||
'Unable to parse .ifc file or no geometrical entities found'
|
||||
)
|
||||
|
||||
@@ -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 == '_')) {
|
||||
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_') || ( c == '-')) {
|
||||
id.push_back(c);
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<float>& floats, const char* coords /* = "XYZ" */) {
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<double>& 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(strlen(coords));
|
||||
source.setAccessorCount(floats.size() / 3);
|
||||
source.setAccessorStride((unsigned long)strlen(coords));
|
||||
source.setAccessorCount((unsigned long)floats.size() / 3);
|
||||
for (unsigned int i = 0; i < source.getAccessorStride(); ++i) {
|
||||
source.getParameterNameList().push_back(std::string(1, coords[i]));
|
||||
}
|
||||
source.prepareToAppendValues();
|
||||
for (std::vector<float>::const_iterator it = floats.begin(); it != floats.end(); ++it) {
|
||||
for (std::vector<double>::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<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 ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials) {
|
||||
openMesh(mesh_id);
|
||||
|
||||
// The normals vector can be empty for example when the WELD_VERTICES setting is used.
|
||||
@@ -68,19 +68,15 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str
|
||||
vertices.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::POSITION, "#" + mesh_id + COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX));
|
||||
vertices.add();
|
||||
|
||||
std::vector<int>::const_iterator index_range_start = indices.begin();
|
||||
std::vector<int>::const_iterator index_range_start = faces.begin();
|
||||
std::vector<int>::const_iterator material_it = material_ids.begin();
|
||||
int previous_material_id = -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())) {
|
||||
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())) {
|
||||
COLLADASW::Triangles triangles(mSW);
|
||||
triangles.setMaterial(collada_id(previous_material_id < 0
|
||||
? default_material_name
|
||||
: materials[previous_material_id].name()));
|
||||
triangles.setMaterial(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++ ) );
|
||||
@@ -100,11 +96,44 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str
|
||||
index_range_start = it;
|
||||
}
|
||||
previous_material_id = current_material_id;
|
||||
if (it == indices.end()) {
|
||||
if (it == faces.end()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::set<int> faces_set (faces.begin(), faces.end());
|
||||
typedef std::vector< std::pair<int, std::vector<unsigned long> > > linelist_t;
|
||||
linelist_t linelist;
|
||||
|
||||
int num_lines = 0;
|
||||
for ( std::vector<int>::const_iterator it = edges.begin(); it != edges.end(); ++num_lines) {
|
||||
const int i1 = *(it++);
|
||||
const int i2 = *(it++);
|
||||
|
||||
if (faces_set.find(i1) != faces_set.end() || faces_set.find(i2) != faces_set.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int current_material_id = *(material_it++);
|
||||
if ((previous_material_id != current_material_id) || (num_lines == 0)) {
|
||||
linelist.resize(linelist.size() + 1);
|
||||
}
|
||||
|
||||
linelist.rbegin()->second.push_back(i1);
|
||||
linelist.rbegin()->second.push_back(i2);
|
||||
}
|
||||
|
||||
for (linelist_t::const_iterator it = linelist.begin(); it != linelist.end(); ++it) {
|
||||
COLLADASW::Lines lines(mSW);
|
||||
lines.setMaterial(materials[it->first].name());
|
||||
lines.setCount((unsigned long)it->second.size());
|
||||
int offset = 0;
|
||||
lines.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX, "#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++));
|
||||
lines.prepareToAppendValues();
|
||||
lines.appendValues(it->second);
|
||||
lines.finish();
|
||||
}
|
||||
|
||||
closeMesh();
|
||||
closeGeometry();
|
||||
}
|
||||
@@ -113,7 +142,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<float>& 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<double>& matrix) {
|
||||
if (!scene_opened) {
|
||||
openVisualScene(scene_id);
|
||||
scene_opened = true;
|
||||
@@ -155,7 +184,7 @@ void ColladaSerializer::ColladaExporter::ColladaScene::write() {
|
||||
}
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeomObjects::Material& material) {
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeom::Material& material) {
|
||||
openEffect(collada_id(material.name()) + "-fx");
|
||||
COLLADASW::EffectProfile effect(mSW);
|
||||
effect.setShaderType(COLLADASW::EffectProfile::LAMBERT);
|
||||
@@ -186,20 +215,20 @@ void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::close
|
||||
closeLibrary();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const IfcGeomObjects::Material& material) {
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const IfcGeom::Material& material) {
|
||||
if (!contains(material)) {
|
||||
effects.write(material);
|
||||
materials.push_back(material);
|
||||
}
|
||||
}
|
||||
|
||||
bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeomObjects::Material& material) {
|
||||
bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeom::Material& material) {
|
||||
return std::find(materials.begin(), materials.end(), material) != materials.end();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::write() {
|
||||
effects.close();
|
||||
for (std::vector<IfcGeomObjects::Material>::const_iterator it = materials.begin(); it != materials.end(); ++it) {
|
||||
for (std::vector<IfcGeom::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");
|
||||
@@ -218,34 +247,16 @@ void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_n
|
||||
asset.add();
|
||||
}
|
||||
|
||||
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));
|
||||
void ColladaSerializer::ColladaExporter::write(const std::string& unique_id, const std::string& type, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& _materials) {
|
||||
std::vector<std::string> material_references;
|
||||
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;
|
||||
for (std::vector<IfcGeom::Material>::const_iterator it = _materials.begin(); it != _materials.end(); ++it) {
|
||||
const IfcGeom::Material& material = *it;
|
||||
if (!materials.contains(material)) {
|
||||
materials.add(material);
|
||||
}
|
||||
material_references.push_back(collada_id(material.name()));
|
||||
}
|
||||
deferreds.push_back(DeferredObject(guid, name, type, obj_id, matrix, vertices, normals, indices, material_ids, _materials, material_references));
|
||||
}
|
||||
|
||||
const std::string ColladaSerializer::ColladaExporter::DeferredObject::Name() const {
|
||||
std::stringstream ss;
|
||||
if (!this->name.empty()) {
|
||||
ss << this->obj_id << "_" << this->name;
|
||||
} else {
|
||||
ss << this->guid;
|
||||
}
|
||||
return collada_id(ss.str());
|
||||
deferreds.push_back(DeferredObject(unique_id, type, matrix, vertices, normals, faces, edges, material_ids, _materials, material_references));
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::endDocument() {
|
||||
@@ -253,13 +264,13 @@ void ColladaSerializer::ColladaExporter::endDocument() {
|
||||
// only at this point all objects are written to the stream.
|
||||
materials.write();
|
||||
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
|
||||
const std::string object_name = it->Name();
|
||||
geometries.write(object_name, it->type, it->vertices, it->normals, it->indices, it->material_ids, it->materials);
|
||||
const std::string object_name = it->unique_id + "-representation";
|
||||
geometries.write(object_name, it->type, it->vertices, it->normals, it->faces, it->edges, it->material_ids, it->materials);
|
||||
}
|
||||
geometries.close();
|
||||
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
|
||||
const std::string object_name = it->Name();
|
||||
scene.add(object_name + "-instance", object_name, object_name, it->material_references, it->matrix);
|
||||
const std::string object_name = it->unique_id;
|
||||
scene.add(object_name, object_name, object_name + "-representation", it->material_references, it->matrix);
|
||||
}
|
||||
scene.write();
|
||||
stream.endDocument();
|
||||
@@ -273,9 +284,9 @@ void ColladaSerializer::writeHeader() {
|
||||
exporter.startDocument(unit_name, unit_magnitude);
|
||||
}
|
||||
|
||||
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::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::finalize() {
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
#ifndef COLLADASERIALIZER_H
|
||||
#define COLLADASERIALIZER_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4201 4512)
|
||||
#endif
|
||||
#include <COLLADASWStreamWriter.h>
|
||||
#include <COLLADASWPrimitves.h>
|
||||
#include <COLLADASWLibraryGeometries.h>
|
||||
@@ -34,30 +38,39 @@
|
||||
#include <COLLADASWLibraryMaterials.h>
|
||||
#include <COLLADASWBaseInputElement.h>
|
||||
#include <COLLADASWAsset.h>
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
#include "../ifcgeom/IfcGeomIterator.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<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 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 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:
|
||||
@@ -66,59 +79,61 @@ 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<float>& 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<double>& 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 IfcGeomObjects::Material& material);
|
||||
void write(const IfcGeom::Material& material);
|
||||
void close();
|
||||
};
|
||||
std::vector<IfcGeomObjects::Material> materials;
|
||||
std::vector<IfcGeom::Material> materials;
|
||||
ColladaEffects effects;
|
||||
public:
|
||||
explicit ColladaMaterials(COLLADASW::StreamWriter& stream)
|
||||
: COLLADASW::LibraryMaterials(&stream)
|
||||
, effects(stream)
|
||||
{}
|
||||
void add(const IfcGeomObjects::Material& material);
|
||||
bool contains(const IfcGeomObjects::Material& material);
|
||||
void add(const IfcGeom::Material& material);
|
||||
bool contains(const IfcGeom::Material& material);
|
||||
void write();
|
||||
};
|
||||
class DeferredObject {
|
||||
public:
|
||||
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::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::vector<int> material_ids;
|
||||
std::vector<IfcGeomObjects::Material> materials;
|
||||
std::vector<IfcGeom::Material> materials;
|
||||
std::vector<std::string> material_references;
|
||||
DeferredObject(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<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)
|
||||
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)
|
||||
, type(type)
|
||||
, obj_id(obj_id)
|
||||
, matrix(matrix)
|
||||
, vertices(vertices)
|
||||
, normals(normals)
|
||||
, indices(indices)
|
||||
, faces(faces)
|
||||
, edges(edges)
|
||||
, material_ids(material_ids)
|
||||
, materials(materials)
|
||||
, material_references(material_references)
|
||||
{}
|
||||
const std::string Name() const;
|
||||
};
|
||||
COLLADABU::NativeString filename;
|
||||
COLLADASW::StreamWriter stream;
|
||||
@@ -136,7 +151,7 @@ private:
|
||||
std::vector<DeferredObject> deferreds;
|
||||
virtual ~ColladaExporter() {}
|
||||
void startDocument(const std::string& unit_name, float unit_magnitude);
|
||||
void 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 write(const std::string& unique_id, const std::string& type, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& materials);
|
||||
void endDocument();
|
||||
};
|
||||
ColladaExporter exporter;
|
||||
@@ -149,14 +164,15 @@ public:
|
||||
{}
|
||||
bool ready();
|
||||
void writeHeader();
|
||||
void writeTesselated(const IfcGeomObjects::IfcGeomObject* o);
|
||||
void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) {}
|
||||
void write(const IfcGeom::TriangulationElement<double>* o);
|
||||
void write(const IfcGeom::BRepElement<double>* /*o*/) {}
|
||||
void finalize();
|
||||
bool isTesselated() const { return true; }
|
||||
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
|
||||
unit_name = name;
|
||||
unit_magnitude = magnitude;
|
||||
}
|
||||
void setFile(IfcParse::IfcFile*) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,17 +20,16 @@
|
||||
#ifndef GEOMETRYSERIALIZER_H
|
||||
#define GEOMETRYSERIALIZER_H
|
||||
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
#include "../ifcconvert/Serializer.h"
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
class GeometrySerializer {
|
||||
class GeometrySerializer : public Serializer {
|
||||
public:
|
||||
virtual bool ready() = 0;
|
||||
virtual void writeHeader() = 0;
|
||||
virtual void finalize() = 0;
|
||||
virtual bool isTesselated() const = 0;
|
||||
virtual ~GeometrySerializer() {}
|
||||
virtual void writeTesselated(const IfcGeomObjects::IfcGeomObject* o) = 0;
|
||||
virtual void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) = 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 void setUnitNameAndMagnitude(const std::string& name, float magnitude) = 0;
|
||||
};
|
||||
|
||||
|
||||
+268
-87
@@ -26,19 +26,37 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#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 "../ifcgeom/IfcGeomObjects.h"
|
||||
#include "../ifcparse/Hdf5Settings.h"
|
||||
#include "../ifcparse/IfcHdf5File.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.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;
|
||||
@@ -51,10 +69,14 @@ void printUsage(const boost::program_options::options_description& generic_optio
|
||||
<< "Converts the geometry in an IFC file into one of the following formats:" << std::endl
|
||||
<< " .obj WaveFront OBJ (a .mtl file is also created)" << std::endl;
|
||||
#ifdef WITH_OPENCOLLADA
|
||||
std::cerr << " .dae Collada Digital Assets Exchange" << std::endl;
|
||||
std::cerr << " .dae Collada Digital Asset Exchange" << std::endl;
|
||||
#endif
|
||||
std::cerr << " .stp STEP Standard for the Exchange of Product Data" << std::endl
|
||||
<< " .igs IGES Initial Graphics Exchange Specification" << std::endl
|
||||
<< " .xml XML Property definitions and decomposition tree" << std::endl
|
||||
<< " .svg SVG Scalable Vector Graphics (2d floor plan)" << std::endl
|
||||
<< " .hdf HDF5 Efficient binary IFC serialization" << std::endl
|
||||
<< " .ifc IFC-SPF Standard p21 IFC serialization" << std::endl
|
||||
<< std::endl
|
||||
<< "Command line options" << std::endl << generic_options << std::endl
|
||||
<< "Advanced options" << std::endl << geom_options << std::endl;
|
||||
@@ -84,35 +106,77 @@ 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::vector<std::string> ignore_types_vector;
|
||||
std::string bounds, hdf5_profile;
|
||||
uint32_t hdf5_chunk_size;
|
||||
|
||||
std::vector<std::string> entity_vector;
|
||||
std::vector<std::string> hdf5_ref_attributes;
|
||||
std::vector<std::string> hdf5_mount_points;
|
||||
|
||||
boost::program_options::options_description geom_options;
|
||||
geom_options.add_options()
|
||||
("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");
|
||||
("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.");
|
||||
|
||||
boost::program_options::options_description cmdline_options;
|
||||
cmdline_options.add(generic_options).add(fileio_options).add(geom_options);
|
||||
@@ -128,13 +192,19 @@ 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 1;
|
||||
return 0;
|
||||
} 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;
|
||||
}
|
||||
@@ -144,23 +214,31 @@ int main(int argc, char** argv) {
|
||||
const bool use_world_coords = vmap.count("use-world-coords") != 0;
|
||||
const bool convert_back_units = vmap.count("convert-back-units") != 0;
|
||||
const bool sew_shells = vmap.count("sew-shells") != 0;
|
||||
#if OCC_VERSION_HEX < 0x60900
|
||||
const bool merge_boolean_operands = vmap.count("merge-boolean-operands") != 0;
|
||||
const bool force_ccw_face_orientation = vmap.count("force-ccw-face-orientation") != 0;
|
||||
#endif
|
||||
const bool disable_opening_subtractions = vmap.count("disable-opening-subtractions") != 0;
|
||||
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> 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");
|
||||
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));
|
||||
}
|
||||
|
||||
const std::string input_filename = vmap["input-file"].as<std::string>();
|
||||
@@ -168,35 +246,117 @@ int main(int argc, char** argv) {
|
||||
// to maintain backwards compatibility with the obsolete IfcObj executable.
|
||||
const std::string output_filename = vmap.count("output-file") == 1
|
||||
? vmap["output-file"].as<std::string>()
|
||||
: change_extension(input_filename, "obj");
|
||||
: change_extension(input_filename, DEFAULT_EXTENSION);
|
||||
|
||||
if (output_filename.size() < 5) {
|
||||
printUsage(generic_options, geom_options);
|
||||
return 1;
|
||||
}
|
||||
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS, use_world_coords);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::WELD_VERTICES, weld_vertices);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::SEW_SHELLS, sew_shells);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::CONVERT_BACK_UNITS, convert_back_units);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::FASTER_BOOLEANS, merge_boolean_operands);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::FORCE_CCW_FACE_ORIENTATION, force_ccw_face_orientation);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::DISABLE_OPENING_SUBTRACTIONS, disable_opening_subtractions);
|
||||
|
||||
std::string output_extension = output_filename.substr(output_filename.size()-4);
|
||||
for (std::string::iterator c = output_extension.begin(); c != output_extension.end(); ++c) {
|
||||
*c = tolower(*c);
|
||||
boost::to_lower(output_extension);
|
||||
|
||||
// If no entities are specified these are the defaults to skip from output
|
||||
if (entity_vector.empty()) {
|
||||
if (output_extension == ".svg") {
|
||||
entities.insert("ifcspace");
|
||||
include_entities = true;
|
||||
} else {
|
||||
entities.insert("ifcopeningelement");
|
||||
entities.insert("ifcspace");
|
||||
}
|
||||
}
|
||||
|
||||
Logger::SetOutput(&std::cout, &log_stream);
|
||||
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");
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS, true);
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true);
|
||||
}
|
||||
serializer = new WaveFrontOBJSerializer(output_filename, mtl_filename);
|
||||
#ifdef WITH_OPENCOLLADA
|
||||
@@ -210,6 +370,15 @@ int main(int argc, char** argv) {
|
||||
// See: http://tracker.dev.opencascade.org/view.php?id=23679
|
||||
IGESControl_Controller::Init();
|
||||
serializer = new IgesSerializer(output_filename);
|
||||
} else if (output_extension == ".svg") {
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
|
||||
serializer = new SvgSerializer(output_filename);
|
||||
if (bounding_width && bounding_height) {
|
||||
((SvgSerializer*) serializer)->setBoundingRectangle(
|
||||
static_cast<double>(*bounding_width),
|
||||
static_cast<double>(*bounding_height)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unknown output filename extension");
|
||||
write_log();
|
||||
@@ -217,30 +386,45 @@ 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);
|
||||
// Parse the file supplied in argv[1]. Returns true on succes.
|
||||
if ( ! IfcGeomObjects::Init(input_filename, &std::cout, &log_stream) ) {
|
||||
|
||||
if (!context_iterator.initialize()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file or no geometrical entities found");
|
||||
write_log();
|
||||
return 1;
|
||||
}
|
||||
|
||||
serializer->setFile(context_iterator.getFile());
|
||||
|
||||
if (convert_back_units) {
|
||||
serializer->setUnitNameAndMagnitude(IfcGeomObjects::GetUnitName(), IfcGeomObjects::GetUnitMagnitude());
|
||||
serializer->setUnitNameAndMagnitude(context_iterator.getUnitName(), static_cast<const float>(context_iterator.getUnitMagnitude()));
|
||||
} else {
|
||||
serializer->setUnitNameAndMagnitude("METER", 1.0f);
|
||||
}
|
||||
@@ -252,35 +436,30 @@ int main(int argc, char** argv) {
|
||||
int old_progress = -1;
|
||||
Logger::Status("Creating geometry...");
|
||||
|
||||
// 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
|
||||
// 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.
|
||||
do {
|
||||
const IfcGeomObjects::IfcObject* geom_object;
|
||||
const IfcGeom::Element<double>* geom_object = context_iterator.get();
|
||||
|
||||
if (serializer->isTesselated()) {
|
||||
geom_object = IfcGeomObjects::Get();
|
||||
serializer->write(static_cast<const IfcGeom::TriangulationElement<double>*>(geom_object));
|
||||
} else {
|
||||
geom_object = IfcGeomObjects::GetShapeModel();
|
||||
serializer->write(static_cast<const IfcGeom::BRepElement<double>*>(geom_object));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
const int progress = context_iterator.progress() / 2;
|
||||
if (old_progress!= progress) Logger::ProgressBar(progress);
|
||||
old_progress = progress;
|
||||
|
||||
} while ( IfcGeomObjects::Next() );
|
||||
} while (context_iterator.next());
|
||||
|
||||
serializer->finalize();
|
||||
delete serializer;
|
||||
@@ -292,6 +471,8 @@ 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() {
|
||||
|
||||
@@ -20,11 +20,10 @@
|
||||
#ifndef IGESSERIALIZER_H
|
||||
#define IGESSERIALIZER_H
|
||||
|
||||
#include <IGESControl_Controller.hxx>
|
||||
#include <IGESControl_Writer.hxx>
|
||||
#include <Interface_Static.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
#include "../ifcconvert/OpenCascadeBasedSerializer.h"
|
||||
|
||||
@@ -43,9 +42,10 @@ public:
|
||||
void finalize() {
|
||||
writer.Write(out_filename.c_str());
|
||||
}
|
||||
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
|
||||
void setUnitNameAndMagnitude(const std::string& /*name*/, float magnitude) {
|
||||
const char* symbol = getSymbolForUnitMagnitude(magnitude);
|
||||
if (symbol) {
|
||||
Interface_Static::SetCVal("xstep.cascade.unit", symbol);
|
||||
Interface_Static::SetCVal("write.iges.unit", symbol);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include <BRepBuilderAPI_GTransform.hxx>
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
|
||||
#include <Standard_Version.hxx>
|
||||
|
||||
#include "OpenCascadeBasedSerializer.h"
|
||||
|
||||
bool OpenCascadeBasedSerializer::ready() {
|
||||
@@ -34,18 +36,19 @@ bool OpenCascadeBasedSerializer::ready() {
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
void OpenCascadeBasedSerializer::writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) {
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->mesh().begin(); it != o->mesh().end(); ++ it) {
|
||||
void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement<double>* o) {
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) {
|
||||
gp_GTrsf gtrsf = it->Placement();
|
||||
|
||||
// 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++]);
|
||||
|
||||
|
||||
const gp_Trsf& o_trsf = o->transformation().data();
|
||||
gtrsf.PreMultiply(o_trsf);
|
||||
|
||||
if (o->geometry().settings().convert_back_units()) {
|
||||
gp_Trsf scale;
|
||||
scale.SetScaleFactor(1.0 / o->geometry().settings().unit_magnitude());
|
||||
gtrsf.PreMultiply(scale);
|
||||
}
|
||||
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
|
||||
bool trsf_valid = false;
|
||||
@@ -64,18 +67,18 @@ void OpenCascadeBasedSerializer::writeShapeModel(const IfcGeomObjects::IfcGeomSh
|
||||
}
|
||||
|
||||
#define RATHER_SMALL (1e-3)
|
||||
#define ALMOST_THE_SAME(a,b) (fabs(a-b) < RATHER_SMALL)
|
||||
#define APPROXIMATELY_THE_SAME(a,b) (fabs(a-b) < RATHER_SMALL)
|
||||
|
||||
const char* OpenCascadeBasedSerializer::getSymbolForUnitMagnitude(float mag) {
|
||||
if (ALMOST_THE_SAME(mag, 0.001f)) {
|
||||
if (APPROXIMATELY_THE_SAME(mag, 0.001f)) {
|
||||
return "MM";
|
||||
} else if (ALMOST_THE_SAME(mag, 0.01f)) {
|
||||
} else if (APPROXIMATELY_THE_SAME(mag, 0.01f)) {
|
||||
return "CM";
|
||||
} else if (ALMOST_THE_SAME(mag, 1.0f)) {
|
||||
} else if (APPROXIMATELY_THE_SAME(mag, 1.0f)) {
|
||||
return "M";
|
||||
} else if (ALMOST_THE_SAME(mag, 0.3048f)) {
|
||||
} else if (APPROXIMATELY_THE_SAME(mag, 0.3048f)) {
|
||||
return "FT";
|
||||
} else if (ALMOST_THE_SAME(mag, 0.0254f)) {
|
||||
} else if (APPROXIMATELY_THE_SAME(mag, 0.0254f)) {
|
||||
return "INCH";
|
||||
} else {
|
||||
return 0;
|
||||
|
||||
@@ -20,13 +20,15 @@
|
||||
#ifndef OPENCASCADEBASEDSERIALIZER_H
|
||||
#define OPENCASCADEBASEDSERIALIZER_H
|
||||
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
#include "../ifcgeom/IfcGeomIterator.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)
|
||||
@@ -35,12 +37,12 @@ public:
|
||||
{}
|
||||
virtual ~OpenCascadeBasedSerializer() {}
|
||||
void writeHeader() {}
|
||||
void writeMaterial(const IfcGeom::SurfaceStyle& style) {}
|
||||
bool ready();
|
||||
virtual void writeShape(const TopoDS_Shape& shape) = 0;
|
||||
void writeTesselated(const IfcGeomObjects::IfcGeomObject* o) {}
|
||||
void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o);
|
||||
void write(const IfcGeom::TriangulationElement<double>* /*o*/) {}
|
||||
void write(const IfcGeom::BRepElement<double>* o);
|
||||
bool isTesselated() const { return false; }
|
||||
void setFile(IfcParse::IfcFile*) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -17,22 +17,19 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file defines the shared pointer implementation to use, shared pointers *
|
||||
* are used extensively in IfcOpenShell *
|
||||
* *
|
||||
********************************************************************************/
|
||||
#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;
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <tr1/memory>
|
||||
#define SHARED_PTR std::tr1::shared_ptr
|
||||
#else
|
||||
#ifdef _MSC_VER
|
||||
#include <memory>
|
||||
#define SHARED_PTR std::tr1::shared_ptr
|
||||
#else
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#define SHARED_PTR boost::shared_ptr
|
||||
#endif
|
||||
#endif
|
||||
@@ -20,11 +20,10 @@
|
||||
#ifndef STEPSERIALIZER_H
|
||||
#define STEPSERIALIZER_H
|
||||
|
||||
#include <STEPControl_Controller.hxx>
|
||||
#include <STEPControl_Writer.hxx>
|
||||
#include <Interface_Static.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
#include "../ifcconvert/OpenCascadeBasedSerializer.h"
|
||||
|
||||
@@ -49,9 +48,10 @@ public:
|
||||
writer.Write(out_filename.c_str());
|
||||
std::cout.rdbuf(sb);
|
||||
}
|
||||
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
|
||||
void setUnitNameAndMagnitude(const std::string& /*name*/, float magnitude) {
|
||||
const char* symbol = getSymbolForUnitMagnitude(magnitude);
|
||||
if (symbol) {
|
||||
Interface_Static::SetCVal("xstep.cascade.unit", symbol);
|
||||
Interface_Static::SetCVal("write.step.unit", symbol);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file defines default materials for several IFC datatypes *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef SURFACESTYLE_H
|
||||
#define SURFACESTYLE_H
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <array>
|
||||
|
||||
class SurfaceStyle {
|
||||
public:
|
||||
class ColorComponent {
|
||||
private:
|
||||
std::array<double, 3> data;
|
||||
public:
|
||||
ColorComponent(double r, double g, double b) {
|
||||
data[0] = r; data[1] = g; data[2] = b;
|
||||
}
|
||||
const double& R() const { return data[0]; }
|
||||
const double& G() const { return data[1]; }
|
||||
const double& B() const { return data[2]; }
|
||||
double& R() { return data[0]; }
|
||||
double& G() { return data[1]; }
|
||||
double& B() { return data[2]; }
|
||||
};
|
||||
private:
|
||||
std::string name;
|
||||
ColorComponent diffuse, specular, ambient;
|
||||
double transparency;
|
||||
double specularity;
|
||||
public:
|
||||
SurfaceStyle(const std::string& name,
|
||||
double dr = 0.7, double dg = 0.7, double db = 0.7,
|
||||
double sr = 0.2, double sg = 0.2, double sb = 0.2,
|
||||
double ar = 0.1, double ag = 0.1, double ab = 0.1,
|
||||
double Ns = 10.0, double Tr = 1.0)
|
||||
: name(name)
|
||||
, diffuse(dr, dg, db)
|
||||
, specular(sr, sg, sb)
|
||||
, ambient(ar, ag, ab)
|
||||
, transparency(Tr)
|
||||
, specularity(Ns)
|
||||
{}
|
||||
const std::string& Name() const { return name; }
|
||||
const ColorComponent& Diffuse() const { return diffuse; }
|
||||
const ColorComponent& Specular() const { return specular; }
|
||||
const ColorComponent& Ambient() const { return ambient; }
|
||||
double Transparency() const { return transparency; }
|
||||
double Specularity() const { return specularity; }
|
||||
};
|
||||
|
||||
SurfaceStyle GetDefaultMaterial(const std::string& s);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,355 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Copyright 2015 IfcOpenShell and ROOT B.V. *
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
|
||||
#include <gp_Pln.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
#include <BRepBuilderAPI_GTransform.hxx>
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepAlgo_Section.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <BRepAlgoAPI_Section.hxx>
|
||||
#include <ShapeAnalysis_FreeBounds.hxx>
|
||||
#include <TopTools_HSequenceOfShape.hxx>
|
||||
|
||||
#include <Geom_Curve.hxx>
|
||||
#include <Geom_Line.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include <gp_Ax22d.hxx>
|
||||
#include <Standard_Version.hxx>
|
||||
#include "../ifcparse/IfcGlobalId.h"
|
||||
|
||||
#include "SvgSerializer.h"
|
||||
|
||||
const double PI2 = M_PI * 2.;
|
||||
|
||||
bool SvgSerializer::ready() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void SvgSerializer::write(path_object& p, const TopoDS_Wire& wire) {
|
||||
/* ShapeFix_Wire fix;
|
||||
Handle(ShapeExtend_WireData) data = new ShapeExtend_WireData;
|
||||
for (TopExp_Explorer edges(result, TopAbs_EDGE); edges.More(); edges.Next()) {
|
||||
data->Add(edges.Current());
|
||||
}
|
||||
fix.Load(data);
|
||||
fix.FixReorder();
|
||||
fix.FixConnected();
|
||||
const TopoDS_Wire fixed_wire = fix.Wire(); */
|
||||
|
||||
bool first = true;
|
||||
util::string_buffer path;
|
||||
path.add(" <path style=\"stroke:black; fill:none;\" d=\"");
|
||||
for (TopExp_Explorer edges(wire, TopAbs_EDGE); edges.More(); edges.Next()) {
|
||||
const TopoDS_Edge& edge = TopoDS::Edge(edges.Current());
|
||||
|
||||
double u1, u2;
|
||||
Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, u1, u2);
|
||||
|
||||
const bool reversed = edge.Orientation() == TopAbs_REVERSED;
|
||||
|
||||
gp_Pnt p1, p2;
|
||||
curve->D0(u1, p1);
|
||||
curve->D0(u2, p2);
|
||||
|
||||
if (reversed) {
|
||||
std::swap(p1, p2);
|
||||
}
|
||||
|
||||
if (first) {
|
||||
path.add("M");
|
||||
addXCoordinate(path.add(p1.X()));
|
||||
path.add(",");
|
||||
addYCoordinate(path.add(p1.Y()));
|
||||
|
||||
growBoundingBox(p1.X(), p1.Y());
|
||||
}
|
||||
|
||||
growBoundingBox(p2.X(), p2.Y());
|
||||
|
||||
Handle(Standard_Type) ty = curve->DynamicType();
|
||||
|
||||
if (ty == STANDARD_TYPE(Geom_Circle) || ty == STANDARD_TYPE(Geom_Ellipse)) {
|
||||
Handle(Geom_Conic) conic = Handle(Geom_Conic)::DownCast(curve);
|
||||
const bool mirrored = conic->Position().Axis().Direction().Z() < 0;
|
||||
|
||||
double r1, r2;
|
||||
bool larger_arc_segment = (fmod(u2 - u1 + PI2, PI2) > M_PI);
|
||||
bool positive_direction = (u2 > u1);
|
||||
|
||||
if (mirrored != reversed) {
|
||||
// In case the local coordinate system is mirrored
|
||||
// the direction is reversed.
|
||||
positive_direction = !positive_direction;
|
||||
}
|
||||
|
||||
if (ty == STANDARD_TYPE(Geom_Circle)) {
|
||||
Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(curve);
|
||||
r1 = r2 = circle->Radius();
|
||||
} else {
|
||||
Handle(Geom_Ellipse) ellipse = Handle(Geom_Ellipse)::DownCast(curve);
|
||||
r1 = ellipse->MajorRadius();
|
||||
r2 = ellipse->MinorRadius();
|
||||
}
|
||||
|
||||
// Calculate the angle between 2d vecs to have signed result
|
||||
const gp_Dir& d = conic->Position().XDirection();
|
||||
const gp_Dir2d d2(d.X(), d.Y());
|
||||
const double ang = d2.Angle(gp::DX2d());
|
||||
|
||||
// Write radii
|
||||
path.add(" A");
|
||||
addSizeComponent(path.add(r1));
|
||||
path.add(",");
|
||||
addSizeComponent(path.add(r2));
|
||||
|
||||
// Write X-axis rotation
|
||||
{ std::stringstream ss; ss << " " << ang << " ";
|
||||
path.add(ss.str()); }
|
||||
|
||||
// Write large-arc-flag and sweep-flag
|
||||
path.add(std::string(1, '0'+static_cast<int>(larger_arc_segment)));
|
||||
path.add(",");
|
||||
path.add(std::string(1, '0'+static_cast<int>(positive_direction)));
|
||||
|
||||
path.add(" ");
|
||||
|
||||
// Write arc end point
|
||||
xcoords.push_back(path.add(p2.X()));
|
||||
path.add(",");
|
||||
ycoords.push_back(path.add(p2.Y()));
|
||||
} else {
|
||||
// Either a Geom_Line or something unimplemented,
|
||||
// drawn as a straight line segment.
|
||||
path.add(" L");
|
||||
xcoords.push_back(path.add(p2.X()));
|
||||
path.add(",");
|
||||
ycoords.push_back(path.add(p2.Y()));
|
||||
}
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
path.add("\"/>\n");
|
||||
p.second.push_back(path);
|
||||
}
|
||||
|
||||
SvgSerializer::path_object& SvgSerializer::start_path(IfcSchema::IfcBuildingStorey* storey, const std::string& id) {
|
||||
SvgSerializer::path_object& p = paths.insert(std::make_pair(storey, path_object()))->second;
|
||||
p.first = id;
|
||||
return p;
|
||||
}
|
||||
|
||||
void SvgSerializer::write(const IfcGeom::BRepElement<double>* o) {
|
||||
IfcSchema::IfcBuildingStorey* storey = 0;
|
||||
IfcSchema::IfcObjectDefinition* obdef = static_cast<IfcSchema::IfcObjectDefinition*>(file->entityById(o->id()));
|
||||
|
||||
#ifndef USE_IFC4
|
||||
typedef IfcSchema::IfcRelDecomposes decomposition_element;
|
||||
#else
|
||||
typedef IfcSchema::IfcRelAggregates decomposition_element;
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
// Iterate over the decomposing element to find the parent IfcBuildingStorey
|
||||
decomposition_element::list::ptr decomposes = obdef->Decomposes();
|
||||
if (!decomposes->size()) {
|
||||
if (obdef->declaration().is(IfcSchema::Type::IfcElement)) {
|
||||
IfcSchema::IfcRelContainedInSpatialStructure::list::ptr containment = ((IfcSchema::IfcElement*)obdef)->ContainedInStructure();
|
||||
if (!containment->size()) {
|
||||
break;
|
||||
}
|
||||
for (IfcSchema::IfcRelContainedInSpatialStructure::list::it it = containment->begin(); it != containment->end(); ++it) {
|
||||
IfcSchema::IfcRelContainedInSpatialStructure* container = *it;
|
||||
if (container->RelatingStructure() != obdef) {
|
||||
obdef = container->RelatingStructure();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
for (decomposition_element::list::it it = decomposes->begin(); it != decomposes->end(); ++it) {
|
||||
decomposition_element* decompose = *it;
|
||||
if (decompose->RelatingObject() != obdef) {
|
||||
obdef = decompose->RelatingObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (obdef->declaration().is(IfcSchema::Type::IfcBuildingStorey)) {
|
||||
storey = static_cast<IfcSchema::IfcBuildingStorey*>(obdef);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!storey) return;
|
||||
|
||||
path_object& p = start_path(storey, nameElement(o));
|
||||
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) {
|
||||
gp_GTrsf gtrsf = it->Placement();
|
||||
|
||||
const gp_Trsf& o_trsf = o->transformation().data();
|
||||
gtrsf.PreMultiply(o_trsf);
|
||||
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
|
||||
bool trsf_valid = false;
|
||||
gp_Trsf trsf;
|
||||
try {
|
||||
trsf = gtrsf.Trsf();
|
||||
trsf_valid = true;
|
||||
} catch (...) {}
|
||||
|
||||
const TopoDS_Shape moved_shape = trsf_valid
|
||||
? BRepBuilderAPI_Transform(s, trsf, true).Shape()
|
||||
: BRepBuilderAPI_GTransform(s, gtrsf, true).Shape();
|
||||
|
||||
const double inf = std::numeric_limits<double>::infinity();
|
||||
double zmin = inf;
|
||||
double zmax = -inf;
|
||||
{TopExp_Explorer exp(moved_shape, TopAbs_VERTEX);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
const TopoDS_Vertex& vertex = TopoDS::Vertex(exp.Current());
|
||||
gp_Pnt pnt = BRep_Tool::Pnt(vertex);
|
||||
if (pnt.Z() < zmin) { zmin = pnt.Z(); }
|
||||
if (pnt.Z() > zmax) { zmax = pnt.Z(); }
|
||||
}}
|
||||
|
||||
if (section_height) {
|
||||
if (zmin > section_height || zmax < section_height) continue;
|
||||
} else {
|
||||
if (zmin == inf || (zmax - zmin) < 1.) continue;
|
||||
}
|
||||
|
||||
const double cut_z = section_height.get_value_or(zmin + 1.);
|
||||
|
||||
// Create a horizontal cross section 1 meter above the bottom point of the shape
|
||||
TopoDS_Shape result = BRepAlgoAPI_Section(moved_shape, gp_Pln(gp_Pnt(0, 0, cut_z), gp::DZ()));
|
||||
|
||||
Handle(TopTools_HSequenceOfShape) edges = new TopTools_HSequenceOfShape();
|
||||
Handle(TopTools_HSequenceOfShape) wires = new TopTools_HSequenceOfShape();
|
||||
{TopExp_Explorer exp(result, TopAbs_EDGE);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
edges->Append(exp.Current());
|
||||
}}
|
||||
ShapeAnalysis_FreeBounds::ConnectEdgesToWires(edges, 1e-5, false, wires);
|
||||
|
||||
gp_Pnt prev;
|
||||
|
||||
for (int i = 1; i <= wires->Length(); ++i) {
|
||||
const TopoDS_Wire& wire = TopoDS::Wire(wires->Value(i));
|
||||
write(p, wire);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SvgSerializer::setBoundingRectangle(double width, double height) {
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->rescale = true;
|
||||
}
|
||||
|
||||
void SvgSerializer::finalize() {
|
||||
|
||||
if (rescale) {
|
||||
// Scale the resulting image to a bounding rectangle specified by command line arguments
|
||||
const double dx = xmax - xmin;
|
||||
const double dy = ymax - ymin;
|
||||
|
||||
double sc = 1.;
|
||||
|
||||
if (dx / width > dy / height) {
|
||||
sc = width / dx;
|
||||
} else {
|
||||
sc = height / dy;
|
||||
}
|
||||
|
||||
const double cx = xmin * sc;
|
||||
const double cy = ymin * sc;
|
||||
|
||||
{std::vector< boost::shared_ptr<util::string_buffer::float_item> >::const_iterator it;
|
||||
for (it = xcoords.begin(); it != xcoords.end(); ++it) {
|
||||
double& v = (*it)->value();
|
||||
v = v * sc - cx;
|
||||
}
|
||||
for (it = ycoords.begin(); it != ycoords.end(); ++it) {
|
||||
double& v = (*it)->value();
|
||||
v = v * sc - cy;
|
||||
}
|
||||
for (it = radii.begin(); it != radii.end(); ++it) {
|
||||
(*it)->value() *= sc;
|
||||
}}
|
||||
}
|
||||
|
||||
std::multimap<IfcSchema::IfcBuildingStorey*, path_object>::const_iterator it;
|
||||
|
||||
IfcSchema::IfcBuildingStorey* previous = 0;
|
||||
bool first = true;
|
||||
for (it = paths.begin(); it != paths.end(); ++it) {
|
||||
if (it->first != previous || first) {
|
||||
if (!first) {
|
||||
svg_file << " </g>\n";
|
||||
}
|
||||
std::ostringstream oss;
|
||||
svg_file << " <g " << nameElement(it->first) << ">\n";
|
||||
}
|
||||
svg_file << " <g " << it->second.first << ">\n";
|
||||
std::vector<util::string_buffer>::const_iterator jt;
|
||||
for (jt = it->second.second.begin(); jt != it->second.second.end(); ++jt) {
|
||||
svg_file << jt->str();
|
||||
}
|
||||
svg_file << " </g>\n";
|
||||
previous = it->first;
|
||||
first = false;
|
||||
}
|
||||
|
||||
svg_file << " </g>\n";
|
||||
svg_file << "</svg>" << std::endl;
|
||||
}
|
||||
|
||||
void SvgSerializer::writeHeader() {
|
||||
svg_file << "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n";
|
||||
}
|
||||
|
||||
std::string SvgSerializer::nameElement(const IfcGeom::Element<double>* elem) {
|
||||
std::ostringstream oss;
|
||||
const std::string type = "product";
|
||||
oss << "id=\"" << type << "-" << elem->unique_id() << "\"";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string SvgSerializer::nameElement(const IfcSchema::IfcProduct* elem) {
|
||||
std::ostringstream oss;
|
||||
const std::string type = elem->declaration().is(IfcSchema::Type::IfcBuildingStorey) ? "storey" : "product";
|
||||
oss << "id=\"product-" << IfcParse::IfcGlobalId(elem->GlobalId()).formatted() << "\"";
|
||||
return oss.str();
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Copyright 2015 IfcOpenShell and ROOT B.V. *
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef SVGSERIALIZER_H
|
||||
#define SVGSERIALIZER_H
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <limits>
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
#include "../ifcconvert/GeometrySerializer.h"
|
||||
#include "../ifcconvert/util.h"
|
||||
|
||||
class SvgSerializer : public GeometrySerializer {
|
||||
public:
|
||||
typedef std::pair<std::string, std::vector<util::string_buffer> > path_object;
|
||||
protected:
|
||||
std::ofstream svg_file;
|
||||
double xmin, ymin, xmax, ymax, width, height;
|
||||
boost::optional<double> section_height;
|
||||
bool rescale;
|
||||
std::multimap<IfcSchema::IfcBuildingStorey*, path_object> paths;
|
||||
std::vector< boost::shared_ptr<util::string_buffer::float_item> > xcoords;
|
||||
std::vector< boost::shared_ptr<util::string_buffer::float_item> > ycoords;
|
||||
std::vector< boost::shared_ptr<util::string_buffer::float_item> > radii;
|
||||
IfcParse::IfcFile* file;
|
||||
public:
|
||||
explicit SvgSerializer(const std::string& out_filename)
|
||||
: GeometrySerializer()
|
||||
, svg_file(out_filename.c_str())
|
||||
, xmin(+std::numeric_limits<double>::infinity())
|
||||
, xmax(-std::numeric_limits<double>::infinity())
|
||||
, ymin(+std::numeric_limits<double>::infinity())
|
||||
, ymax(-std::numeric_limits<double>::infinity())
|
||||
, rescale(false)
|
||||
, file(0)
|
||||
{}
|
||||
virtual void addXCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { xcoords.push_back(fi); }
|
||||
virtual void addYCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { ycoords.push_back(fi); }
|
||||
virtual void addSizeComponent(const boost::shared_ptr<util::string_buffer::float_item>& fi) { radii.push_back(fi); }
|
||||
virtual void growBoundingBox(double x, double y) { if (x < xmin) xmin = x; if (x > xmax) xmax = x; if (y < ymin) ymin = y; if (y > ymax) ymax = y; }
|
||||
virtual ~SvgSerializer() {}
|
||||
virtual void writeHeader();
|
||||
virtual bool ready();
|
||||
virtual void write(const IfcGeom::TriangulationElement<double>* /*o*/) {}
|
||||
virtual void write(const IfcGeom::BRepElement<double>* o);
|
||||
virtual void write(path_object& p, const TopoDS_Wire& wire);
|
||||
virtual path_object& start_path(IfcSchema::IfcBuildingStorey* storey, const std::string& id);
|
||||
virtual bool isTesselated() const { return false; }
|
||||
virtual void finalize();
|
||||
virtual void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
|
||||
virtual void setFile(IfcParse::IfcFile* f) { file = f; }
|
||||
virtual void setBoundingRectangle(double width, double height);
|
||||
virtual void setSectionHeight(double h) { section_height = h; }
|
||||
virtual std::string nameElement(const IfcGeom::Element<double>* elem);
|
||||
virtual std::string nameElement(const IfcSchema::IfcProduct* elem);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -17,12 +17,13 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <limits>
|
||||
#include <iomanip>
|
||||
|
||||
#include "../ifcgeom/IfcGeomRenderStyles.h"
|
||||
|
||||
#include "WavefrontObjSerializer.h"
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
bool WaveFrontOBJSerializer::ready() {
|
||||
return obj_stream.is_open() && mtl_stream.is_open();
|
||||
}
|
||||
@@ -43,7 +44,7 @@ void WaveFrontOBJSerializer::writeHeader() {
|
||||
mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n";
|
||||
}
|
||||
|
||||
void WaveFrontOBJSerializer::writeMaterial(const IfcGeomObjects::Material& style) {
|
||||
void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style) {
|
||||
mtl_stream << "newmtl " << style.name() << "\n";
|
||||
if (style.hasDiffuse()) {
|
||||
const double* diffuse = style.diffuse();
|
||||
@@ -65,25 +66,24 @@ void WaveFrontOBJSerializer::writeMaterial(const IfcGeomObjects::Material& style
|
||||
}
|
||||
}
|
||||
}
|
||||
void WaveFrontOBJSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject* o) {
|
||||
void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<double>* o) {
|
||||
|
||||
std::string tmp = o->name().empty() ? o->guid() : o->name();
|
||||
|
||||
std::replace( tmp.begin(), tmp.end(), ' ', '_');
|
||||
const std::string name = tmp;
|
||||
obj_stream << "g " << name << "\n";
|
||||
obj_stream << "g " << o->unique_id() << "\n";
|
||||
obj_stream << "s 1" << "\n";
|
||||
|
||||
const IfcGeomObjects::IfcRepresentationTriangulation& mesh = o->mesh();
|
||||
obj_stream << std::setprecision(std::numeric_limits<double>::digits10);
|
||||
|
||||
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
|
||||
|
||||
const int vcount = mesh.verts().size() / 3;
|
||||
for ( std::vector<float>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) {
|
||||
const int vcount = (int)mesh.verts().size() / 3;
|
||||
for ( std::vector<double>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) {
|
||||
const double x = *(it++);
|
||||
const double y = *(it++);
|
||||
const double z = *(it++);
|
||||
obj_stream << "v " << x << " " << y << " " << z << "\n";
|
||||
}
|
||||
for ( std::vector<float>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) {
|
||||
|
||||
for ( std::vector<double>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) {
|
||||
const double x = *(it++);
|
||||
const double y = *(it++);
|
||||
const double z = *(it++);
|
||||
@@ -97,12 +97,7 @@ void WaveFrontOBJSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject
|
||||
|
||||
const int material_id = *(material_it++);
|
||||
if (material_id != previous_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 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()) {
|
||||
@@ -116,6 +111,38 @@ void WaveFrontOBJSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject
|
||||
const int v2 = *(it++)+vcount_total;
|
||||
const int v3 = *(it++)+vcount_total;
|
||||
obj_stream << "f " << v1 << "//" << v1 << " " << v2 << "//" << v2 << " " << v3 << "//" << v3 << "\n";
|
||||
|
||||
}
|
||||
vcount_total += vcount;
|
||||
|
||||
std::set<int> faces_set (mesh.faces().begin(), mesh.faces().end());
|
||||
const std::vector<int>& edges = mesh.edges();
|
||||
|
||||
for ( std::vector<int>::const_iterator it = edges.begin(); it != edges.end(); ) {
|
||||
const int i1 = *(it++);
|
||||
const int i2 = *(it++);
|
||||
|
||||
if (faces_set.find(i1) != faces_set.end() || faces_set.find(i2) != faces_set.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int material_id = *(material_it++);
|
||||
|
||||
if (material_id != previous_material_id) {
|
||||
const IfcGeom::Material& material = mesh.materials()[material_id];
|
||||
const std::string material_name = material.name();
|
||||
obj_stream << "usemtl " << material_name << "\n";
|
||||
if (materials.find(material_name) == materials.end()) {
|
||||
writeMaterial(material);
|
||||
materials.insert(material_name);
|
||||
}
|
||||
previous_material_id = material_id;
|
||||
}
|
||||
|
||||
const int v1 = i1 + vcount_total;
|
||||
const int v2 = i2 + vcount_total;
|
||||
|
||||
obj_stream << "l " << v1 << " " << v2 << "\n";
|
||||
}
|
||||
|
||||
vcount_total += vcount;
|
||||
}
|
||||
|
||||
@@ -44,12 +44,13 @@ public:
|
||||
virtual ~WaveFrontOBJSerializer() {}
|
||||
bool ready();
|
||||
void writeHeader();
|
||||
void writeMaterial(const IfcGeomObjects::Material& style);
|
||||
void writeTesselated(const IfcGeomObjects::IfcGeomObject* o);
|
||||
void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) {}
|
||||
void writeMaterial(const IfcGeom::Material& style);
|
||||
void write(const IfcGeom::TriangulationElement<double>* o);
|
||||
void write(const IfcGeom::BRepElement<double>* /*o*/) {}
|
||||
void finalize() {}
|
||||
bool isTesselated() const { return true; }
|
||||
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {}
|
||||
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
|
||||
void setFile(IfcParse::IfcFile*) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,293 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef XMLSERIALIZER_H
|
||||
#define XMLSERIALIZER_H
|
||||
|
||||
#include "../ifcconvert/Serializer.h"
|
||||
|
||||
class XmlSerializer : public Serializer {
|
||||
private:
|
||||
IfcParse::IfcFile* file;
|
||||
std::string xml_filename;
|
||||
public:
|
||||
XmlSerializer(const std::string& xml_filename)
|
||||
: Serializer()
|
||||
, xml_filename(xml_filename)
|
||||
{}
|
||||
|
||||
bool ready() { return true; }
|
||||
void writeHeader() {}
|
||||
void finalize();
|
||||
void setFile(IfcParse::IfcFile* f) { file = f; }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
|
||||
#include "../ifcconvert/util.h"
|
||||
|
||||
using namespace util;
|
||||
|
||||
boost::shared_ptr<string_buffer::string_item> string_buffer::add(const std::string& s) {
|
||||
boost::shared_ptr<string_item> i = boost::shared_ptr<string_item>(new string_item(s));
|
||||
items.push_back(i);
|
||||
return i;
|
||||
}
|
||||
boost::shared_ptr<string_buffer::float_item> string_buffer::add(const double& d) {
|
||||
boost::shared_ptr<float_item> i = boost::shared_ptr<float_item>(new float_item(d));
|
||||
items.push_back(i);
|
||||
return i;
|
||||
}
|
||||
std::string string_buffer::str() const {
|
||||
std::stringstream ss;
|
||||
for (std::vector< boost::shared_ptr<item> >::const_iterator it = items.begin(); it != items.end(); ++it) {
|
||||
ss << (**it).str();
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCCONVERT_UTIL_H
|
||||
#define IFCCONVERT_UTIL_H
|
||||
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace util {
|
||||
class string_buffer {
|
||||
public:
|
||||
class item {
|
||||
public:
|
||||
virtual std::string str() const = 0;
|
||||
};
|
||||
class string_item : public item {
|
||||
std::string s;
|
||||
public:
|
||||
string_item(const std::string& s) : s(s) {}
|
||||
void assign(const std::string& s) { this->s = s; }
|
||||
const std::string& value() const { return s; }
|
||||
std::string& value() { return s; }
|
||||
std::string str() const { return s; }
|
||||
};
|
||||
class float_item : public item {
|
||||
double d;
|
||||
public:
|
||||
float_item(const double& d) : d(d) {}
|
||||
void assign(const double& d) { this->d = d; }
|
||||
const double& value() const { return d; }
|
||||
double& value() { return d; }
|
||||
std::string str() const { std::stringstream ss; ss << d; return ss.str(); }
|
||||
};
|
||||
private:
|
||||
std::vector< boost::shared_ptr<item> > items;
|
||||
void clear();
|
||||
void assign(const std::vector< boost::shared_ptr<item> >& other);
|
||||
public:
|
||||
boost::shared_ptr<string_item> add(const std::string& s);
|
||||
boost::shared_ptr<float_item> add(const double& d);
|
||||
std::string str() const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,71 +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 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
|
||||
@@ -1,779 +0,0 @@
|
||||
header = """
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
""".strip()
|
||||
|
||||
###############################################################################
|
||||
# #
|
||||
# This file can be used to generate C++ code from Express schema files. The #
|
||||
# generated code works alongside the IfcOpenShell IfcParse library. This #
|
||||
# script has only been tested on IFC2X3_TC1.exp and will most probably not #
|
||||
# work on any other schemas. #
|
||||
# #
|
||||
# Note this script uses funcparserlib, which is available at: #
|
||||
# http://code.google.com/p/funcparserlib/ #
|
||||
# The script only works with revision 30f7ee896bc9 because it uses the some() #
|
||||
# parser and is incompatible with other changes as well. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import os, sys
|
||||
import IfcDocumentation
|
||||
|
||||
filename = sys.argv[1]
|
||||
|
||||
#
|
||||
# A class to split the Express schema files into seperate tokens
|
||||
#
|
||||
class Tokenizer(object):
|
||||
comment = ['(*','*)']
|
||||
termchars = ',;()=[]:'
|
||||
def __init__(self, fn):
|
||||
if hasattr(fn,'read'): object.__setattr__(self,'f',fn)
|
||||
else: object.__setattr__(self,'f',open(fn,'rb'))
|
||||
def __getattr__(self, name):
|
||||
return getattr(self.f, name)
|
||||
def __setattr__(self, name, value):
|
||||
setattr(self.f, name, value)
|
||||
def __iter__(self): return self
|
||||
def next(self):
|
||||
def get():
|
||||
buffer = ''
|
||||
in_comment = False
|
||||
in_string = False
|
||||
offset = self.tell()
|
||||
while True:
|
||||
c = self.read(2)
|
||||
if len(c) < 2: raise StopIteration
|
||||
if c in Tokenizer.comment:
|
||||
in_comment = c == Tokenizer.comment[0]
|
||||
continue
|
||||
if in_string and c == "''":
|
||||
buffer += "'"
|
||||
continue
|
||||
self.seek(-1,1)
|
||||
if not in_string and c[0].isspace():
|
||||
if ( len(buffer) ): return buffer
|
||||
else:
|
||||
offset = self.tell()
|
||||
continue
|
||||
if not in_comment:
|
||||
if len(buffer) and (c[0] in Tokenizer.termchars or buffer[-1] in Tokenizer.termchars):
|
||||
self.seek(-1,1)
|
||||
return buffer
|
||||
buffer += c[0]
|
||||
return get()
|
||||
|
||||
#
|
||||
# Some global variables to keep track of variable names
|
||||
#
|
||||
express_to_cpp = {
|
||||
'BOOLEAN':'bool',
|
||||
'LOGICAL':'bool',
|
||||
'INTEGER':'int',
|
||||
'REAL':'double',
|
||||
'NUMBER':'double',
|
||||
'STRING':'std::string'
|
||||
}
|
||||
schema_version = ''
|
||||
enumerations = set()
|
||||
selections = set()
|
||||
entity_names = set()
|
||||
simple_types = {}
|
||||
selectable_simple_types = set()
|
||||
argument_count = {}
|
||||
parent_relations = {}
|
||||
argument_names_and_types = {}
|
||||
entity_map = {}
|
||||
|
||||
#
|
||||
# Since inherited arguments of Express entities are placed in sequence before the
|
||||
# non-inherited ones, we need to keep track of how many inherited arguments exist
|
||||
#
|
||||
def argument_start(c):
|
||||
if c not in parent_relations: return 0
|
||||
i = 0
|
||||
while True:
|
||||
c = parent_relations[c]
|
||||
i += argument_count[c] if c in argument_count else 0
|
||||
if not (c in parent_relations): break
|
||||
return i
|
||||
|
||||
def parent_arguments(c):
|
||||
if c not in parent_relations: return []
|
||||
l = []
|
||||
while True:
|
||||
c = parent_relations[c]
|
||||
i += argument_count[c] if c in argument_count else 0
|
||||
if not (c in parent_relations): break
|
||||
return []
|
||||
|
||||
#
|
||||
# Every constructor also initializes their parent class members, hence they
|
||||
# need be stored as well.
|
||||
#
|
||||
def parent_arguments(c):
|
||||
if c not in parent_relations: return []
|
||||
l = []
|
||||
while True:
|
||||
c = parent_relations[c]
|
||||
i += argument_count[c] if c in argument_count else 0
|
||||
if not (c in parent_relations): break
|
||||
return []
|
||||
|
||||
#
|
||||
# Several classes to generate code from Express types and entities
|
||||
#
|
||||
class ArrayType:
|
||||
def __init__(self,l):
|
||||
self.type = express_to_cpp.get(l[3],l[3])
|
||||
self.upper = l[2]
|
||||
self.lower = l[1]
|
||||
def is_select_list(self): return self.type in selections
|
||||
def __str__(self):
|
||||
if self.type in entity_names:
|
||||
return "SHARED_PTR< IfcTemplatedEntityList< %s > >"%self.type
|
||||
elif self.type in selections:
|
||||
return "SHARED_PTR< IfcTemplatedEntityList< IfcAbstractSelect > >"
|
||||
else:
|
||||
return "std::vector< %(type)s > /*[%(lower)s:%(upper)s]*/"%self.__dict__
|
||||
def is_shared_ptr(self): return self.type in entity_names or self.type in selections
|
||||
def type_enum(self):
|
||||
if self.type in simple_types:
|
||||
t = simple_types[self.type].type_enum()
|
||||
else:
|
||||
t = self.type
|
||||
if t in entity_names or t == "Argument_ENTITY":
|
||||
return "Argument_ENTITY_LIST"
|
||||
elif t in selections:
|
||||
return "Argument_ENTITY_LIST"
|
||||
elif t == "int":
|
||||
return "Argument_VECTOR_INT"
|
||||
elif t == "double" or t == "Argument_DOUBLE":
|
||||
return "Argument_VECTOR_DOUBLE"
|
||||
elif t == "std::string" or t == "Argument_STRING":
|
||||
return "Argument_VECTOR_STRING"
|
||||
elif isinstance(t, BinaryType):
|
||||
return "Argument_UNKNOWN"
|
||||
else:
|
||||
assert False, t
|
||||
|
||||
class ScalarType:
|
||||
def __init__(self,l): self.type = express_to_cpp.get(l,l)
|
||||
def __str__(self): return self.type
|
||||
def is_select_list(self): return False
|
||||
def type_enum(self):
|
||||
if self.type in simple_types:
|
||||
return simple_types[self.type].type_enum()
|
||||
elif self.type in entity_names:
|
||||
return "Argument_ENTITY"
|
||||
else:
|
||||
return { "bool":"Argument_BOOL","int":"Argument_INT","double":"Argument_DOUBLE","std::string":"Argument_STRING"}[self.type]
|
||||
class EnumType:
|
||||
def __init__(self,l):
|
||||
self.v = [(x,'%s_%s'%('%(fancy_name)s',x)) for x in l]
|
||||
self.maxlen = max([len(v) for v in self.v])
|
||||
def __str__(self):
|
||||
if generator_mode == 'HEADER':
|
||||
return "enum {%s}"%", ".join([v2 for v1,v2 in self.v])
|
||||
elif generator_mode == 'SOURCE_TO':
|
||||
return '{ "%s" }'%'","'.join([v1 for v1,v2 in self.v])
|
||||
elif generator_mode == 'SOURCE_FROM':
|
||||
return "".join([' if(s=="%s"%s) return ::%s::%s::%s;\n'%(v1.upper()," "*(self.maxlen-len(v1)),schema_version,"%(name)s",v2) for v1,v2 in self.v])
|
||||
def is_select_list(self): return False
|
||||
def __len__(self): return len(self.v)
|
||||
def type_enum(self):
|
||||
return "Argument_ENUMERATION"
|
||||
class SelectType:
|
||||
def __init__(self,l):
|
||||
for x in l:
|
||||
if x in simple_types: selectable_simple_types.add(x)
|
||||
def __str__(self): return "IfcSchemaEntity"
|
||||
def is_select_list(self): return False
|
||||
def type_enum(self): return "Argument_ENTITY"
|
||||
class BinaryType:
|
||||
def __init__(self,l): self.l = int(l)
|
||||
def __str__(self): return "char[%s]"%self.l
|
||||
def is_select_list(self): return False
|
||||
def type_enum(self): raise NotImplementedError()
|
||||
class InverseType:
|
||||
def __init__(self,l):
|
||||
self.name, self.type, self.reference = l
|
||||
def type_enum(self): return "Argument_ENTITY"
|
||||
def is_select_list(self): return False
|
||||
class Typedef:
|
||||
def __init__(self,l):
|
||||
self.name,self.type=l[1:3]
|
||||
self.fancy_name = self.name[:-4] if self.name.endswith("Enum") else self.name
|
||||
if isinstance(self.type,EnumType):
|
||||
enumerations.add(self.name)
|
||||
self.len = len(self.type)
|
||||
elif isinstance(self.type,SelectType): selections.add(self.name)
|
||||
simple_types[self.name] = self
|
||||
comment = IfcDocumentation.description(self.name)
|
||||
self.comment = comment+"\n" if comment else ''
|
||||
def __str__(self):
|
||||
global generator_mode
|
||||
if generator_mode == 'HEADER' and isinstance(self.type,EnumType):
|
||||
return ("namespace %(name)s {\n%(comment)stypedef %(type)s %(name)s;\nconst char* ToString(%(name)s v);\n%(name)s FromString(const std::string& s);\n}"%self.__dict__)%self.__dict__
|
||||
elif generator_mode == 'HEADER':
|
||||
return "%stypedef %s %s;"%(self.comment,self.type,self.name)
|
||||
elif generator_mode == 'SOURCE' and isinstance(self.type,EnumType):
|
||||
generator_mode = 'SOURCE_TO'
|
||||
s = "const char* %(name)s::ToString(%(name)s v) {\n if ( v < 0 || v >= %(len)d ) throw IfcException(\"Unable to find find keyword in schema\");\n const char* names[] = %(type)s;\n return names[v];\n}\n"%self.__dict__
|
||||
generator_mode = 'SOURCE_FROM'
|
||||
s += ("%(name)s::%(name)s %(name)s::FromString(const std::string& s) {\n%(type)s throw IfcException(\"Unable to find find keyword in schema\");\n}"%self.__dict__)%self.__dict__
|
||||
generator_mode = 'SOURCE'
|
||||
return s
|
||||
def type_enum(self):
|
||||
return self.type.type_enum()
|
||||
class Argument(object):
|
||||
def __init__(self,l):
|
||||
self.name, self.optional, self.type = l
|
||||
def is_enum(self): return str(self.type) in enumerations
|
||||
def type_str(self):
|
||||
if self.type.is_select_list():
|
||||
# This is extremely hackish indeed
|
||||
return "optional< IfcEntities >" if self.optional else "IfcEntities"
|
||||
elif str(self.type) in entity_names:
|
||||
return "%(type)s*"%self.__dict__
|
||||
else:
|
||||
t = "%(type)s::%(type)s"%self.__dict__ if self.is_enum() else self.type
|
||||
return "optional< %s >"%t if self.optional else t
|
||||
class ArgumentList:
|
||||
def __init__(self,l):
|
||||
self.l = [Argument(a) for a in l]
|
||||
self.argstart = 0
|
||||
def __len__(self): return len(self.l)
|
||||
def __str__(self):
|
||||
s = ""
|
||||
argv = self.argstart
|
||||
for a in self.l:
|
||||
class_name = indent = comment = optional_comment = ""
|
||||
is_array = isinstance(a.type,ArrayType) and a.type.is_shared_ptr()
|
||||
return_type = str(a.type)
|
||||
if generator_mode == 'SOURCE':
|
||||
class_name = "%(class_name)s::"
|
||||
if isinstance(a.type,BinaryType) or (isinstance(a.type,ArrayType) and isinstance(a.type.type,BinaryType)):
|
||||
function_body = " { throw; /* Not implemented argument*/ }"
|
||||
elif isinstance(a.type,ArrayType) and str(a.type.type) in entity_names:
|
||||
function_body = " { RETURN_AS_LIST(%s,%d) }"%(a.type.type,argv)
|
||||
elif isinstance(a.type,ArrayType) and str(a.type.type) in selections:
|
||||
function_body = " { RETURN_AS_LIST(IfcAbstractSelect,%d) }"%(argv)
|
||||
elif return_type in entity_names:
|
||||
function_body = " { return reinterpret_pointer_cast<IfcBaseClass,%s>(*entity->getArgument(%d)); }"%(return_type,argv)
|
||||
elif return_type in enumerations:
|
||||
function_body = " { return %s::FromString(*entity->getArgument(%d)); }"%(return_type,argv)
|
||||
else:
|
||||
function_body = " { return *entity->getArgument(%d); }"%argv
|
||||
function_body2 = " { return !entity->getArgument(%d)->isNull(); }"%argv
|
||||
if isinstance(a.type,BinaryType) or (isinstance(a.type,ArrayType) and isinstance(a.type.type,BinaryType)):
|
||||
function_body3 = " { if ( ! entity->isWritable() ) { throw; } }"
|
||||
elif return_type in enumerations:
|
||||
function_body3 = " { if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%d,v%s,%s::ToString(v)); }"%(argv,"->generalize()" if is_array else "",return_type)
|
||||
else:
|
||||
function_body3 = " { if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%d,v%s); }"%(argv,"->generalize()" if is_array else "")
|
||||
else:
|
||||
indent = " "
|
||||
function_body = function_body2 = function_body3 = ";"
|
||||
comment = IfcDocumentation.description((self.class_name,a.name))
|
||||
comment = comment+"\n" if comment else ''
|
||||
comment = comment.replace("///","%s///"%indent)
|
||||
optional_comment = "%s/// Whether the optional attribute %s is defined for this %s\n"%(indent,a.name,self.class_name)
|
||||
if a.optional: s += "\n%s%sbool %shas%s()%s"%(optional_comment,indent,class_name,a.name,function_body2)
|
||||
if ( str(a.type) in enumerations ):
|
||||
return_type = "%(type)s::%(type)s"%a.__dict__
|
||||
elif ( str(a.type) in entity_names ):
|
||||
return_type = "%(type)s*"%a.__dict__
|
||||
s += "\n%s%s%s %s%s()%s"%(comment,indent,return_type,class_name,a.name,function_body)
|
||||
s += "\n%svoid %sset%s(%s v)%s"%(indent,class_name,a.name,return_type,function_body3)
|
||||
argv += 1
|
||||
|
||||
if generator_mode == 'HEADER':
|
||||
s += "\n virtual unsigned int getArgumentCount() const { return %(n_arguments)d; }" % dict(class_name=self.class_name, n_arguments=len(self.l) + argument_start(self.class_name))
|
||||
|
||||
s += "\n virtual ArgumentType getArgumentType(unsigned int i) const {"
|
||||
if len(self.l):
|
||||
s += " switch (i) {"
|
||||
for i, a in enumerate(self.l):
|
||||
s += "case %d: " % (i + argument_start(self.class_name))
|
||||
s += "return %s; " % a.type.type_enum()
|
||||
s += "}"
|
||||
if self.parent_class is not None:
|
||||
s += " return %s::getArgumentType(i); }" % self.parent_class
|
||||
else:
|
||||
s += " throw IfcException(\"argument out of range\"); }"
|
||||
|
||||
s += "\n virtual const char* getArgumentName(unsigned int i) const {"
|
||||
if len(self.l):
|
||||
s += " switch (i) {"
|
||||
for i, a in enumerate(self.l):
|
||||
s += "case %d: " % (i + argument_start(self.class_name))
|
||||
s += "return \"%s\"; " % a.name
|
||||
s += "}"
|
||||
if self.parent_class is not None:
|
||||
s += " return %s::getArgumentName(i); }" % self.parent_class
|
||||
else:
|
||||
s += " throw IfcException(\"argument out of range\"); }"
|
||||
|
||||
s += "\n virtual ArgumentPtr getArgument(unsigned int i) const { return entity->getArgument(i); }"
|
||||
return s
|
||||
class InverseList:
|
||||
def __init__(self,l):
|
||||
self.l = l
|
||||
def __str__(self):
|
||||
if self.l is None: return ""
|
||||
s = ""
|
||||
for i in self.l:
|
||||
if generator_mode == 'HEADER':
|
||||
s += "\n SHARED_PTR< IfcTemplatedEntityList< %s > > %s(); // INVERSE %s::%s"%(i.type.type,i.name,i.type.type,i.reference)
|
||||
elif generator_mode == 'SOURCE':
|
||||
s += "\n%s::list %s::%s() { RETURN_INVERSE(%s) }"%(i.type.type,"%(class_name)s",i.name,i.type.type)
|
||||
return s
|
||||
class Classdef:
|
||||
def __init__(self,l):
|
||||
self.class_name, self.parent_class, self.arguments, self.inverse = l
|
||||
self.arguments.class_name = self.class_name
|
||||
self.arguments.parent_class = self.parent_class
|
||||
entity_names.add(self.class_name)
|
||||
parent_relations[self.class_name] = self.parent_class
|
||||
argument_count[self.class_name] = len(self.arguments)
|
||||
entity_map[self.class_name] = self
|
||||
def get_attributes(self, get_parent=True):
|
||||
s = entity_map[self.parent_class].get_attributes() if get_parent and self.parent_class else []
|
||||
s += [(a.name,not not a.optional,a.type.type_enum(),a.type.type if a.is_enum() else None) for a in self.arguments.l]
|
||||
return s
|
||||
def get_constructor_args(self):
|
||||
s = entity_map[self.parent_class].get_constructor_args() if self.parent_class else []
|
||||
i = len(s) + 1
|
||||
s += ["%s v%d_%s"%(a.type_str(),b+i,a.name) for a,b in zip(self.arguments.l,range(len(self.arguments)))]
|
||||
return s
|
||||
def get_constructor_implementation(self):
|
||||
s = entity_map[self.parent_class].get_constructor_implementation() if self.parent_class else []
|
||||
i = len(s) + 1
|
||||
b = 0
|
||||
for a in self.arguments.l:
|
||||
is_enumeration = str(a.type) in enumerations
|
||||
# boost::optional is not used for pointer types, because they are set to NULL using 0
|
||||
use_boost_optional = a.optional and str(a.type) not in entity_names
|
||||
# boost::optional types need to be dereferenced before passing to the writable entity
|
||||
dereference = "*" if use_boost_optional else ""
|
||||
generalize = "->generalize()" if (isinstance(a.type,ArrayType) and a.type.is_shared_ptr() and not a.type.is_select_list()) else ""
|
||||
if isinstance(a.type,BinaryType) or (isinstance(a.type,ArrayType) and isinstance(a.type.type,BinaryType)):
|
||||
continue
|
||||
if is_enumeration:
|
||||
impl = "e->setArgument(%d,%sv%d_%s,%s::ToString(%sv%d_%s))"%(b+i-1,dereference,b+i,a.name,str(a.type),dereference,b+i,a.name)
|
||||
else:
|
||||
impl = "e->setArgument(%d,(%sv%d_%s)%s)"%(b+i-1,dereference,b+i,a.name,generalize)
|
||||
if use_boost_optional:
|
||||
s.append("if (v%d_%s) { %s; } else { e->setArgument(%d); } "%(b+i,a.name,impl,b+i-1))
|
||||
else: s.append(impl)
|
||||
b += 1
|
||||
return s#"; ".join(s)
|
||||
def __str__(self):
|
||||
self.constructor_args_list = self.get_constructor_args()
|
||||
self.constructor_args = ", ".join(self.constructor_args_list)
|
||||
if generator_mode == 'HEADER':
|
||||
comment = IfcDocumentation.description(self.class_name)
|
||||
comment = comment+"\n" if comment else ''
|
||||
return "%sclass %s : public %s {\npublic:%s%s%s\n};" % (comment,self.class_name,
|
||||
"IfcBaseEntity" if self.parent_class is None else self.parent_class,
|
||||
self.arguments,
|
||||
self.inverse,
|
||||
("\n bool is(Type::Enum v) const;"+
|
||||
"\n Type::Enum type() const;"+
|
||||
"\n static Type::Enum Class();"+
|
||||
"\n %(class_name)s (IfcAbstractEntityPtr e = IfcAbstractEntityPtr());"+
|
||||
("\n %(class_name)s (%(constructor_args)s);" if len(self.constructor_args_list) else "")+
|
||||
"\n typedef %(class_name)s* ptr;"+
|
||||
"\n typedef SHARED_PTR< IfcTemplatedEntityList< %(class_name)s > > list;"+
|
||||
"\n typedef IfcTemplatedEntityList< %(class_name)s >::it it;")%self.__dict__
|
||||
)
|
||||
elif generator_mode == 'SOURCE':
|
||||
self.arguments.argstart = argument_start(self.class_name)
|
||||
self.constructor_implementation = "; ".join(self.get_constructor_implementation())
|
||||
return (("\n// Function implementations for %(class_name)s"+str(self.arguments)+str(self.inverse)+
|
||||
("\nbool %(class_name)s::is(Type::Enum v) const { return v == Type::%(class_name)s; }" if self.parent_class is None else
|
||||
"\nbool %(class_name)s::is(Type::Enum v) const { return v == Type::%(class_name)s || %(parent_class)s::is(v); }")+
|
||||
"\nType::Enum %(class_name)s::type() const { return Type::%(class_name)s; }"+
|
||||
"\nType::Enum %(class_name)s::Class() { return Type::%(class_name)s; }"+
|
||||
"\n%(class_name)s::%(class_name)s(IfcAbstractEntityPtr e) { if (!is(Type::%(class_name)s)) throw IfcException(\"Unable to find find keyword in schema\"); entity = e; }"+
|
||||
("\n%(class_name)s::%(class_name)s(%(constructor_args)s) { IfcWritableEntity* e = new IfcWritableEntity(Class()); %(constructor_implementation)s; entity = e; EntityBuffer::Add(this); }" if len(self.constructor_args_list) else "")
|
||||
)%self.__dict__)%self.__dict__
|
||||
|
||||
|
||||
from funcparserlib.parser import a, skip, many, maybe, some
|
||||
|
||||
#
|
||||
# Lambda functions to map combinator output to classes
|
||||
#
|
||||
array_type = lambda t: ArrayType(t)
|
||||
scalar_type = lambda t: ScalarType(t)
|
||||
enum_type = lambda t: EnumType(t)
|
||||
select_type = lambda t: SelectType(t)
|
||||
binary_type = lambda t: BinaryType(t)
|
||||
inverse_type = lambda t: InverseType(t)
|
||||
format_type = lambda t: Typedef(t)
|
||||
argument_list = lambda t: ArgumentList(t)
|
||||
inverse_list = lambda t: InverseList(t)
|
||||
format_options = lambda t: [t[0]]+t[1]
|
||||
|
||||
#
|
||||
# The actual grammar definition
|
||||
#
|
||||
s = some(lambda t: not t in ['UNIQUE','WHERE','END_ENTITY','END_TYPE','INVERSE','DERIVE'])
|
||||
x = lambda s:skip(a(s))
|
||||
list_or_array = a('ARRAY') | a('LIST') | a('SET')
|
||||
binary = x('BINARY')+x('(') + s + x(')') >> binary_type
|
||||
array = list_or_array + x('[') + s + x(':') + s + x(']') + x('OF') + skip(maybe(a('UNIQUE'))) + (binary|s) >> array_type
|
||||
options = x('(') + s + many(x(',')+s) + x(')') >> format_options
|
||||
enum = x('ENUMERATION') + x('OF') + options >> enum_type
|
||||
select = x('SELECT') + options >> select_type
|
||||
single = s + skip(maybe(x('(')+s+x(')')) + maybe(a('FIXED'))) >> scalar_type
|
||||
type_type = array | enum | select | single
|
||||
type_start = a('TYPE') + s + x('=') + type_type + x(';')
|
||||
type_end = a('END_TYPE') + x(';')
|
||||
|
||||
to_end = many(some(lambda t: t != ';'))
|
||||
clause = s + x(':') + to_end + x(';')
|
||||
where = a('WHERE') + many(clause)
|
||||
|
||||
type = type_start + maybe(where) + type_end >> format_type
|
||||
|
||||
subtype = x('SUBTYPE') + x('OF') + x('(') + s + x(')')
|
||||
supertype = maybe(x('ABSTRACT')) + x('SUPERTYPE') + x('OF') + x('(') + x('ONEOF') + options + x(')')
|
||||
entity_start = x('ENTITY') + s + skip(maybe(supertype)) + maybe(subtype) + x(';')
|
||||
entity_end = x('END_ENTITY') + x(';')
|
||||
key_value = s + x(':') + maybe(a('OPTIONAL')) + (array|binary|single) + x(';')
|
||||
arguments = many(key_value) >> argument_list
|
||||
unique_value = s + x(':') + s + many(a(',')+s) + a(';')
|
||||
unique = skip(a('UNIQUE') + many(unique_value))
|
||||
inverse_def = s + x(':') + (array|single) + x('FOR') + s + x(';') >> inverse_type
|
||||
inverse = maybe(x('INVERSE') + many( inverse_def )) >> inverse_list
|
||||
derive = skip(a('DERIVE') + many(clause))
|
||||
|
||||
entity = entity_start + arguments + skip(maybe(unique)) + skip(maybe(derive)) + inverse + skip(maybe(where)) + entity_end >> Classdef
|
||||
|
||||
schema = skip(a('SCHEMA')) + s + x(';')
|
||||
|
||||
express = schema + many(type) + many(entity)
|
||||
schema_version,types,entities = express.parse(list(Tokenizer(filename)))
|
||||
schema_version = schema_version.capitalize()
|
||||
|
||||
#
|
||||
# Writing of the three generated files starts here
|
||||
#
|
||||
h_file = open("%s.h"%schema_version,'w')
|
||||
h2_file = open("%s-rt.h"%schema_version,'w')
|
||||
enumh_file = open("%senum.h"%schema_version,'w')
|
||||
cpp_file = open("%s.cpp"%schema_version,'w')
|
||||
cpp2_file = open("%s-rt.cpp"%schema_version,'w')
|
||||
|
||||
header += """
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file has been generated from %s. Do not make modifications *
|
||||
* but instead modify the python script that has been used to generate this. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
"""%filename
|
||||
|
||||
generator_mode = 'HEADER'
|
||||
|
||||
print >>h_file, header
|
||||
print >>h2_file, header
|
||||
print >>enumh_file, header
|
||||
print >>cpp_file, header
|
||||
print >>cpp2_file, header
|
||||
print >>h_file, """#ifndef %(schema_upper)s_H
|
||||
#define %(schema_upper)s_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/ArgumentType.h"
|
||||
#include "../ifcparse/%(schema)senum.h"
|
||||
|
||||
using namespace IfcUtil;
|
||||
using IfcParse::IfcException;
|
||||
using boost::optional;
|
||||
|
||||
#define RETURN_INVERSE(T) \\
|
||||
IfcEntities e = entity->getInverse(T::Class()); \\
|
||||
SHARED_PTR< IfcTemplatedEntityList<T> > l ( new IfcTemplatedEntityList<T>() ); \\
|
||||
for ( IfcEntityList::it it = e->begin(); it != e->end(); ++ it ) { \\
|
||||
l->push(reinterpret_pointer_cast<IfcBaseClass,T>(*it)); \\
|
||||
} \\
|
||||
return l;
|
||||
|
||||
#define RETURN_AS_SINGLE(T,a) \\
|
||||
return reinterpret_pointer_cast<IfcBaseClass,T>(*entity->getArgument(a));
|
||||
|
||||
#define RETURN_AS_LIST(T,a) \\
|
||||
IfcEntities e = *entity->getArgument(a); \\
|
||||
SHARED_PTR< IfcTemplatedEntityList<T> > l ( new IfcTemplatedEntityList<T>() ); \\
|
||||
for ( IfcEntityList::it it = e->begin(); it != e->end(); ++ it ) { \\
|
||||
l->push(reinterpret_pointer_cast<IfcBaseClass,T>(*it)); \\
|
||||
} \\
|
||||
return l;
|
||||
|
||||
namespace %(schema)s {
|
||||
"""%{'schema_upper':schema_version.upper(),'schema':schema_version}
|
||||
|
||||
simple_enumerations = sorted(simple_types)
|
||||
entity_enumerations = sorted(entity_names)
|
||||
all_enumerations = simple_enumerations + entity_enumerations
|
||||
|
||||
print >>enumh_file, """#ifndef IFC2X3ENUM_H
|
||||
#define IFC2X3ENUM_H
|
||||
|
||||
#include "../ifcparse/ArgumentType.h"
|
||||
|
||||
namespace Ifc2x3 {
|
||||
|
||||
namespace Type {
|
||||
typedef enum {
|
||||
%(enum)s
|
||||
} Enum;
|
||||
Enum Parent(Enum v);
|
||||
Enum FromString(const std::string& s);
|
||||
std::string ToString(Enum v);
|
||||
bool IsSimple(Enum v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
"""%{'schema_upper':schema_version.upper(),'schema':schema_version,'enum':", ".join(all_enumerations + ["ALL"])}
|
||||
print >>h2_file, """#ifndef IFC2X3RT_H
|
||||
#define IFC2X3RT_H
|
||||
|
||||
#include "../ifcparse/ArgumentType.h"
|
||||
|
||||
namespace Ifc2x3 {
|
||||
namespace Type {
|
||||
int GetAttributeCount(Enum t);
|
||||
int GetAttributeIndex(Enum t, const std::string& a);
|
||||
IfcUtil::ArgumentType GetAttributeType(Enum t, unsigned char a);
|
||||
const std::string& GetAttributeName(Enum t, unsigned char a);
|
||||
bool GetAttributeOptional(Enum t, unsigned char a);
|
||||
std::pair<const char*, int> GetEnumerationIndex(Enum t, const std::string& a);
|
||||
Enum GetAttributeEnumerationClass(Enum t, unsigned char a);
|
||||
}}
|
||||
|
||||
#endif
|
||||
"""
|
||||
|
||||
defined_types = set(express_to_cpp.values())
|
||||
deferred_types = []
|
||||
|
||||
for t in [T for T in types if not (isinstance(T.type,EnumType) or isinstance(T.type,SelectType))]:
|
||||
if isinstance(t.type,ScalarType) and str(t.type) not in defined_types:
|
||||
deferred_types.append(t)
|
||||
else:
|
||||
print >>h_file, t
|
||||
for t in [T for T in types if isinstance(T.type,SelectType)]:
|
||||
print >>h_file, t
|
||||
for t in deferred_types:
|
||||
print >>h_file, t
|
||||
for t in [T for T in types if isinstance(T.type,EnumType)]:
|
||||
print >>h_file, t
|
||||
|
||||
print >>h_file, "// Forward definitions"
|
||||
print >>h_file, "class %s;\n"%"; class ".join([e.class_name for e in entities])
|
||||
|
||||
defined_classes = set()
|
||||
while True:
|
||||
classes = [c for c in entities if c.class_name not in defined_classes]
|
||||
if not len(classes): break
|
||||
for c in classes:
|
||||
if c.parent_class is None or c.parent_class in defined_classes:
|
||||
defined_classes.add(c.class_name)
|
||||
print >>h_file, c
|
||||
|
||||
print >>h_file, "void InitStringMap();"
|
||||
print >>h_file, "IfcSchemaEntity SchemaEntity(IfcAbstractEntityPtr e = 0);"
|
||||
|
||||
print >>h_file, "}\n\n#endif"
|
||||
|
||||
generator_mode = 'SOURCE'
|
||||
print >>cpp2_file, """#include "../ifcparse/%(schema)s.h"
|
||||
#include "../ifcparse/%(schema)s-rt.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/IfcWrite.h"
|
||||
#include "../ifcparse/IfcWritableEntity.h"
|
||||
#include "../ifcparse/ArgumentType.h"
|
||||
|
||||
using namespace %(schema)s;
|
||||
using namespace IfcParse;
|
||||
using namespace IfcWrite;"""%{'schema':schema_version}
|
||||
print >>cpp_file, """#include "../ifcparse/%(schema)s.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/IfcWrite.h"
|
||||
#include "../ifcparse/IfcWritableEntity.h"
|
||||
#include "../ifcparse/ArgumentType.h"
|
||||
|
||||
using namespace %(schema)s;
|
||||
using namespace IfcParse;
|
||||
using namespace IfcWrite;
|
||||
|
||||
IfcSchemaEntity %(schema)s::SchemaEntity(IfcAbstractEntityPtr e) {
|
||||
switch(e->type()){"""%{'schema':schema_version}
|
||||
|
||||
for e in simple_enumerations:
|
||||
print >>cpp_file, " case Type::%s: return new IfcEntitySelect(e); break;"%e
|
||||
for e in entity_enumerations:
|
||||
print >>cpp_file, " case Type::%s: return new %s(e); break;"%(e,e)
|
||||
print >>cpp_file, " default: throw IfcException(\"Unable to find find keyword in schema\"); break; "
|
||||
print >>cpp_file, " }\n}"
|
||||
print >>cpp_file
|
||||
print >>cpp_file, "std::string Type::ToString(Enum v) {"
|
||||
print >>cpp_file, " if (v < 0 || v >= %d) throw IfcException(\"Unable to find find keyword in schema\");"%len(all_enumerations)
|
||||
print >>cpp_file, ' const char* names[] = { "%s" };'%'","'.join(all_enumerations)
|
||||
print >>cpp_file, ' return names[v];'
|
||||
print >>cpp_file, "}"
|
||||
print >>cpp_file
|
||||
|
||||
print >>cpp_file, "std::map<std::string,Type::Enum> string_map;"
|
||||
print >>cpp2_file, "std::map<Type::Enum,IfcEntityDescriptor*> entity_descriptor_map;"
|
||||
print >>cpp2_file, "std::map<Type::Enum,IfcEnumerationDescriptor*> enumeration_descriptor_map;"
|
||||
maxlen = max([len(e) for e in all_enumerations])
|
||||
string_map,attribute_count_map,attribute_index_map,attribute_name_map,attribute_optional_map,attribute_type_map = [""]*6
|
||||
print >>cpp2_file, "void InitDescriptorMap() {"
|
||||
print >>cpp2_file, " IfcEntityDescriptor* current;"
|
||||
for k,v in simple_types.items():
|
||||
if k in enumerations or k in selections: continue
|
||||
print >>cpp2_file, " current = entity_descriptor_map[Type::%s] = new IfcEntityDescriptor(Type::%s,0);"%(k,k)
|
||||
print >>cpp2_file, " current->add(\"wrappedValue\",false,%s);"%(v.type_enum())
|
||||
rt_entities = set()
|
||||
while True:
|
||||
todo = [e for e in entities if e.class_name not in rt_entities]
|
||||
if len(todo) == 0: break
|
||||
for e in todo:
|
||||
if e.parent_class and e.parent_class not in rt_entities: continue
|
||||
rt_entities.add(e.class_name)
|
||||
args = e.get_attributes(False)
|
||||
parent_descriptor = ("entity_descriptor_map.find(Type::%s)->second"%e.parent_class) if e.parent_class else "0"
|
||||
print >>cpp2_file, " current = entity_descriptor_map[Type::%s] = new IfcEntityDescriptor(Type::%s,%s);"%(e.class_name,e.class_name,parent_descriptor)
|
||||
for a,i in zip(args,range(len(args))):
|
||||
name,optional,type,enum_class = a
|
||||
if enum_class:
|
||||
print >>cpp2_file, " current->add(\"%s\",%s,%s,Type::%s);"%(name,"true" if optional else "false",type,enum_class)
|
||||
else:
|
||||
print >>cpp2_file, " current->add(\"%s\",%s,%s);"%(name,"true" if optional else "false",type)
|
||||
print >>cpp2_file, " // Enumerations"
|
||||
print >>cpp2_file, " IfcEnumerationDescriptor* current_enum;"
|
||||
print >>cpp2_file, " std::vector<std::string> values;"
|
||||
for e, name in [(e, name) for name, e in simple_types.items() if name in enumerations]:
|
||||
print >>cpp2_file, " values.clear(); values.reserve(128);"
|
||||
for value in e.type.v:
|
||||
print >>cpp2_file, " values.push_back(\"%s\");"%value[0]
|
||||
print >>cpp2_file, " current_enum = enumeration_descriptor_map[Type::%s] = new IfcEnumerationDescriptor(Type::%s, values);"%(name,name)
|
||||
print >>cpp2_file, "}"
|
||||
|
||||
for e in all_enumerations:
|
||||
string_map += ' string_map["%s"%s] = Type::%s;\n'%(e.upper()," "*(maxlen-len(e)),e)
|
||||
print >>cpp_file, """void Ifc2x3::InitStringMap() {
|
||||
%(string_map)s
|
||||
}"""%locals()
|
||||
|
||||
print >>cpp_file, """Type::Enum Type::FromString(const std::string& s) {
|
||||
if (string_map.empty()) ::Ifc2x3::InitStringMap();
|
||||
std::map<std::string,Type::Enum>::const_iterator it = string_map.find(s);
|
||||
if ( it == string_map.end() ) throw IfcException("Unable to find find keyword in schema");
|
||||
else return it->second;
|
||||
}"""
|
||||
|
||||
print >>cpp_file, "Type::Enum Type::Parent(Enum v){"
|
||||
print >>cpp_file, " if (v < 0 || v >= %d) return (Enum)-1;"%len(all_enumerations)
|
||||
for e in entity_enumerations:
|
||||
if e not in parent_relations or parent_relations[e] is None: continue
|
||||
print >>cpp_file, ' if(v==%s%s) { return %s; }'%(e," "*(maxlen-len(e)),parent_relations[e])
|
||||
print >>cpp_file, " return (Enum)-1;"
|
||||
print >>cpp_file, "}"
|
||||
|
||||
print >>cpp_file, "bool Type::IsSimple(Enum v){"
|
||||
print >>cpp_file, " return v == Type::%s;"%" || v == Type::".join(simple_enumerations)
|
||||
print >>cpp_file, "}"
|
||||
|
||||
for t in [T for T in types if isinstance(T.type,EnumType)]:
|
||||
print >>cpp_file, t
|
||||
for e in entities: print >>cpp_file, e,
|
||||
print >>cpp_file, ""
|
||||
|
||||
print >>cpp2_file, """int Type::GetAttributeIndex(Enum t, const std::string& a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else return i->second->getArgumentIndex(a);
|
||||
}
|
||||
|
||||
int Type::GetAttributeCount(Enum t) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else return i->second->getArgumentCount();
|
||||
}
|
||||
|
||||
ArgumentType Type::GetAttributeType(Enum t, unsigned char a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else return i->second->getArgumentType(a);
|
||||
}
|
||||
|
||||
const std::string& Type::GetAttributeName(Enum t, unsigned char a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else return i->second->getArgumentName(a);
|
||||
}
|
||||
|
||||
bool Type::GetAttributeOptional(Enum t, unsigned char a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else return i->second->getArgumentOptional(a);
|
||||
}
|
||||
|
||||
std::pair<const char*, int> Type::GetEnumerationIndex(Enum t, const std::string& a) {
|
||||
if (enumeration_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEnumerationDescriptor*>::const_iterator i = enumeration_descriptor_map.find(t);
|
||||
if ( i == enumeration_descriptor_map.end() ) throw IfcException("Value not found");
|
||||
else return i->second->getIndex(a);
|
||||
}
|
||||
|
||||
Type::Enum Type::GetAttributeEnumerationClass(Enum t, unsigned char a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
|
||||
else {
|
||||
Type::Enum t = i->second->getArgumentEnumerationClass(a);
|
||||
if ( t == Type::ALL ) throw IfcException("Not an enumeration");
|
||||
else return t;
|
||||
}
|
||||
}
|
||||
"""
|
||||
@@ -4,6 +4,8 @@ the IFC schema and will most likely fail on any other Express schema.
|
||||
|
||||
The code can be invoked in the following way and results in two header files
|
||||
and a single implementation file named according to the schema name in the
|
||||
Express file. A python 3 interpreter with the pyparsing library is required.
|
||||
Express file. A python 3 interpreter with the pyparsing [1] library is required.
|
||||
|
||||
$ python bootstrap.py express.bnf > express_parser.py && python express_parser.py IFC2X3_TC1.exp
|
||||
|
||||
[1] http://pyparsing.wikispaces.com/Download+and+Installation
|
||||
|
||||
@@ -115,7 +115,7 @@ actions = {
|
||||
'general_aggregation_types' : "lambda t: AggregationType(t)",
|
||||
'select_type' : "lambda t: SelectType(t)",
|
||||
'binary_type' : "lambda t: BinaryType(t)",
|
||||
'subtype_declaration' : "lambda t: SubtypeExpression(t)",
|
||||
'subtype_declaration' : "lambda t: SubTypeExpression(t)",
|
||||
'derive_clause' : "lambda t: AttributeList('derive', t)",
|
||||
'derived_attr' : "lambda t: DerivedAttribute(t)",
|
||||
'inverse_clause' : "lambda t: AttributeList('inverse', t)",
|
||||
@@ -158,36 +158,45 @@ for id in to_emit:
|
||||
stmt = "Suppress%s" % stmt
|
||||
statements.append("%s << %s" % (id, stmt))
|
||||
|
||||
print ("""import sys
|
||||
from pyparsing import *
|
||||
from nodes import *
|
||||
print ("""import os
|
||||
import sys
|
||||
import pickle
|
||||
|
||||
%s
|
||||
cache_file = sys.argv[1] + ".cache.dat"
|
||||
if os.path.exists(cache_file):
|
||||
with open(cache_file, "rb") as f:
|
||||
mapping = pickle.load(f)
|
||||
else:
|
||||
from pyparsing import *
|
||||
from nodes import *
|
||||
|
||||
import schema
|
||||
import mapping
|
||||
|
||||
%s
|
||||
|
||||
syntax.ignore("--" + restOfLine)
|
||||
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
|
||||
ast = syntax.parseFile(sys.argv[1])
|
||||
schema = schema.Schema(ast)
|
||||
mapping = mapping.Mapping(schema)
|
||||
|
||||
import schema
|
||||
import mapping
|
||||
with open(cache_file, "wb") as f:
|
||||
pickle.dump(mapping, f, protocol=0)
|
||||
|
||||
import header
|
||||
import enum_header
|
||||
import implementation
|
||||
import rt_header
|
||||
import rt_implementation
|
||||
|
||||
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
|
||||
ast = syntax.parseFile(sys.argv[1])
|
||||
schema = schema.Schema(ast)
|
||||
mapping = mapping.Mapping(schema)
|
||||
import latebound_header
|
||||
import latebound_implementation
|
||||
import schema_class
|
||||
|
||||
header.Header(mapping).emit()
|
||||
enum_header.EnumHeader(mapping).emit()
|
||||
implementation.Implementation(mapping).emit()
|
||||
rt_header.RuntimeTypingHeader(mapping).emit()
|
||||
rt_implementation.RuntimeTypingImplementation(mapping).emit()
|
||||
latebound_header.LateBoundHeader(mapping).emit()
|
||||
latebound_implementation.LateBoundImplementation(mapping).emit()
|
||||
schema_class.SchemaClass(mapping).emit()
|
||||
|
||||
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)))
|
||||
sys.stdout.write(mapping.schema.name)
|
||||
"""%('\n '.join(statements)))
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
class Base(object):
|
||||
"""
|
||||
A base class for all code generation classes. Currently only working around
|
||||
some python 2/3 incompatibilities in terms of unicode file handling.
|
||||
"""
|
||||
def emit(self):
|
||||
import platform
|
||||
if tuple(map(int, platform.python_version_tuple())) < (2, 8):
|
||||
from io import open as unicode_open
|
||||
unicode_type = unicode
|
||||
else:
|
||||
unicode_open = open
|
||||
unicode_type = lambda x, *args, **kwargs: x
|
||||
f = unicode_open(self.file_name, 'w', encoding='utf-8')
|
||||
f.write(unicode_type(repr(self), encoding='utf-8', errors='ignore'))
|
||||
f.close()
|
||||
@@ -27,11 +27,17 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import re,csv
|
||||
import re
|
||||
import os
|
||||
import csv
|
||||
|
||||
from builtins import open
|
||||
|
||||
try: from html.entities import entitydefs
|
||||
except: from htmlentitydefs import entitydefs
|
||||
|
||||
make_absolute = lambda fn: os.path.join(os.path.dirname(os.path.realpath(__file__)), fn)
|
||||
|
||||
name_to_oid = {}
|
||||
oid_to_desc = {}
|
||||
oid_to_name = {}
|
||||
@@ -39,18 +45,19 @@ oid_to_pid = {}
|
||||
regices = list(zip([re.compile(s,re.M) for s in [r'<[\w\n=" \-/\.;_\t:%#,\?\(\)]+>',r'(\n[\t ]*){2,}',r'^[\t ]+']],['','\n\n',' ']))
|
||||
|
||||
definition_files = ['DocEntity.csv', 'DocEnumeration.csv', 'DocDefined.csv', 'DocSelect.csv']
|
||||
definition_files = map(make_absolute, definition_files)
|
||||
for fn in definition_files:
|
||||
with open(fn) as f:
|
||||
with open(fn, encoding='utf-8', errors='ignore') as f:
|
||||
for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'):
|
||||
name_to_oid[name] = oid
|
||||
oid_to_name[oid] = name
|
||||
oid_to_desc[oid] = desc
|
||||
|
||||
with open('DocEntityAttributes.csv') as f:
|
||||
with open(make_absolute('DocEntityAttributes.csv'), encoding='utf-8', errors='ignore') as f:
|
||||
for pid, x, oid in csv.reader(f, delimiter=';', quotechar='"'):
|
||||
oid_to_pid[oid] = pid
|
||||
|
||||
with open('DocAttribute.csv') as f:
|
||||
with open(make_absolute('DocAttribute.csv'), encoding='utf-8', errors='ignore') as f:
|
||||
for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'):
|
||||
pid = oid_to_pid[oid]
|
||||
pname = oid_to_name[pid]
|
||||
|
||||
@@ -18,10 +18,11 @@
|
||||
###############################################################################
|
||||
|
||||
import templates
|
||||
import codegen
|
||||
|
||||
class EnumHeader:
|
||||
class EnumHeader(codegen.Base):
|
||||
def __init__(self, mapping):
|
||||
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]))
|
||||
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]), key=lambda s: s.lower())
|
||||
|
||||
self.str = templates.enum_header % {
|
||||
'schema_name_upper' : mapping.schema.name.upper(),
|
||||
@@ -30,9 +31,9 @@ class EnumHeader:
|
||||
}
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
self.file_name = '%senum.h'%self.schema_name
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return self.str
|
||||
def emit(self):
|
||||
f = open('%senum.h'%self.schema_name, 'w', encoding='utf-8')
|
||||
f.write(str(self))
|
||||
f.close()
|
||||
|
||||
@@ -17,39 +17,40 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import codegen
|
||||
import templates
|
||||
import documentation
|
||||
|
||||
class Header:
|
||||
class Header(codegen.Base):
|
||||
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))
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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.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]))
|
||||
|
||||
forward_definitions = "".join(["class %s; "%n for n in mapping.schema.entities.keys()])
|
||||
|
||||
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)
|
||||
|
||||
class_definitions = []
|
||||
|
||||
@@ -65,11 +66,11 @@ class Header:
|
||||
def write_method(attr):
|
||||
if attr.optional:
|
||||
attr_lines.append(templates.optional_attribute_description % (attr.name, name))
|
||||
attr_lines.append("bool has%s();"%(attr.name))
|
||||
attr_lines.append("bool has%s() const;"%(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();"%(type_str, attr.name))
|
||||
attr_lines.append("%s %s() const;"%(type_str, attr.name))
|
||||
attr_lines.append("void set%s(%s v);"%(attr.name, type_str))
|
||||
|
||||
[write_method(attr) for attr in type.attributes]
|
||||
@@ -95,14 +96,19 @@ class Header:
|
||||
argument_start = argument_count - len(type.attributes)
|
||||
|
||||
argument_name_function_body_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return "%s"; '%(i+argument_start, attr.name) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
|
||||
argument_name_function_body_tail = (" return %s::getArgumentName(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcException("argument out of range"); '
|
||||
argument_name_function_body_tail = (" return %s::getArgumentName(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
|
||||
|
||||
argument_name_function_body = argument_name_function_body_switch_stmt + argument_name_function_body_tail
|
||||
|
||||
argument_type_function_body_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return %s; '%(i+argument_start, mapping.make_argument_type(attr)) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
|
||||
argument_type_function_body_tail = (" return %s::getArgumentType(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcException("argument out of range"); '
|
||||
argument_type_function_body_tail = (" return %s::getArgumentType(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
|
||||
|
||||
argument_type_function_body = argument_type_function_body_switch_stmt + argument_type_function_body_tail
|
||||
|
||||
argument_entity_function_body_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return %s; '%(i+argument_start, mapping.make_argument_entity(attr)) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
|
||||
argument_entity_function_body_tail = (" return %s::getArgumentEntity(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::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))
|
||||
|
||||
@@ -118,10 +124,9 @@ class Header:
|
||||
}
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
self.file_name = '%s.h'%self.schema_name
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return self.str
|
||||
def emit(self):
|
||||
f = open('%s.h'%self.schema_name, 'w', encoding='utf-8')
|
||||
f.write(str(self))
|
||||
f.close()
|
||||
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import codegen
|
||||
import templates
|
||||
|
||||
class Implementation:
|
||||
class Implementation(codegen.Base):
|
||||
def __init__(self, mapping):
|
||||
enumeration_functions = []
|
||||
entity_implementations = []
|
||||
@@ -61,17 +62,27 @@ class Implementation:
|
||||
if not arg['is_inherited'] and not arg['is_derived']:
|
||||
if arg['is_optional']:
|
||||
write_attr(
|
||||
templates.function,
|
||||
templates.const_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 = 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
|
||||
tmpl = find_template(arg)
|
||||
write_attr(
|
||||
templates.function,
|
||||
templates.const_function,
|
||||
class_name = name,
|
||||
name = arg['name'],
|
||||
arguments = '',
|
||||
@@ -80,8 +91,16 @@ class Implementation:
|
||||
'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 = 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
|
||||
tmpl = find_template(arg)
|
||||
write_attr(
|
||||
templates.function,
|
||||
class_name = name,
|
||||
@@ -110,16 +129,20 @@ class Implementation:
|
||||
'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.function % {
|
||||
inverse = [templates.const_function % {
|
||||
'class_name' : name,
|
||||
'name' : i.name,
|
||||
'arguments' : '',
|
||||
'return_type' : '%s::list' % i.entity,
|
||||
'body' : templates.get_inverse % {'type': i.entity}
|
||||
'return_type' : '%s::list::ptr' % i.entity,
|
||||
'body' : templates.get_inverse % {'type': i.entity, 'index':get_attribute_index(i.entity, i.attribute)}
|
||||
} for i in (type.inverse.elements if type.inverse else [])]
|
||||
|
||||
superclass = "%s((IfcAbstractEntityPtr)0)" % type.supertypes[0] if len(type.supertypes) == 1 else 'IfcUtil::IfcBaseEntity()'
|
||||
superclass = "%s((IfcAbstractEntity*)0)" % type.supertypes[0] if len(type.supertypes) == 1 else 'IfcUtil::IfcBaseEntity()'
|
||||
|
||||
write(
|
||||
templates.entity_implementation,
|
||||
@@ -133,10 +156,10 @@ class Implementation:
|
||||
)
|
||||
|
||||
selectable_simple_types = sorted(set(sum([b.values for a,b in mapping.schema.selects.items()], [])) & set(mapping.schema.types.keys()))
|
||||
schema_entity_statements += [templates.schema_simple_stmt%locals() for name in selectable_simple_types]
|
||||
schema_entity_statements += [templates.schema_entity_stmt%locals() for name, type in mapping.schema.simpletypes.items()]
|
||||
schema_entity_statements += [templates.schema_entity_stmt%locals() for name, type in mapping.schema.entities.items()]
|
||||
|
||||
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]))
|
||||
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]), key=lambda s: s.lower())
|
||||
max_len = max(map(len, enumerable_types))
|
||||
type_name_strings = catc(map(stringify, enumerable_types))
|
||||
string_map_statements = [templates.string_map_statement % {
|
||||
@@ -154,6 +177,48 @@ class Implementation:
|
||||
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(),
|
||||
@@ -165,14 +230,15 @@ class Implementation:
|
||||
'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)
|
||||
'entity_implementations' : catnl(entity_implementations),
|
||||
'simple_type_impl' : catnl(simple_type_impl),
|
||||
'external_definitions' : catnl(external_definitions)
|
||||
}
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
self.file_name = '%s.cpp'%self.schema_name
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return self.str
|
||||
def emit(self):
|
||||
f = open('%s.cpp'%self.schema_name, 'w', encoding='utf-8')
|
||||
f.write(str(self))
|
||||
f.close()
|
||||
|
||||
|
||||
@@ -17,19 +17,20 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import codegen
|
||||
import templates
|
||||
|
||||
class RuntimeTypingHeader:
|
||||
class LateBoundHeader(codegen.Base):
|
||||
def __init__(self, mapping):
|
||||
self.str = templates.rt_header % {
|
||||
self.str = templates.lb_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()
|
||||
+15
-13
@@ -17,9 +17,10 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import codegen
|
||||
import templates
|
||||
|
||||
class RuntimeTypingImplementation:
|
||||
class LateBoundImplementation(codegen.Base):
|
||||
def __init__(self, mapping):
|
||||
schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
@@ -32,7 +33,7 @@ class RuntimeTypingImplementation:
|
||||
entity_descriptors.append(templates.entity_descriptor % {
|
||||
'type' : name,
|
||||
'parent_statement' : '0',
|
||||
'entity_descriptor_attributes' : templates.entity_descriptor_attribute % {
|
||||
'entity_descriptor_attributes' : templates.entity_descriptor_attribute_without_entity % {
|
||||
'name' : 'wrappedValue',
|
||||
'optional' : 'false',
|
||||
'type' : mapping.make_argument_type(mapping.schema.types[name].type)
|
||||
@@ -49,12 +50,14 @@ class RuntimeTypingImplementation:
|
||||
entity_descriptor_attributes = []
|
||||
for arg in constructor_arguments:
|
||||
if not arg['is_inherited']:
|
||||
tmpl = templates.entity_descriptor_attribute_enum if arg['argument_type_enum'] == 'IfcUtil::Argument_ENUMERATION' else templates.entity_descriptor_attribute
|
||||
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]
|
||||
entity_descriptor_attributes.append(tmpl % {
|
||||
'name' : arg['name'],
|
||||
'optional' : 'true' if arg['is_optional'] else 'false',
|
||||
'type' : arg['argument_type_enum'],
|
||||
'enum_type' : arg['argument_type']
|
||||
'name' : arg['name'],
|
||||
'optional' : 'true' if arg['is_optional'] else 'false',
|
||||
'type' : arg['argument_type_enum'],
|
||||
'entity_name': entity_name
|
||||
})
|
||||
|
||||
emitted_entities.add(name)
|
||||
@@ -98,7 +101,7 @@ class RuntimeTypingImplementation:
|
||||
'index' : related_attrs.index(attr.attribute)
|
||||
})
|
||||
|
||||
self.str = templates.rt_implementation % {
|
||||
self.str = templates.lb_implementation % {
|
||||
'schema_name_upper' : mapping.schema.name.upper(),
|
||||
'schema_name' : mapping.schema.name.capitalize(),
|
||||
'entity_descriptors' : '\n'.join(entity_descriptors),
|
||||
@@ -108,10 +111,9 @@ class RuntimeTypingImplementation:
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import nodes
|
||||
import templates
|
||||
|
||||
@@ -24,24 +27,44 @@ class Mapping:
|
||||
|
||||
express_to_cpp_typemapping = {
|
||||
'boolean' : 'bool',
|
||||
'logical' : 'bool',
|
||||
'logical' : 'boost::logic::tribool',
|
||||
'integer' : 'int',
|
||||
'real' : 'double',
|
||||
'number' : 'double',
|
||||
'string' : 'std::string'
|
||||
'string' : 'std::string',
|
||||
'binary' : 'boost::dynamic_bitset<>'
|
||||
}
|
||||
|
||||
supported_argument_types = set([
|
||||
'INT', 'BOOL', 'TRIBOOL', 'DOUBLE', 'STRING', 'BINARY', 'ENUMERATION', 'ENTITY_INSTANCE',
|
||||
'AGGREGATE_OF_INT', 'AGGREGATE_OF_BOOL', 'AGGREGATE_OF_TRIBOOL', 'AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_STRING', 'AGGREGATE_OF_BINARY', 'AGGREGATE_OF_ENTITY_INSTANCE',
|
||||
'AGGREGATE_OF_AGGREGATE_OF_INT', 'AGGREGATE_OF_AGGREGATE_OF_BOOL', 'AGGREGATE_OF_AGGREGATE_OF_TRIBOOL', 'AGGREGATE_OF_AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE',
|
||||
])
|
||||
|
||||
def __init__(self, schema):
|
||||
self.schema = schema
|
||||
|
||||
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):
|
||||
return self.express_to_cpp_typemapping.get(type, type)
|
||||
if isinstance(type, (str, nodes.BinaryType)):
|
||||
return self.express_to_cpp_typemapping.get(str(type), type)
|
||||
else:
|
||||
is_list = self.schema.is_entity(type.type)
|
||||
tmpl = templates.list_type if is_list else templates.array_type
|
||||
is_nested_list = isinstance(type.type, nodes.AggregationType)
|
||||
tmpl = templates.list_list_type if is_nested_list else templates.list_type if is_list else templates.array_type
|
||||
return tmpl % {
|
||||
'instance_type' : self.make_type_string(type.type),
|
||||
'instance_type' : self.make_type_string(self.flatten_type_string(type.type)),
|
||||
'lower' : type.bounds.lower,
|
||||
'upper' : type.bounds.upper,
|
||||
}
|
||||
@@ -53,61 +76,73 @@ 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 type in self.express_to_cpp_typemapping:
|
||||
return self.express_to_cpp_typemapping.get(type, type).split('::')[-1].upper()
|
||||
elif self.schema.is_entity(type):
|
||||
return "ENTITY"
|
||||
elif self.schema.is_type(type):
|
||||
return _make_argument_type(self.schema.types[type].type.type)
|
||||
if self.schema.is_entity(type) or isinstance(type, nodes.SelectType):
|
||||
return "ENTITY_INSTANCE"
|
||||
elif isinstance(type, nodes.BinaryType):
|
||||
return "UNKNOWN"
|
||||
return "BINARY"
|
||||
elif isinstance(type, nodes.EnumerationType):
|
||||
return "ENUMERATION"
|
||||
elif isinstance(type, nodes.SelectType):
|
||||
return "ENTITY"
|
||||
elif isinstance(type, nodes.AggregationType):
|
||||
ty = _make_argument_type(type.type)
|
||||
if ty == "UNKNOWN": return "UNKNOWN"
|
||||
return "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 "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 "IfcUtil::Argument_%s" % ty
|
||||
|
||||
def get_type_dep(self, type):
|
||||
if isinstance(type, str):
|
||||
return self.express_to_cpp_typemapping.get(type, type)
|
||||
return self.express_to_cpp_typemapping.get(str(type), type)
|
||||
else:
|
||||
return self.get_type_dep(type.type)
|
||||
|
||||
def get_parameter_type(self, attr, allow_optional, allow_entities, allow_pointer = True):
|
||||
type_str = self.express_to_cpp_typemapping.get(str(attr.type), attr.type)
|
||||
attr_type = self.flatten_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):
|
||||
ty = self.get_parameter_type(attr.type, False, allow_entities, allow_pointer=False)
|
||||
if allow_entities and self.schema.is_select(attr.type.type):
|
||||
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):
|
||||
type_str = templates.untyped_list
|
||||
elif self.schema.is_simpletype(ty) or ty in self.express_to_cpp_typemapping.values():
|
||||
type_str = templates.array_type % {
|
||||
elif self.schema.is_simpletype(ty) or str(ty) in self.express_to_cpp_typemapping.values():
|
||||
tmpl = templates.nested_array_type if is_nested_list else templates.array_type
|
||||
type_str = tmpl % {
|
||||
'instance_type' : ty,
|
||||
'lower' : attr.type.bounds.lower,
|
||||
'upper' : attr.type.bounds.upper
|
||||
'lower' : attr_type.bounds.lower,
|
||||
'upper' : attr_type.bounds.upper
|
||||
}
|
||||
else:
|
||||
type_str = templates.list_type % {
|
||||
tmpl = templates.list_list_type if is_nested_list else templates.list_type
|
||||
type_str = tmpl % {
|
||||
'instance_type': ty
|
||||
}
|
||||
elif allow_pointer and self.schema.is_entity(type_str):
|
||||
elif allow_pointer and (self.schema.is_entity(type_str) or self.schema.is_select(type_str)):
|
||||
type_str += '*'
|
||||
is_ptr = True
|
||||
elif not allow_pointer and self.schema.is_select(type_str):
|
||||
type_str = "IfcUtil::IfcAbstractSelect"
|
||||
type_str = "IfcUtil::IfcBaseClass*"
|
||||
is_ptr = True
|
||||
if allow_optional and attr.optional and not is_ptr:
|
||||
type_str = "boost::optional< %s >"%type_str
|
||||
@@ -126,19 +161,29 @@ class Mapping:
|
||||
return c + ([str(s) for s in t.derive.elements] if t.derive else [])
|
||||
|
||||
def list_instance_type(self, attr):
|
||||
f = lambda v : 'IfcUtil::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
|
||||
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
|
||||
|
||||
def is_templated_list(self, attr):
|
||||
attr_type = attr.type if isinstance(attr, nodes.ExplicitAttribute) else attr
|
||||
if isinstance(attr, str): return False
|
||||
ty = self.list_instance_type(attr)
|
||||
arr = self.is_array(attr.type)
|
||||
if ty is None: return False
|
||||
arr = self.is_array(attr_type)
|
||||
simple = self.schema.is_simpletype(ty)
|
||||
express = ty in self.express_to_cpp_typemapping
|
||||
select = ty == 'IfcUtil::IfcAbstractSelect'
|
||||
express = self.flatten_type_string(ty) in self.express_to_cpp_typemapping
|
||||
select = ty == 'IfcUtil::IfcBaseClass'
|
||||
return arr and not simple and not express and not select
|
||||
|
||||
def get_assignable_arguments(self, t, include_derived = False):
|
||||
@@ -163,9 +208,11 @@ 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)]
|
||||
|
||||
|
||||
@@ -44,15 +44,17 @@ class TypeDeclaration(Node):
|
||||
class EntityDeclaration(Node):
|
||||
name = property(lambda self: self.tokens[1])
|
||||
attributes = property(lambda self: self.tokens_of_type(ExplicitAttribute))
|
||||
abstract = property(lambda self: self.single_token_of_type(SuperTypeExpression) is not None and \
|
||||
self.single_token_of_type(SuperTypeExpression).abstract)
|
||||
def init(self):
|
||||
assert self.tokens[0] == 'entity'
|
||||
s = self.single_token_of_type(SubtypeExpression)
|
||||
s = self.single_token_of_type(SubTypeExpression)
|
||||
self.inverse = self.single_token_of_type(AttributeList, 'type', 'inverse')
|
||||
self.derive = self.single_token_of_type(AttributeList, 'type', 'derive')
|
||||
self.supertypes = s.types if s else []
|
||||
def __repr__(self):
|
||||
builder = ""
|
||||
builder += "Entity(%s)" % (self.name)
|
||||
builder += "%sEntity(%s)" % ("Abstract " if self.abstract else "", self.name)
|
||||
if len(self.supertypes):
|
||||
builder += "\n Supertypes: %s"%(",".join(self.supertypes))
|
||||
if len(self.attributes):
|
||||
@@ -106,12 +108,20 @@ class SelectType(Node):
|
||||
class SubSuperTypeExpression(Node):
|
||||
type = property(lambda self: self.tokens[0])
|
||||
types = property(lambda self: self.tokens[3::2])
|
||||
abstract = False
|
||||
def init(self):
|
||||
assert self.type == self.class_type
|
||||
if self.tokens[0] == 'abstract':
|
||||
self.tokens = self.tokens[1:]
|
||||
self.abstract = True
|
||||
assert self.type == self.type_relationship
|
||||
|
||||
|
||||
class SubtypeExpression(SubSuperTypeExpression):
|
||||
class_type = 'subtype'
|
||||
class SubTypeExpression(SubSuperTypeExpression):
|
||||
type_relationship = 'subtype'
|
||||
|
||||
|
||||
class SuperTypeExpression(SubSuperTypeExpression):
|
||||
type_relationship = 'supertype'
|
||||
|
||||
|
||||
class AttributeList(Node):
|
||||
@@ -127,7 +137,7 @@ class AttributeList(Node):
|
||||
|
||||
class InverseAttribute(Node):
|
||||
name = property(lambda self: self.tokens[0])
|
||||
type = property(lambda self: self.tokens[2])
|
||||
type = property(lambda self: None if len(self.tokens) == 6 else self.tokens[2])
|
||||
bounds = property(lambda self: None if len(self.tokens) == 6 else self.tokens[3])
|
||||
entity = property(lambda self: self.tokens[-4])
|
||||
attribute = property(lambda self: self.tokens[-2])
|
||||
@@ -149,7 +159,7 @@ class BinaryType(Node):
|
||||
def init(self):
|
||||
pass
|
||||
def __repr__(self):
|
||||
return "BINARY"
|
||||
return "binary"
|
||||
|
||||
|
||||
class BoundSpecification(Node):
|
||||
|
||||
@@ -18,29 +18,34 @@
|
||||
###############################################################################
|
||||
|
||||
import nodes
|
||||
import platform
|
||||
import collections
|
||||
|
||||
if tuple(map(int, platform.python_version_tuple())) < (2, 7):
|
||||
import ordereddict
|
||||
collections.OrderedDict = ordereddict.OrderedDict
|
||||
|
||||
class Schema:
|
||||
def is_enumeration(self, v):
|
||||
return v in self.enumerations
|
||||
return str(v) in self.enumerations
|
||||
def is_select(self, v):
|
||||
return v in self.selects
|
||||
return str(v) in self.selects
|
||||
def is_simpletype(self, v):
|
||||
return v in self.simpletypes
|
||||
return str(v) in self.simpletypes
|
||||
def is_type(self, v):
|
||||
return v in self.types
|
||||
return str(v) in self.types
|
||||
def is_entity(self, v):
|
||||
return v in self.entities
|
||||
return str(v) in self.entities
|
||||
def __init__(self, parsetree):
|
||||
self.name = parsetree[1]
|
||||
|
||||
sort = lambda d: collections.OrderedDict(sorted(d.items()))
|
||||
sort = lambda d: collections.OrderedDict(sorted(d))
|
||||
|
||||
self.types = sort({t.name:t for t in parsetree if isinstance(t, nodes.TypeDeclaration)})
|
||||
self.entities = sort({t.name:t for t in parsetree if isinstance(t, nodes.EntityDeclaration)})
|
||||
self.types = sort([(t.name,t) for t in parsetree if isinstance(t, nodes.TypeDeclaration)])
|
||||
self.entities = sort([(t.name,t) for t in parsetree if isinstance(t, nodes.EntityDeclaration)])
|
||||
|
||||
of_type = lambda *types: sort({a: b.type.type for a,b in self.types.items() if any(isinstance(b.type.type, ty) for ty in types)})
|
||||
of_type = lambda *types: sort([(a, b.type.type) for a,b in self.types.items() if any(isinstance(b.type.type, ty) for ty in types)])
|
||||
|
||||
self.enumerations = of_type(nodes.EnumerationType)
|
||||
self.selects = of_type(nodes.SelectType)
|
||||
self.simpletypes = of_type(str, nodes.AggregationType)
|
||||
self.simpletypes = of_type(str, nodes.AggregationType, nodes.BinaryType)
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import operator
|
||||
|
||||
import nodes
|
||||
import codegen
|
||||
import templates
|
||||
|
||||
class SchemaClass(codegen.Base):
|
||||
def __init__(self, mapping):
|
||||
|
||||
class UnmetDependenciesException(Exception): pass
|
||||
|
||||
schema_name = mapping.schema.name
|
||||
declared_types = []
|
||||
|
||||
def get_declared_type(type, emitted_names=None):
|
||||
if isinstance(type, nodes.AggregationType):
|
||||
aggr_type = type.aggregate_type
|
||||
make_bound = lambda b: -1 if b == '?' else int(b)
|
||||
bound1, bound2 = map(make_bound, (type.bounds.lower, type.bounds.upper))
|
||||
decl_type = get_declared_type(type.type, emitted_names)
|
||||
return "new aggregation_type(aggregation_type::%(aggr_type)s_type, %(bound1)d, %(bound2)d, %(decl_type)s)" % locals()
|
||||
elif isinstance(type, nodes.BinaryType):
|
||||
return "new simple_type(simple_type::binary_type)"
|
||||
elif isinstance(type, str):
|
||||
if mapping.schema.is_type(type) or mapping.schema.is_entity(type):
|
||||
if emitted_names is None or type in emitted_types:
|
||||
return "new named_type(%s_type)" % type
|
||||
else:
|
||||
raise UnmetDependenciesException(type)
|
||||
else:
|
||||
return "new simple_type(simple_type::%s_type)" % type
|
||||
|
||||
def find_inverse_name_and_index(entity_name, attribute_name):
|
||||
attributes_per_subtype = []
|
||||
while True:
|
||||
entity = mapping.schema.entities[entity_name]
|
||||
attr_names = list(map(operator.attrgetter('name'), entity.attributes))
|
||||
if len(attr_names):
|
||||
attributes_per_subtype.append((entity_name, attr_names))
|
||||
if len(entity.supertypes) != 1: break
|
||||
entity_name = entity.supertypes[0]
|
||||
index = 0
|
||||
for et, attrs in attributes_per_subtype[::-1]:
|
||||
try: return et, attrs.index(attribute_name)
|
||||
except: pass
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
statements = ['',
|
||||
'#include "../ifcparse/IfcSchema.h"',
|
||||
'',
|
||||
'using namespace IfcParse;'
|
||||
'']
|
||||
|
||||
collections_by_type = (('entity', mapping.schema.entities ),
|
||||
('type_declaration', mapping.schema.simpletypes ),
|
||||
('select_type', mapping.schema.selects ),
|
||||
('enumeration_type', mapping.schema.enumerations))
|
||||
|
||||
for cpp_type, collection in collections_by_type:
|
||||
for name in collection.keys():
|
||||
statements.append('%(cpp_type)s* %(name)s_type = 0;' % locals())
|
||||
|
||||
statements.append("""
|
||||
#if defined(__clang__)
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("O0")
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma optimize("", off)
|
||||
#endif
|
||||
""")
|
||||
|
||||
statements.append('schema_definition* populate_schema() {')
|
||||
|
||||
emitted_types = set()
|
||||
# while len(emitted_types) < len(set(mapping.schema.simpletypes.keys()) - {"IfcPropertySetDefinitionSet"}):
|
||||
while len(emitted_types) < len(set(mapping.schema.simpletypes.keys()) - {"IfcPropertySetDefinitionSet"}):
|
||||
for name, type in mapping.schema.simpletypes.items():
|
||||
if name in emitted_types: continue
|
||||
|
||||
# No support for types refering to entities :(
|
||||
if name == "IfcPropertySetDefinitionSet": continue
|
||||
|
||||
try:
|
||||
declared_type = get_declared_type(type, emitted_types)
|
||||
except UnmetDependenciesException:
|
||||
continue
|
||||
|
||||
statements.append(' %(name)s_type = new type_declaration(IfcSchema::Type::%(name)s, %(declared_type)s);' % locals())
|
||||
emitted_types.add(name)
|
||||
|
||||
declared_types.append('%(name)s_type' % locals())
|
||||
|
||||
for name, enum in mapping.schema.enumerations.items():
|
||||
statements.append(' {')
|
||||
statements.append(' std::vector<std::string> items; items.reserve(%d);' % len(enum.values))
|
||||
statements.extend(map(lambda v: ' items.push_back("%s");' % v, sorted(enum.values)))
|
||||
statements.append(' %(name)s_type = new enumeration_type(IfcSchema::Type::%(name)s, items);' % locals())
|
||||
statements.append(' }')
|
||||
|
||||
declared_types.append('%(name)s_type' % locals())
|
||||
|
||||
emitted_entities = set()
|
||||
while len(emitted_entities) < len(mapping.schema.entities):
|
||||
for name, type in mapping.schema.entities.items():
|
||||
if name in emitted_entities: continue
|
||||
if len(type.supertypes) == 0 or set(type.supertypes) < emitted_entities:
|
||||
supertype = '0' if len(type.supertypes) == 0 else '%s_type' % type.supertypes[0]
|
||||
statements.append(' %(name)s_type = new entity(IfcSchema::Type::%(name)s, %(supertype)s);' % locals())
|
||||
emitted_entities.add(name)
|
||||
|
||||
declared_types.append('%(name)s_type' % locals())
|
||||
|
||||
emmited = emitted_types | emitted_entities | set(mapping.schema.enumerations.keys())
|
||||
|
||||
emitted_selects = set()
|
||||
while len(emitted_selects) < len(mapping.schema.selects):
|
||||
for name, type in mapping.schema.selects.items():
|
||||
if name in emitted_selects: continue
|
||||
type_values = sorted(set(type.values) - {"IfcPropertySetDefinitionSet"})
|
||||
if set(type_values) < emmited:
|
||||
statements.append(' {')
|
||||
statements.append(' std::vector<const declaration*> items; items.reserve(%d);' % len(type_values))
|
||||
statements.extend(map(lambda v: ' items.push_back(%s_type);' % v, sorted(type_values)))
|
||||
statements.append(' %(name)s_type = new select_type(IfcSchema::Type::%(name)s, items);' % locals())
|
||||
statements.append(' }')
|
||||
emitted_selects.add(name)
|
||||
emmited.add(name)
|
||||
|
||||
declared_types.append('%(name)s_type' % locals())
|
||||
|
||||
num_declarations = len(declared_types)
|
||||
|
||||
for name, type in mapping.schema.entities.items():
|
||||
derived = set(mapping.derived_in_supertype(type))
|
||||
attribute_names = list(map(operator.attrgetter('name'), mapping.arguments(type)))
|
||||
|
||||
statements.append(' {')
|
||||
statements.append(' std::vector<const entity::attribute*> attributes; attributes.reserve(%d);' % len(type.attributes))
|
||||
for attr in type.attributes:
|
||||
attr_name, optional = attr.name, str(attr.optional).lower()
|
||||
decl_type = get_declared_type(attr.type)
|
||||
statements.append(' attributes.push_back(new entity::attribute("%(attr_name)s", %(decl_type)s, %(optional)s));' % locals())
|
||||
statements.append(' std::vector<bool> derived; derived.reserve(%d);' % len(attribute_names))
|
||||
statements.append(' ' + " ".join(map(lambda b: 'derived.push_back(%s);' % str(b in derived).lower(), attribute_names)))
|
||||
statements.append(' %(name)s_type->set_attributes(attributes, derived);' % locals())
|
||||
statements.append(' }')
|
||||
|
||||
for name, type in mapping.schema.entities.items():
|
||||
if type.inverse:
|
||||
statements.append(' {')
|
||||
statements.append(' std::vector<const entity::inverse_attribute*> attributes; attributes.reserve(%d);' % len(type.inverse.elements))
|
||||
for attr in type.inverse.elements:
|
||||
if attr.bounds:
|
||||
make_bound = lambda b: -1 if b == '?' else int(b)
|
||||
bound1, bound2 = map(make_bound, (attr.bounds.lower, attr.bounds.upper))
|
||||
else:
|
||||
bound1, bound2 = -1, -1
|
||||
attr_name, aggr_type, entity_ref = attr.name, attr.type, attr.entity
|
||||
if aggr_type is None: aggr_type = 'unspecified'
|
||||
attribute_entity, attribute_entity_index = find_inverse_name_and_index(entity_ref, attr.attribute)
|
||||
statements.append(' attributes.push_back(new entity::inverse_attribute("%(attr_name)s", entity::inverse_attribute::%(aggr_type)s_type, %(bound1)d, %(bound2)d, %(entity_ref)s_type, %(attribute_entity)s_type->attributes()[%(attribute_entity_index)d]));' % locals())
|
||||
statements.append(' %(name)s_type->set_inverse_attributes(attributes);' % locals())
|
||||
statements.append(' }')
|
||||
|
||||
statements.append('')
|
||||
statements.append(' std::vector<const declaration*> declarations; declarations.reserve(%(num_declarations)d);' % locals())
|
||||
for type_name in declared_types:
|
||||
statements.append(' declarations.push_back(%(type_name)s);' % locals())
|
||||
|
||||
statements.append(' return new schema_definition("%(schema_name)s", declarations, true);' % locals())
|
||||
|
||||
statements.extend(('}',''))
|
||||
|
||||
statements.append("""
|
||||
#if defined(__clang__)
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
#pragma GCC pop_options
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma optimize("", on)
|
||||
#endif
|
||||
""")
|
||||
|
||||
statements.extend(('const schema_definition& get_schema() {',
|
||||
'',
|
||||
' static const schema_definition* s = populate_schema();',
|
||||
' return *s;',
|
||||
'}','',''))
|
||||
|
||||
self.str = "\n".join(statements)
|
||||
|
||||
self.file_name = '%s-schema.cpp'%self.schema_name
|
||||
|
||||
def __repr__(self):
|
||||
return self.str
|
||||
@@ -23,18 +23,27 @@ 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
|
||||
|
||||
@@ -42,9 +51,13 @@ namespace %(schema_name)s {
|
||||
|
||||
%(class_definitions)s
|
||||
void InitStringMap();
|
||||
IfcUtil::IfcSchemaEntity SchemaEntity(IfcAbstractEntityPtr e = 0);
|
||||
IfcUtil::IfcBaseClass* SchemaEntity(IfcAbstractEntity* e = 0);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
"""
|
||||
|
||||
@@ -58,7 +71,7 @@ namespace %(schema_name)s {
|
||||
|
||||
namespace Type {
|
||||
typedef enum {
|
||||
%(types)s, ALL
|
||||
%(types)s, UNDEFINED
|
||||
} Enum;
|
||||
Enum Parent(Enum v);
|
||||
Enum FromString(const std::string& s);
|
||||
@@ -71,7 +84,7 @@ namespace Type {
|
||||
#endif
|
||||
"""
|
||||
|
||||
rt_header = """
|
||||
lb_header = """
|
||||
#ifndef %(schema_name_upper)sRT_H
|
||||
#define %(schema_name_upper)sRT_H
|
||||
|
||||
@@ -86,12 +99,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);
|
||||
Enum GetAttributeEnumerationClass(Enum t, unsigned char a);
|
||||
std::set<std::string> GetInverseAttributeNames(Enum t);
|
||||
void PopulateDerivedFields(IfcWrite::IfcWritableEntity* e);
|
||||
}}
|
||||
|
||||
@@ -100,15 +114,21 @@ 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;
|
||||
|
||||
IfcUtil::IfcSchemaEntity %(schema_name)s::SchemaEntity(IfcAbstractEntityPtr e) {
|
||||
// External definitions
|
||||
%(external_definitions)s
|
||||
|
||||
IfcUtil::IfcBaseClass* %(schema_name)s::SchemaEntity(IfcAbstractEntity* e) {
|
||||
switch(e->type()) {
|
||||
%(schema_entity_statements)s
|
||||
default: throw IfcException("Unable to find find keyword in schema"); break;
|
||||
@@ -145,33 +165,16 @@ bool Type::IsSimple(Enum v) {
|
||||
|
||||
%(enumeration_functions)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;
|
||||
%(simple_type_impl)s
|
||||
|
||||
%(entity_implementations)s
|
||||
"""
|
||||
|
||||
rt_implementation = """
|
||||
lb_implementation = """
|
||||
#include <set>
|
||||
|
||||
#include "../ifcparse/%(schema_name)s.h"
|
||||
#include "../ifcparse/%(schema_name)s-rt.h"
|
||||
#include "../ifcparse/%(schema_name)s-latebound.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/IfcWrite.h"
|
||||
#include "../ifcparse/IfcWritableEntity.h"
|
||||
@@ -183,10 +186,23 @@ using namespace IfcParse;
|
||||
using namespace IfcWrite;
|
||||
using namespace IfcUtil;
|
||||
|
||||
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;
|
||||
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
|
||||
|
||||
void InitDescriptorMap() {
|
||||
IfcEntityDescriptor* current;
|
||||
@@ -205,6 +221,13 @@ void InitDerivedMap() {
|
||||
%(derived_field_statements)s
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
#pragma GCC pop_options
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma optimize("", on)
|
||||
#endif
|
||||
|
||||
int Type::GetAttributeIndex(Enum t, const std::string& a) {
|
||||
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
|
||||
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
|
||||
@@ -226,6 +249,13 @@ 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);
|
||||
@@ -254,35 +284,49 @@ std::pair<const char*, int> Type::GetEnumerationIndex(Enum t, const std::string&
|
||||
}
|
||||
|
||||
std::pair<Type::Enum, unsigned> Type::GetInverseAttribute(Enum t, const std::string& a) {
|
||||
if (inverse_map.empty()) ::InitInverseMap();
|
||||
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;
|
||||
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;
|
||||
}
|
||||
throw IfcException("Attribute not found");
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
@@ -290,8 +334,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 = ' current->add("%(name)s",%(optional)s,%(type)s);'
|
||||
entity_descriptor_attribute_enum = ' current->add("%(name)s",%(optional)s,%(type)s,Type::%(enum_type)s);'
|
||||
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);'
|
||||
|
||||
enumeration_descriptor = """ values.clear(); values.reserve(128);
|
||||
%(enumeration_descriptor_values)s
|
||||
@@ -303,11 +347,32 @@ derived_field_statement = ' {std::set<int> idxs; %(statements)sderived_map[Ty
|
||||
derived_field_statement_attrs = 'idxs.insert(%d); '
|
||||
|
||||
simpletype = """%(documentation)s
|
||||
typedef %(type)s %(name)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;
|
||||
};
|
||||
"""
|
||||
|
||||
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::IfcSchemaEntity %(name)s;
|
||||
typedef IfcUtil::IfcBaseClass %(name)s;
|
||||
"""
|
||||
|
||||
enumeration = """namespace %(name)s {
|
||||
@@ -321,18 +386,11 @@ const char* ToString(%(name)s v);
|
||||
entity = """%(documentation)s
|
||||
class %(name)s %(superclass)s{
|
||||
public:
|
||||
%(attributes)s virtual unsigned int getArgumentCount() const { return %(argument_count)d; }
|
||||
virtual IfcUtil::ArgumentType getArgumentType(unsigned int i) const {%(argument_type_function_body)s}
|
||||
virtual 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;
|
||||
%(attributes)s %(inverse)s virtual const IfcParse::entity& declaration() const;
|
||||
static Type::Enum Class();
|
||||
%(name)s (IfcAbstractEntityPtr e);
|
||||
%(name)s (IfcAbstractEntity* e);
|
||||
%(name)s (%(constructor_arguments)s);
|
||||
typedef %(name)s* ptr;
|
||||
typedef SHARED_PTR< IfcTemplatedEntityList< %(name)s > > list;
|
||||
typedef IfcTemplatedEntityList< %(name)s >::it it;
|
||||
typedef IfcTemplatedEntityList< %(name)s > list;
|
||||
};
|
||||
"""
|
||||
|
||||
@@ -350,43 +408,50 @@ const char* %(name)s::ToString(%(name)s v) {
|
||||
"""
|
||||
|
||||
entity_implementation = """// Function implementations for %(name)s
|
||||
%(attributes)s%(inverse)sbool %(name)s::is(Type::Enum v) const { return v == Type::%(name)s%(parent_type_test)s; }
|
||||
Type::Enum %(name)s::type() const { return Type::%(name)s; }
|
||||
%(attributes)s
|
||||
%(inverse)s
|
||||
const IfcParse::entity& %(name)s::declaration() const { return *%(name)s_type; }
|
||||
Type::Enum %(name)s::Class() { return Type::%(name)s; }
|
||||
%(name)s::%(name)s(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); }
|
||||
%(name)s::%(name)s(IfcAbstractEntity* e) : %(superclass)s { if (!e) return; if (!e->is(Type::%(name)s)) throw IfcException("Unable to find find keyword in schema"); data_ = e; }
|
||||
%(name)s::%(name)s(%(constructor_arguments)s) : %(superclass)s { IfcWritableEntity* e = new IfcWritableEntity(Class());%(constructor_implementation)s data_ = e; EntityBuffer::Add(this); }
|
||||
"""
|
||||
|
||||
optional_attribute_description = "/// Whether the optional attribute %s is defined for this %s"
|
||||
|
||||
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]*/"
|
||||
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"
|
||||
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"
|
||||
|
||||
enum_from_string_stmt = ' if (s == "%(value)s") return ::%(schema_name)s::%(name)s::%(short_name)s_%(value)s;'
|
||||
|
||||
schema_entity_stmt = ' case Type::%(name)s: return new %(name)s(e); break;'
|
||||
schema_simple_stmt = ' case Type::%(name)s: return new IfcUtil::IfcEntitySelect(e); break;'
|
||||
string_map_statement = ' string_map["%(uppercase_name)s"%(padding)s] = Type::%(name)s;'
|
||||
parent_type_stmt = ' if(v==%(name)s%(padding)s) { return %(parent)s; }'
|
||||
|
||||
parent_type_test = " || %s::is(v)"
|
||||
|
||||
optional_attr_stmt = "return !entity->getArgument(%(index)d)->isNull();"
|
||||
optional_attr_stmt = "return !data_->getArgument(%(index)d)->isNull();"
|
||||
|
||||
get_attr_stmt = "return *entity->getArgument(%(index)d);"
|
||||
get_attr_stmt_enum = "return %(type)s::FromString(*entity->getArgument(%(index)d));"
|
||||
get_attr_stmt_entity = "return (%(type)s)((IfcUtil::IfcSchemaEntity)(*entity->getArgument(%(index)d)));"
|
||||
get_attr_stmt_array = "RETURN_AS_LIST(%(list_instance_type)s,%(index)d)"
|
||||
get_attr_stmt = "return *data_->getArgument(%(index)d);"
|
||||
get_attr_stmt_enum = "return %(type)s::FromString(*data_->getArgument(%(index)d));"
|
||||
get_attr_stmt_entity = "return (%(type)s)((IfcUtil::IfcBaseClass*)(*data_->getArgument(%(index)d)));"
|
||||
get_attr_stmt_array = "IfcEntityList::ptr es = *data_->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
|
||||
get_attr_stmt_nested_array = "IfcEntityListList::ptr es = *data_->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
|
||||
|
||||
get_inverse = "RETURN_INVERSE(%(type)s)"
|
||||
get_inverse = "return data_->getInverse(Type::%(type)s, %(index)d)->as<%(type)s>();"
|
||||
|
||||
set_attr_stmt = "if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%(index)d,v);"
|
||||
set_attr_stmt_enum = "if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%(index)d,v,%(type)s::ToString(v));"
|
||||
set_attr_stmt_array = "if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%(index)d,v->generalize());"
|
||||
set_attr_stmt = "if ( ! data_->isWritable() ) { data_ = new IfcWritableEntity(data_); } ((IfcWritableEntity*)data_)->setArgument(%(index)d,v);"
|
||||
set_attr_stmt_enum = "if ( ! data_->isWritable() ) { data_ = new IfcWritableEntity(data_); } ((IfcWritableEntity*)data_)->setArgument(%(index)d,v,%(type)s::ToString(v));"
|
||||
set_attr_stmt_array = "if ( ! data_->isWritable() ) { data_ = new IfcWritableEntity(data_); } ((IfcWritableEntity*)data_)->setArgument(%(index)d,v->generalize());"
|
||||
|
||||
constructor_stmt = " e->setArgument(%(index)d,(%(name)s));"
|
||||
constructor_stmt_enum = " e->setArgument(%(index)d,%(name)s,%(type)s::ToString(%(name)s));"
|
||||
@@ -394,7 +459,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.insert(std::make_pair(std::make_pair(Type::%(type)s, \"%(name)s\"), std::make_pair(Type::%(related_type)s, %(index)d)));"
|
||||
inverse_implementation = " inverse_map[Type::%(type)s].insert(std::make_pair(\"%(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 ""
|
||||
|
||||
+90
-22
@@ -36,14 +36,33 @@
|
||||
#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
|
||||
@@ -62,9 +81,6 @@ namespace IfcGeom {
|
||||
// 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
|
||||
@@ -76,25 +92,24 @@ namespace IfcGeom {
|
||||
// The precision used in boolean operations, setting this value too low results
|
||||
// in artefacts and potentially modelling failures
|
||||
// Default: 0.00001 (obtained from IfcGeometricRepresentationContext if available)
|
||||
GV_PRECISION
|
||||
GV_PRECISION,
|
||||
// Whether to process shapes of type Face or higher (1) Wire or lower (-1) or all (0)
|
||||
GV_DIMENSIONALITY
|
||||
};
|
||||
|
||||
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);
|
||||
bool is_shape_collection(const IfcUtil::IfcBaseClass* L);
|
||||
IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseClass* L);
|
||||
bool convert_shape(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
|
||||
bool flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse);
|
||||
bool convert_wire(const IfcUtil::IfcBaseClass* L, TopoDS_Wire& result);
|
||||
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::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);
|
||||
bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
|
||||
bool convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
|
||||
IfcSchema::IfcSurfaceStyleShading* get_surface_style(IfcSchema::IfcRepresentationItem* item);
|
||||
const IfcSchema::IfcRepresentationItem* find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item);
|
||||
bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid);
|
||||
bool is_compound(const TopoDS_Shape& shape);
|
||||
bool is_convex(const TopoDS_Wire& wire);
|
||||
@@ -106,19 +121,72 @@ namespace IfcGeom {
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
namespace Cache {
|
||||
void Purge();
|
||||
void PurgeShapeCache();
|
||||
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) {
|
||||
// For certain representation items, most notably boolean operands,
|
||||
// a style definition might reside on one of its operands.
|
||||
representation_item = find_item_carrying_style(representation_item);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#include "IfcRegisterGeomHeader.h"
|
||||
|
||||
};
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* tesselate(TopoDS_Shape& shape, double deflection, IfcEntityList::ptr es);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -77,32 +77,36 @@
|
||||
|
||||
#include <TopLoc_Location.hxx>
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include <Geom_BSplineCurve.hxx>
|
||||
#endif
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcCircle::ptr l, Handle(Geom_Curve)& curve) {
|
||||
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircle* l, Handle(Geom_Curve)& curve) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
if ( r < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l);
|
||||
return false;
|
||||
}
|
||||
gp_Trsf trsf;
|
||||
IfcSchema::IfcAxis2Placement placement = l->Position();
|
||||
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
IfcGeom::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
IfcSchema::IfcAxis2Placement* placement = l->Position();
|
||||
if (placement->declaration().is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
} else {
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::convert((IfcAxis2Placement2D*)placement,trsf2d);
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d);
|
||||
trsf = trsf2d;
|
||||
}
|
||||
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
|
||||
curve = new Geom_Circle(ax, r);
|
||||
return true;
|
||||
}
|
||||
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);
|
||||
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);
|
||||
if (x < ALMOST_ZERO || y < ALMOST_ZERO) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l);
|
||||
return false;
|
||||
}
|
||||
// Open Cascade does not allow ellipses of which the minor radius
|
||||
@@ -111,12 +115,12 @@ bool IfcGeom::convert(const IfcSchema::IfcEllipse::ptr l, Handle(Geom_Curve)& cu
|
||||
// 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->is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
IfcGeom::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
IfcSchema::IfcAxis2Placement* placement = l->Position();
|
||||
if (placement->declaration().is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
} else {
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d);
|
||||
convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d);
|
||||
trsf = trsf2d;
|
||||
}
|
||||
gp_Ax2 ax = gp_Ax2();
|
||||
@@ -128,11 +132,46 @@ bool IfcGeom::convert(const IfcSchema::IfcEllipse::ptr l, Handle(Geom_Curve)& cu
|
||||
curve = new Geom_Ellipse(ax, x, y);
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const IfcSchema::IfcLine::ptr l, Handle(Geom_Curve)& curve) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcLine* l, Handle(Geom_Curve)& curve) {
|
||||
gp_Pnt pnt;gp_Vec vec;
|
||||
IfcGeom::convert(l->Pnt(),pnt);
|
||||
IfcGeom::convert(l->Dir(),vec);
|
||||
convert(l->Pnt(),pnt);
|
||||
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
|
||||
@@ -0,0 +1,162 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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
|
||||
+425
-235
@@ -47,6 +47,7 @@
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
#include <Geom_Line.hxx>
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include <Geom_TrimmedCurve.hxx>
|
||||
@@ -70,6 +71,7 @@
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopoDS_Iterator.hxx>
|
||||
|
||||
#include <BRepAlgoAPI_Cut.hxx>
|
||||
|
||||
@@ -83,134 +85,238 @@
|
||||
#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::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();
|
||||
}
|
||||
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 ( ! 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;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
|
||||
|
||||
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());
|
||||
Handle(Geom_Surface) face_surface;
|
||||
const bool is_face_surface = l->declaration().is(IfcSchema::Type::IfcFaceSurface);
|
||||
|
||||
double x = 0, y = 0, z = 0;
|
||||
gp_Pnt current, previous, first;
|
||||
int n = 0;
|
||||
// Iterate over the vertices of the outer wire (discarding
|
||||
// any potential holes)
|
||||
for ( TopExp_Explorer exp(outer_wire,TopAbs_VERTEX);; exp.Next()) {
|
||||
unsigned has_more = exp.More();
|
||||
if ( has_more ) {
|
||||
const TopoDS_Vertex& v = TopoDS::Vertex(exp.Current());
|
||||
current = BRep_Tool::Pnt(v);
|
||||
} else {
|
||||
current = first;
|
||||
}
|
||||
if ( n ) {
|
||||
const double& xn = previous.X();
|
||||
const double& yn = previous.Y();
|
||||
const double& zn = previous.Z();
|
||||
const double& xn1 = current.X();
|
||||
const double& yn1 = current.Y();
|
||||
const double& zn1 = current.Z();
|
||||
x += (yn-yn1)*(zn+zn1);
|
||||
y += (xn+xn1)*(zn-zn1);
|
||||
z += (xn-xn1)*(yn+yn1);
|
||||
} else {
|
||||
first = current;
|
||||
}
|
||||
if ( !has_more ) {
|
||||
break;
|
||||
}
|
||||
previous = current;
|
||||
++n;
|
||||
}
|
||||
if (is_face_surface) {
|
||||
IfcSchema::IfcFaceSurface* fs = (IfcSchema::IfcFaceSurface*) l;
|
||||
fs->FaceSurface();
|
||||
// FIXME: Surfaces are interpreted as a TopoDS_Shape
|
||||
TopoDS_Shape surface_shape;
|
||||
if (!convert_shape(fs->FaceSurface(), surface_shape)) return false;
|
||||
|
||||
// If Newell's normal does not point in the same direction
|
||||
// as the topological face normal the face orientation is
|
||||
// reversed
|
||||
gp_Vec face_normal2(x,y,z);
|
||||
if ( face_normal1.Dot(face_normal2) < 0 ) {
|
||||
TopAbs_Orientation o = face.Orientation();
|
||||
face.Orientation(o == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD);
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
|
||||
// It might be a good idea to globally discard faces
|
||||
// smaller than a certain treshold value. But for now
|
||||
// only when processing IfcConnectedFacesets the small
|
||||
// faces are skipped.
|
||||
// return face_area(face) > 0.0001;
|
||||
return true;
|
||||
const int num_bounds = bounds->size();
|
||||
int num_outer_bounds = 0;
|
||||
|
||||
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
|
||||
IfcSchema::IfcFaceBound* bound = *it;
|
||||
if (bound->declaration().is(IfcSchema::Type::IfcFaceOuterBound)) num_outer_bounds ++;
|
||||
}
|
||||
|
||||
// The number of outer bounds should be one according to the schema. Also Open Cascade
|
||||
// expects this, but it is not strictly checked. Regardless, if the number is greater,
|
||||
// the face will still be processed as long as there are no holes. A compound of faces
|
||||
// is returned in that case.
|
||||
if (num_bounds > 1 && num_outer_bounds > 1 && num_bounds != num_outer_bounds) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
if (num_outer_bounds > 1) {
|
||||
builder.MakeCompound(compound);
|
||||
}
|
||||
|
||||
// The builder is initialized on the heap because of the various different moments
|
||||
// of initialization depending on the configuration of surfaces and boundaries.
|
||||
BRepBuilderAPI_MakeFace* mf = 0;
|
||||
|
||||
bool success = false;
|
||||
int processed = 0;
|
||||
|
||||
for (int process_interior = 0; process_interior <= 1; ++process_interior) {
|
||||
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
|
||||
IfcSchema::IfcFaceBound* bound = *it;
|
||||
IfcSchema::IfcLoop* loop = bound->Bound();
|
||||
|
||||
bool same_sense = bound->Orientation();
|
||||
const bool is_interior =
|
||||
!bound->declaration().is(IfcSchema::Type::IfcFaceOuterBound) &&
|
||||
(num_bounds > 1) &&
|
||||
(num_outer_bounds < num_bounds);
|
||||
|
||||
// The exterior face boundary is processed first
|
||||
if (is_interior == !process_interior) continue;
|
||||
|
||||
TopoDS_Wire wire;
|
||||
if (!convert_wire(loop, wire)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop);
|
||||
delete mf;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
The approach below does not result in a significant speed-up
|
||||
if (loop->declaration().is(IfcSchema::Type::IfcPolyLoop) && processed == 0 && face_surface.IsNull()) {
|
||||
IfcSchema::IfcPolyLoop* polyloop = (IfcSchema::IfcPolyLoop*) loop;
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points = polyloop->Polygon();
|
||||
|
||||
if (points->size() == 3) {
|
||||
// Help Open Cascade by finding the plane more efficiently
|
||||
IfcSchema::IfcCartesianPoint::list::it point_iterator = points->begin();
|
||||
gp_Pnt a, b, c;
|
||||
convert(*point_iterator++, a);
|
||||
convert(*point_iterator++, b);
|
||||
convert(*point_iterator++, c);
|
||||
const gp_XYZ ab = (b.XYZ() - a.XYZ());
|
||||
const gp_XYZ ac = (c.XYZ() - a.XYZ());
|
||||
const gp_Vec cross = ab.Crossed(ac);
|
||||
if (cross.SquareMagnitude() > ALMOST_ZERO) {
|
||||
const gp_Dir n = cross;
|
||||
face_surface = new Geom_Plane(a, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (!same_sense) {
|
||||
wire.Reverse();
|
||||
}
|
||||
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
FTol.SetTolerance(wire, getValue(GV_PRECISION), TopAbs_WIRE);
|
||||
|
||||
if (!mf) {
|
||||
if (face_surface.IsNull()) {
|
||||
mf = new BRepBuilderAPI_MakeFace(wire);
|
||||
} else {
|
||||
mf = new BRepBuilderAPI_MakeFace(face_surface, wire);
|
||||
}
|
||||
|
||||
/* BRepBuilderAPI_FaceError er = mf->Error();
|
||||
if (er == BRepBuilderAPI_NotPlanar) {
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
FTol.SetTolerance(wire, getValue(GV_PRECISION), TopAbs_WIRE);
|
||||
delete mf;
|
||||
mf = new BRepBuilderAPI_MakeFace(wire);
|
||||
} */
|
||||
|
||||
if (mf->IsDone()) {
|
||||
TopoDS_Face outer_face_bound = mf->Face();
|
||||
|
||||
if (BRepCheck_Face(outer_face_bound).OrientationOfWires() == BRepCheck_BadOrientationOfSubshape) {
|
||||
wire.Reverse();
|
||||
same_sense = !same_sense;
|
||||
delete mf;
|
||||
if (face_surface.IsNull()) {
|
||||
mf = new BRepBuilderAPI_MakeFace(wire);
|
||||
} else {
|
||||
mf = new BRepBuilderAPI_MakeFace(face_surface, wire);
|
||||
}
|
||||
ShapeFix_Face fix(mf->Face());
|
||||
fix.FixOrientation();
|
||||
fix.Perform();
|
||||
outer_face_bound = fix.Face();
|
||||
}
|
||||
|
||||
// If the wires are reversed the face needs to be reversed as well in order
|
||||
// to maintain the counter-clock-wise ordering of the bounding wire's vertices.
|
||||
bool all_reversed = true;
|
||||
TopoDS_Iterator jt(outer_face_bound, false);
|
||||
for (; jt.More(); jt.Next()) {
|
||||
const TopoDS_Wire& w = TopoDS::Wire(jt.Value());
|
||||
if ((w.Orientation() != TopAbs_REVERSED) == same_sense) {
|
||||
all_reversed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_reversed) {
|
||||
outer_face_bound.Reverse();
|
||||
}
|
||||
|
||||
if (num_outer_bounds > 1) {
|
||||
builder.Add(compound, outer_face_bound);
|
||||
delete mf; mf = 0;
|
||||
} else if (num_bounds > 1) {
|
||||
// Reinitialize the builder to the outer face
|
||||
// bound in order to add holes more robustly.
|
||||
delete mf;
|
||||
// TODO: What about the face_surface?
|
||||
mf = new BRepBuilderAPI_MakeFace(outer_face_bound);
|
||||
} else {
|
||||
face = outer_face_bound;
|
||||
success = true;
|
||||
}
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary", bound);
|
||||
delete mf;
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
mf->Add(wire);
|
||||
}
|
||||
processed ++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
success = processed == num_bounds;
|
||||
if (success) {
|
||||
if (num_outer_bounds > 1) {
|
||||
face = compound;
|
||||
} else {
|
||||
success = success && mf->IsDone();
|
||||
if (success) {
|
||||
face = mf->Face();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
FTol.SetTolerance(face, getValue(GV_PRECISION), TopAbs_FACE);
|
||||
}
|
||||
|
||||
delete mf;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcArbitraryClosedProfileDef::ptr l, TopoDS_Shape& face) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, TopoDS_Shape& face) {
|
||||
TopoDS_Wire wire;
|
||||
if ( ! IfcGeom::convert_wire(l->OuterCurve(),wire) ) return false;
|
||||
if ( ! convert_wire(l->OuterCurve(),wire) ) return false;
|
||||
|
||||
TopoDS_Face f;
|
||||
bool success = IfcGeom::convert_wire_to_face(wire, f);
|
||||
bool success = convert_wire_to_face(wire, f);
|
||||
if (success) face = f;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids::ptr l, TopoDS_Shape& face) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids* l, TopoDS_Shape& face) {
|
||||
TopoDS_Wire profile;
|
||||
if ( ! IfcGeom::convert_wire(l->OuterCurve(),profile) ) return false;
|
||||
if ( ! convert_wire(l->OuterCurve(),profile) ) return false;
|
||||
BRepBuilderAPI_MakeFace mf(profile);
|
||||
IfcSchema::IfcCurve::list voids = l->InnerCurves();
|
||||
for( IfcSchema::IfcCurve::it it = voids->begin(); it != voids->end(); ++ it ) {
|
||||
IfcSchema::IfcCurve::list::ptr voids = l->InnerCurves();
|
||||
for( IfcSchema::IfcCurve::list::it it = voids->begin(); it != voids->end(); ++ it ) {
|
||||
TopoDS_Wire hole;
|
||||
if ( IfcGeom::convert_wire(*it,hole) ) {
|
||||
if ( convert_wire(*it,hole) ) {
|
||||
mf.Add(hole);
|
||||
}
|
||||
}
|
||||
@@ -220,52 +326,52 @@ bool IfcGeom::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids::ptr l, T
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::convert(l->Position(),trsf2d);
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf2d);
|
||||
double coords[8] = {-x,-y,x,-y,x,y,-x,y};
|
||||
return IfcGeom::profile_helper(4,coords,0,0,0,trsf2d,face);
|
||||
return profile_helper(4,coords,0,0,0,trsf2d,face);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || r < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::convert(l->Position(),trsf2d);
|
||||
IfcGeom::Kernel::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 IfcGeom::profile_helper(4,coords,4,fillets,radii,trsf2d,face);
|
||||
return profile_helper(4,coords,4,fillets,radii,trsf2d,face);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
const bool fr1 = l->hasInnerFilletRadius();
|
||||
const bool fr1 = l->hasOuterFilletRadius();
|
||||
const bool fr2 = l->hasInnerFilletRadius();
|
||||
|
||||
const double r1 = fr2 ? l->OuterFilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT) : 0.;
|
||||
const double r2 = fr1 ? l->InnerFilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT) : 0.;
|
||||
const double r1 = fr1 ? l->OuterFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.;
|
||||
const double r2 = fr2 ? l->InnerFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.;
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -273,15 +379,15 @@ bool IfcGeom::convert(const IfcSchema::IfcRectangleHollowProfileDef::ptr l, Topo
|
||||
TopoDS_Face f2;
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::convert(l->Position(),trsf2d);
|
||||
IfcGeom::Kernel::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 = 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);
|
||||
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);
|
||||
|
||||
if (!s1 || !s2) return false;
|
||||
|
||||
@@ -300,53 +406,69 @@ bool IfcGeom::convert(const IfcSchema::IfcRectangleHollowProfileDef::ptr l, Topo
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
if ( x1 < ALMOST_ZERO || w < ALMOST_ZERO || y < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::convert(l->Position(),trsf2d);
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf2d);
|
||||
double coords[8] = {-x1,-y, x1,-y, dx+w-x1,y, dx-x1,y};
|
||||
return IfcGeom::profile_helper(4,coords,0,0,0,trsf2d,face);
|
||||
return profile_helper(4,coords,0,0,0,trsf2d,face);
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
if ( x == 0.0f || y == 0.0f || d1 == 0.0f || d2 == 0.0f ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::convert(l->Position(),trsf2d);
|
||||
convert(l->Position(),trsf2d);
|
||||
|
||||
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};
|
||||
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};
|
||||
int fillets[4] = {3,4,9,10};
|
||||
double radii[4] = {f,f,f,f};
|
||||
return IfcGeom::profile_helper(12,coords,doFillet ? 4 : 0,fillets,radii,trsf2d,face);
|
||||
double radii[4] = {f1,f1,f2,f2};
|
||||
return profile_helper(12,coords,(doFillet1||doFillet2) ? 4 : 0,fillets,radii,trsf2d,face);
|
||||
}
|
||||
|
||||
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 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 doFillet = l->hasFilletRadius();
|
||||
bool doEdgeFillet = l->hasEdgeRadius();
|
||||
@@ -355,74 +477,74 @@ bool IfcGeom::convert(const IfcSchema::IfcZShapeProfileDef::ptr l, TopoDS_Shape&
|
||||
double f2 = 0.;
|
||||
|
||||
if ( doFillet ) {
|
||||
f1 = l->FilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
if ( doEdgeFillet ) {
|
||||
f2 = l->EdgeRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
f2 = l->EdgeRadius() * 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->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::convert(l->Position(),trsf2d);
|
||||
IfcGeom::Kernel::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 IfcGeom::profile_helper(8,coords,(doFillet || doEdgeFillet) ? 4 : 0,fillets,radii,trsf2d,face);
|
||||
return profile_helper(8,coords,(doFillet || doEdgeFillet) ? 4 : 0,fillets,radii,trsf2d,face);
|
||||
}
|
||||
|
||||
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 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 doFillet = l->hasInternalFilletRadius();
|
||||
double f1 = 0;
|
||||
double f2 = 0;
|
||||
if ( doFillet ) {
|
||||
f1 = l->InternalFilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
f1 = l->InternalFilletRadius() * 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->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::convert(l->Position(),trsf2d);
|
||||
IfcGeom::Kernel::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 IfcGeom::profile_helper(12,coords,doFillet ? 8 : 0,fillets,radii,trsf2d,face);
|
||||
return profile_helper(12,coords,doFillet ? 8 : 0,fillets,radii,trsf2d,face);
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcLShapeProfileDef::ptr l, TopoDS_Shape& face) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* 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 * 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.;
|
||||
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.;
|
||||
|
||||
double f1 = 0.0f;
|
||||
double f2 = 0.0f;
|
||||
if (doFillet) {
|
||||
f1 = l->FilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
if ( doEdgeFillet) {
|
||||
f2 = l->EdgeRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -454,7 +576,7 @@ bool IfcGeom::convert(const IfcSchema::IfcLShapeProfileDef::ptr l, TopoDS_Shape&
|
||||
const double det = a1*b2 - a2*b1;
|
||||
|
||||
if (ALMOST_THE_SAME(det, 0.)) {
|
||||
Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -463,24 +585,24 @@ bool IfcGeom::convert(const IfcSchema::IfcLShapeProfileDef::ptr l, TopoDS_Shape&
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::convert(l->Position(),trsf2d);
|
||||
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 IfcGeom::profile_helper(6,coords,doFillet ? 3 : 0,fillets,radii,trsf2d,face);
|
||||
return profile_helper(6,coords,doFillet ? 3 : 0,fillets,radii,trsf2d,face);
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcUShapeProfileDef::ptr l, TopoDS_Shape& face) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcUShapeProfileDef* 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 * 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.;
|
||||
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.;
|
||||
|
||||
double dy1 = 0.0f;
|
||||
double dy2 = 0.0f;
|
||||
@@ -488,10 +610,10 @@ bool IfcGeom::convert(const IfcSchema::IfcUShapeProfileDef::ptr l, TopoDS_Shape&
|
||||
double f2 = 0.0f;
|
||||
|
||||
if (doFillet) {
|
||||
f1 = l->FilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
if (doEdgeFillet) {
|
||||
f2 = l->EdgeRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
|
||||
if (hasSlope) {
|
||||
@@ -500,35 +622,35 @@ bool IfcGeom::convert(const IfcSchema::IfcUShapeProfileDef::ptr l, TopoDS_Shape&
|
||||
}
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::convert(l->Position(),trsf2d);
|
||||
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 IfcGeom::profile_helper(8, coords, (doFillet || doEdgeFillet) ? 4 : 0, fillets, radii, trsf2d, face);
|
||||
return profile_helper(8, coords, (doFillet || doEdgeFillet) ? 4 : 0, fillets, radii, trsf2d, face);
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcTShapeProfileDef::ptr l, TopoDS_Shape& face) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* 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 * 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.;
|
||||
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.;
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -541,13 +663,13 @@ bool IfcGeom::convert(const IfcSchema::IfcTShapeProfileDef::ptr l, TopoDS_Shape&
|
||||
double f3 = 0.0f;
|
||||
|
||||
if (doFillet) {
|
||||
f1 = l->FilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
if (doWebEdgeFillet) {
|
||||
f2 = l->WebEdgeRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
f2 = l->WebEdgeRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
if (doFlangeEdgeFillet) {
|
||||
f3 = l->FlangeEdgeRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
f3 = l->FlangeEdgeRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
|
||||
double xx, xy;
|
||||
@@ -576,7 +698,7 @@ bool IfcGeom::convert(const IfcSchema::IfcTShapeProfileDef::ptr l, TopoDS_Shape&
|
||||
const double det = a1*b2 - a2*b1;
|
||||
|
||||
if (ALMOST_THE_SAME(det, 0.)) {
|
||||
Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -588,23 +710,23 @@ bool IfcGeom::convert(const IfcSchema::IfcTShapeProfileDef::ptr l, TopoDS_Shape&
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::convert(l->Position(),trsf2d);
|
||||
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 IfcGeom::profile_helper(8, coords, (doFillet || doWebEdgeFillet || doFlangeEdgeFillet) ? 6 : 0, fillets, radii, trsf2d, face);
|
||||
return profile_helper(8, coords, (doFillet || doWebEdgeFillet || doFlangeEdgeFillet) ? 6 : 0, fillets, radii, trsf2d, face);
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcCircleProfileDef::ptr l, TopoDS_Shape& face) {
|
||||
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleProfileDef* l, TopoDS_Shape& face) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
if ( r == 0.0f ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf;
|
||||
IfcGeom::convert(l->Position(),trsf);
|
||||
convert(l->Position(),trsf);
|
||||
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
|
||||
@@ -613,22 +735,22 @@ bool IfcGeom::convert(const IfcSchema::IfcCircleProfileDef::ptr l, TopoDS_Shape&
|
||||
w.Add(edge);
|
||||
|
||||
TopoDS_Face f;
|
||||
bool success = IfcGeom::convert_wire_to_face(w, f);
|
||||
bool success = convert_wire_to_face(w, f);
|
||||
if (success) face = f;
|
||||
return success;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
if ( r == 0.0f || t == 0.0f ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf;
|
||||
IfcGeom::convert(l->Position(),trsf);
|
||||
convert(l->Position(),trsf);
|
||||
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
|
||||
|
||||
BRepBuilderAPI_MakeWire outer;
|
||||
@@ -647,18 +769,18 @@ bool IfcGeom::convert(const IfcSchema::IfcCircleHollowProfileDef::ptr l, TopoDS_
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
if ( rx < ALMOST_ZERO || ry < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool rotated = ry > rx;
|
||||
gp_Trsf2d trsf;
|
||||
IfcGeom::convert(l->Position(),trsf);
|
||||
convert(l->Position(),trsf);
|
||||
|
||||
gp_Ax2 ax = gp_Ax2();
|
||||
if (rotated) {
|
||||
@@ -673,16 +795,16 @@ bool IfcGeom::convert(const IfcSchema::IfcEllipseProfileDef::ptr l, TopoDS_Shape
|
||||
w.Add(edge);
|
||||
|
||||
TopoDS_Face f;
|
||||
bool success = IfcGeom::convert_wire_to_face(w, f);
|
||||
bool success = convert_wire_to_face(w, f);
|
||||
if (success) face = f;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcCenterLineProfileDef::ptr l, TopoDS_Shape& face) {
|
||||
const double d = l->Thickness() * IfcGeom::GetValue(GV_LENGTH_UNIT) / 2.;
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCenterLineProfileDef* l, TopoDS_Shape& face) {
|
||||
const double d = l->Thickness() * getValue(GV_LENGTH_UNIT) / 2.;
|
||||
|
||||
TopoDS_Wire wire;
|
||||
if (!IfcGeom::convert_wire(l->Curve(), wire)) return false;
|
||||
if (!convert_wire(l->Curve(), wire)) return false;
|
||||
|
||||
// BRepOffsetAPI_MakeOffset insists on creating circular arc
|
||||
// segments for joining the curves that constitute the center
|
||||
@@ -727,18 +849,18 @@ bool IfcGeom::convert(const IfcSchema::IfcCenterLineProfileDef::ptr l, TopoDS_Sh
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcCompositeProfileDef::ptr l, TopoDS_Shape& face) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeProfileDef* l, TopoDS_Shape& face) {
|
||||
// BRepBuilderAPI_MakeFace mf;
|
||||
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
|
||||
IfcSchema::IfcProfileDef::list profiles = l->Profiles();
|
||||
bool first = true;
|
||||
for (IfcSchema::IfcProfileDef::it it = profiles->begin(); it != profiles->end(); ++it) {
|
||||
IfcSchema::IfcProfileDef::list::ptr profiles = l->Profiles();
|
||||
//bool first = true;
|
||||
for (IfcSchema::IfcProfileDef::list::it it = profiles->begin(); it != profiles->end(); ++it) {
|
||||
TopoDS_Face f;
|
||||
if (IfcGeom::convert_face(*it, f)) {
|
||||
if (convert_face(*it, f)) {
|
||||
builder.Add(compound, f);
|
||||
/* TopExp_Explorer exp(f, TopAbs_WIRE);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
@@ -757,10 +879,10 @@ bool IfcGeom::convert(const IfcSchema::IfcCompositeProfileDef::ptr l, TopoDS_Sha
|
||||
return !face.IsNull();
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcDerivedProfileDef::ptr l, TopoDS_Shape& face) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcDerivedProfileDef* l, TopoDS_Shape& face) {
|
||||
TopoDS_Face f;
|
||||
gp_Trsf2d trsf2d;
|
||||
if (IfcGeom::convert_face(l->ParentProfile(), f) && IfcGeom::convert(l->Operator(), trsf2d)) {
|
||||
if (convert_face(l->ParentProfile(), f) && IfcGeom::Kernel::convert(l->Operator(), trsf2d)) {
|
||||
gp_Trsf trsf = trsf2d;
|
||||
face = TopoDS::Face(BRepBuilderAPI_Transform(f, trsf));
|
||||
return true;
|
||||
@@ -768,3 +890,71 @@ bool IfcGeom::convert(const IfcSchema::IfcDerivedProfileDef::ptr l, TopoDS_Shape
|
||||
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
|
||||
+685
-302
File diff suppressed because it is too large
Load Diff
@@ -77,29 +77,19 @@
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
|
||||
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) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianPoint* l, gp_Pnt& point) {
|
||||
IN_CACHE(IfcCartesianPoint,l,gp_Pnt,point)
|
||||
std::vector<double> xyz = l->Coordinates();
|
||||
point = gp_Pnt(
|
||||
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
|
||||
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
|
||||
);
|
||||
CACHE(IfcCartesianPoint,l,point)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcDirection::ptr l, gp_Dir& dir) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcDirection* l, gp_Dir& dir) {
|
||||
IN_CACHE(IfcDirection,l,gp_Dir,dir)
|
||||
std::vector<double> xyz = l->DirectionRatios();
|
||||
dir = gp_Dir(
|
||||
@@ -111,22 +101,22 @@ bool IfcGeom::convert(const IfcSchema::IfcDirection::ptr l, gp_Dir& dir) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcVector::ptr l, gp_Vec& v) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcVector* l, gp_Vec& v) {
|
||||
IN_CACHE(IfcVector,l,gp_Vec,v)
|
||||
gp_Dir d;
|
||||
IfcGeom::convert(l->Orientation(),d);
|
||||
v = l->Magnitude() * IfcGeom::GetValue(GV_LENGTH_UNIT) * d;
|
||||
IfcGeom::Kernel::convert(l->Orientation(),d);
|
||||
v = l->Magnitude() * getValue(GV_LENGTH_UNIT) * d;
|
||||
CACHE(IfcVector,l,v)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcAxis2Placement3D::ptr l, gp_Trsf& trsf) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement3D* 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::convert(l->Location(),o);
|
||||
IfcGeom::Kernel::convert(l->Location(),o);
|
||||
bool hasRef = l->hasRefDirection();
|
||||
if ( l->hasAxis() ) IfcGeom::convert(l->Axis(),axis);
|
||||
if ( hasRef ) IfcGeom::convert(l->RefDirection(),refDirection);
|
||||
if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(),axis);
|
||||
if ( hasRef ) IfcGeom::Kernel::convert(l->RefDirection(),refDirection);
|
||||
gp_Ax3 ax3;
|
||||
if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection);
|
||||
else ax3 = gp_Ax3(o,axis);
|
||||
@@ -135,27 +125,26 @@ bool IfcGeom::convert(const IfcSchema::IfcAxis2Placement3D::ptr l, gp_Trsf& trsf
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcAxis1Placement::ptr l, gp_Ax1& ax) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis1Placement* l, gp_Ax1& ax) {
|
||||
IN_CACHE(IfcAxis1Placement,l,gp_Ax1,ax)
|
||||
gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);
|
||||
IfcGeom::convert(l->Location(),o);
|
||||
if ( l->hasAxis() ) IfcGeom::convert(l->Axis(), axis);
|
||||
IfcGeom::Kernel::convert(l->Location(),o);
|
||||
if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(), axis);
|
||||
ax = gp_Ax1(o, axis);
|
||||
CACHE(IfcAxis1Placement,l,ax)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator3D::ptr l, gp_Trsf& trsf) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator3D* l, gp_Trsf& trsf) {
|
||||
IN_CACHE(IfcCartesianTransformationOperator3D,l,gp_Trsf,trsf)
|
||||
gp_Pnt origin;
|
||||
IfcGeom::convert(l->LocalOrigin(),origin);
|
||||
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
|
||||
gp_Dir axis1 (1.,0.,0.);
|
||||
gp_Dir axis2 (0.,1.,0.);
|
||||
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_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_Ax3 ax3 (origin,axis3,axis1);
|
||||
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
|
||||
trsf.SetTransformation(ax3);
|
||||
@@ -165,16 +154,16 @@ bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator3D::ptr
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator2D::ptr l, gp_Trsf2d& trsf) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator2D* 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::convert(l->LocalOrigin(),origin);
|
||||
if ( l->hasAxis1() ) IfcGeom::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::convert(l->Axis2(),axis2);
|
||||
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
|
||||
if ( l->hasAxis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2);
|
||||
|
||||
const gp_Pnt2d origin2d(origin.X(), origin.Y());
|
||||
const gp_Dir2d axis12d(axis1.X(), axis1.Y());
|
||||
@@ -199,18 +188,17 @@ bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator2D::ptr
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform::ptr l, gp_GTrsf& gtrsf) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* l, gp_GTrsf& gtrsf) {
|
||||
IN_CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gp_GTrsf,gtrsf)
|
||||
gp_Trsf trsf;
|
||||
gp_Pnt origin;
|
||||
IfcGeom::convert(l->LocalOrigin(),origin);
|
||||
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
|
||||
gp_Dir axis1 (1.,0.,0.);
|
||||
gp_Dir axis2 (0.,1.,0.);
|
||||
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_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_Ax3 ax3 (origin,axis3,axis1);
|
||||
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
|
||||
trsf.SetTransformation(ax3);
|
||||
@@ -227,7 +215,7 @@ bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator3DnonUn
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform::ptr l, gp_GTrsf2d& gtrsf) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* l, gp_GTrsf2d& gtrsf) {
|
||||
IN_CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gp_GTrsf2d,gtrsf)
|
||||
|
||||
gp_Trsf2d trsf;
|
||||
@@ -235,9 +223,9 @@ bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUn
|
||||
gp_Dir axis1 (1.,0.,0.);
|
||||
gp_Dir axis2 (0.,1.,0.);
|
||||
|
||||
IfcGeom::convert(l->LocalOrigin(),origin);
|
||||
if ( l->hasAxis1() ) IfcGeom::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::convert(l->Axis2(),axis2);
|
||||
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
|
||||
if ( l->hasAxis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2);
|
||||
|
||||
const gp_Pnt2d origin2d(origin.X(), origin.Y());
|
||||
const gp_Dir2d axis12d(axis1.X(), axis1.Y());
|
||||
@@ -263,14 +251,14 @@ bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUn
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcPlane::ptr pln, gp_Pln& plane) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPlane* pln, gp_Pln& plane) {
|
||||
IN_CACHE(IfcPlane,pln,gp_Pln,plane)
|
||||
IfcSchema::IfcAxis2Placement3D::ptr l = pln->Position();
|
||||
IfcSchema::IfcAxis2Placement3D* l = pln->Position();
|
||||
gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);gp_Dir refDirection;
|
||||
IfcGeom::convert(l->Location(),o);
|
||||
IfcGeom::Kernel::convert(l->Location(),o);
|
||||
bool hasRef = l->hasRefDirection();
|
||||
if ( l->hasAxis() ) IfcGeom::convert(l->Axis(),axis);
|
||||
if ( hasRef ) IfcGeom::convert(l->RefDirection(),refDirection);
|
||||
if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(),axis);
|
||||
if ( hasRef ) IfcGeom::Kernel::convert(l->RefDirection(),refDirection);
|
||||
gp_Ax3 ax3;
|
||||
if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection);
|
||||
else ax3 = gp_Ax3(o,axis);
|
||||
@@ -279,12 +267,12 @@ bool IfcGeom::convert(const IfcSchema::IfcPlane::ptr pln, gp_Pln& plane) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcAxis2Placement2D::ptr l, gp_Trsf2d& trsf) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d& trsf) {
|
||||
IN_CACHE(IfcAxis2Placement2D,l,gp_Trsf2d,trsf)
|
||||
gp_Pnt P; gp_Dir V (1,0,0);
|
||||
IfcGeom::convert(l->Location(),P);
|
||||
IfcGeom::Kernel::convert(l->Location(),P);
|
||||
if ( l->hasRefDirection() )
|
||||
IfcGeom::convert(l->RefDirection(),V);
|
||||
IfcGeom::Kernel::convert(l->RefDirection(),V);
|
||||
|
||||
gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()),gp_Dir2d(V.X(),V.Y()));
|
||||
trsf.SetTransformation(axis,gp_Ax2d());
|
||||
@@ -292,32 +280,27 @@ bool IfcGeom::convert(const IfcSchema::IfcAxis2Placement2D::ptr l, gp_Trsf2d& tr
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcObjectPlacement::ptr l, gp_Trsf& trsf) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf) {
|
||||
IN_CACHE(IfcObjectPlacement,l,gp_Trsf,trsf)
|
||||
if ( ! l->is(IfcSchema::Type::IfcLocalPlacement) ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity);
|
||||
if ( ! l->declaration().is(IfcSchema::Type::IfcLocalPlacement) ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l);
|
||||
return false;
|
||||
}
|
||||
IfcSchema::IfcLocalPlacement::ptr current = reinterpret_pointer_cast<IfcSchema::IfcObjectPlacement,IfcSchema::IfcLocalPlacement>(l);
|
||||
while (1) {
|
||||
IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l;
|
||||
for (;;) {
|
||||
gp_Trsf trsf2;
|
||||
IfcSchema::IfcAxis2Placement relplacement = current->RelativePlacement();
|
||||
if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) {
|
||||
IfcGeom::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2);
|
||||
IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement();
|
||||
if ( relplacement->declaration().is(IfcSchema::Type::IfcAxis2Placement3D) ) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2);
|
||||
trsf.PreMultiply(trsf2);
|
||||
}
|
||||
if ( current->hasPlacementRelTo() ) {
|
||||
IfcSchema::IfcObjectPlacement::ptr relto = current->PlacementRelTo();
|
||||
if ( relto->is(IfcSchema::Type::IfcLocalPlacement) )
|
||||
current = reinterpret_pointer_cast<IfcSchema::IfcObjectPlacement,IfcSchema::IfcLocalPlacement>(current->PlacementRelTo());
|
||||
IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo();
|
||||
if ( relto->declaration().is(IfcSchema::Type::IfcLocalPlacement) )
|
||||
current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo();
|
||||
else break;
|
||||
} else break;
|
||||
}
|
||||
CACHE(IfcObjectPlacement,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
void IfcGeom::Cache::Purge() {
|
||||
#include "IfcRegisterPurgeCache.h"
|
||||
IfcGeom::Cache::PurgeShapeCache();
|
||||
}
|
||||
@@ -0,0 +1,513 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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
|
||||
@@ -0,0 +1,179 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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
|
||||
@@ -0,0 +1,34 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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; }
|
||||
@@ -0,0 +1,50 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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
|
||||
@@ -1,727 +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 <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; }
|
||||
|
||||
@@ -1,286 +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). *
|
||||
* *
|
||||
* IfcMesh is a class that represents a triangulated IfcShapeRepresentation. *
|
||||
* IfcMesh.verts is a 1 dimensional vector of float defining the cartesian *
|
||||
* coordinates of the vertices of the triangulated shape in the format of *
|
||||
* [x1,y1,z1,..,xn,yn,zn] *
|
||||
* IfcMesh.faces is a 1 dimensional vector of int containing the indices of *
|
||||
* the triangles referencing positions in IfcMesh.verts *
|
||||
* IfcMesh.edges is a 1 dimensional vector of int in {0,1} that dictates *
|
||||
* the visibility of the edges that span the faces in IfcMesh.faces *
|
||||
* *
|
||||
* IfcGeomObject represents the actual IfcBuildingElements. *
|
||||
* IfcGeomObject.name is the GUID of the element *
|
||||
* IfcGeomObject.type is the datatype of the element e.g. IfcWindow *
|
||||
* IfcGeomObject.mesh is a pointer to an IfcMesh *
|
||||
* IfcGeomObject.matrix is a 4x3 matrix that defines the orientation and *
|
||||
* translation of the mesh in relation to the world origin *
|
||||
* *
|
||||
* Init(char* fn) parses the IFC file in fn, returns true on succes. *
|
||||
* *
|
||||
* Get() returns a pointer to the current IfcGeomObject *
|
||||
* *
|
||||
* Next() returns true if there is an entity yet available *
|
||||
* *
|
||||
* Progress() returns an int in [0..100] that indicates the overall progress *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCOBJECTS_H
|
||||
#define IFCOBJECTS_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <gp_Mat.hxx>
|
||||
#include <gp_Mat2d.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <gp_GTrsf2d.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
|
||||
#include "../ifcparse/IfcParse.h"
|
||||
#include "../ifcgeom/IfcRepresentationShapeItem.h"
|
||||
|
||||
namespace IfcGeomObjects {
|
||||
|
||||
// Enumeration of setting identifiers. These settings define the
|
||||
// behaviour of various aspects of IfcOpenShell.
|
||||
|
||||
// Specifies whether vertices are welded, meaning that the coordinates
|
||||
// vector will only contain unique xyz-triplets. This results in a
|
||||
// manifold mesh which is useful for modelling applications, but might
|
||||
// result in unwanted shading artifacts in rendering applications.
|
||||
const int WELD_VERTICES = 1;
|
||||
// Specifies whether to apply the local placements of building elements
|
||||
// directly to the coordinates of the representation mesh rather than
|
||||
// to represent the local placement in the 4x3 matrix, which will in that
|
||||
// case be the identity matrix.
|
||||
const int USE_WORLD_COORDS = 2;
|
||||
// Internally IfcOpenShell measures everything in meters. This settings
|
||||
// specifies whether to convert IfcGeomObjects back to the units in which
|
||||
// the geometry in the IFC file is specified.
|
||||
const int CONVERT_BACK_UNITS = 3;
|
||||
// Specifies whether to use the Open Cascade BREP format for representation
|
||||
// items rather than to create triangle meshes. This is useful is IfcOpenShell
|
||||
// is used as a library in an application that is also built on Open Cascade.
|
||||
const int USE_BREP_DATA = 4;
|
||||
// Specifies whether to sew IfcConnectedFaceSets (open and closed shells) to
|
||||
// TopoDS_Shells or whether to keep them as a loose collection of faces.
|
||||
const int SEW_SHELLS = 5;
|
||||
// Specifies whether to compose IfcOpeningElements into a single compound
|
||||
// in order to speed up the processing of opening subtractions.
|
||||
const int FASTER_BOOLEANS = 6;
|
||||
// By default singular faces have no explicitly defined orientation, to
|
||||
// force faces to be defined CounterClockWise set this to true.
|
||||
const int FORCE_CCW_FACE_ORIENTATION = 7;
|
||||
// Disables the subtraction of IfcOpeningElement representations from
|
||||
// the related building element representations.
|
||||
const int DISABLE_OPENING_SUBTRACTIONS = 8;
|
||||
// Disables the triangulation of the topological representations. Useful if
|
||||
// the client application understands Open Cascade's native format.
|
||||
const int DISABLE_TRIANGULATION = 9;
|
||||
|
||||
// End of settings enumeration.
|
||||
|
||||
// A nested pair of floats and a material index to be able to store an XYZ coordinate in a map.
|
||||
// TODO: Make this a std::tuple when compilers add support for that.
|
||||
typedef std::pair<int, std::pair<float,std::pair<float,float> > > VertKey;
|
||||
typedef std::map<VertKey,int> VertKeyMap;
|
||||
typedef std::pair<int,int> Edge;
|
||||
|
||||
class Material {
|
||||
private:
|
||||
const IfcGeom::SurfaceStyle* style;
|
||||
public:
|
||||
explicit Material(const IfcGeom::SurfaceStyle* style);
|
||||
// Material(const Material& other);
|
||||
// Material& operator=(const Material& other);
|
||||
bool hasDiffuse() const;
|
||||
bool hasSpecular() const;
|
||||
bool hasTransparency() const;
|
||||
bool hasSpecularity() const;
|
||||
const double* diffuse() const;
|
||||
const double* specular() const;
|
||||
double transparency() const;
|
||||
double specularity() const;
|
||||
const std::string name() const;
|
||||
bool operator==(const Material& other) const;
|
||||
};
|
||||
|
||||
class IfcRepresentationShapeModel {
|
||||
private:
|
||||
unsigned int id;
|
||||
const IfcGeom::IfcRepresentationShapeItems shapes;
|
||||
IfcRepresentationShapeModel(const IfcRepresentationShapeModel& other);
|
||||
IfcRepresentationShapeModel& operator=(const IfcRepresentationShapeModel& other);
|
||||
public:
|
||||
IfcRepresentationShapeModel(unsigned int id, const IfcGeom::IfcRepresentationShapeItems& shapes)
|
||||
: id(id)
|
||||
, shapes(shapes)
|
||||
{}
|
||||
virtual ~IfcRepresentationShapeModel() {}
|
||||
IfcGeom::IfcRepresentationShapeItems::const_iterator begin() const { return shapes.begin(); }
|
||||
IfcGeom::IfcRepresentationShapeItems::const_iterator end() const { return shapes.end(); }
|
||||
const unsigned int& getId() const { return id; }
|
||||
};
|
||||
|
||||
class IfcRepresentationBrepData {
|
||||
private:
|
||||
int _id;
|
||||
std::string _brep_data;
|
||||
public:
|
||||
int id() const;
|
||||
const std::string& brep_data() const;
|
||||
IfcRepresentationBrepData(const IfcRepresentationShapeModel& s);
|
||||
virtual ~IfcRepresentationBrepData() {}
|
||||
private:
|
||||
IfcRepresentationBrepData();
|
||||
IfcRepresentationBrepData(const IfcRepresentationBrepData&);
|
||||
IfcRepresentationBrepData& operator=(const IfcRepresentationBrepData&);
|
||||
};
|
||||
|
||||
class IfcRepresentationTriangulation {
|
||||
private:
|
||||
int _id;
|
||||
std::vector<float> _verts;
|
||||
std::vector<int> _faces;
|
||||
std::vector<int> _edges;
|
||||
std::vector<float> _normals;
|
||||
std::vector<int> _material_ids;
|
||||
std::vector<Material> _materials;
|
||||
VertKeyMap welds;
|
||||
public:
|
||||
int id() const;
|
||||
const std::vector<float>& verts() const;
|
||||
const std::vector<int>& faces() const;
|
||||
const std::vector<int>& edges() const;
|
||||
const std::vector<float>& normals() const;
|
||||
const std::vector<int>& material_ids() const;
|
||||
const std::vector<Material>& materials() const;
|
||||
IfcRepresentationTriangulation(const IfcRepresentationShapeModel& s);
|
||||
virtual ~IfcRepresentationTriangulation() {}
|
||||
private:
|
||||
int addvert(int material_index, const gp_XYZ& p);
|
||||
inline void addedge(int n1, int n2, std::map<std::pair<int,int>,int>& edgecount, std::vector<std::pair<int,int> >& edges_temp) {
|
||||
const Edge e = Edge( (std::min)(n1,n2),(std::max)(n1,n2) );
|
||||
if ( edgecount.find(e) == edgecount.end() ) edgecount[e] = 1;
|
||||
else edgecount[e] ++;
|
||||
edges_temp.push_back(e);
|
||||
}
|
||||
IfcRepresentationTriangulation();
|
||||
IfcRepresentationTriangulation(const IfcRepresentationTriangulation&);
|
||||
IfcRepresentationTriangulation& operator=(const IfcRepresentationTriangulation&);
|
||||
};
|
||||
|
||||
class IfcObject {
|
||||
private:
|
||||
int _id;
|
||||
int _parent_id;
|
||||
std::string _name;
|
||||
std::string _type;
|
||||
std::string _guid;
|
||||
std::vector<float> _matrix;
|
||||
public:
|
||||
int id() const;
|
||||
int parent_id() const;
|
||||
const std::string& name() const;
|
||||
const std::string& type() const;
|
||||
const std::string& guid() const;
|
||||
const std::vector<float>& matrix() const;
|
||||
IfcObject(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf);
|
||||
virtual ~IfcObject() {}
|
||||
};
|
||||
|
||||
class IfcGeomShapeModelObject : public IfcObject {
|
||||
private:
|
||||
IfcRepresentationShapeModel* _mesh;
|
||||
public:
|
||||
const IfcRepresentationShapeModel& mesh() const;
|
||||
IfcGeomShapeModelObject(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf, IfcRepresentationShapeModel* mesh);
|
||||
virtual ~IfcGeomShapeModelObject() {
|
||||
delete _mesh;
|
||||
}
|
||||
private:
|
||||
IfcGeomShapeModelObject(const IfcGeomShapeModelObject& other);
|
||||
IfcGeomShapeModelObject& operator=(const IfcGeomShapeModelObject& other);
|
||||
};
|
||||
|
||||
class IfcGeomObject : public IfcObject {
|
||||
private:
|
||||
IfcRepresentationTriangulation* _mesh;
|
||||
public:
|
||||
const IfcRepresentationTriangulation& mesh() const;
|
||||
IfcGeomObject(const IfcGeomShapeModelObject& shape_model);
|
||||
virtual ~IfcGeomObject() {
|
||||
delete _mesh;
|
||||
}
|
||||
private:
|
||||
IfcGeomObject(const IfcGeomObject& other);
|
||||
IfcGeomObject& operator=(const IfcGeomObject& other);
|
||||
};
|
||||
|
||||
class IfcGeomBrepDataObject : public IfcObject {
|
||||
private:
|
||||
IfcRepresentationBrepData* _mesh;
|
||||
public:
|
||||
const IfcRepresentationBrepData& mesh() const;
|
||||
IfcGeomBrepDataObject(const IfcGeomShapeModelObject& shape_model);
|
||||
virtual ~IfcGeomBrepDataObject() {
|
||||
delete _mesh;
|
||||
}
|
||||
private:
|
||||
IfcGeomBrepDataObject(const IfcGeomBrepDataObject& other);
|
||||
IfcGeomBrepDataObject& operator=(const IfcGeomBrepDataObject& other);
|
||||
};
|
||||
|
||||
bool Init(const std::string fn);
|
||||
bool Init(void* data, int len);
|
||||
bool Init(const std::string fn, std::ostream* log1= 0, std::ostream* log2= 0);
|
||||
bool Init(std::istream& f, int len, std::ostream* log1= 0, std::ostream* log2= 0);
|
||||
|
||||
void Settings(int setting, bool value);
|
||||
void InitUnits();
|
||||
void InitPrecision();
|
||||
|
||||
const IfcGeomObject* Get();
|
||||
const IfcObject* GetObject(int id);
|
||||
const IfcGeomBrepDataObject* GetBrepData();
|
||||
const IfcGeomShapeModelObject* GetShapeModel();
|
||||
|
||||
bool Next();
|
||||
int Progress();
|
||||
|
||||
const std::string& GetUnitName();
|
||||
const float GetUnitMagnitude();
|
||||
|
||||
const std::string GetLog();
|
||||
IfcParse::IfcFile* GetFile();
|
||||
|
||||
bool CleanUp();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -19,18 +19,9 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "IfcGeomRenderStyles.h"
|
||||
#include "IfcGeom.h"
|
||||
|
||||
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) {
|
||||
bool process_colour(IfcSchema::IfcColourRgb* colour, double* rgb) {
|
||||
if (colour != 0) {
|
||||
rgb[0] = colour->Red();
|
||||
rgb[1] = colour->Green();
|
||||
@@ -39,34 +30,34 @@ bool process_colour(IfcSchema::IfcColourRgb* colour, std::tr1::array<double, 3>&
|
||||
return colour != 0;
|
||||
}
|
||||
|
||||
bool process_colour(IfcUtil::IfcBaseEntity* factor, std::tr1::array<double, 3>& rgb) {
|
||||
bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, double* rgb) {
|
||||
if (factor != 0) {
|
||||
const double f = *factor->entity->getArgument(0);
|
||||
const double f = *factor;
|
||||
rgb[0] = rgb[1] = rgb[2] = f;
|
||||
}
|
||||
return factor != 0;
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourOrFactor colour_or_factor, std::tr1::array<double, 3>& rgb) {
|
||||
bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, double* rgb) {
|
||||
if (colour_or_factor == 0) {
|
||||
return false;
|
||||
} else if (colour_or_factor->is(IfcSchema::Type::IfcColourRgb)) {
|
||||
} else if (colour_or_factor->declaration().is(IfcSchema::Type::IfcColourRgb)) {
|
||||
return process_colour(static_cast<IfcSchema::IfcColourRgb*>(colour_or_factor), rgb);
|
||||
} else if (colour_or_factor->is(IfcSchema::Type::IfcNormalisedRatioMeasure)) {
|
||||
return process_colour(static_cast<IfcUtil::IfcBaseEntity*>(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 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::get_style(IfcSchema::IfcRepresentationItem* item) {
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepresentationItem* item) {
|
||||
std::pair<IfcSchema::IfcSurfaceStyle*, IfcSchema::IfcSurfaceStyleShading*> shading_styles = get_surface_style<IfcSchema::IfcSurfaceStyleShading>(item);
|
||||
if (shading_styles.second == 0) {
|
||||
return 0;
|
||||
}
|
||||
int surface_style_id = shading_styles.first->entity->id();
|
||||
std::map<int,SurfaceStyle>::const_iterator it = Cache::Style.find(surface_style_id);
|
||||
if (it != Cache::Style.end()) {
|
||||
int surface_style_id = shading_styles.first->data().id();
|
||||
std::map<int,SurfaceStyle>::const_iterator it = cache.Style.find(surface_style_id);
|
||||
if (it != cache.Style.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
SurfaceStyle surface_style;
|
||||
@@ -75,11 +66,11 @@ const IfcGeom::SurfaceStyle* IfcGeom::get_style(IfcSchema::IfcRepresentationItem
|
||||
} else {
|
||||
surface_style = SurfaceStyle(surface_style_id);
|
||||
}
|
||||
std::tr1::array<double, 3> rgb;
|
||||
double rgb[3];
|
||||
if (process_colour(shading_styles.second->SurfaceColour(), rgb)) {
|
||||
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
|
||||
}
|
||||
if (shading_styles.second->is(IfcSchema::Type::IfcSurfaceStyleRendering)) {
|
||||
if (shading_styles.second->declaration().is(IfcSchema::Type::IfcSurfaceStyleRendering)) {
|
||||
IfcSchema::IfcSurfaceStyleRendering* rendering_style = static_cast<IfcSchema::IfcSurfaceStyleRendering*>(shading_styles.second);
|
||||
if (rendering_style->hasDiffuseColour() && process_colour(rendering_style->DiffuseColour(), rgb)) {
|
||||
SurfaceStyle::ColorComponent diffuse = surface_style.Diffuse().get_value_or(SurfaceStyle::ColorComponent(1,1,1));
|
||||
@@ -95,7 +86,15 @@ const IfcGeom::SurfaceStyle* IfcGeom::get_style(IfcSchema::IfcRepresentationItem
|
||||
surface_style.Specular().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
|
||||
}
|
||||
if (rendering_style->hasSpecularHighlight()) {
|
||||
// Not supported
|
||||
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));
|
||||
}
|
||||
}
|
||||
if (rendering_style->hasTransmissionColour()) {
|
||||
// Not supported
|
||||
@@ -105,7 +104,7 @@ const IfcGeom::SurfaceStyle* IfcGeom::get_style(IfcSchema::IfcRepresentationItem
|
||||
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;
|
||||
@@ -153,9 +152,11 @@ 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()) return &default_material;
|
||||
else {
|
||||
const IfcGeom::SurfaceStyle& surface_style = it->second;
|
||||
return &surface_style;
|
||||
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);
|
||||
}
|
||||
const IfcGeom::SurfaceStyle& surface_style = it->second;
|
||||
return &surface_style;
|
||||
}
|
||||
|
||||
@@ -20,12 +20,6 @@
|
||||
#ifndef IFCGEOMRENDERSTYLES_H
|
||||
#define IFCGEOMRENDERSTYLES_H
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <tr1/array>
|
||||
#else
|
||||
#include <array>
|
||||
#endif
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include "../ifcparse/Ifc4.h"
|
||||
#else
|
||||
@@ -37,7 +31,7 @@ namespace IfcGeom {
|
||||
public:
|
||||
class ColorComponent {
|
||||
private:
|
||||
std::tr1::array<double, 3> data;
|
||||
double data[3];
|
||||
public:
|
||||
ColorComponent(double r, double g, double b) {
|
||||
data[0] = r; data[1] = g; data[2] = b;
|
||||
@@ -56,10 +50,23 @@ namespace IfcGeom {
|
||||
boost::optional<double> transparency;
|
||||
boost::optional<double> specularity;
|
||||
public:
|
||||
SurfaceStyle() {}
|
||||
SurfaceStyle(int id) : id(id) {}
|
||||
SurfaceStyle() {
|
||||
this->name = "surface-style";
|
||||
}
|
||||
SurfaceStyle(int id) : id(id) {
|
||||
std::stringstream sstr;
|
||||
sstr << "surface-style-" << id;
|
||||
this->name = sstr.str();
|
||||
}
|
||||
SurfaceStyle(const std::string& name) : name(name) {}
|
||||
SurfaceStyle(int id, const std::string& name) : id(id), 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();
|
||||
}
|
||||
|
||||
// Not used at this point. In fact, equality testing in the current
|
||||
// architecture can just as easily be accomplished by comparing the
|
||||
@@ -75,21 +82,7 @@ namespace IfcGeom {
|
||||
}
|
||||
}
|
||||
|
||||
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 std::string& Name() const { return *name; }
|
||||
|
||||
const boost::optional<ColorComponent>& Diffuse() const { return diffuse; }
|
||||
const boost::optional<ColorComponent>& Specular() const { return specular; }
|
||||
@@ -101,52 +94,7 @@ 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
|
||||
@@ -0,0 +1,59 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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();
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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
|
||||
@@ -0,0 +1,38 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMSHAPETYPE_H
|
||||
#define IFCGEOMSHAPETYPE_H
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
enum ShapeType {
|
||||
ST_SHAPELIST,
|
||||
ST_SHAPE,
|
||||
ST_FACE,
|
||||
ST_WIRE,
|
||||
ST_CURVE,
|
||||
ST_EDGE,
|
||||
ST_VERTEX,
|
||||
ST_OTHER
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+453
-183
@@ -65,6 +65,8 @@
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopoDS_CompSolid.hxx>
|
||||
|
||||
#include <TopExp_Explorer.hxx>
|
||||
|
||||
#include <BRepPrimAPI_MakePrism.hxx>
|
||||
@@ -74,6 +76,7 @@
|
||||
#include <BRepPrimAPI_MakeCylinder.hxx>
|
||||
#include <BRepPrimAPI_MakeSphere.hxx>
|
||||
#include <BRepPrimAPI_MakeWedge.hxx>
|
||||
#include <BRepBuilderAPI_MakePolygon.hxx>
|
||||
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
#include <BRepBuilderAPI_MakeShell.hxx>
|
||||
@@ -91,35 +94,71 @@
|
||||
#include <TopLoc_Location.hxx>
|
||||
|
||||
#include <BRepCheck_Analyzer.hxx>
|
||||
#include <BRepClass3d_SolidClassifier.hxx>
|
||||
|
||||
#include <Standard_Version.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::convert(l->Position(),trsf);
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
|
||||
gp_Dir dir;
|
||||
convert(l->ExtrudedDirection(),dir);
|
||||
|
||||
shape = BRepPrimAPI_MakePrism(face,height*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.Move(trsf);
|
||||
return ! shape.IsNull();
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion::ptr l, TopoDS_Shape& shape) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion* l, TopoDS_Shape& shape) {
|
||||
TopoDS_Wire wire;
|
||||
if ( !IfcGeom::convert_wire(l->SweptCurve(), wire) ) {
|
||||
if ( !convert_wire(l->SweptCurve(), wire) ) {
|
||||
TopoDS_Face face;
|
||||
if ( !IfcGeom::convert_face(l->SweptCurve(),face) ) return false;
|
||||
if ( !convert_face(l->SweptCurve(),face) ) return false;
|
||||
TopExp_Explorer exp(face, TopAbs_WIRE);
|
||||
wire = TopoDS::Wire(exp.Current());
|
||||
}
|
||||
const double height = l->Depth() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
const double height = l->Depth() * getValue(GV_LENGTH_UNIT);
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::convert(l->Position(),trsf);
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
|
||||
gp_Dir dir;
|
||||
convert(l->ExtrudedDirection(),dir);
|
||||
@@ -129,20 +168,20 @@ bool IfcGeom::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion::ptr l, TopoD
|
||||
return !shape.IsNull();
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcSurfaceOfRevolution::ptr l, TopoDS_Shape& shape) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfRevolution* l, TopoDS_Shape& shape) {
|
||||
TopoDS_Wire wire;
|
||||
if ( !IfcGeom::convert_wire(l->SweptCurve(), wire) ) {
|
||||
if ( !convert_wire(l->SweptCurve(), wire) ) {
|
||||
TopoDS_Face face;
|
||||
if ( !IfcGeom::convert_face(l->SweptCurve(),face) ) return false;
|
||||
if ( !convert_face(l->SweptCurve(),face) ) return false;
|
||||
TopExp_Explorer exp(face, TopAbs_WIRE);
|
||||
wire = TopoDS::Wire(exp.Current());
|
||||
}
|
||||
|
||||
gp_Ax1 ax1;
|
||||
IfcGeom::convert(l->AxisPosition(), ax1);
|
||||
IfcGeom::Kernel::convert(l->AxisPosition(), ax1);
|
||||
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::convert(l->Position(),trsf);
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
|
||||
shape = BRepPrimAPI_MakeRevol(wire, ax1);
|
||||
|
||||
@@ -150,17 +189,17 @@ bool IfcGeom::convert(const IfcSchema::IfcSurfaceOfRevolution::ptr l, TopoDS_Sha
|
||||
return !shape.IsNull();
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcRevolvedAreaSolid::ptr l, TopoDS_Shape& shape) {
|
||||
const double ang = l->Angle() * IfcGeom::GetValue(GV_PLANEANGLE_UNIT);
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRevolvedAreaSolid* l, TopoDS_Shape& shape) {
|
||||
const double ang = l->Angle() * getValue(GV_PLANEANGLE_UNIT);
|
||||
|
||||
TopoDS_Face face;
|
||||
if ( ! IfcGeom::convert_face(l->SweptArea(),face) ) return false;
|
||||
if ( ! convert_face(l->SweptArea(),face) ) return false;
|
||||
|
||||
gp_Ax1 ax1;
|
||||
IfcGeom::convert(l->Axis(), ax1);
|
||||
IfcGeom::Kernel::convert(l->Axis(), ax1);
|
||||
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::convert(l->Position(),trsf);
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
|
||||
if (ang >= M_PI * 2. - ALMOST_ZERO) {
|
||||
shape = BRepPrimAPI_MakeRevol(face, ax1);
|
||||
@@ -172,10 +211,10 @@ bool IfcGeom::convert(const IfcSchema::IfcRevolvedAreaSolid::ptr l, TopoDS_Shape
|
||||
return !shape.IsNull();
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcFacetedBrep::ptr l, IfcRepresentationShapeItems& shape) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFacetedBrep* l, IfcRepresentationShapeItems& shape) {
|
||||
TopoDS_Shape s;
|
||||
const SurfaceStyle* collective_style = get_style(l);
|
||||
if (IfcGeom::convert_shape(l->Outer(),s) ) {
|
||||
if (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;
|
||||
@@ -183,39 +222,49 @@ bool IfcGeom::convert(const IfcSchema::IfcFacetedBrep::ptr l, IfcRepresentationS
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcFaceBasedSurfaceModel::ptr l, IfcRepresentationShapeItems& shapes) {
|
||||
IfcSchema::IfcConnectedFaceSet::list facesets = l->FbsmFaces();
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFaceBasedSurfaceModel* l, IfcRepresentationShapeItems& shapes) {
|
||||
IfcSchema::IfcConnectedFaceSet::list::ptr facesets = l->FbsmFaces();
|
||||
const SurfaceStyle* collective_style = get_style(l);
|
||||
for( IfcSchema::IfcConnectedFaceSet::it it = facesets->begin(); it != facesets->end(); ++ it ) {
|
||||
for( IfcSchema::IfcConnectedFaceSet::list::it it = facesets->begin(); it != facesets->end(); ++ it ) {
|
||||
TopoDS_Shape s;
|
||||
const SurfaceStyle* shell_style = get_style(*it);
|
||||
if (IfcGeom::convert_shape(*it,s)) {
|
||||
if (convert_shape(*it,s)) {
|
||||
shapes.push_back(IfcRepresentationShapeItem(s, shell_style ? shell_style : collective_style));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
gp_Pln pln;
|
||||
IfcGeom::convert(reinterpret_pointer_cast<IfcSchema::IfcSurface,IfcSchema::IfcPlane>(surface),pln);
|
||||
IfcGeom::Kernel::convert((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::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace::ptr l, TopoDS_Shape& shape) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l, TopoDS_Shape& shape) {
|
||||
TopoDS_Shape halfspace;
|
||||
if ( ! IfcGeom::convert(reinterpret_pointer_cast<IfcSchema::IfcPolygonalBoundedHalfSpace,IfcSchema::IfcHalfSpaceSolid>(l),halfspace) ) return false;
|
||||
if ( ! IfcGeom::Kernel::convert((IfcSchema::IfcHalfSpaceSolid*)l,halfspace) ) return false;
|
||||
|
||||
TopoDS_Wire wire;
|
||||
if ( ! IfcGeom::convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false;
|
||||
if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false;
|
||||
|
||||
gp_Trsf trsf;
|
||||
convert(l->Position(),trsf);
|
||||
if ( ! convert(l->Position(),trsf) ) return false;
|
||||
|
||||
TColgp_SequenceOfPnt points;
|
||||
if (wire_to_sequence_of_point(wire, points)) {
|
||||
remove_duplicate_points_from_loop(points, wire.Closed()); // Note: wire always closed, as per if statement above
|
||||
remove_collinear_points_from_loop(points, wire.Closed());
|
||||
sequence_of_point_to_wire(points, wire, wire.Closed());
|
||||
}
|
||||
|
||||
TopoDS_Shape prism = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,200));
|
||||
gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-100.0));
|
||||
prism.Move(trsf*down);
|
||||
@@ -223,60 +272,117 @@ bool IfcGeom::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace::ptr l, Topo
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcShellBasedSurfaceModel::ptr l, IfcRepresentationShapeItems& shapes) {
|
||||
IfcUtil::IfcAbstractSelect::list shells = l->SbsmBoundary();
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, IfcRepresentationShapeItems& shapes) {
|
||||
IfcEntityList::ptr shells = l->SbsmBoundary();
|
||||
const SurfaceStyle* collective_style = get_style(l);
|
||||
for( IfcUtil::IfcAbstractSelect::it it = shells->begin(); it != shells->end(); ++ it ) {
|
||||
for( IfcEntityList::it it = shells->begin(); it != shells->end(); ++ it ) {
|
||||
TopoDS_Shape s;
|
||||
const SurfaceStyle* shell_style = 0;
|
||||
if ((*it)->is(IfcSchema::Type::IfcRepresentationItem)) {
|
||||
if ((*it)->declaration().is(IfcSchema::Type::IfcRepresentationItem)) {
|
||||
shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it);
|
||||
}
|
||||
if (IfcGeom::convert_shape(*it,s)) {
|
||||
if (convert_shape(*it,s)) {
|
||||
shapes.push_back(IfcRepresentationShapeItem(s, shell_style ? shell_style : collective_style));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcBooleanResult::ptr l, TopoDS_Shape& shape) {
|
||||
TopoDS_Shape s1, s2;
|
||||
TopoDS_Wire boundary_wire;
|
||||
IfcSchema::IfcBooleanOperand operand1 = l->FirstOperand();
|
||||
IfcSchema::IfcBooleanOperand operand2 = l->SecondOperand();
|
||||
bool is_halfspace = operand2->is(IfcSchema::Type::IfcHalfSpaceSolid);
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) {
|
||||
|
||||
if ( ! IfcGeom::convert_shape(operand1,s1) )
|
||||
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);
|
||||
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
||||
const double first_operand_volume = shape_volume(s1);
|
||||
if ( first_operand_volume <= ALMOST_ZERO )
|
||||
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand()->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Empty solid for:", l->FirstOperand());
|
||||
|
||||
if ( !IfcGeom::convert_shape(l->SecondOperand(),s2) ) {
|
||||
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) {
|
||||
shape = s1;
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to convert SecondOperand of:", l);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ! is_halfspace ) {
|
||||
if (!is_halfspace) {
|
||||
const double second_operand_volume = shape_volume(s2);
|
||||
if ( second_operand_volume <= ALMOST_ZERO )
|
||||
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Empty solid for:", operand2);
|
||||
}
|
||||
|
||||
const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator();
|
||||
|
||||
/*
|
||||
// TK: A little debugging trick to output both operands for visual inspection
|
||||
|
||||
BRep_Builder builder;
|
||||
TopoDS_Compound compound;
|
||||
builder.MakeCompound(compound);
|
||||
builder.Add(compound, s1);
|
||||
builder.Add(compound, s2);
|
||||
shape = compound;
|
||||
return true;
|
||||
*/
|
||||
|
||||
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
|
||||
|
||||
bool valid_cut = false;
|
||||
BRepAlgoAPI_Cut brep_cut(s1,s2);
|
||||
|
||||
#if OCC_VERSION_HEX < 0x60900
|
||||
BRepAlgoAPI_Cut brep_cut(s1, s2);
|
||||
#else
|
||||
BRepAlgoAPI_Cut brep_cut;
|
||||
TopTools_ListOfShape s1s;
|
||||
s1s.Append(s1);
|
||||
TopTools_ListOfShape s2s;
|
||||
s2s.Append(s2);
|
||||
brep_cut.SetFuzzyValue(getValue(GV_PRECISION));
|
||||
brep_cut.SetArguments(s1s);
|
||||
brep_cut.SetTools(s2s);
|
||||
brep_cut.Build();
|
||||
#endif
|
||||
|
||||
if ( brep_cut.IsDone() ) {
|
||||
TopoDS_Shape result = brep_cut;
|
||||
|
||||
ShapeFix_Shape fix(result);
|
||||
fix.Perform();
|
||||
result = fix.Shape();
|
||||
try {
|
||||
fix.Perform();
|
||||
result = fix.Shape();
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Shape healing failed on boolean result", l);
|
||||
}
|
||||
|
||||
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
|
||||
if ( is_valid ) {
|
||||
@@ -288,9 +394,9 @@ bool IfcGeom::convert(const IfcSchema::IfcBooleanResult::ptr l, TopoDS_Shape& sh
|
||||
if ( valid_cut ) {
|
||||
const double volume_after_subtraction = shape_volume(shape);
|
||||
if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) )
|
||||
Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",l->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Subtraction yields unchanged volume:", l);
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to process subtraction:", l);
|
||||
shape = s1;
|
||||
}
|
||||
|
||||
@@ -309,10 +415,9 @@ bool IfcGeom::convert(const IfcSchema::IfcBooleanResult::ptr l, TopoDS_Shape& sh
|
||||
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
|
||||
if ( is_valid ) {
|
||||
shape = result;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) {
|
||||
|
||||
@@ -327,53 +432,74 @@ bool IfcGeom::convert(const IfcSchema::IfcBooleanResult::ptr l, TopoDS_Shape& sh
|
||||
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
|
||||
if ( is_valid ) {
|
||||
shape = result;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcConnectedFaceSet::ptr l, TopoDS_Shape& shape) {
|
||||
IfcSchema::IfcFace::list faces = l->CfsFaces();
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Shape& shape) {
|
||||
IfcSchema::IfcFace::list::ptr faces = l->CfsFaces();
|
||||
bool facesAdded = false;
|
||||
const unsigned int num_faces = faces->Size();
|
||||
if ( num_faces < GetValue(GV_MAX_FACES_TO_SEW) ) {
|
||||
const unsigned int num_faces = (unsigned)faces->size();
|
||||
bool valid_shell = false;
|
||||
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::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::list::it it = faces->begin(); it != faces->end(); ++ it ) {
|
||||
TopoDS_Face face;
|
||||
if ( IfcGeom::convert_face(*it,face) && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) {
|
||||
bool converted_face = false;
|
||||
try {
|
||||
converted_face = convert_face(*it,face);
|
||||
} catch (...) {}
|
||||
if ( converted_face && face_area(face) > getValue(GV_MINIMAL_FACE_AREA) ) {
|
||||
builder.Add(face);
|
||||
facesAdded = true;
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Invalid face:", *it);
|
||||
}
|
||||
}
|
||||
if ( ! facesAdded ) return false;
|
||||
builder.Perform();
|
||||
shape = builder.SewedShape();
|
||||
try {
|
||||
ShapeFix_Solid solid;
|
||||
solid.LimitTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
|
||||
shape = solid.SolidFromShell(TopoDS::Shell(shape));
|
||||
builder.Perform();
|
||||
shape = builder.SewedShape();
|
||||
valid_shell = BRepCheck_Analyzer(shape).IsValid();
|
||||
} catch(...) {}
|
||||
} else {
|
||||
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( IfcSchema::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) {
|
||||
for( IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++ it ) {
|
||||
TopoDS_Face face;
|
||||
if ( IfcGeom::convert_face(*it,face) && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) {
|
||||
bool converted_face = false;
|
||||
try {
|
||||
converted_face = convert_face(*it,face);
|
||||
} catch (...) {}
|
||||
if ( converted_face && face_area(face) > getValue(GV_MINIMAL_FACE_AREA) ) {
|
||||
builder.Add(compound,face);
|
||||
facesAdded = true;
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Invalid face:", *it);
|
||||
}
|
||||
}
|
||||
if ( ! facesAdded ) return false;
|
||||
@@ -382,162 +508,185 @@ bool IfcGeom::convert(const IfcSchema::IfcConnectedFaceSet::ptr l, TopoDS_Shape&
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcMappedItem::ptr l, IfcRepresentationShapeItems& shapes) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentationShapeItems& shapes) {
|
||||
gp_GTrsf gtrsf;
|
||||
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);
|
||||
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);
|
||||
return false;
|
||||
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) {
|
||||
} else if ( transform->declaration().is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) {
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::convert(reinterpret_pointer_cast<IfcSchema::IfcCartesianTransformationOperator,
|
||||
IfcSchema::IfcCartesianTransformationOperator3D>(transform),trsf);
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf);
|
||||
gtrsf = trsf;
|
||||
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) {
|
||||
} else if ( transform->declaration().is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) {
|
||||
gp_Trsf2d trsf_2d;
|
||||
IfcGeom::convert(reinterpret_pointer_cast<IfcSchema::IfcCartesianTransformationOperator,
|
||||
IfcSchema::IfcCartesianTransformationOperator2D>(transform),trsf_2d);
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,trsf_2d);
|
||||
gtrsf = (gp_Trsf) trsf_2d;
|
||||
}
|
||||
IfcSchema::IfcRepresentationMap::ptr map = l->MappingSource();
|
||||
IfcSchema::IfcAxis2Placement placement = map->MappingOrigin();
|
||||
IfcSchema::IfcRepresentationMap* map = l->MappingSource();
|
||||
IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin();
|
||||
gp_Trsf trsf;
|
||||
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
IfcGeom::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
if (placement->declaration().is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
} else {
|
||||
gp_Trsf2d trsf_2d;
|
||||
IfcGeom::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf_2d);
|
||||
IfcGeom::Kernel::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 = IfcGeom::convert_shapes(map->MappedRepresentation(),shapes);
|
||||
bool b = convert_shapes(map->MappedRepresentation(), shapes);
|
||||
|
||||
for ( unsigned int i = previous_size; i < shapes.size(); ++ i ) {
|
||||
shapes[i].append(gtrsf);
|
||||
|
||||
// Apply styles assigned to the mapped item only if on
|
||||
// a more granular level no styles have been applied
|
||||
if (!shapes[i].hasStyle()) {
|
||||
shapes[i].setStyle(mapped_item_style);
|
||||
}
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
bool IfcGeom::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)));
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return part_succes;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcGeometricSet::ptr l, IfcRepresentationShapeItems& shapes) {
|
||||
IfcUtil::IfcAbstractSelect::list elements = l->Elements();
|
||||
if ( !elements->Size() ) return false;
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcGeometricSet* l, IfcRepresentationShapeItems& shapes) {
|
||||
IfcEntityList::ptr elements = l->Elements();
|
||||
if ( !elements->size() ) return false;
|
||||
bool part_succes = false;
|
||||
const IfcGeom::SurfaceStyle* parent_style = get_style(l);
|
||||
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));
|
||||
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);
|
||||
}
|
||||
shapes.push_back(IfcRepresentationShapeItem(s, style ? style : parent_style));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return part_succes;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
BRepPrimAPI_MakeBox builder(dx, dy, dz);
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::convert(l->Position(),trsf);
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
shape = builder.Solid().Moved(trsf);
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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, Precision::Confusion(), Precision::Confusion());
|
||||
trsf2.SetValues(
|
||||
1, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 1, 0, 0
|
||||
#if OCC_VERSION_HEX < 0x60800
|
||||
, Precision::Angular(), Precision::Confusion()
|
||||
#endif
|
||||
);
|
||||
|
||||
IfcGeom::convert(l->Position(), trsf1);
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf1);
|
||||
shape = BRepBuilderAPI_Transform(builder.Solid(), trsf1 * trsf2);
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
BRepPrimAPI_MakeCylinder builder(r, h);
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::convert(l->Position(),trsf);
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
shape = builder.Solid().Moved(trsf);
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
BRepPrimAPI_MakeCone builder(r, 0., h);
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::convert(l->Position(),trsf);
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
shape = builder.Solid().Moved(trsf);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcSphere::ptr l, TopoDS_Shape& shape) {
|
||||
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSphere* l, TopoDS_Shape& shape) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
BRepPrimAPI_MakeSphere builder(r);
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::convert(l->Position(),trsf);
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
shape = builder.Solid().Moved(trsf);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcCsgSolid::ptr l, TopoDS_Shape& shape) {
|
||||
return IfcGeom::convert_shape(l->TreeRootExpression(), shape);
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCsgSolid* l, TopoDS_Shape& shape) {
|
||||
return convert_shape(l->TreeRootExpression(), shape);
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcCurveBoundedPlane::ptr l, TopoDS_Shape& face) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_Shape& face) {
|
||||
gp_Pln pln;
|
||||
IfcGeom::convert(l->BasisSurface(), pln);
|
||||
IfcGeom::Kernel::convert(l->BasisSurface(), pln);
|
||||
|
||||
gp_Trsf trsf;
|
||||
trsf.SetTransformation(pln.Position());
|
||||
trsf.SetTransformation(pln.Position(), gp::XOY());
|
||||
|
||||
TopoDS_Wire outer;
|
||||
IfcGeom::convert_wire(l->OuterBoundary(), outer);
|
||||
convert_wire(l->OuterBoundary(), outer);
|
||||
|
||||
BRepBuilderAPI_MakeFace mf (outer);
|
||||
mf.Add(outer);
|
||||
|
||||
IfcSchema::IfcCurve::list inner = l->InnerBoundaries();
|
||||
IfcSchema::IfcCurve::list::ptr boundaries = l->InnerBoundaries();
|
||||
|
||||
for (IfcSchema::IfcCurve::it it = inner->begin(); it != inner->end(); ++it) {
|
||||
for (IfcSchema::IfcCurve::list::it it = boundaries->begin(); it != boundaries->end(); ++it) {
|
||||
TopoDS_Wire inner;
|
||||
IfcGeom::convert_wire(*it, inner);
|
||||
convert_wire(*it, inner);
|
||||
|
||||
mf.Add(inner);
|
||||
}
|
||||
@@ -549,13 +698,13 @@ bool IfcGeom::convert(const IfcSchema::IfcCurveBoundedPlane::ptr l, TopoDS_Shape
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
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());
|
||||
return false;
|
||||
}
|
||||
gp_Pln pln;
|
||||
IfcGeom::convert((IfcSchema::IfcPlane*) l->BasisSurface(), pln);
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcPlane*) l->BasisSurface(), pln);
|
||||
|
||||
BRepBuilderAPI_MakeFace mf(pln, l->U1(), l->U2(), l->V1(), l->V2());
|
||||
|
||||
@@ -564,19 +713,19 @@ bool IfcGeom::convert(const IfcSchema::IfcRectangularTrimmedSurface::ptr l, Topo
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid::ptr l, TopoDS_Shape& shape) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, TopoDS_Shape& shape) {
|
||||
gp_Trsf directrix, position;
|
||||
TopoDS_Shape face;
|
||||
TopoDS_Wire wire, section;
|
||||
|
||||
if (!l->ReferenceSurface()->is(IfcSchema::Type::IfcPlane)) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Reference surface not supported", l->ReferenceSurface()->entity);
|
||||
if (!l->ReferenceSurface()->declaration().is(IfcSchema::Type::IfcPlane)) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Reference surface not supported", l->ReferenceSurface());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IfcGeom::convert(l->Position(), position) ||
|
||||
!IfcGeom::convert_face(l->SweptArea(), face) ||
|
||||
!IfcGeom::convert_wire(l->Directrix(), wire) ) {
|
||||
if (!IfcGeom::Kernel::convert(l->Position(), position) ||
|
||||
!convert_face(l->SweptArea(), face) ||
|
||||
!convert_wire(l->Directrix(), wire) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -584,7 +733,7 @@ bool IfcGeom::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid::ptr l, Top
|
||||
gp_Pnt directrix_origin;
|
||||
gp_Vec directrix_tangent;
|
||||
bool directrix_on_plane = true;
|
||||
IfcGeom::convert((IfcSchema::IfcPlane*) l->ReferenceSurface(), pln);
|
||||
IfcGeom::Kernel::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
|
||||
@@ -595,7 +744,7 @@ bool IfcGeom::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid::ptr l, Top
|
||||
for (TopExp_Explorer exp(wire, TopAbs_VERTEX); exp.More(); exp.Next()) {
|
||||
if (pln.Distance(BRep_Tool::Pnt(TopoDS::Vertex(exp.Current()))) > ALMOST_ZERO) {
|
||||
directrix_on_plane = false;
|
||||
Logger::Message(Logger::LOG_WARNING, "The Directrix does not lie on the ReferenceSurface", l->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "The Directrix does not lie on the ReferenceSurface", l);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -637,12 +786,12 @@ bool IfcGeom::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid::ptr l, Top
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcSweptDiskSolid::ptr l, TopoDS_Shape& shape) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shape& shape) {
|
||||
TopoDS_Wire wire, section1, section2;
|
||||
|
||||
const bool hasInnerRadius = l->hasInnerRadius();
|
||||
bool hasInnerRadius = l->hasInnerRadius();
|
||||
|
||||
if (!IfcGeom::convert_wire(l->Directrix(), wire)) {
|
||||
if (!convert_wire(l->Directrix(), wire)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -658,14 +807,19 @@ bool IfcGeom::convert(const IfcSchema::IfcSweptDiskSolid::ptr l, TopoDS_Shape& s
|
||||
directrix = gp_Ax2(directrix_origin, directrix_tangent);
|
||||
}
|
||||
|
||||
const double r1 = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
const double r1 = l->Radius() * 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() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
Handle(Geom_Circle) circle = new Geom_Circle(directrix, r2);
|
||||
section2 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle));
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
// NB: Note that StartParam and EndParam param are ignored and the assumption is
|
||||
@@ -705,7 +859,7 @@ bool IfcGeom::convert(const IfcSchema::IfcSweptDiskSolid::ptr l, TopoDS_Shape& s
|
||||
}
|
||||
|
||||
if (!is_valid) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Failed to subtract inner radius void for:", l->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Failed to subtract inner radius void for:", l);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -714,12 +868,128 @@ bool IfcGeom::convert(const IfcSchema::IfcSweptDiskSolid::ptr l, TopoDS_Shape& s
|
||||
|
||||
#ifdef USE_IFC4
|
||||
|
||||
bool IfcGeom::convert(const IfcSchema::IfcCylindricalSurface::ptr l, TopoDS_Shape& face) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCylindricalSurface* l, TopoDS_Shape& face) {
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::convert(l->Position(),trsf);
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
|
||||
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius()), GetValue(GV_PRECISION)).Face().Moved(trsf);
|
||||
#if OCC_VERSION_HEX < 0x60502
|
||||
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius())).Face().Moved(trsf);
|
||||
#else
|
||||
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius()), getValue(GV_PRECISION)).Face().Moved(trsf);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
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
|
||||
|
||||
+278
-88
@@ -47,47 +47,50 @@
|
||||
#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 <BRepOffsetAPI_Sewing.hxx>
|
||||
#include <BRepBuilderAPI_MakeVertex.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_Explorer.hxx>
|
||||
|
||||
#include <BRepPrimAPI_MakePrism.hxx>
|
||||
#include <BRepBuilderAPI_MakeShell.hxx>
|
||||
#include <BRepBuilderAPI_MakeSolid.hxx>
|
||||
#include <BRepPrimAPI_MakeHalfSpace.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 <BRepPrimAPI_MakeHalfSpace.hxx>
|
||||
#include <BRepFilletAPI_MakeFillet2d.hxx>
|
||||
|
||||
#include <BRep_Tool.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::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);
|
||||
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);
|
||||
|
||||
// Temporarily pretend we do have unit information
|
||||
IfcGeom::SetValue(GV_PLANEANGLE_UNIT,1.0);
|
||||
setValue(GV_PLANEANGLE_UNIT,1.0);
|
||||
|
||||
bool succes_radians = false;
|
||||
bool succes_degrees = false;
|
||||
@@ -97,17 +100,17 @@ bool IfcGeom::convert(const IfcSchema::IfcCompositeCurve::ptr l, TopoDS_Wire& wi
|
||||
// First try radians
|
||||
TopoDS_Wire wire_radians, wire_degrees;
|
||||
try {
|
||||
succes_radians = IfcGeom::convert(l,wire_radians);
|
||||
succes_radians = IfcGeom::Kernel::convert(l,wire_radians);
|
||||
} catch (...) {}
|
||||
|
||||
// Now try degrees
|
||||
IfcGeom::SetValue(GV_PLANEANGLE_UNIT,0.0174532925199433);
|
||||
setValue(GV_PLANEANGLE_UNIT,0.0174532925199433);
|
||||
try {
|
||||
succes_degrees = IfcGeom::convert(l,wire_degrees);
|
||||
succes_degrees = IfcGeom::Kernel::convert(l,wire_degrees);
|
||||
} catch (...) {}
|
||||
|
||||
// Restore to unknown unit state
|
||||
IfcGeom::SetValue(GV_PLANEANGLE_UNIT,-1.0);
|
||||
setValue(GV_PLANEANGLE_UNIT,-1.0);
|
||||
|
||||
if ( succes_degrees && ! succes_radians ) {
|
||||
use_degrees = true;
|
||||
@@ -138,19 +141,19 @@ bool IfcGeom::convert(const IfcSchema::IfcCompositeCurve::ptr l, TopoDS_Wire& wi
|
||||
|
||||
return use_radians || use_degrees;
|
||||
}
|
||||
IfcSchema::IfcCompositeCurveSegment::list segments = l->Segments();
|
||||
IfcSchema::IfcCompositeCurveSegment::list::ptr segments = l->Segments();
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
//TopoDS_Vertex last_vertex;
|
||||
for( IfcSchema::IfcCompositeCurveSegment::it it = segments->begin(); it != segments->end(); ++ it ) {
|
||||
const IfcSchema::IfcCurve::ptr curve = (*it)->ParentCurve();
|
||||
for( IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++ it ) {
|
||||
IfcSchema::IfcCurve* curve = (*it)->ParentCurve();
|
||||
TopoDS_Wire wire2;
|
||||
if ( ! IfcGeom::convert_wire(curve,wire2) ) {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve->entity);
|
||||
if ( !convert_wire(curve,wire2) ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to convert curve:", curve);
|
||||
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());
|
||||
@@ -164,48 +167,66 @@ bool IfcGeom::convert(const IfcSchema::IfcCompositeCurve::ptr l, TopoDS_Wire& wi
|
||||
w.Add(wire2);
|
||||
//last_vertex = w.Vertex();
|
||||
if ( w.Error() != BRepBuilderAPI_WireDone ) {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to join curve segments:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to join curve segments:", l);
|
||||
|
||||
TopoDS_Vertex v1, v2, last;
|
||||
last = w.Vertex();
|
||||
|
||||
if (!last.IsNull()) {
|
||||
std::stringstream ss;
|
||||
gp_Pnt p = BRep_Tool::Pnt(last);
|
||||
ss << std::setprecision(4) << "Last vertex at (" << p.X() << " " << p.Y() << " " << p.Z() << ")";
|
||||
Logger::Message(Logger::LOG_NOTICE, ss.str());
|
||||
}
|
||||
|
||||
TopExp::Vertices(wire2, v1, v2);
|
||||
if (!v1.IsNull()) {
|
||||
std::stringstream ss;
|
||||
gp_Pnt p = BRep_Tool::Pnt(v1);
|
||||
ss << std::setprecision(4) << "Segment starts at (" << p.X() << " " << p.Y() << " " << p.Z() << ") for:";
|
||||
Logger::Message(Logger::LOG_NOTICE, ss.str(), *it);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
wire = w.Wire();
|
||||
return true;
|
||||
}
|
||||
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);
|
||||
|
||||
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);
|
||||
Handle(Geom_Curve) curve;
|
||||
if ( ! IfcGeom::convert_curve(basis_curve,curve) ) return false;
|
||||
if ( !convert_curve(basis_curve,curve) ) return false;
|
||||
bool trim_cartesian = l->MasterRepresentation() == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN;
|
||||
IfcUtil::IfcAbstractSelect::list trims1 = l->Trim1();
|
||||
IfcUtil::IfcAbstractSelect::list trims2 = l->Trim2();
|
||||
bool trimmed1 = false;
|
||||
bool trimmed2 = false;
|
||||
IfcEntityList::ptr trims1 = l->Trim1();
|
||||
IfcEntityList::ptr trims2 = l->Trim2();
|
||||
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 ( 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] );
|
||||
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] );
|
||||
has_pnts[sense_agreement] = true;
|
||||
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
|
||||
const double value = *((IfcUtil::IfcBaseEntity*)i)->entity->getArgument(0);
|
||||
} else if ( i->declaration().is(IfcSchema::Type::IfcParameterValue) ) {
|
||||
const double value = *((IfcSchema::IfcParameterValue*)i);
|
||||
flts[sense_agreement] = value * parameterFactor;
|
||||
has_flts[sense_agreement] = true;
|
||||
}
|
||||
}
|
||||
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] );
|
||||
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] );
|
||||
has_pnts[1-sense_agreement] = true;
|
||||
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
|
||||
const double value = *((IfcUtil::IfcBaseEntity*)i)->entity->getArgument(0);
|
||||
} else if ( i->declaration().is(IfcSchema::Type::IfcParameterValue) ) {
|
||||
const double value = *((IfcSchema::IfcParameterValue*)i);
|
||||
flts[1-sense_agreement] = value * parameterFactor;
|
||||
has_flts[1-sense_agreement] = true;
|
||||
}
|
||||
@@ -213,20 +234,20 @@ bool IfcGeom::convert(const IfcSchema::IfcTrimmedCurve::ptr l, TopoDS_Wire& 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->entity);
|
||||
if ( pnts[0].Distance(pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE) ) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Skipping segment with length below tolerance level:", l);
|
||||
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->entity);
|
||||
Logger::Message(Logger::LOG_WARNING, "Point projection failed for:", l);
|
||||
trim_cartesian_failed = true;
|
||||
}
|
||||
} else {
|
||||
@@ -238,22 +259,22 @@ bool IfcGeom::convert(const IfcSchema::IfcTrimmedCurve::ptr l, TopoDS_Wire& wire
|
||||
// is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because
|
||||
// the vector is normalised when passed to Geom_Line constructor the magnitude
|
||||
// needs to be factored in with the IfcParameterValue here.
|
||||
if ( basis_curve->is(IfcSchema::Type::IfcLine) ) {
|
||||
if ( basis_curve->declaration().is(IfcSchema::Type::IfcLine) ) {
|
||||
IfcSchema::IfcLine* line = static_cast<IfcSchema::IfcLine*>(basis_curve);
|
||||
const double magnitude = line->Dir()->Magnitude();
|
||||
flts[0] *= magnitude; flts[1] *= magnitude;
|
||||
}
|
||||
if ( basis_curve->is(IfcSchema::Type::IfcEllipse) ) {
|
||||
if ( basis_curve->declaration().is(IfcSchema::Type::IfcEllipse) ) {
|
||||
IfcSchema::IfcEllipse* ellipse = static_cast<IfcSchema::IfcEllipse*>(basis_curve);
|
||||
double x = ellipse->SemiAxis1() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
double y = ellipse->SemiAxis2() * IfcGeom::GetValue(GV_LENGTH_UNIT);
|
||||
double x = ellipse->SemiAxis1() * getValue(GV_LENGTH_UNIT);
|
||||
double y = ellipse->SemiAxis2() * 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],(double)(M_PI*2.0)),0.0f) ) {
|
||||
if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],M_PI*2.),0.) ) {
|
||||
w.Add(BRepBuilderAPI_MakeEdge(curve));
|
||||
} else {
|
||||
BRepBuilderAPI_MakeEdge e (curve,flts[0],flts[1]);
|
||||
@@ -269,44 +290,213 @@ bool IfcGeom::convert(const IfcSchema::IfcTrimmedCurve::ptr l, TopoDS_Wire& wire
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool IfcGeom::convert(const IfcSchema::IfcPolyline::ptr l, TopoDS_Wire& result) {
|
||||
IfcSchema::IfcCartesianPoint::list points = l->Points();
|
||||
|
||||
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;
|
||||
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));
|
||||
}
|
||||
|
||||
result = w.Wire();
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const IfcSchema::IfcPolyLoop::ptr l, TopoDS_Wire& result) {
|
||||
IfcSchema::IfcCartesianPoint::list points = l->Polygon();
|
||||
|
||||
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;
|
||||
}
|
||||
if ( !P1.IsEqual(F,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) {
|
||||
w.Add(BRepBuilderAPI_MakeEdge(P1,F));
|
||||
count ++;
|
||||
}
|
||||
if ( count < 3 ) return false;
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& result) {
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points = l->Polygon();
|
||||
|
||||
result = w.Wire();
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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();
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const IfcSchema::IfcArbitraryOpenProfileDef::ptr l, TopoDS_Wire& result) {
|
||||
return IfcGeom::convert_wire(l->Curve(), result);
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryOpenProfileDef* l, TopoDS_Wire& result) {
|
||||
return 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+73
-32
@@ -18,60 +18,101 @@
|
||||
********************************************************************************/
|
||||
|
||||
#include "IfcGeom.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
namespace Cache {
|
||||
std::map<int,TopoDS_Shape> Shape;
|
||||
void PurgeShapeCache() {
|
||||
Shape.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
#include "IfcGeomShapeType.h"
|
||||
|
||||
using namespace IfcSchema;
|
||||
using namespace IfcUtil;
|
||||
|
||||
bool IfcGeom::convert_shapes(const IfcBaseClass* l, IfcRepresentationShapeItems& r) {
|
||||
bool IfcGeom::Kernel::convert_shapes(const IfcBaseClass* l, IfcRepresentationShapeItems& r) {
|
||||
if (shape_type(l) != ST_SHAPELIST) {
|
||||
TopoDS_Shape shp;
|
||||
if (convert_shape(l, shp)) {
|
||||
r.push_back(IfcGeom::IfcRepresentationShapeItem(shp, get_style(l->as<IfcSchema::IfcRepresentationItem>())));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "IfcRegisterConvertShapes.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l);
|
||||
return false;
|
||||
}
|
||||
bool IfcGeom::is_shape_collection(const IfcBaseClass* l) {
|
||||
#include "IfcRegisterIsShapeCollection.h"
|
||||
return false;
|
||||
|
||||
IfcGeom::ShapeType IfcGeom::Kernel::shape_type(const IfcBaseClass* l) {
|
||||
#include "IfcRegisterShapeType.h"
|
||||
return ST_OTHER;
|
||||
}
|
||||
bool IfcGeom::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) {
|
||||
const unsigned int id = l->entity->id();
|
||||
|
||||
bool IfcGeom::Kernel::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) {
|
||||
const unsigned int id = l->data().id();
|
||||
bool success = false;
|
||||
bool processed = false;
|
||||
std::map<int,TopoDS_Shape>::const_iterator it = Cache::Shape.find(id);
|
||||
if ( it != Cache::Shape.end() ) { r = it->second; return true; }
|
||||
bool ignored = false;
|
||||
|
||||
std::map<int,TopoDS_Shape>::const_iterator it = cache.Shape.find(id);
|
||||
if ( it != cache.Shape.end() ) { r = it->second; return true; }
|
||||
const bool include_curves = getValue(GV_DIMENSIONALITY) != +1;
|
||||
const bool include_solids_and_surfaces = getValue(GV_DIMENSIONALITY) != -1;
|
||||
|
||||
IfcGeom::ShapeType st = shape_type(l);
|
||||
ignored = (!include_solids_and_surfaces && (st == ST_SHAPE || st == ST_FACE)) || (!include_curves && (st == ST_WIRE || st == ST_CURVE));
|
||||
if (st == ST_SHAPELIST) {
|
||||
processed = true;
|
||||
IfcRepresentationShapeItems items;
|
||||
success = convert_shapes(l, items) && flatten_shape_list(items, r, false);
|
||||
} else if (st == ST_SHAPE && include_solids_and_surfaces) {
|
||||
#include "IfcRegisterConvertShape.h"
|
||||
if ( processed ) {
|
||||
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);
|
||||
} 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);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
bool IfcGeom::convert_wire(const IfcBaseClass* l, TopoDS_Wire& r) {
|
||||
|
||||
bool IfcGeom::Kernel::convert_wire(const IfcBaseClass* l, TopoDS_Wire& r) {
|
||||
#include "IfcRegisterConvertWire.h"
|
||||
Handle(Geom_Curve) curve;
|
||||
if (IfcGeom::convert_curve(l, curve)) {
|
||||
return IfcGeom::convert_curve_to_wire(curve, r);
|
||||
if (IfcGeom::Kernel::convert_curve(l, curve)) {
|
||||
return IfcGeom::Kernel::convert_curve_to_wire(curve, r);
|
||||
}
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l);
|
||||
return false;
|
||||
}
|
||||
bool IfcGeom::convert_face(const IfcBaseClass* l, TopoDS_Shape& r) {
|
||||
|
||||
bool IfcGeom::Kernel::convert_face(const IfcBaseClass* l, TopoDS_Shape& r) {
|
||||
#include "IfcRegisterConvertFace.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l);
|
||||
return false;
|
||||
}
|
||||
bool IfcGeom::convert_curve(const IfcBaseClass* l, Handle(Geom_Curve)& r) {
|
||||
|
||||
bool IfcGeom::Kernel::convert_curve(const IfcBaseClass* l, Handle(Geom_Curve)& r) {
|
||||
#include "IfcRegisterConvertCurve.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l);
|
||||
return false;
|
||||
}
|
||||
@@ -41,21 +41,28 @@
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcParse.h"
|
||||
|
||||
using namespace IfcSchema;
|
||||
|
||||
SHAPES(IfcShellBasedSurfaceModel);
|
||||
SHAPES(IfcFaceBasedSurfaceModel);
|
||||
SHAPES(IfcShapeRepresentation);
|
||||
SHAPES(IfcRepresentation);
|
||||
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);
|
||||
@@ -68,9 +75,6 @@ SHAPE(IfcCurveBoundedPlane);
|
||||
SHAPE(IfcRectangularTrimmedSurface);
|
||||
SHAPE(IfcSurfaceCurveSweptAreaSolid);
|
||||
SHAPE(IfcSweptDiskSolid);
|
||||
#ifdef USE_IFC4
|
||||
SHAPE(IfcCylindricalSurface);
|
||||
#endif
|
||||
|
||||
FACE(IfcArbitraryProfileDefWithVoids);
|
||||
FACE(IfcArbitraryClosedProfileDef);
|
||||
@@ -79,6 +83,7 @@ FACE(IfcRectangleHollowProfileDef);
|
||||
FACE(IfcRectangleProfileDef);
|
||||
FACE(IfcTrapeziumProfileDef)
|
||||
FACE(IfcCShapeProfileDef);
|
||||
// IfcAsymmetricIShapeProfileDef included
|
||||
FACE(IfcIShapeProfileDef);
|
||||
FACE(IfcLShapeProfileDef);
|
||||
FACE(IfcTShapeProfileDef);
|
||||
@@ -90,8 +95,15 @@ 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);
|
||||
@@ -101,6 +113,9 @@ WIRE(IfcArbitraryOpenProfileDef);
|
||||
CURVE(IfcCircle);
|
||||
CURVE(IfcEllipse);
|
||||
CURVE(IfcLine);
|
||||
#ifdef USE_IFC4
|
||||
CURVE(IfcBSplineCurveWithKnots);
|
||||
#endif
|
||||
|
||||
CLASS(IfcCartesianPoint,gp_Pnt);
|
||||
CLASS(IfcDirection,gp_Dir);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define CURVE(T) \
|
||||
if ( l->is(T::Class()) ) return convert((T*)l,r);
|
||||
if ( l->declaration().is(T::Class()) ) return convert(l->as<T>(), r);
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
#include "IfcRegister.h"
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define FACE(T) \
|
||||
if ( l->is(T::Class()) ) return convert((T*)l,r);
|
||||
if ( l->declaration().is(T::Class()) ) return convert(l->as<T>(), r);
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
#include "IfcRegister.h"
|
||||
@@ -1,14 +1,14 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define SHAPE(T) \
|
||||
if ( !processed && l->is(T::Class()) ) { \
|
||||
if ( !processed && l->declaration().is(T::Class()) ) { \
|
||||
processed = true; \
|
||||
try { \
|
||||
if ( convert((T*)l,r) ) { \
|
||||
if ( convert(l->as<T>(), r) ) { \
|
||||
success = true; \
|
||||
} \
|
||||
} catch(...) { } \
|
||||
if ( !success) { \
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to convert:", l); \
|
||||
return false; \
|
||||
} \
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define SHAPES(T) \
|
||||
if ( l->is(T::Class()) ) { \
|
||||
if ( l->declaration().is(T::Class()) ) { \
|
||||
try { \
|
||||
return IfcGeom::convert((T*)l,r); \
|
||||
return convert(l->as<T>(), r); \
|
||||
} catch (...) { } \
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to convert:", l); \
|
||||
return false; \
|
||||
}
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define WIRE(T) \
|
||||
if ( l->is(T::Class()) ) return convert((T*)l,r);
|
||||
if ( l->declaration().is(T::Class()) ) return convert((T*)l,r);
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
#include "IfcRegister.h"
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define CLASS(T,V) bool convert(const T::ptr L, V& r);
|
||||
#define CLASS(T,V) bool convert(const IfcSchema::T* L, V& r);
|
||||
#define SHAPES(T) CLASS(T,IfcRepresentationShapeItems)
|
||||
#define SHAPE(T) CLASS(T,TopoDS_Shape)
|
||||
#define WIRE(T) CLASS(T,TopoDS_Wire)
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define SHAPES(T) \
|
||||
if ( l->is(T::Class()) ) return true;
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
#include "IfcRegister.h"
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define SHAPES(T) \
|
||||
if ( l->declaration().is(T::Class()) ) return ST_SHAPELIST;
|
||||
#define SHAPE(T) \
|
||||
if ( l->declaration().is(T::Class()) ) return ST_SHAPE;
|
||||
#define WIRE(T) \
|
||||
if ( l->declaration().is(T::Class()) ) return ST_WIRE;
|
||||
#define FACE(T) \
|
||||
if ( l->declaration().is(T::Class()) ) return ST_FACE;
|
||||
#define CURVE(T) \
|
||||
if ( l->declaration().is(T::Class()) ) return ST_CURVE;
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
#include "IfcRegister.h"
|
||||
@@ -46,6 +46,7 @@ namespace IfcGeom {
|
||||
const gp_GTrsf& Placement() const { return placement; }
|
||||
bool hasStyle() const { return style != 0; }
|
||||
const SurfaceStyle& Style() const { return *style; }
|
||||
void setStyle(const SurfaceStyle* style) { this->style = style; }
|
||||
};
|
||||
typedef std::vector<IfcRepresentationShapeItem> IfcRepresentationShapeItems;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,11 @@
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
#endif
|
||||
|
||||
using namespace boost;
|
||||
|
||||
@@ -69,7 +73,7 @@ void swrite(std::ostream& s, T t) {
|
||||
|
||||
template <>
|
||||
void swrite(std::ostream& s, std::string t) {
|
||||
int32_t len = t.size();
|
||||
int32_t len = (int32_t)t.size();
|
||||
swrite(s, len);
|
||||
s.write(t.c_str(), len);
|
||||
while (len++ % 4) s.put(0);
|
||||
@@ -156,16 +160,16 @@ public:
|
||||
|
||||
class Get : public Command {
|
||||
protected:
|
||||
void read_content(std::istream& s) {}
|
||||
void write_content(std::ostream& s) {}
|
||||
void read_content(std::istream& /*s*/) {}
|
||||
void write_content(std::ostream& /*s*/) {}
|
||||
public:
|
||||
Get() : Command(GET) {};
|
||||
};
|
||||
|
||||
class GetLog : public Command {
|
||||
protected:
|
||||
void read_content(std::istream& s) {}
|
||||
void write_content(std::ostream& s) {}
|
||||
void read_content(std::istream& /*s*/) {}
|
||||
void write_content(std::ostream& /*s*/) {}
|
||||
public:
|
||||
GetLog() : Command(GET_LOG) {};
|
||||
};
|
||||
@@ -186,16 +190,17 @@ public:
|
||||
|
||||
class Entity : public Command {
|
||||
private:
|
||||
const IfcGeomObjects::IfcGeomObject* geom;
|
||||
const IfcGeom::TriangulationElement<float>* geom;
|
||||
bool append_line_data;
|
||||
protected:
|
||||
void read_content(std::istream& s) {}
|
||||
void read_content(std::istream& /*s*/) {}
|
||||
void write_content(std::ostream& s) {
|
||||
swrite<int32_t>(s, geom->id());
|
||||
swrite(s, geom->guid());
|
||||
swrite(s, geom->name());
|
||||
swrite(s, geom->type());
|
||||
swrite<int32_t>(s, geom->parent_id());
|
||||
const std::vector<float>& m = geom->matrix();
|
||||
const std::vector<float>& m = geom->transformation().matrix().data();
|
||||
const float matrix_array[16] = {
|
||||
m[0], m[3], m[6], m[ 9],
|
||||
m[1], m[4], m[7], m[10],
|
||||
@@ -203,19 +208,43 @@ protected:
|
||||
0, 0, 0, 1
|
||||
};
|
||||
swrite(s, std::string((char*)matrix_array, 16 * sizeof(float)));
|
||||
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))); }
|
||||
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)));
|
||||
}
|
||||
}
|
||||
{ std::vector<float> diffuse_color_array;
|
||||
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();
|
||||
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();
|
||||
diffuse_color_array.push_back(static_cast<float>(color[0]));
|
||||
diffuse_color_array.push_back(static_cast<float>(color[1]));
|
||||
diffuse_color_array.push_back(static_cast<float>(color[2]));
|
||||
@@ -224,44 +253,40 @@ protected:
|
||||
diffuse_color_array.push_back(0.f);
|
||||
diffuse_color_array.push_back(0.f);
|
||||
}
|
||||
if (m.hasTransparency()) {
|
||||
diffuse_color_array.push_back(static_cast<float>(1. - m.transparency()));
|
||||
if (mat.hasTransparency()) {
|
||||
diffuse_color_array.push_back(static_cast<float>(1. - mat.transparency()));
|
||||
} else {
|
||||
diffuse_color_array.push_back(1.f);
|
||||
}
|
||||
}
|
||||
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->mesh().material_ids().begin(); it != geom->mesh().material_ids().end(); ++it) {
|
||||
for (std::vector<int>::const_iterator it = geom->geometry().material_ids().begin(); it != geom->geometry().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 IfcGeomObjects::IfcGeomObject* geom) : Command(ENTITY), geom(geom) {};
|
||||
Entity(const IfcGeom::TriangulationElement<float>* geom) : Command(ENTITY), geom(geom), append_line_data(true) {};
|
||||
};
|
||||
|
||||
class Next : public Command {
|
||||
protected:
|
||||
void read_content(std::istream& s) {}
|
||||
void write_content(std::ostream& s) {}
|
||||
void read_content(std::istream& /*s*/) {}
|
||||
void write_content(std::ostream& /*s*/) {}
|
||||
public:
|
||||
Next() : Command(NEXT) {};
|
||||
};
|
||||
|
||||
class Bye : public Command {
|
||||
protected:
|
||||
void read_content(std::istream& s) {}
|
||||
void write_content(std::ostream& s) {}
|
||||
void read_content(std::istream& /*s*/) {}
|
||||
void write_content(std::ostream& /*s*/) {}
|
||||
public:
|
||||
Bye() : Command(BYE) {};
|
||||
};
|
||||
|
||||
int main (int argc, char** argv) {
|
||||
if (sizeof(float) != 4 || sizeof(int32_t) != 4) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main () {
|
||||
// Redirect stdout to this stream, so that involuntary
|
||||
// writes to stdout do not interfere with our protocol.
|
||||
std::ostringstream oss;
|
||||
@@ -278,10 +303,12 @@ int main (int argc, char** argv) {
|
||||
|
||||
bool has_more = false;
|
||||
|
||||
IfcGeom::Iterator<float>* iterator = 0;
|
||||
|
||||
Hello().write(std::cout);
|
||||
|
||||
int exit_code = 0;
|
||||
while (1) {
|
||||
for (;;) {
|
||||
const int32_t msg_type = sread<int32_t>(std::cin);
|
||||
switch (msg_type) {
|
||||
case IFC_MODEL: {
|
||||
@@ -290,12 +317,15 @@ int main (int argc, char** argv) {
|
||||
char* data = new char[len];
|
||||
memcpy(data, m.string().c_str(), len);
|
||||
|
||||
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);
|
||||
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();
|
||||
|
||||
has_more = IfcGeomObjects::Init(data, len);
|
||||
More(has_more).write(std::cout);
|
||||
continue;
|
||||
}
|
||||
@@ -305,22 +335,23 @@ int main (int argc, char** argv) {
|
||||
exit_code = 1;
|
||||
break;
|
||||
}
|
||||
const IfcGeomObjects::IfcGeomObject* geom = IfcGeomObjects::Get();
|
||||
const IfcGeom::TriangulationElement<float>* geom = static_cast<const IfcGeom::TriangulationElement<float>*>(iterator->get());
|
||||
Entity(geom).write(std::cout);
|
||||
continue;
|
||||
}
|
||||
case NEXT: {
|
||||
Next n; n.read(std::cin);
|
||||
has_more = IfcGeomObjects::Next();
|
||||
has_more = iterator->next();
|
||||
if (!has_more) {
|
||||
IfcGeomObjects::CleanUp();
|
||||
delete iterator;
|
||||
iterator = 0;
|
||||
}
|
||||
More(has_more).write(std::cout);
|
||||
continue;
|
||||
}
|
||||
case GET_LOG: {
|
||||
GetLog gl; gl.read(std::cin);
|
||||
WriteLog(IfcGeomObjects::GetLog()).write(std::cout);
|
||||
WriteLog(iterator->getLog()).write(std::cout);
|
||||
continue;
|
||||
}
|
||||
case BYE: {
|
||||
|
||||
+54
-24
@@ -17,12 +17,15 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include <Max.h>
|
||||
#include <stdmat.h>
|
||||
#include <istdplug.h>
|
||||
|
||||
#include "../ifcmax/IfcMax.h"
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
static const int NUM_MATERIAL_SLOTS = 24;
|
||||
|
||||
@@ -119,7 +122,7 @@ Mtl* FindMaterialByName(MtlBaseLib* library, const std::string& material_name) {
|
||||
return m;
|
||||
}
|
||||
|
||||
Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& slot, const IfcGeomObjects::Material& material) {
|
||||
Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& slot, const IfcGeom::Material& material) {
|
||||
Mtl* m = FindMaterialByName(library, material.name());
|
||||
if (m == 0) {
|
||||
StdMat2* stdm = NewDefaultStdMat();
|
||||
@@ -148,7 +151,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<IfcGeomObjects::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<IfcGeom::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) {
|
||||
@@ -200,9 +203,10 @@ Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi_mats,
|
||||
|
||||
int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, BOOL suppressPrompts) {
|
||||
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS,false);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::WELD_VERTICES,true);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::SEW_SHELLS,true);
|
||||
IfcGeom::IteratorSettings settings;
|
||||
settings.use_world_coords() = false;
|
||||
settings.weld_vertices() = true;
|
||||
settings.sew_shells() = true;
|
||||
|
||||
#ifdef _UNICODE
|
||||
int fn_buffer_size = WideCharToMultiByte(CP_UTF8, 0, name, -1, 0, 0, 0, 0);
|
||||
@@ -212,7 +216,9 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
|
||||
const char* fn_mb = name;
|
||||
#endif
|
||||
|
||||
if ( ! IfcGeomObjects::Init(fn_mb,0,0) ) return false;
|
||||
IfcGeom::Iterator<float> iterator(settings, fn_mb);
|
||||
|
||||
if (!iterator.initialize()) return false;
|
||||
|
||||
itfc->ProgressStart(_T("Importing file..."), TRUE, fn, NULL);
|
||||
|
||||
@@ -222,31 +228,56 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
|
||||
std::map<std::vector<std::string>, Mtl*> material_cache;
|
||||
|
||||
do{
|
||||
|
||||
const IfcGeomObjects::IfcGeomObject* o = IfcGeomObjects::Get();
|
||||
const IfcGeom::TriangulationElement<float>* o = static_cast<const IfcGeom::TriangulationElement<float>*>(iterator.get());
|
||||
|
||||
TSTR o_type = S(o->type());
|
||||
TSTR o_guid = S(o->guid());
|
||||
|
||||
Mtl *m = ComposeMultiMaterial(material_cache, mats, itfc, slot, o->mesh().materials(), o->type(), o->mesh().material_ids());
|
||||
Mtl *m = ComposeMultiMaterial(material_cache, mats, itfc, slot, o->geometry().materials(), o->type(), o->geometry().material_ids());
|
||||
|
||||
TriObject* tri = CreateNewTriObject();
|
||||
|
||||
const int numVerts = o->mesh().verts().size()/3;
|
||||
const int numVerts = o->geometry().verts().size()/3;
|
||||
tri->mesh.setNumVerts(numVerts);
|
||||
for( int i = 0; i < numVerts; i ++ ) {
|
||||
tri->mesh.setVert(i,o->mesh().verts()[3*i+0],o->mesh().verts()[3*i+1],o->mesh().verts()[3*i+2]);
|
||||
tri->mesh.setVert(i,o->geometry().verts()[3*i+0],o->geometry().verts()[3*i+1],o->geometry().verts()[3*i+2]);
|
||||
}
|
||||
const int numFaces = o->mesh().faces().size()/3;
|
||||
const int numFaces = o->geometry().faces().size()/3;
|
||||
tri->mesh.setNumFaces(numFaces);
|
||||
|
||||
bool needs_default = std::find(o->mesh().material_ids().begin(), o->mesh().material_ids().end(), -1) != o->mesh().material_ids().end();
|
||||
bool needs_default = std::find(o->geometry().material_ids().begin(), o->geometry().material_ids().end(), -1) != o->geometry().material_ids().end();
|
||||
|
||||
typedef std::pair<int, int> edge_t;
|
||||
|
||||
std::set<edge_t> face_boundaries;
|
||||
for(std::vector<int>::const_iterator it = o->geometry().edges().begin(); it != o->geometry().edges().end();) {
|
||||
const int v1 = *it++;
|
||||
const int v2 = *it++;
|
||||
|
||||
const edge_t e((std::min)(v1, v2), (std::max)(v1, v2));
|
||||
face_boundaries.insert(e);
|
||||
}
|
||||
|
||||
for( int i = 0; i < numFaces; i ++ ) {
|
||||
tri->mesh.faces[i].setVerts(o->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 ++;
|
||||
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].setMatID(mtlid);
|
||||
}
|
||||
|
||||
@@ -267,15 +298,14 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
|
||||
if (m) {
|
||||
node->GetINode()->SetMtl(m);
|
||||
}
|
||||
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]) ));
|
||||
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]) ));
|
||||
impitfc->AddNodeToScene(node);
|
||||
|
||||
itfc->ProgressUpdate(IfcGeomObjects::Progress(),true,_T(""));
|
||||
itfc->ProgressUpdate(iterator.progress(), true, _T(""));
|
||||
|
||||
} while ( IfcGeomObjects::Next() );
|
||||
|
||||
IfcGeomObjects::CleanUp();
|
||||
} while (iterator.next());
|
||||
|
||||
itfc->ProgressEnd();
|
||||
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file defines 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;
|
||||
}
|
||||
@@ -1,127 +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 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 );
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#include "../IfcObj/Materials.h"
|
||||
|
||||
void InitMaterials() {
|
||||
materials["IFCSITE"] = ObjMaterial("IFCSITE",0.7f,0.8f,0.5f);
|
||||
}
|
||||
@@ -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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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);
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# 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()
|
||||
@@ -0,0 +1,88 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# 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
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# 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
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
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:])
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef HDF5SETTINGS_H
|
||||
#define HDF5SETTINGS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace IfcParse {
|
||||
|
||||
struct Hdf5Settings {
|
||||
private:
|
||||
bool compress_, fix_cartesian_point_, fix_global_id_, instantiate_select_, instantiate_inverse_;
|
||||
unsigned int chunk_size_;
|
||||
std::vector<std::string> ref_attributes_;
|
||||
|
||||
public:
|
||||
enum Profile {
|
||||
standard,
|
||||
padded,
|
||||
standard_referenced,
|
||||
padded_referenced
|
||||
};
|
||||
|
||||
static Profile ProfileFromString(const std::string& s) {
|
||||
if (s == "standard") return standard;
|
||||
if (s == "padded") return padded;
|
||||
if (s == "referenced") return standard_referenced;
|
||||
if (s == "padded-referenced") return padded_referenced;
|
||||
throw std::runtime_error("Unrecognized profile");
|
||||
}
|
||||
|
||||
private:
|
||||
Profile profile_;
|
||||
|
||||
public:
|
||||
Hdf5Settings()
|
||||
: compress_(false)
|
||||
, fix_cartesian_point_(false)
|
||||
, fix_global_id_(false)
|
||||
, instantiate_select_(false)
|
||||
, instantiate_inverse_(false)
|
||||
, chunk_size_(false)
|
||||
, profile_(standard)
|
||||
{}
|
||||
|
||||
bool compress() const { return compress_; }
|
||||
bool fix_cartesian_point() const { return fix_cartesian_point_; }
|
||||
bool fix_global_id() const { return fix_global_id_; }
|
||||
bool instantiate_select() const { return instantiate_select_; }
|
||||
bool instantiate_inverse() const { return instantiate_inverse_; }
|
||||
|
||||
bool& compress() { return compress_; }
|
||||
bool& fix_cartesian_point() { return fix_cartesian_point_; }
|
||||
bool& fix_global_id() { return fix_global_id_; }
|
||||
bool& instantiate_select() { return instantiate_select_; }
|
||||
bool& instantiate_inverse() { return instantiate_inverse_; }
|
||||
|
||||
unsigned int chunk_size() const { return chunk_size_; }
|
||||
unsigned int& chunk_size() { return chunk_size_; }
|
||||
|
||||
Profile profile() const { return profile_; }
|
||||
Profile& profile() { return profile_; }
|
||||
|
||||
const std::vector<std::string>& ref_attributes() const { return ref_attributes_; }
|
||||
std::vector<std::string>& ref_attributes() { return ref_attributes_; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,9 @@
|
||||
* but instead modify the python script that has been used to generate this. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
#ifndef USE_IFC4
|
||||
|
||||
#ifndef IFC2X3RT_H
|
||||
#define IFC2X3RT_H
|
||||
|
||||
@@ -38,13 +40,15 @@ 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);
|
||||
Enum GetAttributeEnumerationClass(Enum t, unsigned char a);
|
||||
std::set<std::string> GetInverseAttributeNames(Enum t);
|
||||
void PopulateDerivedFields(IfcWrite::IfcWritableEntity* e);
|
||||
}}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
+8368
-6113
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
Reference in New Issue
Block a user