mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-06 07:51:47 +00:00
Compare commits
200 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 214c228962 | |||
| 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 | |||
| da616ffd64 | |||
| 0ef6577407 | |||
| 6f1e1c3bad | |||
| 31daf8dd20 | |||
| 975d0caa0f | |||
| 4b2bbc63de | |||
| 04aea46757 | |||
| f6e33313fb | |||
| 3e95e7474b | |||
| e4e8f05980 | |||
| b4e42025fd | |||
| cec7117eb5 | |||
| 6ced646413 | |||
| 1d4a999381 | |||
| 95d2cdc4b6 | |||
| 217a7c6599 | |||
| 00de61cbfc | |||
| c5c8bbf425 | |||
| dc4b10ef74 | |||
| 1aa3a52b72 | |||
| 4975de6d74 | |||
| 9a54a64311 | |||
| eb0b865501 | |||
| 887ce9f9ef |
+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.
|
||||
+88
-13
@@ -1,6 +1,10 @@
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (IfcOpenShell)
|
||||
|
||||
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 "")
|
||||
SET(OCC_INCLUDE_DIR "/usr/include/opencascade/" CACHE FILEPATH "Open CASCADE header files")
|
||||
@@ -50,10 +54,39 @@ ENDIF()
|
||||
FIND_LIBRARY(icu "icuuc" /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR})
|
||||
|
||||
IF(icu)
|
||||
MESSAGE(STATUS "ICU libraries found")
|
||||
MESSAGE(STATUS "ICU libraries found")
|
||||
ADD_DEFINITIONS(-DHAVE_ICU)
|
||||
ELSE()
|
||||
MESSAGE(STATUS "Unable to find ICU library files, continuing")
|
||||
MESSAGE(STATUS "Unable to find ICU library files, continuing")
|
||||
ENDIF()
|
||||
|
||||
IF("$ENV{OPENCOLLADA_INCLUDE_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No OpenCOLLADA include directory specified")
|
||||
SET(OPENCOLLADA_INCLUDE_DIR "/usr/local/include/opencollada" CACHE FILEPATH "OpenCOLLADA header files")
|
||||
ElSE()
|
||||
SET(OPENCOLLADA_INCLUDE_DIR "$ENV{OPENCOLLADA_INCLUDE_DIR}" CACHE FILEPATH "OpenCOLLADA header files")
|
||||
ENDIF()
|
||||
|
||||
IF("$ENV{OPENCOLLADA_LIBRARY_DIR}" STREQUAL "")
|
||||
MESSAGE(STATUS "No OpenCOLLADA library directory specified")
|
||||
SET(OPENCOLLADA_LIBRARY_DIR "/usr/local/lib/opencollada" CACHE FILEPATH "OpenCOLLADA library files")
|
||||
ElSE()
|
||||
SET(OPENCOLLADA_LIBRARY_DIR "$ENV{OPENCOLLADA_LIBRARY_DIR}" CACHE FILEPATH "OpenCOLLADA library files")
|
||||
ENDIF()
|
||||
|
||||
SET(OPENCOLLADA_INCLUDE_DIRS "${OPENCOLLADA_INCLUDE_DIR}/COLLADABaseUtils" "${OPENCOLLADA_INCLUDE_DIR}/COLLADAStreamWriter")
|
||||
|
||||
FIND_FILE(COLLADASWStreamWriter_h "COLLADASWStreamWriter.h" ${OPENCOLLADA_INCLUDE_DIRS})
|
||||
IF(COLLADASWStreamWriter_h)
|
||||
MESSAGE(STATUS "OpenCOLLADA header files found")
|
||||
ADD_DEFINITIONS(-DWITH_OPENCOLLADA)
|
||||
SET(OPENCOLLADA_LIBRARIES
|
||||
GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils
|
||||
OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader
|
||||
OpenCOLLADAStreamWriter UTF buffer ftoa pcre
|
||||
)
|
||||
ELSE()
|
||||
MESSAGE(STATUS "OpenCOLLADA header files not found, continuing without COLLADA support")
|
||||
ENDIF()
|
||||
|
||||
INCLUDE(CheckIncludeFileCXX)
|
||||
@@ -88,13 +121,22 @@ ElSE(MSVC)
|
||||
ADD_DEFINITIONS(-fPIC -Wno-non-virtual-dtor)
|
||||
ENDIF(MSVC)
|
||||
|
||||
INCLUDE_DIRECTORIES(${OCC_INCLUDE_DIR} /usr/inc /usr/local/inc /usr/local/include/oce ${ICU_INCLUDE_DIR})
|
||||
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} /usr/inc /usr/local/inc /usr/local/include/oce ${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS})
|
||||
|
||||
ADD_LIBRARY(IfcParse STATIC
|
||||
ADD_LIBRARY(IfcParse STATIC
|
||||
../src/ifcparse/Ifc2x3-latebound.cpp
|
||||
../src/ifcparse/Ifc2x3.cpp
|
||||
../src/ifcparse/IfcUtil.cpp
|
||||
../src/ifcparse/IfcParse.cpp
|
||||
../src/ifcparse/Ifc4-latebound.cpp
|
||||
../src/ifcparse/Ifc4.cpp
|
||||
../src/ifcparse/IfcCharacterDecoder.cpp
|
||||
../src/ifcparse/IfcGuidHelper.cpp
|
||||
../src/ifcparse/IfcHierarchyHelper.cpp
|
||||
../src/ifcparse/IfcLateBoundEntity.cpp
|
||||
../src/ifcparse/IfcParse.cpp
|
||||
../src/ifcparse/IfcSIPrefix.cpp
|
||||
../src/ifcparse/IfcSpfHeader.cpp
|
||||
../src/ifcparse/IfcUtil.cpp
|
||||
../src/ifcparse/IfcWrite.cpp
|
||||
)
|
||||
|
||||
ADD_LIBRARY(IfcGeom STATIC
|
||||
@@ -102,7 +144,9 @@ ADD_LIBRARY(IfcGeom STATIC
|
||||
../src/ifcgeom/IfcGeomFaces.cpp
|
||||
../src/ifcgeom/IfcGeomFunctions.cpp
|
||||
../src/ifcgeom/IfcGeomHelpers.cpp
|
||||
../src/ifcgeom/IfcGeomObjects.cpp
|
||||
../src/ifcgeom/IfcGeomMaterial.cpp
|
||||
../src/ifcgeom/IfcGeomRenderStyles.cpp
|
||||
../src/ifcgeom/IfcGeomRepresentation.cpp
|
||||
../src/ifcgeom/IfcGeomShapes.cpp
|
||||
../src/ifcgeom/IfcGeomWires.cpp
|
||||
../src/ifcgeom/IfcRegister.cpp
|
||||
@@ -114,11 +158,23 @@ ENDIF()
|
||||
|
||||
TARGET_LINK_LIBRARIES(IfcGeom IfcParse)
|
||||
|
||||
LINK_DIRECTORIES (${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR})
|
||||
LINK_DIRECTORIES (${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} ${OPENCOLLADA_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS})
|
||||
|
||||
ADD_EXECUTABLE(IfcObj ../src/ifcobj/IfcObj.cpp)
|
||||
ADD_EXECUTABLE(IfcConvert
|
||||
../src/ifcconvert/ColladaSerializer.cpp
|
||||
../src/ifcconvert/IfcConvert.cpp
|
||||
../src/ifcconvert/OpenCascadeBasedSerializer.cpp
|
||||
../src/ifcconvert/WavefrontObjSerializer.cpp
|
||||
../src/ifcconvert/XmlSerializer.cpp
|
||||
)
|
||||
|
||||
TARGET_LINK_LIBRARIES (IfcObj IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet)
|
||||
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})
|
||||
|
||||
ADD_EXECUTABLE(IfcGeomServer
|
||||
../src/ifcgeomserver/IfcGeomServer.cpp
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
# Build python wrapper using separate CMakeLists.txt
|
||||
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
|
||||
@@ -126,10 +182,17 @@ ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
|
||||
# Build IfcParseExamples using separate CMakeLists.txt
|
||||
ADD_SUBDIRECTORY(../src/examples examples)
|
||||
|
||||
# ADD_SUBDIRECTORY(../src/qtviewer qtviewer)
|
||||
|
||||
# CMake installation targets
|
||||
SET(include_files_geom
|
||||
../src/ifcgeom/IfcGeom.h
|
||||
../src/ifcgeom/IfcGeomObjects.h
|
||||
../src/ifcgeom/IfcGeomElement.h
|
||||
../src/ifcgeom/IfcGeomIterator.h
|
||||
../src/ifcgeom/IfcGeomIteratorSettings.h
|
||||
../src/ifcgeom/IfcGeomMaterial.h
|
||||
../src/ifcgeom/IfcGeomRenderStyles.h
|
||||
../src/ifcgeom/IfcGeomRepresentation.h
|
||||
../src/ifcgeom/IfcRegister.h
|
||||
../src/ifcgeom/IfcRegisterConvertCurve.h
|
||||
../src/ifcgeom/IfcRegisterConvertFace.h
|
||||
@@ -142,19 +205,31 @@ SET(include_files_geom
|
||||
../src/ifcgeom/IfcRegisterIsShapeCollection.h
|
||||
../src/ifcgeom/IfcRegisterPurgeCache.h
|
||||
../src/ifcgeom/IfcRegisterUndef.h
|
||||
../src/ifcgeom/IfcShapeList.h
|
||||
../src/ifcgeom/IfcRepresentationShapeItem.h
|
||||
)
|
||||
SET(include_files_parse
|
||||
../src/ifcparse/Ifc2x3-latebound.h
|
||||
../src/ifcparse/Ifc2x3.h
|
||||
../src/ifcparse/Ifc2x3enum.h
|
||||
../src/ifcparse/Ifc4-latebound.h
|
||||
../src/ifcparse/Ifc4.h
|
||||
../src/ifcparse/Ifc4enum.h
|
||||
../src/ifcparse/IfcCharacterDecoder.h
|
||||
../src/ifcparse/IfcEntityDescriptor.h
|
||||
../src/ifcparse/IfcException.h
|
||||
../src/ifcparse/IfcFile.h
|
||||
../src/ifcparse/IfcHierarchyHelper.h
|
||||
../src/ifcparse/IfcLateBoundEntity.h
|
||||
../src/ifcparse/IfcParse.h
|
||||
../src/ifcparse/IfcSIPrefix.h
|
||||
../src/ifcparse/IfcSpfHeader.h
|
||||
../src/ifcparse/IfcSpfStream.h
|
||||
../src/ifcparse/IfcUtil.h
|
||||
../src/ifcparse/IfcWritableEntity.h
|
||||
../src/ifcparse/IfcWrite.h
|
||||
../src/ifcparse/SharedPointer.h
|
||||
)
|
||||
INSTALL(FILES ${include_files_geom} DESTINATION include/ifcgeom)
|
||||
INSTALL(FILES ${include_files_parse} DESTINATION include/ifcparse)
|
||||
INSTALL(TARGETS IfcObj DESTINATION bin)
|
||||
INSTALL(TARGETS IfcConvert DESTINATION bin)
|
||||
INSTALL(TARGETS IfcParse IfcGeom DESTINATION lib)
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
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)
|
||||
|
||||
@@ -0,0 +1,533 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <TColgp_Array2OfPnt.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
|
||||
#include <Geom_BSplineSurface.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
|
||||
#include <Standard_Version.hxx>
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include "../ifcparse/Ifc4.h"
|
||||
#else
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#endif
|
||||
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
// Some convenience typedefs and definitions.
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
typedef std::pair<double, double> XY;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
// The creation of Nurbs-surface for the IfcSite mesh, to be implemented lateron
|
||||
void createGroundShape(TopoDS_Shape& shape);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
// The IfcHierarchyHelper is a subclass of the regular IfcFile that provides several
|
||||
// convenience functions for working with geometry in IFC files.
|
||||
IfcHierarchyHelper file;
|
||||
file.header().file_name().name("IfcOpenHouse.ifc");
|
||||
|
||||
// Start by adding a wall to the file, initially leaving most attributes blank.
|
||||
IfcSchema::IfcWallStandardCase* south_wall = new IfcSchema::IfcWallStandardCase(
|
||||
guid(), // GlobalId
|
||||
0, // OwnerHistory
|
||||
S("South wall"), // Name
|
||||
null, // Description
|
||||
null, // ObjectType
|
||||
null, // ObjectPlacement
|
||||
null, // Representation
|
||||
null // Tag
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
|
||||
#endif
|
||||
);
|
||||
file.addBuildingProduct(south_wall);
|
||||
|
||||
// By adding a wall, a hierarchy has been automatically created that consists of the following
|
||||
// structure: IfcProject > IfcSite > IfcBuilding > IfcBuildingStorey > IfcWall
|
||||
|
||||
// Lateron changing the name of the IfcProject can be done by obtaining a reference to the
|
||||
// project, which has been created automatically.
|
||||
file.getSingle<IfcSchema::IfcProject>()->Name(S("IfcOpenHouse"));
|
||||
|
||||
// An IfcOwnerHistory has been initialized as well, which should be assigned to the wall.
|
||||
south_wall->OwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
// The wall will be shaped as a box, with the dimensions specified in millimeters. The resulting
|
||||
// product definition will consist of both a body representation as well as an axis representation
|
||||
// that runs over the centerline of the box in the X-axis.
|
||||
IfcSchema::IfcProductDefinitionShape* south_wall_shape = file.addAxisBox(10000, 360, 3000);
|
||||
|
||||
// Obtain a reference to the placement of the IfcBuildingStorey in order to create a hierarchy
|
||||
// of placements for the products
|
||||
IfcSchema::IfcObjectPlacement* storey_placement = *file.getSingle<IfcSchema::IfcBuildingStorey>()->ObjectPlacement();
|
||||
|
||||
// The shape has to be assigned to the representation of the wall and is placed at the origin
|
||||
// of the coordinate system.
|
||||
south_wall->Representation(south_wall_shape);
|
||||
south_wall->ObjectPlacement(file.addLocalPlacement(storey_placement));
|
||||
|
||||
// A pale white colour is assigned to the wall.
|
||||
IfcSchema::IfcPresentationStyleAssignment* wall_colour = file.setSurfaceColour(
|
||||
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>(),
|
||||
S("Footing"), null, null, null, null, null, IfcSchema::IfcFootingTypeEnum::IfcFootingType_STRIP_FOOTING);
|
||||
|
||||
file.addBuildingProduct(footing);
|
||||
|
||||
// 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->Representation(file.addBox(10100, 5460, 2000));
|
||||
footing->ObjectPlacement(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:
|
||||
IfcSchema::IfcOpeningElement* west_opening = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, file.addLocalPlacement(*south_wall->ObjectPlacement(), -2500, 0, 400),
|
||||
file.addBox(6000, 3630, 1600), null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING
|
||||
#endif
|
||||
);
|
||||
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);
|
||||
|
||||
// Now create an additional opening
|
||||
IfcSchema::IfcOpeningElement* south_opening = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, file.addLocalPlacement(storey_placement, 3000, 0, 400),
|
||||
file.addBox(1860, 3000, 1600), null
|
||||
#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));
|
||||
|
||||
// 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), null, 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, null, null, 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->Representation(file.addMappedItem(roof_rep));
|
||||
south_roof_part->ObjectPlacement(file.addLocalPlacement(*roof->ObjectPlacement(), 0, -400, 2700));
|
||||
|
||||
// The same roof geometry is re-used on the north side of the roof, by inverting the X-axis of
|
||||
// the local placement the roof is rotated 180 degrees around the Z-axis
|
||||
IfcSchema::IfcSlab* north_roof_part = new IfcSchema::IfcSlab(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("North roof"),
|
||||
null, null, null, null, null, IfcSchema::IfcSlabTypeEnum::IfcSlabType_ROOF);
|
||||
north_roof_part->OwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
north_roof_part->Representation(file.addMappedItem(roof_rep));
|
||||
north_roof_part->ObjectPlacement(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);
|
||||
|
||||
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
|
||||
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);
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* clipped_wall_body_rep = file.addEmptyRepresentation();
|
||||
file.addBox(clipped_wall_body_rep, 5000, 360, 6000);
|
||||
// The east wall geometry is clipped using two IfcHalfSpaceSolids, created from an
|
||||
// 'axis 3d placement' that specifies the plane against which the geometry is clipped.
|
||||
file.clipRepresentation(clipped_wall_body_rep, file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false);
|
||||
file.clipRepresentation(clipped_wall_body_rep, file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false);
|
||||
|
||||
// Now create a wall on the east of the building, again starting with just a box shape
|
||||
IfcSchema::IfcWallStandardCase* east_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
S("East wall"), null, null, file.addLocalPlacement(storey_placement, 4820, 2500, 0, 0, 0, 1, 0, 1, 0), file.addMappedItem(clipped_wall_body_rep), null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
|
||||
#endif
|
||||
);
|
||||
file.addBuildingProduct(east_wall);
|
||||
|
||||
file.setSurfaceColour(clipped_wall_body_rep, wall_colour);
|
||||
|
||||
// The east wall is copied to the west location of the house
|
||||
IfcSchema::IfcWallStandardCase* west_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
S("West wall"), null, null, file.addLocalPlacement(storey_placement, -4820, 2500, 0, 0, 0, 1, 0, -1, 0), file.addMappedItem(clipped_wall_body_rep), null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
|
||||
#endif
|
||||
);
|
||||
file.addBuildingProduct(west_wall);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
// CV-2x3-161: MappedItems are not allowed for Axis representations
|
||||
IfcSchema::IfcWallStandardCase* wall = i == 0 ? east_wall : west_wall;
|
||||
IfcSchema::IfcShapeRepresentation* wall_axis_rep = file.addEmptyRepresentation("Axis", "Curve2D");
|
||||
file.addAxis(wall_axis_rep, 5000);
|
||||
IfcSchema::IfcRepresentation::list::ptr reps = wall->Representation().get()->Representations();
|
||||
reps->push(wall_axis_rep);
|
||||
wall->Representation().get()->Representations(reps);
|
||||
}
|
||||
|
||||
// The west wall is assigned an opening element we created for the south wall, opening elements are
|
||||
// not shared accross building elements, even if they share the same representation. Hence, the east
|
||||
// wall will not feature this opening.
|
||||
// NB: an Opening Element can only be used to create a single void within a single Element, as per:
|
||||
// http://www.buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcproductextension/lexical/ifcfeatureelementsubtraction.htm
|
||||
|
||||
// Not all viewers support opening elements with mapped representations, hence an exact copy of the
|
||||
// same subtraction box is instantiated for the otherwise identical opening element.
|
||||
IfcSchema::IfcOpeningElement* west_opening_copy = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, file.addLocalPlacement(*west_wall->ObjectPlacement(), 2500, -2500+4820, 400, 0, 0, 1, 0, 1, 0),
|
||||
file.addBox(6000, 3630, 1600), null
|
||||
#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));
|
||||
|
||||
// Up until now we have only used simple extrusions for the creation of the geometry. For the
|
||||
// ground mesh of the IfcSite we will use a Nurbs surface created in Open Cascade. The surface
|
||||
// will be tesselated using the deflection specified.
|
||||
TopoDS_Shape shape;
|
||||
createGroundShape(shape);
|
||||
IfcEntityList::ptr geometrical_entities(new IfcEntityList);
|
||||
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::tesselate(shape, 100., geometrical_entities);
|
||||
file.getSingle<IfcSchema::IfcSite>()->Representation(ground_representation);
|
||||
file.addEntities(geometrical_entities);
|
||||
IfcSchema::IfcShapeRepresentation::list::ptr ground_reps = geometrical_entities->as<IfcSchema::IfcShapeRepresentation>();
|
||||
for (IfcSchema::IfcShapeRepresentation::list::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
|
||||
(*it)->ContextOfItems(file.getRepresentationContext("Model"));
|
||||
}
|
||||
file.setSurfaceColour(ground_representation, 0.15, 0.25, 0.05);
|
||||
|
||||
// According to the Ifc2x3 schema an IfcWallStandardCase needs to have an IfcMaterialLayerSet
|
||||
// assigned. Note that this material definition is independent of the surface styles we have
|
||||
// been assigning to the walls already. The surface styles determine the colour in the
|
||||
// '3D viewport' of most applications.
|
||||
// Some BIM authoring applications, such as Autodesk Revit, ignore the geometrical representation
|
||||
// by and large and construct native walls using the layer thickness and reference line offset
|
||||
// provided here.
|
||||
#ifdef USE_IFC4
|
||||
IfcSchema::IfcMaterial* material = new IfcSchema::IfcMaterial("Brick", null, null);
|
||||
#else
|
||||
IfcSchema::IfcMaterial* material = new IfcSchema::IfcMaterial("Brick");
|
||||
#endif
|
||||
IfcSchema::IfcMaterialLayer* layer = new IfcSchema::IfcMaterialLayer(
|
||||
material,
|
||||
360,
|
||||
null
|
||||
#ifdef USE_IFC4
|
||||
, null
|
||||
, null
|
||||
, null
|
||||
, null
|
||||
#endif
|
||||
);
|
||||
IfcSchema::IfcMaterialLayer::list::ptr layers (new IfcTemplatedEntityList<IfcSchema::IfcMaterialLayer>());
|
||||
layers->push(layer);
|
||||
IfcSchema::IfcMaterialLayerSet* layer_set = new IfcSchema::IfcMaterialLayerSet(
|
||||
layers,
|
||||
S("Wall")
|
||||
#ifdef USE_IFC4
|
||||
, null
|
||||
#endif
|
||||
);
|
||||
IfcSchema::IfcMaterialLayerSetUsage* layer_usage = new IfcSchema::IfcMaterialLayerSetUsage(
|
||||
layer_set,
|
||||
IfcSchema::IfcLayerSetDirectionEnum::IfcLayerSetDirection_AXIS2,
|
||||
IfcSchema::IfcDirectionSenseEnum::IfcDirectionSense_POSITIVE,
|
||||
-180
|
||||
#ifdef USE_IFC4
|
||||
, null
|
||||
#endif
|
||||
);
|
||||
|
||||
IfcSchema::IfcRelAssociatesMaterial* associates_material = new IfcSchema::IfcRelAssociatesMaterial(
|
||||
guid(),
|
||||
file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null,
|
||||
null,
|
||||
#ifdef USE_IFC4
|
||||
file.entitiesByType<IfcSchema::IfcWallStandardCase>()->generalize(),
|
||||
#else
|
||||
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);
|
||||
|
||||
// In addition, another common way to represent geometry in IFC files is to use extrusions of
|
||||
// planar areas bounded by a polygon.
|
||||
std::vector<XY> stair_points;
|
||||
stair_points.push_back(XY( 0, 0));
|
||||
stair_points.push_back(XY(250, 0));
|
||||
stair_points.push_back(XY(250, 200));
|
||||
stair_points.push_back(XY(500, 200));
|
||||
stair_points.push_back(XY(500, 400));
|
||||
stair_points.push_back(XY( 0, 400));
|
||||
IfcSchema::IfcStairFlight* stair = new IfcSchema::IfcStairFlight(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, file.addLocalPlacement(storey_placement, 5050, 1000, 0, 0, 1, 0, 1, 0, 0),
|
||||
file.addExtrudedPolyline(stair_points, 1200), null, 2, 2, 0.2, 0.25
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcStairFlightTypeEnum::IfcStairFlightType_STRAIGHT
|
||||
#endif
|
||||
);
|
||||
|
||||
file.addBuildingProduct(stair);
|
||||
file.setSurfaceColour(*stair->Representation(), footing_colour);
|
||||
|
||||
IfcSchema::IfcOpeningElement* door_opening = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, file.addLocalPlacement(storey_placement, 5000-180, 2500-900, 0), file.addBox(1000, 1000, 2200), null
|
||||
#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));
|
||||
|
||||
// A single shape representation can contain multiple representiation items. This way a product
|
||||
// can be a composition of multiple solids. The following door will be composed of four boxes
|
||||
// which constitute the door and its frame.
|
||||
IfcSchema::IfcDoor* door = new IfcSchema::IfcDoor(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, null,
|
||||
file.addLocalPlacement(storey_placement, 4800, 1600, 0, 0, 0, 1, 0, 1, 0), null, null, 2200, 1000
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcDoorTypeEnum::IfcDoorType_DOOR
|
||||
, IfcSchema::IfcDoorTypeOperationEnum::IfcDoorTypeOperation_SINGLE_SWING_LEFT
|
||||
, null
|
||||
#endif
|
||||
);
|
||||
door->Representation(file.addBox(80, 80, 2120, 0, file.addPlacement3d(460, 0, 0)));
|
||||
IfcSchema::IfcRepresentation::list::ptr door_representations = door->Representation().get()->Representations();
|
||||
IfcSchema::IfcShapeRepresentation* door_body = 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
file.addBox(door_body, 80, 80, 2120, 0, file.addPlacement3d(-460, 0, 0));
|
||||
file.addBox(door_body, 1000, 80, 80, 0, file.addPlacement3d( 0, 0, 2120));
|
||||
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));
|
||||
|
||||
// Surface styles are assigned to representation items, hence there is no real limitation to
|
||||
// assign different colours within the same representation. However, some viewers have
|
||||
// difficulties rendering products with representation items with different surface styles.
|
||||
// Therefore we will construct the window as a decomposition of beams and a plate, in which
|
||||
// only the plate will have a transparent material assigned.
|
||||
|
||||
// The window frame will consists of four seperate beams.
|
||||
// AutoCAD Architecture will create an internal window type for the IfcWindow created.
|
||||
// Therefore the OverallWidth and OverallHeight of the window attributes will need to
|
||||
// match the bounding box of the representation. Furthermore, the window placement needs
|
||||
// to align with the lowerleft corner of the constituent parts.
|
||||
IfcSchema::IfcShapeRepresentation::list::ptr frame_representations(new IfcSchema::IfcShapeRepresentation::list);
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* horizontal_bar = file.addEmptyRepresentation();
|
||||
IfcSchema::IfcShapeRepresentation* vertical_bar = file.addEmptyRepresentation();
|
||||
file.addBox(horizontal_bar, 1860, 90, 90);
|
||||
file.addBox(vertical_bar, 90, 90, 1420);
|
||||
|
||||
frame_representations->push(horizontal_bar);
|
||||
frame_representations->push(horizontal_bar); // Add another reference to the horizontal bar created above
|
||||
frame_representations->push(vertical_bar);
|
||||
frame_representations->push(vertical_bar); // Add another reference to the vertical bar created above
|
||||
|
||||
// The beams all have the same surface style assigned
|
||||
IfcSchema::IfcPresentationStyleAssignment* frame_style = 0;
|
||||
for (IfcSchema::IfcShapeRepresentation::list::it i = frame_representations->begin(); i != frame_representations->end(); i += 2) {
|
||||
if (frame_style) {
|
||||
file.setSurfaceColour(*i, frame_style);
|
||||
} else {
|
||||
frame_style = file.setSurfaceColour(*i, 0.5, 0.4, 0.3);
|
||||
}
|
||||
// Because of the duplication the iterator is incremented twice
|
||||
}
|
||||
|
||||
// This window will be placed at five locations within the building. A list of placements is
|
||||
// created and is iterated over to create all window instances.
|
||||
IfcSchema::IfcLocalPlacement::list::ptr window_placements (new IfcSchema::IfcLocalPlacement::list);
|
||||
window_placements->push(file.addLocalPlacement(storey_placement, 2*-1770-430-930, -45, 400));
|
||||
window_placements->push(file.addLocalPlacement(storey_placement, -1770-430-930, -45, 400));
|
||||
window_placements->push(file.addLocalPlacement(storey_placement, -430-930, -45, 400));
|
||||
window_placements->push(file.addLocalPlacement(storey_placement, 3000-930, -45, 400));
|
||||
window_placements->push(file.addLocalPlacement(storey_placement, -4855+45, 885-930, 400, 0, 0, 1, 0, 1, 0));
|
||||
|
||||
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;
|
||||
IfcSchema::IfcWindow* window = new IfcSchema::IfcWindow(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, place, null, null, 1600, 1860
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcWindowTypeEnum::IfcWindowType_WINDOW
|
||||
, IfcSchema::IfcWindowTypePartitioningEnum::IfcWindowTypePartitioning_SINGLE_PANEL
|
||||
, null
|
||||
#endif
|
||||
);
|
||||
file.addBuildingProduct(window);
|
||||
|
||||
// Initalize a list of parts for the window to be composed of
|
||||
IfcSchema::IfcObjectDefinition::list::ptr window_parts(new IfcTemplatedEntityList<IfcSchema::IfcObjectDefinition>());
|
||||
|
||||
// The placements for the beams are not shared accross the different windows because every
|
||||
// beam is placed relative to its parent window entity.
|
||||
IfcSchema::IfcLocalPlacement::list::ptr frame_placements (new IfcTemplatedEntityList<IfcSchema::IfcLocalPlacement>());
|
||||
frame_placements->push(file.addLocalPlacement(storey_placement, 930,45));
|
||||
frame_placements->push(file.addLocalPlacement(storey_placement, 930, 45, 1510));
|
||||
frame_placements->push(file.addLocalPlacement(storey_placement, -885+930, 45, 90));
|
||||
frame_placements->push(file.addLocalPlacement(storey_placement, 885+930, 45, 90));
|
||||
|
||||
// Now iterate over the placements and representations of the beam and add them to list of parts
|
||||
IfcSchema::IfcLocalPlacement::list::it frame_placement;
|
||||
IfcSchema::IfcShapeRepresentation::list::it frame_representation;
|
||||
for (frame_placement = frame_placements->begin(), frame_representation = frame_representations->begin();
|
||||
frame_placement != frame_placements->end() && frame_representation != frame_representations->end();
|
||||
++frame_placement, ++frame_representation)
|
||||
{
|
||||
IfcSchema::IfcMember* frame_part = new IfcSchema::IfcMember(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, *frame_placement, file.addMappedItem(*frame_representation), null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcMemberTypeEnum::IfcMemberType_MULLION
|
||||
#endif
|
||||
);
|
||||
file.addEntity(frame_part);
|
||||
window_parts->push(frame_part);
|
||||
file.relatePlacements(window, frame_part);
|
||||
}
|
||||
|
||||
// Add the glass plate to the list of parts
|
||||
IfcSchema::IfcPlate* glass_part = new IfcSchema::IfcPlate(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null,
|
||||
null, null, file.addLocalPlacement(storey_placement, 930, 45, 90), file.addBox(1680, 10, 1420), null
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcPlateTypeEnum::IfcPlateType_SHEET
|
||||
#endif
|
||||
);
|
||||
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);
|
||||
|
||||
// Now create a decomposition relation between the window and the parts. Most viewers and authoring
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Finally create a file stream for our output and write the IFC file to it.
|
||||
std::ofstream f("IfcOpenHouse.ifc");
|
||||
f << file;
|
||||
}
|
||||
|
||||
void createGroundShape(TopoDS_Shape& shape) {
|
||||
TColgp_Array2OfPnt cv (0, 4, 0, 4);
|
||||
cv.SetValue(0, 0, gp_Pnt(-10000, -10000, -4130));
|
||||
cv.SetValue(0, 1, gp_Pnt(-10000, -4330, -4130));
|
||||
cv.SetValue(0, 2, gp_Pnt(-10000, 0, -5130));
|
||||
cv.SetValue(0, 3, gp_Pnt(-10000, 4330, -7130));
|
||||
cv.SetValue(0, 4, gp_Pnt(-10000, 10000, -7130));
|
||||
cv.SetValue(1, 0, gp_Pnt( -3330, -10000, -5130));
|
||||
cv.SetValue(1, 1, gp_Pnt( -7670, -3670, 5000));
|
||||
cv.SetValue(1, 2, gp_Pnt( -9000, 0, 1000));
|
||||
cv.SetValue(1, 3, gp_Pnt( -7670, 7670, 6000));
|
||||
cv.SetValue(1, 4, gp_Pnt( -3330, 10000, -4130));
|
||||
cv.SetValue(2, 0, gp_Pnt( 0, -10000, -5530));
|
||||
cv.SetValue(2, 1, gp_Pnt( 0, -3670, 3000));
|
||||
cv.SetValue(2, 2, gp_Pnt( 0, 0, -12000));
|
||||
cv.SetValue(2, 3, gp_Pnt( 0, 7670, 1500));
|
||||
cv.SetValue(2, 4, gp_Pnt( 0, 10000, -4130));
|
||||
cv.SetValue(3, 0, gp_Pnt( 3330, -10000, -6130));
|
||||
cv.SetValue(3, 1, gp_Pnt( 7670, -3670, 6000));
|
||||
cv.SetValue(3, 2, gp_Pnt( 9000, 0, 5000));
|
||||
cv.SetValue(3, 3, gp_Pnt( 7670, 9000, 7000));
|
||||
cv.SetValue(3, 4, gp_Pnt( 3330, 10000, -4130));
|
||||
cv.SetValue(4, 0, gp_Pnt( 10000, -10000, -6130));
|
||||
cv.SetValue(4, 1, gp_Pnt( 10000, -4330, -5130));
|
||||
cv.SetValue(4, 2, gp_Pnt( 10000, 0, -4130));
|
||||
cv.SetValue(4, 3, gp_Pnt( 10000, 4330, -4130));
|
||||
cv.SetValue(4, 4, gp_Pnt( 10000, 10000, -8130));
|
||||
TColStd_Array1OfReal knots(0, 1);
|
||||
knots(0) = 0;
|
||||
knots(1) = 1;
|
||||
TColStd_Array1OfInteger mult(0, 1);
|
||||
mult(0) = 5;
|
||||
mult(1) = 5;
|
||||
Handle(Geom_BSplineSurface) surf = new Geom_BSplineSurface(cv, knots, knots, mult, mult, 4, 4);
|
||||
#if OCC_VERSION_HEX < 0x60502
|
||||
shape = BRepBuilderAPI_MakeFace(surf);
|
||||
#else
|
||||
shape = BRepBuilderAPI_MakeFace(surf, Precision::Confusion());
|
||||
#endif
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -17,9 +17,9 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../ifcparse/IfcParse.h"
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
|
||||
using namespace Ifc2x3;
|
||||
using namespace IfcSchema;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -29,17 +29,18 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
// Redirect the output (both progress and log) to stdout
|
||||
Ifc::SetOutput(&std::cout,&std::cout);
|
||||
Logger::SetOutput(&std::cout,&std::cout);
|
||||
|
||||
// Parse the IFC file provided in argv[1]
|
||||
if ( ! Ifc::Init(argv[1]) ) {
|
||||
IfcParse::IfcFile file;
|
||||
if ( ! file.Init(argv[1]) ) {
|
||||
std::cout << "Unable to parse .ifc file" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 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,
|
||||
@@ -53,26 +54,21 @@ 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.
|
||||
//
|
||||
// Since we are accessing properties that represent a length
|
||||
// measure we can multiply the value by Ifc::LengthUnit, which
|
||||
// contains the ratio of the unit defined in the IfcUnitAssignment
|
||||
// to the standard SI Unit, the meter.
|
||||
IfcBuildingElement::list elements = Ifc::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 float area = window->OverallWidth()*window->OverallHeight() * (Ifc::LengthUnit*Ifc::LengthUnit);
|
||||
std::cout << "This window has an area of " << area << "m2" << std::endl;
|
||||
if ( window->OverallWidth() && window->OverallHeight() ) {
|
||||
const double area = window->OverallWidth().get() * window->OverallHeight().get();
|
||||
std::cout << "The area of this window is " << area << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 representations from *
|
||||
* IfcArbitraryOpenProfileDefs and its subclass IfcCenterLineProfileDef *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
static int i = 0;
|
||||
|
||||
void create_product_from_item(IfcHierarchyHelper& file, IfcSchema::IfcRepresentationItem* item, const std::string& s) {
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, S("product"), null, null, 0, 0, null, null);
|
||||
file.addBuildingProduct(product);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement(120 * i++));
|
||||
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
items->push(item);
|
||||
|
||||
if (s == "GeometricSet") {
|
||||
IfcSchema::IfcGeometricSet* set = new IfcSchema::IfcGeometricSet(items->generalize());
|
||||
file.addEntity(set);
|
||||
items = IfcSchema::IfcRepresentationItem::list(new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
items->push(set);
|
||||
}
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
create_product_from_item(file, extrusion, "GeometricSet");
|
||||
create_product_from_item(file, revolution, "GeometricSet");
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
create_product_from_item(file, extrusion, "SweptSolid");
|
||||
create_product_from_item(file, revolution1, "SweptSolid");
|
||||
create_product_from_item(file, revolution2, "SweptSolid");
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
create_surfaces_from_profile(file, open);
|
||||
create_solids_from_profile(file, center_line);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "IfcArbitraryOpenProfileDef.ifc";
|
||||
IfcHierarchyHelper file;
|
||||
file.filename(filename);
|
||||
|
||||
double coords1[] = {-50.0, 0.0};
|
||||
double coords2[] = { 50.0, 0.0};
|
||||
IfcSchema::IfcCartesianPoint::list points (new IfcTemplatedEntityList<IfcSchema::IfcCartesianPoint>());
|
||||
points->push(new IfcSchema::IfcCartesianPoint(std::vector<double>(coords1, coords1+2)));
|
||||
points->push(new IfcSchema::IfcCartesianPoint(std::vector<double>(coords2, coords2+2)));
|
||||
file.addEntities(points->generalize());
|
||||
IfcSchema::IfcPolyline* poly = new IfcSchema::IfcPolyline(points);
|
||||
file.addEntity(poly);
|
||||
|
||||
create_products_from_curve(file, poly);
|
||||
|
||||
IfcSchema::IfcEllipse* ellipse = new IfcSchema::IfcEllipse(file.addPlacement2d(), 50., 25.);
|
||||
file.addEntity(ellipse);
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
trim1->push(new IfcWrite::IfcSelectHelper( 0., Ifc2x3::Type::IfcParameterValue));
|
||||
trim2->push(new IfcWrite::IfcSelectHelper(180., Ifc2x3::Type::IfcParameterValue));
|
||||
IfcSchema::IfcTrimmedCurve* trim = new IfcSchema::IfcTrimmedCurve(ellipse, trim1, trim2, true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
file.addEntity(trim);
|
||||
|
||||
create_products_from_curve(file, trim);
|
||||
|
||||
file.getSingle<Ifc2x3::IfcProject>()->setName("IfcArbitraryOpenProfileDef");
|
||||
|
||||
std::ofstream f(filename);
|
||||
f << file;
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 extrusions of parameterized profiles. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "IfcCompositeProfileDef.ifc";
|
||||
IfcHierarchyHelper file;
|
||||
file.filename(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::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);
|
||||
|
||||
IfcSchema::IfcProfileDef* p1 = new Ifc2x3::IfcIShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, file.addPlacement2d(), 25.0, 50.0, 5.0, 5.0, 2.0);
|
||||
|
||||
IfcSchema::IfcProfileDef* p2 = new Ifc2x3::IfcLShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, file.addPlacement2d(), 50.0, 25.0, 5.0, 1.0, 2.0, 2.0, null, null);
|
||||
|
||||
IfcSchema::IfcProfileDef* p3 = new Ifc2x3::IfcTShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, file.addPlacement2d(), 50.0, 40.0, 10.0, 10.0, 3.0, 2.0, 1.0, 2.0, 2.0, null);
|
||||
|
||||
IfcSchema::IfcProfileDef* p4 = new Ifc2x3::IfcCShapeProfileDef(
|
||||
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(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);
|
||||
|
||||
profiles->push(p1);
|
||||
profiles->push(p5);
|
||||
profiles->push(p6);
|
||||
profiles->push(p4);
|
||||
|
||||
file.addEntities(profiles->generalize());
|
||||
|
||||
IfcSchema::IfcCompositeProfileDef* composite = new IfcSchema::IfcCompositeProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, S("IFC"), profiles, null);
|
||||
|
||||
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());
|
||||
|
||||
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(composite,
|
||||
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
|
||||
|
||||
file.addEntity(composite);
|
||||
file.addEntity(solid);
|
||||
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
|
||||
items->push(solid);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("SweptSolid"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
|
||||
file.getSingle<IfcSchema::IfcProject>()->setName("IfcCompositeProfileDef");
|
||||
|
||||
std::ofstream f(filename);
|
||||
f << file;
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 a Constructive Solid Geometry example *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
class Node {
|
||||
private:
|
||||
typedef enum {
|
||||
OP_ADD, OP_SUBTRACT, OP_INTERSECT, OP_TERMINAL
|
||||
} Op;
|
||||
typedef enum {
|
||||
PRIM_BOX, PRIM_CONE, PRIM_CYLINDER, PRIM_PYRAMID, PRIM_SPHERE
|
||||
} Prim;
|
||||
|
||||
double x,y,z, zx,zy,zz, xx,xy,xz, a,b,c;
|
||||
const Node *left, *right;
|
||||
|
||||
Op op;
|
||||
Prim prim;
|
||||
|
||||
Node& operate(Op op, const Node& p) {
|
||||
left = new Node(*this);
|
||||
right = new Node(p);
|
||||
this->op = op;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Node(Prim p, double la, double lb=0., double lc=0.)
|
||||
: prim(p), op(OP_TERMINAL),
|
||||
x(0.), y(0.), z(0.),
|
||||
zx(0.), zy(0.), zz(1.),
|
||||
xx(1.), xy(0.), xz(0.),
|
||||
a(la), b(lb), c(lc) {}
|
||||
public:
|
||||
static Node Sphere(double r) {
|
||||
return Node(PRIM_SPHERE, r);
|
||||
}
|
||||
static Node Box(double dx, double dy, double dz) {
|
||||
return Node(PRIM_BOX, dx, dy, dz);
|
||||
}
|
||||
static Node Pyramid(double dx, double dy, double dz) {
|
||||
return Node(PRIM_PYRAMID, dx, dy, dz);
|
||||
}
|
||||
static Node Cylinder(double r, double h) {
|
||||
return Node(PRIM_CYLINDER, r, h);
|
||||
}
|
||||
static Node Cone(double r, double h) {
|
||||
return Node(PRIM_CONE, r, h);
|
||||
}
|
||||
|
||||
Node& move(
|
||||
double px = 0., double py = 0., double pz = 0.,
|
||||
double zx = 0., double zy = 0., double zz = 1.,
|
||||
double xx = 1., double xy = 0., double xz = 0.)
|
||||
{
|
||||
this->x = px; this->y = py; this->z = pz;
|
||||
this->zx = zx; this->zy = zy; this->zz = zz;
|
||||
this->xx = xx; this->xy = xy; this->xz = xz;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Node& add(const Node& p) {
|
||||
return operate(OP_ADD, p);
|
||||
}
|
||||
Node& subtract(const Node& p) {
|
||||
return operate(OP_SUBTRACT, p);
|
||||
}
|
||||
Node& intersect(const Node& p) {
|
||||
return operate(OP_INTERSECT, p);
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentationItem* serialize(IfcHierarchyHelper& file) const {
|
||||
IfcSchema::IfcRepresentationItem* my;
|
||||
if (op == OP_TERMINAL) {
|
||||
IfcSchema::IfcAxis2Placement3D* place = file.addPlacement3d(x,y,z,zx,zy,zz,xx,xy,xz);
|
||||
if (prim == PRIM_SPHERE) {
|
||||
my = new IfcSchema::IfcSphere(place, a);
|
||||
} else if (prim == PRIM_BOX) {
|
||||
my = new IfcSchema::IfcBlock(place, a, b, c);
|
||||
} else if (prim == PRIM_PYRAMID) {
|
||||
my = new IfcSchema::IfcRectangularPyramid(place, a, b, c);
|
||||
} else if (prim == PRIM_CYLINDER) {
|
||||
my = new IfcSchema::IfcRightCircularCylinder(place, b, a);
|
||||
} else if (prim == PRIM_CONE) {
|
||||
my = new IfcSchema::IfcRightCircularCone(place, b, a);
|
||||
}
|
||||
} else {
|
||||
IfcSchema::IfcBooleanOperator::IfcBooleanOperator o;
|
||||
if (op == OP_ADD) {
|
||||
o = IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION;
|
||||
} else if (op == OP_SUBTRACT) {
|
||||
o = IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE;
|
||||
} else if (op == OP_INTERSECT) {
|
||||
o = IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION;
|
||||
}
|
||||
my = new IfcSchema::IfcBooleanResult(o, left->serialize(file), right->serialize(file));
|
||||
}
|
||||
file.addEntity(my);
|
||||
return my;
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "IfcCsgPrimitive.ifc";
|
||||
IfcHierarchyHelper file;
|
||||
file.filename(filename);
|
||||
|
||||
IfcSchema::IfcRepresentationItem* csg1 = Node::Box(8000.,6000.,3000.).subtract(
|
||||
Node::Box(7600.,5600.,2800.).move(200.,200.,200.)
|
||||
).add(
|
||||
Node::Pyramid(8000.,6000.,3000.).move(0,0,3000.).add(
|
||||
Node::Cylinder(1000.,4000.).move(4000.,1000.,4000., 0.,1.,0.)
|
||||
).subtract(
|
||||
Node::Pyramid(7600.,5600.,2800.).move(200.,200.,3000.)
|
||||
).subtract(
|
||||
Node::Cylinder(900.,4000.).move(4000.,1000.,4000., 0.,1.,0.).intersect(
|
||||
Node::Box(2000.,4000.,1000.).move(3000.,1000.,4000.)
|
||||
)
|
||||
)
|
||||
).serialize(file);
|
||||
|
||||
const double x = 1000.; const double y = -4000.;
|
||||
|
||||
IfcSchema::IfcRepresentationItem* csg2 = Node::Sphere(5000.).move(x,y,-4500.).intersect(
|
||||
Node::Box(6000., 6000., 6000.).move(x-3000., y-3000., 0.)
|
||||
).add(
|
||||
Node::Cone(500., 3000.).move(x,y).add(
|
||||
Node::Cone(1500., 1000.).move(x,y, 900.).add(
|
||||
Node::Cone(1100., 1000.).move(x,y, 1800.).add(
|
||||
Node::Cone(750., 600.).move(x,y, 2700.)
|
||||
)))).serialize(file);
|
||||
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, S("IfcCsgPrimitive"), null, null, 0, 0, null, null);
|
||||
|
||||
file.addBuildingProduct(product);
|
||||
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement());
|
||||
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
|
||||
items->push(csg1);
|
||||
items->push(csg2);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
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);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
|
||||
file.getSingle<IfcSchema::IfcProject>()->setName("IfcCompositeProfileDef");
|
||||
|
||||
std::ofstream f(filename);
|
||||
f << file;
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 profiles of trimmed ellipses. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
typedef struct {
|
||||
double r1;
|
||||
double r2;
|
||||
double t1;
|
||||
double t2;
|
||||
} EllipsePie;
|
||||
|
||||
static int i = 0;
|
||||
|
||||
void create_testcase_for(IfcHierarchyHelper& file, const EllipsePie& pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference pref) {
|
||||
const double deg = 1. / 180. * 3.141592653;
|
||||
double flt1[] = {0. , 0. };
|
||||
double flt2[] = {pie.r1 * cos(pie.t1*deg), pie.r2 * sin(pie.t1*deg)};
|
||||
double flt3[] = {pie.r1 * cos(pie.t2*deg), pie.r2 * sin(pie.t2*deg)};
|
||||
|
||||
std::vector<double> coords1(flt1, flt1 + 2);
|
||||
std::vector<double> coords2(flt2, flt2 + 2);
|
||||
std::vector<double> coords3(flt3, flt3 + 2);
|
||||
|
||||
Ifc2x3::IfcCartesianPoint* p1 = new Ifc2x3::IfcCartesianPoint(coords1);
|
||||
Ifc2x3::IfcCartesianPoint* p2 = new Ifc2x3::IfcCartesianPoint(coords2);
|
||||
Ifc2x3::IfcCartesianPoint* p3 = new Ifc2x3::IfcCartesianPoint(coords3);
|
||||
|
||||
Ifc2x3::IfcCartesianPoint::list points(new IfcTemplatedEntityList<Ifc2x3::IfcCartesianPoint>());
|
||||
points->push(p3);
|
||||
points->push(p1);
|
||||
points->push(p2);
|
||||
file.addEntities(points->generalize());
|
||||
|
||||
|
||||
Ifc2x3::IfcEllipse* ellipse = new Ifc2x3::IfcEllipse(file.addPlacement2d(), pie.r1, pie.r2);
|
||||
file.addEntity(ellipse);
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
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));
|
||||
} else {
|
||||
trim1->push(p2);
|
||||
trim2->push(p3);
|
||||
}
|
||||
Ifc2x3::IfcTrimmedCurve* trim = new Ifc2x3::IfcTrimmedCurve(ellipse, trim1, trim2, true, pref);
|
||||
file.addEntity(trim);
|
||||
|
||||
Ifc2x3::IfcCompositeCurveSegment::list segments(new IfcTemplatedEntityList<Ifc2x3::IfcCompositeCurveSegment>());
|
||||
Ifc2x3::IfcCompositeCurveSegment* s2 = new Ifc2x3::IfcCompositeCurveSegment(Ifc2x3::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, trim);
|
||||
|
||||
Ifc2x3::IfcPolyline* poly = new Ifc2x3::IfcPolyline(points);
|
||||
file.addEntity(poly);
|
||||
Ifc2x3::IfcCompositeCurveSegment* s1 = new Ifc2x3::IfcCompositeCurveSegment(Ifc2x3::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, poly);
|
||||
segments->push(s1);
|
||||
|
||||
segments->push(s2);
|
||||
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);
|
||||
|
||||
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++));
|
||||
|
||||
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(profile,
|
||||
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
|
||||
|
||||
file.addEntity(solid);
|
||||
|
||||
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
|
||||
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
|
||||
|
||||
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);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const std::string filename = "ellipse_pies.ifc";
|
||||
IfcHierarchyHelper file;
|
||||
{ EllipsePie pie = {80., 50., 0., 150.};
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
{ EllipsePie pie = {80, 50., 30., 300.};
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
{ EllipsePie pie = {80, 50., 300., 30.};
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
{ EllipsePie pie = {50., 80., 0., 150.};
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
{ EllipsePie pie = {50, 80., 30., 300.};
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
{ EllipsePie pie = {50, 80., 300., 30.};
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
std::ofstream f(filename.c_str());
|
||||
f << file;
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 extrusions of parameterized profiles. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
void create_testcase_for(IfcSchema::IfcProfileDef::list::ptr profiles) {
|
||||
IfcSchema::IfcProfileDef* profile = *profiles->begin();
|
||||
const std::string profile_type = IfcSchema::Type::ToString(profile->type());
|
||||
const std::string filename = profile_type + ".ifc";
|
||||
|
||||
IfcHierarchyHelper file;
|
||||
file.filename(filename);
|
||||
|
||||
int i = 0;
|
||||
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);
|
||||
file.addBuildingProduct(product);
|
||||
file.getSingle<IfcSchema::IfcProject>()->setName(profile_type);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement(0, 100. * i));
|
||||
|
||||
if (profile->is(IfcSchema::Type::IfcParameterizedProfileDef)) {
|
||||
((IfcSchema::IfcParameterizedProfileDef*) profile)->setPosition(file.addPlacement2d());
|
||||
}
|
||||
|
||||
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(profile,
|
||||
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
|
||||
|
||||
file.addEntity(profile);
|
||||
file.addEntity(solid);
|
||||
|
||||
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);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
}
|
||||
|
||||
std::ofstream f(filename.c_str());
|
||||
f << file;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
{ 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));
|
||||
profiles->push(new Ifc2x3::IfcUShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, 2.0, 2.0, null, null));
|
||||
profiles->push(new Ifc2x3::IfcUShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, null, null, 4.0, null));
|
||||
profiles->push(new Ifc2x3::IfcUShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, 1.0, 3.0, 6.0, null));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
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));
|
||||
profiles->push(new Ifc2x3::IfcTShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, 2.0, 2.0, 2.0, null, null, null));
|
||||
profiles->push(new Ifc2x3::IfcTShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, null, null, null, 2.0, 2.0, null));
|
||||
profiles->push(new Ifc2x3::IfcTShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, 3.0, 2.0, 1.0, 2.0, 2.0, null));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcZShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, null, null));
|
||||
profiles->push(new Ifc2x3::IfcZShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, 2.0, 2.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcEllipseProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0, 15.0));
|
||||
profiles->push(new Ifc2x3::IfcEllipseProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 15.0, 25.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ 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::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));
|
||||
profiles->push(new Ifc2x3::IfcLShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 2.0, 2.0, null, null, null));
|
||||
profiles->push(new Ifc2x3::IfcLShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, null, null, 2.0, null, null));
|
||||
profiles->push(new Ifc2x3::IfcLShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 1.0, 2.0, 2.0, null, null));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcCShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 10.0, null, null));
|
||||
profiles->push(new Ifc2x3::IfcCShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 10.0, 2.0, null));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcCircleProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0));
|
||||
profiles->push(new Ifc2x3::IfcCircleHollowProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0, 5.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcRectangleProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0));
|
||||
profiles->push(new Ifc2x3::IfcRoundedRectangleProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0));
|
||||
profiles->push(new Ifc2x3::IfcRectangleHollowProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, null, null));
|
||||
profiles->push(new Ifc2x3::IfcRectangleHollowProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 2.0, 4.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcTrapeziumProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 30.0, 25.0, 0.0));
|
||||
profiles->push(new Ifc2x3::IfcTrapeziumProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 60.0, 25.0, -20.0));
|
||||
profiles->push(new Ifc2x3::IfcTrapeziumProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 10.0, 25.0, 30.0));
|
||||
create_testcase_for(profiles); }
|
||||
}
|
||||
@@ -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.findContext()
|
||||
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'
|
||||
)
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifdef WITH_OPENCOLLADA
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ColladaSerializer.h"
|
||||
|
||||
std::string collada_id(const std::string& s) {
|
||||
std::string id;
|
||||
id.reserve(s.size());
|
||||
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
|
||||
const std::string::value_type c = *it;
|
||||
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_')) {
|
||||
id.push_back(c);
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<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);
|
||||
for (unsigned int i = 0; i < source.getAccessorStride(); ++i) {
|
||||
source.getParameterNameList().push_back(std::string(1, coords[i]));
|
||||
}
|
||||
source.prepareToAppendValues();
|
||||
for (std::vector<double>::const_iterator it = floats.begin(); it != floats.end(); ++it) {
|
||||
source.appendValues(*it);
|
||||
}
|
||||
source.finish();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials) {
|
||||
// The goal of the IfcGeom::Iterator is to filter out empty geometries, but
|
||||
// since this function would crash trying to deference the material_ids in
|
||||
// that case, a hard return statement is added just in case.
|
||||
if (indices.empty()) return;
|
||||
|
||||
openMesh(mesh_id);
|
||||
|
||||
// The normals vector can be empty for example when the WELD_VERTICES setting is used.
|
||||
// IfcOpenShell does not provide them with multiple face normals collapsed into a single vertex.
|
||||
const bool has_normals = !normals.empty();
|
||||
|
||||
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX, positions);
|
||||
if (has_normals) {
|
||||
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, normals);
|
||||
}
|
||||
|
||||
COLLADASW::VerticesElement vertices(mSW);
|
||||
vertices.setId(mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX );
|
||||
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 material_it = material_ids.begin();
|
||||
int previous_material_id = -1;
|
||||
for (std::vector<int>::const_iterator it = indices.begin(); ; it += 3) {
|
||||
const int current_material_id = *(material_it++);
|
||||
const int num_triangles = std::distance(index_range_start, it) / 3;
|
||||
if ((previous_material_id != current_material_id && num_triangles > 0) || (it == indices.end())) {
|
||||
COLLADASW::Triangles triangles(mSW);
|
||||
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++ ) );
|
||||
if (has_normals) {
|
||||
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::NORMAL,"#" + mesh_id + COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, offset++ ) );
|
||||
}
|
||||
triangles.prepareToAppendValues();
|
||||
for (std::vector<int>::const_iterator jt = index_range_start; jt != it; ++jt) {
|
||||
const int idx = *jt;
|
||||
if (has_normals) {
|
||||
triangles.appendValues(idx, idx);
|
||||
} else {
|
||||
triangles.appendValues(idx);
|
||||
}
|
||||
}
|
||||
triangles.finish();
|
||||
index_range_start = it;
|
||||
}
|
||||
previous_material_id = current_material_id;
|
||||
if (it == indices.end()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
closeMesh();
|
||||
closeGeometry();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::close() {
|
||||
closeLibrary();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaScene::add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<double>& matrix) {
|
||||
if (!scene_opened) {
|
||||
openVisualScene(scene_id);
|
||||
scene_opened = true;
|
||||
}
|
||||
|
||||
COLLADASW::Node node(mSW);
|
||||
node.setNodeId(node_id);
|
||||
node.setNodeName(node_name);
|
||||
node.setType(COLLADASW::Node::NODE);
|
||||
|
||||
// The matrix attribute of an entity is basically a 4x3 representation of its ObjectPlacement.
|
||||
// Note that this placement is absolute, ie it is multiplied with all parent placements.
|
||||
double matrix_array[4][4] = {
|
||||
{matrix[0], matrix[3], matrix[6], matrix[ 9]},
|
||||
{matrix[1], matrix[4], matrix[7], matrix[10]},
|
||||
{matrix[2], matrix[5], matrix[8], matrix[11]},
|
||||
{ 0, 0, 0, 1}
|
||||
};
|
||||
|
||||
node.start();
|
||||
node.addMatrix(matrix_array);
|
||||
COLLADASW::InstanceGeometry instanceGeometry(mSW);
|
||||
instanceGeometry.setUrl ("#" + geom_name);
|
||||
for (std::vector<std::string>::const_iterator it = material_ids.begin(); it != material_ids.end(); ++it) {
|
||||
COLLADASW::InstanceMaterial material (*it, "#" + *it);
|
||||
instanceGeometry.getBindMaterial().getInstanceMaterialList().push_back(material);
|
||||
}
|
||||
instanceGeometry.add();
|
||||
node.end();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaScene::write() {
|
||||
if (scene_opened) {
|
||||
closeVisualScene();
|
||||
closeLibrary();
|
||||
|
||||
COLLADASW::Scene scene (mSW, COLLADASW::URI ("#" + scene_id));
|
||||
scene.add();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
if (material.hasDiffuse()) {
|
||||
const double* diffuse = material.diffuse();
|
||||
effect.setDiffuse(COLLADASW::ColorOrTexture(COLLADASW::Color(diffuse[0],diffuse[1],diffuse[2])));
|
||||
}
|
||||
if (material.hasSpecular()) {
|
||||
const double* specular = material.specular();
|
||||
effect.setSpecular(COLLADASW::ColorOrTexture(COLLADASW::Color(specular[0],specular[1],specular[2])));
|
||||
}
|
||||
if (material.hasSpecularity()) {
|
||||
effect.setShininess(material.specularity());
|
||||
}
|
||||
if (material.hasTransparency()) {
|
||||
const double transparency = material.transparency();
|
||||
if (transparency > 0) {
|
||||
// The default opacity mode for Collada is A_ONE, which apparently indicates a
|
||||
// transparency value of 1 to be fully opaque. Hence transparency is inverted.
|
||||
effect.setTransparency(1.0 - transparency);
|
||||
}
|
||||
}
|
||||
addEffectProfile(effect);
|
||||
closeEffect();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::close() {
|
||||
closeLibrary();
|
||||
}
|
||||
|
||||
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 IfcGeom::Material& material) {
|
||||
return std::find(materials.begin(), materials.end(), material) != materials.end();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::write() {
|
||||
effects.close();
|
||||
for (std::vector<IfcGeom::Material>::const_iterator it = materials.begin(); it != materials.end(); ++it) {
|
||||
const std::string& material_name = collada_id((*it).name());
|
||||
openMaterial(material_name);
|
||||
addInstanceEffect("#" + material_name + "-fx");
|
||||
closeMaterial();
|
||||
}
|
||||
closeLibrary();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_name, float unit_magnitude) {
|
||||
stream.startDocument();
|
||||
|
||||
COLLADASW::Asset asset(&stream);
|
||||
asset.getContributor().mAuthoringTool = std::string("IfcOpenShell ") + IFCOPENSHELL_VERSION;
|
||||
asset.setUnit(unit_name, unit_magnitude);
|
||||
asset.setUpAxisType(COLLADASW::Asset::Z_UP);
|
||||
asset.add();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::write(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& _materials) {
|
||||
std::vector<std::string> material_references;
|
||||
for (std::vector<IfcGeom::Material>::const_iterator it = _materials.begin(); it != _materials.end(); ++it) {
|
||||
const IfcGeom::Material& material = *it;
|
||||
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());
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::endDocument() {
|
||||
// In fact due the XML based nature of Collada and its dependency on library nodes,
|
||||
// only at this point all objects are written to the stream.
|
||||
materials.write();
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
scene.write();
|
||||
stream.endDocument();
|
||||
}
|
||||
|
||||
bool ColladaSerializer::ready() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void ColladaSerializer::writeHeader() {
|
||||
exporter.startDocument(unit_name, unit_magnitude);
|
||||
}
|
||||
|
||||
void ColladaSerializer::write(const IfcGeom::TriangulationElement<double>* o) {
|
||||
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
|
||||
exporter.write(o->guid(), o->name(), o->type(), o->id(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.material_ids(), mesh.materials());
|
||||
}
|
||||
|
||||
void ColladaSerializer::finalize() {
|
||||
exporter.endDocument();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,165 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifdef WITH_OPENCOLLADA
|
||||
|
||||
#ifndef COLLADASERIALIZER_H
|
||||
#define COLLADASERIALIZER_H
|
||||
|
||||
#include <COLLADASWStreamWriter.h>
|
||||
#include <COLLADASWPrimitves.h>
|
||||
#include <COLLADASWLibraryGeometries.h>
|
||||
#include <COLLADASWSource.h>
|
||||
#include <COLLADASWScene.h>
|
||||
#include <COLLADASWNode.h>
|
||||
#include <COLLADASWInstanceGeometry.h>
|
||||
#include <COLLADASWLibraryVisualScenes.h>
|
||||
#include <COLLADASWLibraryEffects.h>
|
||||
#include <COLLADASWLibraryMaterials.h>
|
||||
#include <COLLADASWBaseInputElement.h>
|
||||
#include <COLLADASWAsset.h>
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
#include "../ifcconvert/GeometrySerializer.h"
|
||||
|
||||
class ColladaSerializer : public GeometrySerializer
|
||||
{
|
||||
private:
|
||||
class ColladaExporter
|
||||
{
|
||||
private:
|
||||
class ColladaGeometries : public COLLADASW::LibraryGeometries
|
||||
{
|
||||
public:
|
||||
explicit ColladaGeometries(COLLADASW::StreamWriter& stream)
|
||||
: COLLADASW::LibraryGeometries(&stream)
|
||||
{}
|
||||
void addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<double>& floats, const char* coords = "XYZ");
|
||||
void write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials);
|
||||
void close();
|
||||
};
|
||||
class ColladaScene : public COLLADASW::LibraryVisualScenes
|
||||
{
|
||||
private:
|
||||
const std::string scene_id;
|
||||
bool scene_opened;
|
||||
public:
|
||||
ColladaScene(const std::string& scene_id, COLLADASW::StreamWriter& stream)
|
||||
: COLLADASW::LibraryVisualScenes(&stream)
|
||||
, scene_id(scene_id)
|
||||
, scene_opened(false)
|
||||
{}
|
||||
void add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<double>& matrix);
|
||||
void write();
|
||||
};
|
||||
class ColladaMaterials : public COLLADASW::LibraryMaterials
|
||||
{
|
||||
private:
|
||||
class ColladaEffects : public COLLADASW::LibraryEffects
|
||||
{
|
||||
public:
|
||||
explicit ColladaEffects(COLLADASW::StreamWriter& stream)
|
||||
: COLLADASW::LibraryEffects(&stream)
|
||||
{}
|
||||
void write(const IfcGeom::Material& material);
|
||||
void close();
|
||||
};
|
||||
std::vector<IfcGeom::Material> materials;
|
||||
ColladaEffects effects;
|
||||
public:
|
||||
explicit ColladaMaterials(COLLADASW::StreamWriter& stream)
|
||||
: COLLADASW::LibraryMaterials(&stream)
|
||||
, effects(stream)
|
||||
{}
|
||||
void add(const IfcGeom::Material& material);
|
||||
bool contains(const IfcGeom::Material& material);
|
||||
void write();
|
||||
};
|
||||
class DeferredObject {
|
||||
public:
|
||||
std::string guid, name, type;
|
||||
int obj_id;
|
||||
std::vector<double> matrix;
|
||||
std::vector<double> vertices;
|
||||
std::vector<double> normals;
|
||||
std::vector<int> indices;
|
||||
std::vector<int> material_ids;
|
||||
std::vector<IfcGeom::Material> materials;
|
||||
std::vector<std::string> material_references;
|
||||
DeferredObject(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<double>& matrix, const std::vector<double>& vertices,
|
||||
const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids,
|
||||
const std::vector<IfcGeom::Material>& materials, const std::vector<std::string>& material_references)
|
||||
: guid(guid)
|
||||
, name(name)
|
||||
, type(type)
|
||||
, obj_id(obj_id)
|
||||
, matrix(matrix)
|
||||
, vertices(vertices)
|
||||
, normals(normals)
|
||||
, indices(indices)
|
||||
, material_ids(material_ids)
|
||||
, materials(materials)
|
||||
, material_references(material_references)
|
||||
{}
|
||||
const std::string Name() const;
|
||||
};
|
||||
COLLADABU::NativeString filename;
|
||||
COLLADASW::StreamWriter stream;
|
||||
ColladaGeometries geometries;
|
||||
ColladaScene scene;
|
||||
ColladaMaterials materials;
|
||||
public:
|
||||
ColladaExporter(const std::string& scene_name, const std::string& fn)
|
||||
: filename(fn.c_str())
|
||||
, stream(filename)
|
||||
, geometries(stream)
|
||||
, scene(scene_name, stream)
|
||||
, materials(stream)
|
||||
{}
|
||||
std::vector<DeferredObject> deferreds;
|
||||
virtual ~ColladaExporter() {}
|
||||
void startDocument(const std::string& unit_name, float unit_magnitude);
|
||||
void write(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& materials);
|
||||
void endDocument();
|
||||
};
|
||||
ColladaExporter exporter;
|
||||
std::string unit_name;
|
||||
float unit_magnitude;
|
||||
public:
|
||||
ColladaSerializer(const std::string& dae_filename)
|
||||
: GeometrySerializer()
|
||||
, exporter("IfcOpenShell", dae_filename)
|
||||
{}
|
||||
bool ready();
|
||||
void writeHeader();
|
||||
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
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 GEOMETRYSERIALIZER_H
|
||||
#define GEOMETRYSERIALIZER_H
|
||||
|
||||
#include "../ifcconvert/Serializer.h"
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
class GeometrySerializer : public Serializer {
|
||||
public:
|
||||
virtual ~GeometrySerializer() {}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,356 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 started as a brief example of how IfcOpenShell can be interfaced from *
|
||||
* within a C++ context, it has since then evolved into a fullfledged command *
|
||||
* line application that is able to convert geometry in an IFC files into *
|
||||
* several tesselated and topological output formats. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <time.h>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
#include "../ifcconvert/ColladaSerializer.h"
|
||||
#include "../ifcconvert/IgesSerializer.h"
|
||||
#include "../ifcconvert/StepSerializer.h"
|
||||
#include "../ifcconvert/WavefrontObjSerializer.h"
|
||||
#include "../ifcconvert/XmlSerializer.h"
|
||||
|
||||
void printVersion() {
|
||||
std::cerr << "IfcOpenShell IfcConvert " << IFCOPENSHELL_VERSION << std::endl;
|
||||
}
|
||||
|
||||
void printUsage(const boost::program_options::options_description& generic_options, const boost::program_options::options_description& geom_options) {
|
||||
printVersion();
|
||||
std::cerr << "Usage: IfcConvert [options] <input.ifc> [<output>]" << std::endl
|
||||
<< std::endl
|
||||
<< "Converts the geometry in an IFC file into one of the following formats:" << std::endl
|
||||
<< " .obj WaveFront OBJ (a .mtl file is also created)" << std::endl;
|
||||
#ifdef WITH_OPENCOLLADA
|
||||
std::cerr << " .dae Collada Digital Assets Exchange" << std::endl;
|
||||
#endif
|
||||
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
|
||||
<< std::endl
|
||||
<< "Command line options" << std::endl << generic_options << std::endl
|
||||
<< "Advanced options" << std::endl << geom_options << std::endl;
|
||||
}
|
||||
|
||||
std::string change_extension(const std::string& fn, const std::string& ext) {
|
||||
std::string::size_type dot = fn.find_last_of('.');
|
||||
if (dot != std::string::npos) {
|
||||
return fn.substr(0,dot+1) + ext;
|
||||
} else {
|
||||
return fn + "." + ext;
|
||||
}
|
||||
}
|
||||
|
||||
static std::stringstream log_stream;
|
||||
void write_log();
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
boost::program_options::options_description generic_options;
|
||||
generic_options.add_options()
|
||||
("help", "display usage information")
|
||||
("version", "display version information")
|
||||
("verbose,v", "more verbose output");
|
||||
|
||||
boost::program_options::options_description fileio_options;
|
||||
fileio_options.add_options()
|
||||
("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> entity_vector;
|
||||
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 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.")
|
||||
("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.")
|
||||
("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);
|
||||
|
||||
boost::program_options::positional_options_description positional_options;
|
||||
positional_options.add("input-file", 1);
|
||||
positional_options.add("output-file", 1);
|
||||
|
||||
boost::program_options::variables_map vmap;
|
||||
try {
|
||||
boost::program_options::store(boost::program_options::command_line_parser(argc, argv).
|
||||
options(cmdline_options).positional(positional_options).run(), vmap);
|
||||
} catch (const boost::program_options::unknown_option& e) {
|
||||
std::cerr << "[Error] Unknown option '" << e.get_option_name() << "'" << std::endl << std::endl;
|
||||
// Usage information will be emitted below
|
||||
} catch (...) {
|
||||
// Catch other errors such as invalid command line syntax
|
||||
}
|
||||
boost::program_options::notify(vmap);
|
||||
|
||||
if (vmap.count("version")) {
|
||||
printVersion();
|
||||
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;
|
||||
}
|
||||
|
||||
const bool verbose = vmap.count("verbose") != 0;
|
||||
const bool weld_vertices = vmap.count("weld-vertices") != 0;
|
||||
const bool use_world_coords = vmap.count("use-world-coords") != 0;
|
||||
const bool convert_back_units = vmap.count("convert-back-units") != 0;
|
||||
const bool sew_shells = vmap.count("sew-shells") != 0;
|
||||
const bool merge_boolean_operands = vmap.count("merge-boolean-operands") != 0;
|
||||
const bool force_ccw_face_orientation = vmap.count("force-ccw-face-orientation") != 0;
|
||||
const bool disable_opening_subtractions = vmap.count("disable-opening-subtractions") != 0;
|
||||
const bool include_entities = vmap.count("include") != 0;
|
||||
|
||||
// Gets the set ifc types to be ignored from the command line.
|
||||
std::set<std::string> entities;
|
||||
for (std::vector<std::string>::const_iterator it = entity_vector.begin(); it != entity_vector.end(); ++it) {
|
||||
std::string lowercase_type = *it;
|
||||
for (std::string::iterator c = lowercase_type.begin(); c != lowercase_type.end(); ++c) {
|
||||
*c = tolower(*c);
|
||||
}
|
||||
entities.insert(lowercase_type);
|
||||
}
|
||||
|
||||
// If no entities are specified these are the defaults to skip from output
|
||||
if (entity_vector.empty()) {
|
||||
entities.insert("ifcopeningelement");
|
||||
entities.insert("ifcspace");
|
||||
}
|
||||
|
||||
const std::string input_filename = vmap["input-file"].as<std::string>();
|
||||
// If no output filename is specified a Wavefront OBJ file will be output
|
||||
// to maintain backwards compatibility with the obsolete IfcObj executable.
|
||||
const std::string output_filename = vmap.count("output-file") == 1
|
||||
? vmap["output-file"].as<std::string>()
|
||||
: change_extension(input_filename, "obj");
|
||||
|
||||
if (output_filename.size() < 5) {
|
||||
printUsage(generic_options, geom_options);
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string output_extension = output_filename.substr(output_filename.size()-4);
|
||||
for (std::string::iterator c = output_extension.begin(); c != output_extension.end(); ++c) {
|
||||
*c = tolower(*c);
|
||||
}
|
||||
|
||||
Logger::SetOutput(&std::cout, &log_stream);
|
||||
Logger::Verbosity(verbose ? Logger::LOG_NOTICE : Logger::LOG_ERROR);
|
||||
|
||||
if (output_extension == ".xml") {
|
||||
int exit_code = 1;
|
||||
try {
|
||||
XmlSerializer s(output_filename);
|
||||
IfcParse::IfcFile f;
|
||||
if (!f.Init(input_filename)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file");
|
||||
} else {
|
||||
s.setFile(&f);
|
||||
s.finalize();
|
||||
exit_code = 0;
|
||||
}
|
||||
} catch (...) {}
|
||||
write_log();
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
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);
|
||||
settings.set(IfcGeom::IteratorSettings::FASTER_BOOLEANS, merge_boolean_operands);
|
||||
settings.set(IfcGeom::IteratorSettings::FORCE_CCW_FACE_ORIENTATION, force_ccw_face_orientation);
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, disable_opening_subtractions);
|
||||
|
||||
GeometrySerializer* serializer;
|
||||
if (output_extension == ".obj") {
|
||||
const std::string mtl_filename = output_filename.substr(0,output_filename.size()-3) + "mtl";
|
||||
if (!use_world_coords) {
|
||||
Logger::Message(Logger::LOG_NOTICE, "Using world coords when writing WaveFront OBJ files");
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true);
|
||||
}
|
||||
serializer = new WaveFrontOBJSerializer(output_filename, mtl_filename);
|
||||
#ifdef WITH_OPENCOLLADA
|
||||
} else if (output_extension == ".dae") {
|
||||
serializer = new ColladaSerializer(output_filename);
|
||||
#endif
|
||||
} else if (output_extension == ".stp") {
|
||||
serializer = new StepSerializer(output_filename);
|
||||
} else if (output_extension == ".igs") {
|
||||
// Not sure why this is needed, but it is.
|
||||
// See: http://tracker.dev.opencascade.org/view.php?id=23679
|
||||
IGESControl_Controller::Init();
|
||||
serializer = new IgesSerializer(output_filename);
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unknown output filename extension");
|
||||
write_log();
|
||||
printUsage(generic_options, geom_options);
|
||||
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;
|
||||
}
|
||||
|
||||
time_t start,end;
|
||||
time(&start);
|
||||
|
||||
if (!context_iterator.findContext()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file or no geometrical entities found");
|
||||
write_log();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (convert_back_units) {
|
||||
serializer->setUnitNameAndMagnitude(context_iterator.getUnitName(), static_cast<const float>(context_iterator.getUnitMagnitude()));
|
||||
} else {
|
||||
serializer->setUnitNameAndMagnitude("METER", 1.0f);
|
||||
}
|
||||
|
||||
serializer->writeHeader();
|
||||
|
||||
std::set<std::string> materials;
|
||||
|
||||
int old_progress = -1;
|
||||
Logger::Status("Creating geometry...");
|
||||
|
||||
// The functions IfcGeom::Iterator::get() and IfcGeom::Iterator::next()
|
||||
// wrap an iterator of all geometrical products in the Ifc file.
|
||||
// IfcGeom::Iterator::get() returns an IfcGeom::TriangulationElement or
|
||||
// -BRepElement pointer, based on current settings. (see IfcGeomIterator.h
|
||||
// for definition) IfcGeom::Iterator::next() is used to poll whether more
|
||||
// geometrical entities are available. None of these functions throw
|
||||
// exceptions, neither for parsing errors or geometrical errors. Upon
|
||||
// calling next() the entity to be returned has already been processed, a
|
||||
// true return value guarantees that a successfully processed product is
|
||||
// available.
|
||||
do {
|
||||
const IfcGeom::Element<double>* geom_object = context_iterator.get();
|
||||
|
||||
if (serializer->isTesselated()) {
|
||||
serializer->write(static_cast<const IfcGeom::TriangulationElement<double>*>(geom_object));
|
||||
} else {
|
||||
serializer->write(static_cast<const IfcGeom::BRepElement<double>*>(geom_object));
|
||||
}
|
||||
|
||||
const int progress = context_iterator.progress() / 2;
|
||||
if (old_progress!= progress) Logger::ProgressBar(progress);
|
||||
old_progress = progress;
|
||||
|
||||
} while (context_iterator.next());
|
||||
|
||||
serializer->finalize();
|
||||
delete serializer;
|
||||
|
||||
Logger::Status("\rDone creating geometry ");
|
||||
|
||||
write_log();
|
||||
|
||||
time(&end);
|
||||
int dif = (int) difftime (end,start);
|
||||
printf ("\nConversion took %d seconds\n", dif );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void write_log() {
|
||||
std::string log = log_stream.str();
|
||||
if (!log.empty()) {
|
||||
std::cerr << std::endl << "Log:" << std::endl;
|
||||
std::cerr << log << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 IGESSERIALIZER_H
|
||||
#define IGESSERIALIZER_H
|
||||
|
||||
#include <IGESControl_Controller.hxx>
|
||||
#include <IGESControl_Writer.hxx>
|
||||
#include <Interface_Static.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
#include "../ifcconvert/OpenCascadeBasedSerializer.h"
|
||||
|
||||
class IgesSerializer : public OpenCascadeBasedSerializer
|
||||
{
|
||||
private:
|
||||
IGESControl_Writer writer;
|
||||
public:
|
||||
explicit IgesSerializer(const std::string& out_filename)
|
||||
: OpenCascadeBasedSerializer(out_filename)
|
||||
{}
|
||||
virtual ~IgesSerializer() {}
|
||||
void writeShape(const TopoDS_Shape& shape) {
|
||||
writer.AddShape(shape);
|
||||
}
|
||||
void finalize() {
|
||||
writer.Write(out_filename.c_str());
|
||||
}
|
||||
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
|
||||
const char* symbol = getSymbolForUnitMagnitude(magnitude);
|
||||
if (symbol) {
|
||||
Interface_Static::SetCVal("write.iges.unit", symbol);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,92 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 <BRepBuilderAPI_GTransform.hxx>
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
|
||||
#include <Standard_Version.hxx>
|
||||
|
||||
#include "OpenCascadeBasedSerializer.h"
|
||||
|
||||
bool OpenCascadeBasedSerializer::ready() {
|
||||
std::ofstream test_file(out_filename.c_str(), std::ios_base::binary);
|
||||
bool succeeded = test_file.is_open();
|
||||
test_file.close();
|
||||
remove(out_filename.c_str());
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement<double>* o) {
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) {
|
||||
gp_GTrsf gtrsf = it->Placement();
|
||||
|
||||
const std::vector<double>& matrix = o->transformation().matrix().data();
|
||||
|
||||
// Convert the matrix back into a transformation object. The tolerance values
|
||||
// are taken into consideration to reconstruct the form of the transformation.
|
||||
gp_Trsf o_trsf;
|
||||
o_trsf.SetValues(
|
||||
matrix[0], matrix[3], matrix[6], matrix[ 9],
|
||||
matrix[1], matrix[4], matrix[7], matrix[10],
|
||||
matrix[2], matrix[5], matrix[8], matrix[11]
|
||||
#if OCC_VERSION_HEX < 0x60800
|
||||
, Precision::Angular(), Precision::Confusion()
|
||||
#endif
|
||||
);
|
||||
gtrsf.PreMultiply(o_trsf);
|
||||
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
|
||||
bool trsf_valid = false;
|
||||
gp_Trsf trsf;
|
||||
try {
|
||||
trsf = gtrsf.Trsf();
|
||||
trsf_valid = true;
|
||||
} catch (...) {}
|
||||
|
||||
const TopoDS_Shape moved_shape = trsf_valid
|
||||
? BRepBuilderAPI_Transform(s, trsf, true).Shape()
|
||||
: BRepBuilderAPI_GTransform(s, gtrsf, true).Shape();
|
||||
|
||||
writeShape(moved_shape);
|
||||
}
|
||||
}
|
||||
|
||||
#define RATHER_SMALL (1e-3)
|
||||
#define APPROXIMATELY_THE_SAME(a,b) (fabs(a-b) < RATHER_SMALL)
|
||||
|
||||
const char* OpenCascadeBasedSerializer::getSymbolForUnitMagnitude(float mag) {
|
||||
if (APPROXIMATELY_THE_SAME(mag, 0.001f)) {
|
||||
return "MM";
|
||||
} else if (APPROXIMATELY_THE_SAME(mag, 0.01f)) {
|
||||
return "CM";
|
||||
} else if (APPROXIMATELY_THE_SAME(mag, 1.0f)) {
|
||||
return "M";
|
||||
} else if (APPROXIMATELY_THE_SAME(mag, 0.3048f)) {
|
||||
return "FT";
|
||||
} else if (APPROXIMATELY_THE_SAME(mag, 0.0254f)) {
|
||||
return "INCH";
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 OPENCASCADEBASEDSERIALIZER_H
|
||||
#define OPENCASCADEBASEDSERIALIZER_H
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
#include "../ifcconvert/GeometrySerializer.h"
|
||||
|
||||
class OpenCascadeBasedSerializer : public GeometrySerializer {
|
||||
protected:
|
||||
const std::string& out_filename;
|
||||
const char* getSymbolForUnitMagnitude(float mag);
|
||||
public:
|
||||
explicit OpenCascadeBasedSerializer(const std::string& out_filename)
|
||||
: GeometrySerializer()
|
||||
, out_filename(out_filename)
|
||||
{}
|
||||
virtual ~OpenCascadeBasedSerializer() {}
|
||||
void writeHeader() {}
|
||||
void writeMaterial(const IfcGeom::SurfaceStyle& style) {}
|
||||
bool ready();
|
||||
virtual void writeShape(const TopoDS_Shape& shape) = 0;
|
||||
void write(const IfcGeom::TriangulationElement<double>* o) {}
|
||||
void write(const IfcGeom::BRepElement<double>* o);
|
||||
bool isTesselated() const { return false; }
|
||||
void setFile(IfcParse::IfcFile*) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef SERIALIZER_H
|
||||
#define SERIALIZER_H
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
|
||||
class Serializer {
|
||||
public:
|
||||
virtual ~Serializer() {}
|
||||
|
||||
virtual bool ready() = 0;
|
||||
virtual void writeHeader() = 0;
|
||||
virtual void finalize() = 0;
|
||||
virtual void setFile(IfcParse::IfcFile*) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,60 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 STEPSERIALIZER_H
|
||||
#define STEPSERIALIZER_H
|
||||
|
||||
#include <STEPControl_Controller.hxx>
|
||||
#include <STEPControl_Writer.hxx>
|
||||
#include <Interface_Static.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
#include "../ifcconvert/OpenCascadeBasedSerializer.h"
|
||||
|
||||
class StepSerializer : public OpenCascadeBasedSerializer
|
||||
{
|
||||
private:
|
||||
STEPControl_Writer writer;
|
||||
public:
|
||||
explicit StepSerializer(const std::string& out_filename)
|
||||
: OpenCascadeBasedSerializer(out_filename)
|
||||
{}
|
||||
virtual ~StepSerializer() {}
|
||||
void writeShape(const TopoDS_Shape& shape) {
|
||||
std::stringstream ss;
|
||||
std::streambuf *sb = std::cout.rdbuf(ss.rdbuf());
|
||||
writer.Transfer(shape, STEPControl_AsIs);
|
||||
std::cout.rdbuf(sb);
|
||||
}
|
||||
void finalize() {
|
||||
std::stringstream ss;
|
||||
std::streambuf *sb = std::cout.rdbuf(ss.rdbuf());
|
||||
writer.Write(out_filename.c_str());
|
||||
std::cout.rdbuf(sb);
|
||||
}
|
||||
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
|
||||
const char* symbol = getSymbolForUnitMagnitude(magnitude);
|
||||
if (symbol) {
|
||||
Interface_Static::SetCVal("write.step.unit", symbol);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,78 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file defines default materials for several IFC datatypes *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef SURFACESTYLE_H
|
||||
#define SURFACESTYLE_H
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <array>
|
||||
|
||||
class SurfaceStyle {
|
||||
public:
|
||||
class ColorComponent {
|
||||
private:
|
||||
std::array<double, 3> data;
|
||||
public:
|
||||
ColorComponent(double r, double g, double b) {
|
||||
data[0] = r; data[1] = g; data[2] = b;
|
||||
}
|
||||
const double& R() const { return data[0]; }
|
||||
const double& G() const { return data[1]; }
|
||||
const double& B() const { return data[2]; }
|
||||
double& R() { return data[0]; }
|
||||
double& G() { return data[1]; }
|
||||
double& B() { return data[2]; }
|
||||
};
|
||||
private:
|
||||
std::string name;
|
||||
ColorComponent diffuse, specular, ambient;
|
||||
double transparency;
|
||||
double specularity;
|
||||
public:
|
||||
SurfaceStyle(const std::string& name,
|
||||
double dr = 0.7, double dg = 0.7, double db = 0.7,
|
||||
double sr = 0.2, double sg = 0.2, double sb = 0.2,
|
||||
double ar = 0.1, double ag = 0.1, double ab = 0.1,
|
||||
double Ns = 10.0, double Tr = 1.0)
|
||||
: name(name)
|
||||
, diffuse(dr, dg, db)
|
||||
, specular(sr, sg, sb)
|
||||
, ambient(ar, ag, ab)
|
||||
, transparency(Tr)
|
||||
, specularity(Ns)
|
||||
{}
|
||||
const std::string& Name() const { return name; }
|
||||
const ColorComponent& Diffuse() const { return diffuse; }
|
||||
const ColorComponent& Specular() const { return specular; }
|
||||
const ColorComponent& Ambient() const { return ambient; }
|
||||
double Transparency() const { return transparency; }
|
||||
double Specularity() const { return specularity; }
|
||||
};
|
||||
|
||||
SurfaceStyle GetDefaultMaterial(const std::string& s);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,116 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 "../ifcgeom/IfcGeomRenderStyles.h"
|
||||
|
||||
#include "WavefrontObjSerializer.h"
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
bool WaveFrontOBJSerializer::ready() {
|
||||
return obj_stream.is_open() && mtl_stream.is_open();
|
||||
}
|
||||
|
||||
void WaveFrontOBJSerializer::writeHeader() {
|
||||
obj_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n";
|
||||
#ifdef WIN32
|
||||
const char dir_separator = '\\';
|
||||
#else
|
||||
const char dir_separator = '/';
|
||||
#endif
|
||||
std::string mtl_basename = mtl_filename;
|
||||
std::string::size_type slash = mtl_basename.find_last_of(dir_separator);
|
||||
if (slash != std::string::npos) {
|
||||
mtl_basename = mtl_basename.substr(slash+1);
|
||||
}
|
||||
obj_stream << "mtllib " << mtl_basename << "\n";
|
||||
mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n";
|
||||
}
|
||||
|
||||
void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style) {
|
||||
mtl_stream << "newmtl " << style.name() << "\n";
|
||||
if (style.hasDiffuse()) {
|
||||
const double* diffuse = style.diffuse();
|
||||
mtl_stream << "Kd " << diffuse[0] << " " << diffuse[1] << " " << diffuse[2] << "\n";
|
||||
}
|
||||
if (style.hasSpecular()) {
|
||||
const double* specular = style.specular();
|
||||
mtl_stream << "Ks " << specular[0] << " " << specular[1] << " " << specular[2] << "\n";
|
||||
}
|
||||
if (style.hasSpecularity()) {
|
||||
mtl_stream << "Ns " << style.specularity() << "\n";
|
||||
}
|
||||
if (style.hasTransparency()) {
|
||||
const double transparency = 1.0 - style.transparency();
|
||||
if (transparency < 1) {
|
||||
mtl_stream << "Tr " << transparency << "\n";
|
||||
mtl_stream << "d " << transparency << "\n";
|
||||
mtl_stream << "D " << transparency << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
void WaveFrontOBJSerializer::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 << "s 1" << "\n";
|
||||
|
||||
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
|
||||
|
||||
const int vcount = mesh.verts().size() / 3;
|
||||
for ( std::vector<double>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) {
|
||||
const double x = *(it++);
|
||||
const double y = *(it++);
|
||||
const double z = *(it++);
|
||||
obj_stream << "v " << x << " " << y << " " << z << "\n";
|
||||
}
|
||||
for ( std::vector<double>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) {
|
||||
const double x = *(it++);
|
||||
const double y = *(it++);
|
||||
const double z = *(it++);
|
||||
obj_stream << "vn " << x << " " << y << " " << z << "\n";
|
||||
}
|
||||
|
||||
int previous_material_id = -2;
|
||||
std::vector<int>::const_iterator material_it = mesh.material_ids().begin();
|
||||
|
||||
for ( std::vector<int>::const_iterator it = mesh.faces().begin(); it != mesh.faces().end(); ) {
|
||||
|
||||
const int material_id = *(material_it++);
|
||||
if (material_id != previous_material_id) {
|
||||
const IfcGeom::Material& material = mesh.materials()[material_id];
|
||||
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 = *(it++)+vcount_total;
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 WAVEFRONTOBJSERIALIZER_H
|
||||
#define WAVEFRONTOBJSERIALIZER_H
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
#include "../ifcconvert/GeometrySerializer.h"
|
||||
|
||||
class WaveFrontOBJSerializer : public GeometrySerializer {
|
||||
private:
|
||||
const std::string mtl_filename;
|
||||
std::ofstream obj_stream;
|
||||
std::ofstream mtl_stream;
|
||||
unsigned int vcount_total;
|
||||
std::set<std::string> materials;
|
||||
public:
|
||||
WaveFrontOBJSerializer(const std::string& obj_filename, const std::string& mtl_filename)
|
||||
: GeometrySerializer()
|
||||
, obj_stream(obj_filename.c_str())
|
||||
, mtl_filename(mtl_filename)
|
||||
, mtl_stream(mtl_filename.c_str())
|
||||
, vcount_total(1)
|
||||
{}
|
||||
virtual ~WaveFrontOBJSerializer() {}
|
||||
bool ready();
|
||||
void writeHeader();
|
||||
void writeMaterial(const IfcGeom::Material& style);
|
||||
void write(const IfcGeom::TriangulationElement<double>* o);
|
||||
void write(const IfcGeom::BRepElement<double>* o) {}
|
||||
void finalize() {}
|
||||
bool isTesselated() const { return true; }
|
||||
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {}
|
||||
void setFile(IfcParse::IfcFile*) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,262 @@
|
||||
#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"
|
||||
|
||||
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: {
|
||||
IfcUtil::IfcBaseClass* e = *argument;
|
||||
if (Type::IsSimple(e->type())) {
|
||||
IfcUtil::IfcBaseType* f = (IfcUtil::IfcBaseType*) e;
|
||||
value = format_attribute(f->getArgument(0), f->getArgumentType(0));
|
||||
} else if (e->is(IfcSchema::Type::IfcSIUnit) || e->is(IfcSchema::Type::IfcConversionBasedUnit)) {
|
||||
// Some string concatenation to have a unit name as a XML attribute.
|
||||
|
||||
std::string unit_name;
|
||||
|
||||
if (e->is(IfcSchema::Type::IfcSIUnit)) {
|
||||
IfcSchema::IfcSIUnit* unit = (IfcSchema::IfcSIUnit*) e;
|
||||
unit_name = IfcSchema::IfcSIUnitName::ToString(unit->Name());
|
||||
if (unit->Prefix()) {
|
||||
unit_name = IfcSchema::IfcSIPrefix::ToString(*unit->Prefix()) + unit_name;
|
||||
}
|
||||
} else {
|
||||
IfcSchema::IfcConversionBasedUnit* unit = (IfcSchema::IfcConversionBasedUnit*) e;
|
||||
unit_name = unit->Name();
|
||||
}
|
||||
|
||||
for (std::string::iterator c = unit_name.begin(); c != unit_name.end(); ++c) *c = tolower(*c);
|
||||
|
||||
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->getArgumentCount();
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
const Argument* argument = instance->getArgument(i);
|
||||
if (argument->isNull()) continue;
|
||||
|
||||
std::string argument_name = instance->getArgumentName(i);
|
||||
std::map<std::string, std::string>::const_iterator argument_name_it;
|
||||
argument_name_it = argument_name_map.find(argument_name);
|
||||
if (argument_name_it != argument_name_map.end()) {
|
||||
argument_name = argument_name_it->second;
|
||||
}
|
||||
const IfcUtil::ArgumentType argument_type = instance->getArgumentType(i);
|
||||
|
||||
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->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)());
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
// Member functions for IFC attributes have identical names for getters and setters. Hence a full member function signature is needed to identify them.
|
||||
typedef IfcTemplatedEntityList<IfcProduct>::ptr (IfcRelContainedInSpatialStructure::*get_related_elements) (void) const;
|
||||
typedef IfcTemplatedEntityList<IfcObjectDefinition>::ptr (IfcRelDecomposes::*get_related_objects) (void) const;
|
||||
typedef IfcPropertySetDefinition* (IfcRelDefinesByProperties::*get_related_properties) (void) const;
|
||||
|
||||
// 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->is(Type::IfcSpatialStructureElement)) {
|
||||
IfcSpatialStructureElement* structure = (IfcSpatialStructureElement*) product;
|
||||
|
||||
IfcProduct::list::ptr elements = get_related
|
||||
<IfcSpatialStructureElement, IfcRelContainedInSpatialStructure, IfcProduct>
|
||||
(structure, &IfcSpatialStructureElement::ContainsElements, static_cast<get_related_elements>(&IfcRelContainedInSpatialStructure::RelatedElements));
|
||||
|
||||
for (IfcProduct::list::it it = elements->begin(); it != elements->end(); ++it) {
|
||||
descend(*it, child);
|
||||
}
|
||||
}
|
||||
|
||||
IfcObjectDefinition::list::ptr structures = get_related
|
||||
<IfcProduct, IfcRelDecomposes, IfcObjectDefinition>
|
||||
(product, &IfcProduct::IsDecomposedBy, static_cast<get_related_objects>(&IfcRelDecomposes::RelatedObjects));
|
||||
|
||||
for (IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
|
||||
IfcObjectDefinition* ob = *it;
|
||||
if (ob->is(Type::IfcSpatialStructureElement)) {
|
||||
descend((IfcProduct*)ob, child);
|
||||
} else {
|
||||
descend(ob, child);
|
||||
}
|
||||
}
|
||||
|
||||
IfcPropertySetDefinition::list::ptr property_sets = get_related
|
||||
<IfcProduct, IfcRelDefinesByProperties, IfcPropertySetDefinition>
|
||||
(product, &IfcProduct::IsDefinedBy, static_cast<get_related_properties>(&IfcRelDefinesByProperties::RelatingPropertyDefinition));
|
||||
|
||||
for (IfcPropertySetDefinition::list::it it = property_sets->begin(); it != property_sets->end(); ++it) {
|
||||
IfcPropertySetDefinition* pset = *it;
|
||||
if (pset->is(Type::IfcPropertySet)) {
|
||||
format_entity_instance(pset, child, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Descends into the tree by recursing into IfcRelDecomposes relations.
|
||||
template <>
|
||||
void descend(IfcProject* project, ptree& tree) {
|
||||
ptree& child = format_entity_instance(project, tree);
|
||||
|
||||
IfcObjectDefinition::list::ptr structures = get_related
|
||||
<IfcProject, IfcRelDecomposes, IfcObjectDefinition>
|
||||
(project, &IfcProject::IsDecomposedBy, static_cast<get_related_objects>(&IfcRelDecomposes::RelatedObjects));
|
||||
|
||||
for (IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
|
||||
IfcObjectDefinition* ob = *it;
|
||||
if (ob->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->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
|
||||
@@ -1,557 +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 = {}
|
||||
|
||||
#
|
||||
# Since inherited arguments of Express entities are placed in sequence before the non-inherited once, 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
|
||||
|
||||
#
|
||||
# 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 __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 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 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;\n'%(v1.upper()," "*(self.maxlen-len(v1)),"%(name)s",v2) for v1,v2 in self.v])
|
||||
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 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 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"
|
||||
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;\nstd::string 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 = "std::string %(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
|
||||
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 = ""
|
||||
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 7 */ }"
|
||||
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
|
||||
else:
|
||||
indent = " "
|
||||
function_body = function_body2 = ";"
|
||||
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)
|
||||
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)
|
||||
def __str__(self):
|
||||
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 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)
|
||||
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; }")%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')
|
||||
enumh_file = open("%senum.h"%schema_version,'w')
|
||||
cpp_file = open("%s.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 >>enumh_file, header
|
||||
print >>cpp_file, header
|
||||
print >>h_file, """#ifndef %(schema_upper)s_H
|
||||
#define %(schema_upper)s_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/%(schema)senum.h"
|
||||
|
||||
using namespace IfcUtil;
|
||||
using IfcParse::IfcException;
|
||||
|
||||
#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(selectable_simple_types)
|
||||
entity_enumerations = sorted(entity_names)
|
||||
all_enumerations = simple_enumerations + entity_enumerations
|
||||
|
||||
print >>enumh_file, """#ifndef IFC2X3ENUM_H
|
||||
#define IFC2X3ENUM_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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
"""%{'schema_upper':schema_version.upper(),'schema':schema_version,'enum':", ".join(all_enumerations + ["ALL"])}
|
||||
|
||||
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 >>cpp_file, """#include "%(schema)s.h"
|
||||
#include "IfcException.h"
|
||||
|
||||
using namespace %(schema)s;
|
||||
using namespace IfcParse;
|
||||
|
||||
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, "Type::Enum Type::FromStringOld(const std::string& s){"
|
||||
#elseif = "if"
|
||||
#maxlen = max([len(e) for e in all_enumerations])
|
||||
#for e in all_enumerations:
|
||||
# print >>cpp_file, ' %s(s=="%s"%s) { return %s; }'%(elseif,e.upper()," "*(maxlen-len(e)),e)
|
||||
#print >>cpp_file, " throw;"
|
||||
#print >>cpp_file, "}"
|
||||
print >>cpp_file, "std::map<std::string,Type::Enum> string_map;"
|
||||
print >>cpp_file, "void Ifc2x3::InitStringMap() {"
|
||||
maxlen = max([len(e) for e in all_enumerations])
|
||||
for e in all_enumerations:
|
||||
print >>cpp_file, ' string_map["%s"%s] = Type::%s;'%(e.upper()," "*(maxlen-len(e)),e)
|
||||
print >>cpp_file, """}
|
||||
Type::Enum Type::FromString(const std::string& s) {
|
||||
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, "}"
|
||||
|
||||
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,
|
||||
@@ -0,0 +1,9 @@
|
||||
This folder contains Python code to generate C++ type information based on an
|
||||
Express schema. In particular is has only been tested using recent version of
|
||||
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.
|
||||
|
||||
$ python bootstrap.py express.bnf > express_parser.py && python express_parser.py IFC2X3_TC1.exp
|
||||
@@ -0,0 +1,186 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# 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 sys
|
||||
import string
|
||||
from pyparsing import *
|
||||
|
||||
class Expression:
|
||||
def __init__(self, contents):
|
||||
self.contents = contents[0]
|
||||
def __repr__(self):
|
||||
if self.op is None: return repr(self.contents)
|
||||
c = [isinstance(c,str) and c or str(c) for c in self.contents]
|
||||
if "%s" in self.op: return self.op % (" ".join(c))
|
||||
else: return "(%s)" % (" %s "%self.op).join(c)
|
||||
def __iter__(self):
|
||||
return self.contents.__iter__()
|
||||
|
||||
class Union(Expression):
|
||||
op = "|"
|
||||
|
||||
class Concat(Expression):
|
||||
op = "+"
|
||||
|
||||
class Optional(Expression):
|
||||
op = "Optional(%s)"
|
||||
|
||||
class Repeated(Expression):
|
||||
op = "ZeroOrMore(%s)"
|
||||
|
||||
class Term(Expression):
|
||||
op = None
|
||||
|
||||
class Keyword:
|
||||
def __init__(self, contents):
|
||||
self.contents = contents[0]
|
||||
def __repr__(self):
|
||||
return self.contents
|
||||
|
||||
class Terminal:
|
||||
def __init__(self, contents):
|
||||
self.contents = contents[0]
|
||||
def __repr__(self):
|
||||
s = self.contents
|
||||
is_keyword = len(s) >= 4 and s[0::len(s)-1] == '""' and \
|
||||
all(c in alphanums+"_" for c in s[1:-1])
|
||||
ty = "CaselessKeyword" if is_keyword else "CaselessLiteral"
|
||||
return "%s(%s)" % (ty, s)
|
||||
|
||||
|
||||
LPAREN = Suppress("(")
|
||||
RPAREN = Suppress(")")
|
||||
LBRACK = Suppress("[")
|
||||
RBRACK = Suppress("]")
|
||||
LBRACE = Suppress("{")
|
||||
RBRACE = Suppress("}")
|
||||
EQUALS = Suppress("=")
|
||||
VBAR = Suppress("|")
|
||||
PERIOD = Suppress(".")
|
||||
HASH = Suppress("#")
|
||||
|
||||
identifier = Word(alphanums+"_")
|
||||
keyword = Word(alphanums+"_").setParseAction(Keyword)
|
||||
expression = Forward()
|
||||
optional = Group(LBRACK + expression + RBRACK).setParseAction(Optional)
|
||||
repeated = Group(LBRACE + expression + RBRACE).setParseAction(Repeated)
|
||||
terminal = quotedString.setParseAction(Terminal)
|
||||
term = (keyword | terminal | optional | repeated | (LPAREN + expression + RPAREN)).setParseAction(Term)
|
||||
concat = Group(term + OneOrMore(term)).setParseAction(Concat)
|
||||
factor = concat | term
|
||||
union = Group(factor + OneOrMore(VBAR + factor)).setParseAction(Union)
|
||||
rule = identifier + EQUALS + expression + PERIOD
|
||||
|
||||
expression << (union | factor)
|
||||
|
||||
grammar = OneOrMore(Group(rule))
|
||||
grammar.ignore(HASH + restOfLine)
|
||||
|
||||
express = grammar.parseFile(sys.argv[1])
|
||||
|
||||
def find_keywords(expr, li = None):
|
||||
if li is None: li = []
|
||||
if isinstance(expr, Term):
|
||||
expr = expr.contents
|
||||
if isinstance(expr, Keyword):
|
||||
li.append(repr(expr))
|
||||
return li
|
||||
elif isinstance(expr, Expression):
|
||||
for term in expr:
|
||||
find_keywords(term, li)
|
||||
return set(li)
|
||||
|
||||
actions = {
|
||||
'type_decl' : "lambda t: TypeDeclaration(t)",
|
||||
'entity_decl' : "lambda t: EntityDeclaration(t)",
|
||||
'underlying_type' : "lambda t: UnderlyingType(t)",
|
||||
'enumeration_type' : "lambda t: EnumerationType(t)",
|
||||
'aggregation_types' : "lambda t: AggregationType(t)",
|
||||
'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)",
|
||||
'derive_clause' : "lambda t: AttributeList('derive', t)",
|
||||
'derived_attr' : "lambda t: DerivedAttribute(t)",
|
||||
'inverse_clause' : "lambda t: AttributeList('inverse', t)",
|
||||
'inverse_attr' : "lambda t: InverseAttribute(t)",
|
||||
'bound_spec' : "lambda t: BoundSpecification(t)",
|
||||
'explicit_attr' : "lambda t: ExplicitAttribute(t)",
|
||||
}
|
||||
|
||||
to_emit = set(id for id, expr in express)
|
||||
emitted = set()
|
||||
to_combine = set(["simple_id"])
|
||||
to_ignore = set(["where_clause", "supertype_constraint", "unique_clause"])
|
||||
statements = []
|
||||
|
||||
while True:
|
||||
emitted_in_loop = set()
|
||||
for id, expr in express:
|
||||
kws = find_keywords(expr)
|
||||
found = [k in emitted for k in kws]
|
||||
if id in to_emit and all(found):
|
||||
emitted_in_loop.add(id)
|
||||
emitted.add(id)
|
||||
stmt = "(%s)" % expr
|
||||
if id in to_combine:
|
||||
stmt = "originalTextFor(Combine%s)" % stmt
|
||||
if id in actions:
|
||||
stmt = "%s.setParseAction(%s)" % (stmt, actions[id])
|
||||
statements.append("%s = %s" % (id, stmt))
|
||||
to_emit -= emitted_in_loop
|
||||
if not emitted_in_loop: break
|
||||
|
||||
for id in to_emit:
|
||||
action = ".setParseAction(%s)" % actions[id] if id in actions else ""
|
||||
statements.append("%s = Forward()%s" % (id, action))
|
||||
|
||||
for id in to_emit:
|
||||
expr = [e for k, e in express if k == id][0]
|
||||
stmt = "(%s)" % expr
|
||||
if id in to_combine:
|
||||
stmt = "Suppress%s" % stmt
|
||||
statements.append("%s << %s" % (id, stmt))
|
||||
|
||||
print ("""import sys
|
||||
from pyparsing import *
|
||||
from nodes import *
|
||||
|
||||
%s
|
||||
|
||||
import schema
|
||||
import mapping
|
||||
|
||||
import header
|
||||
import enum_header
|
||||
import implementation
|
||||
import latebound_header
|
||||
import latebound_implementation
|
||||
|
||||
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
|
||||
ast = syntax.parseFile(sys.argv[1])
|
||||
schema = schema.Schema(ast)
|
||||
mapping = mapping.Mapping(schema)
|
||||
|
||||
header.Header(mapping).emit()
|
||||
enum_header.EnumHeader(mapping).emit()
|
||||
implementation.Implementation(mapping).emit()
|
||||
latebound_header.LateBoundHeader(mapping).emit()
|
||||
latebound_implementation.LateBoundImplementation(mapping).emit()
|
||||
"""%('\n'.join(statements)))
|
||||
@@ -36,7 +36,7 @@ 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',' ','/// ']))
|
||||
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:
|
||||
@@ -49,23 +49,22 @@ for fn in definition_files:
|
||||
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)
|
||||
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)
|
||||
for r,s in regices: desc = r.sub(s,desc)
|
||||
desc = desc.strip()
|
||||
r,s = regices[-1]
|
||||
desc = r.sub(s,desc)
|
||||
return desc
|
||||
return desc.split("\n")
|
||||
else: return []
|
||||
@@ -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/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import templates
|
||||
|
||||
class EnumHeader:
|
||||
def __init__(self, mapping):
|
||||
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]))
|
||||
|
||||
self.str = templates.enum_header % {
|
||||
'schema_name_upper' : mapping.schema.name.upper(),
|
||||
'schema_name' : mapping.schema.name.capitalize(),
|
||||
'types' : ', '.join(enumerable_types)
|
||||
}
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
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()
|
||||
@@ -0,0 +1,344 @@
|
||||
# Taken from http://sourceforge.net/p/exp-engine/expresso/ci/master/tree/docs/iso-10303-11--2004.bnf
|
||||
|
||||
ABS = "abs" .
|
||||
ABSTRACT = "abstract" .
|
||||
ACOS = "acos" .
|
||||
AGGREGATE = "aggregate" .
|
||||
ALIAS = "alias" .
|
||||
AND = "and" .
|
||||
ANDOR = "andor" .
|
||||
ARRAY = "array" .
|
||||
AS = "as" .
|
||||
ASIN = "asin" .
|
||||
ATAN = "atan" .
|
||||
BAG = "bag" .
|
||||
BASED_ON = "based_on" .
|
||||
BEGIN = "begin" .
|
||||
BINARY = "binary" .
|
||||
BLENGTH = "blength" .
|
||||
BOOLEAN = "boolean" .
|
||||
BY = "by" .
|
||||
CASE = "case" .
|
||||
CONSTANT = "constant" .
|
||||
CONST_E = "const_e" .
|
||||
COS = "cos" .
|
||||
DERIVE = "derive" .
|
||||
DIV = "div" .
|
||||
ELSE = "else" .
|
||||
END = "end" .
|
||||
END_ALIAS = "end_alias" .
|
||||
END_CASE = "end_case" .
|
||||
END_CONSTANT = "end_constant" .
|
||||
END_ENTITY = "end_entity" .
|
||||
END_FUNCTION = "end_function" .
|
||||
END_IF = "end_if" .
|
||||
END_LOCAL = "end_local" .
|
||||
END_PROCEDURE = "end_procedure" .
|
||||
END_REPEAT = "end_repeat" .
|
||||
END_RULE = "end_rule" .
|
||||
END_SCHEMA = "end_schema" .
|
||||
END_SUBTYPE_CONSTRAINT = "end_subtype_constraint" .
|
||||
END_TYPE = "end_type" .
|
||||
ENTITY = "entity" .
|
||||
ENUMERATION = "enumeration" .
|
||||
ESCAPE = "escape" .
|
||||
EXISTS = "exists" .
|
||||
EXTENSIBLE = "extensible" .
|
||||
EXP = "exp" .
|
||||
FALSE = "false" .
|
||||
FIXED = "fixed" .
|
||||
FOR = "for" .
|
||||
FORMAT = "format" .
|
||||
FROM = "from" .
|
||||
FUNCTION = "function" .
|
||||
GENERIC = "generic" .
|
||||
GENERIC_ENTITY = "generic_entity" .
|
||||
HIBOUND = "hibound" .
|
||||
HIINDEX = "hiindex" .
|
||||
IF = "if" .
|
||||
IN = "in" .
|
||||
INSERT = "insert" .
|
||||
INTEGER = "integer" .
|
||||
INVERSE = "inverse" .
|
||||
LENGTH = "length" .
|
||||
LIKE = "like" .
|
||||
LIST = "list" .
|
||||
LOBOUND = "lobound" .
|
||||
LOCAL = "local" .
|
||||
LOG = "log" .
|
||||
LOG10 = "log10" .
|
||||
LOG2 = "log2" .
|
||||
LOGICAL = "logical" .
|
||||
LOINDEX = "loindex" .
|
||||
MOD = "mod" .
|
||||
NOT = "not" .
|
||||
NUMBER = "number" .
|
||||
NVL = "nvl" .
|
||||
ODD = "odd" .
|
||||
OF = "of" .
|
||||
ONEOF = "oneof" .
|
||||
OPTIONAL = "optional" .
|
||||
OR = "or" .
|
||||
OTHERWISE = "otherwise" .
|
||||
PI = "pi" .
|
||||
PROCEDURE = "procedure" .
|
||||
QUERY = "query" .
|
||||
REAL = "real" .
|
||||
REFERENCE = "reference" .
|
||||
REMOVE = "remove" .
|
||||
RENAMED = "renamed" .
|
||||
REPEAT = "repeat" .
|
||||
RETURN = "return" .
|
||||
ROLESOF = "rolesof" .
|
||||
RULE = "rule" .
|
||||
SCHEMA = "schema" .
|
||||
SELECT = "select" .
|
||||
SELF = "self" .
|
||||
SET = "set" .
|
||||
SIN = "sin" .
|
||||
SIZEOF = "sizeof" .
|
||||
SKIP = "skip" .
|
||||
SQRT = "sqrt" .
|
||||
STRING = "string" .
|
||||
SUBTYPE = "subtype" .
|
||||
SUBTYPE_CONSTRAINT = "subtype_constraint" .
|
||||
SUPERTYPE = "supertype" .
|
||||
TAN = "tan" .
|
||||
THEN = "then" .
|
||||
TO = "to" .
|
||||
TOTAL_OVER = "total_over" .
|
||||
TRUE = "true" .
|
||||
TYPE = "type" .
|
||||
TYPEOF = "typeof" .
|
||||
UNIQUE = "unique" .
|
||||
UNKNOWN = "unknown" .
|
||||
UNTIL = "until" .
|
||||
USE = "use" .
|
||||
USEDIN = "usedin" .
|
||||
VALUE = "value" .
|
||||
VALUE_IN = "value_in" .
|
||||
VALUE_UNIQUE = "value_unique" .
|
||||
VAR = "var" .
|
||||
WHERE = "where" .
|
||||
WHILE = "while" .
|
||||
WITH = "with" .
|
||||
XOR = "xor" .
|
||||
bit = "0" | "1" .
|
||||
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" .
|
||||
digits = digit { digit } .
|
||||
encoded_character = octet octet octet octet .
|
||||
hex_digit = digit | "a" | "b" | "c" | "d" | "e" | "f" .
|
||||
letter = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" .
|
||||
lparen_then_not_lparen_star = "(" { "(" } not_lparen_star { not_lparen_star } .
|
||||
not_lparen_star = not_paren_star | ")" .
|
||||
not_paren_star = letter | digit | not_paren_star_special .
|
||||
not_paren_star_quote_special = "!" | "#" | "$" | "%" | "&" | "+" | "," | "-" | "." | "/" | ":" | ";" | "<" | "=" | ">" | "?" | "@" | "[" | "\\" | "]" | "^" | "_" | "{" | "|" | "}" | "~" .
|
||||
not_paren_star_special = not_paren_star_quote_special | "\"\"" .
|
||||
not_quote = not_paren_star_quote_special | letter | digit | "(" | ")" | "*" .
|
||||
not_rparen_star = not_paren_star | "(" .
|
||||
octet = hex_digit hex_digit .
|
||||
special = not_paren_star_quote_special | "(" | ")" | "*" | "\"\"" .
|
||||
not_rparen_star_then_rparen = not_rparen_star { not_rparen_star } ")" { ")" } .
|
||||
binary_literal = "%" bit { bit } .
|
||||
encoded_string_literal = "\"" encoded_character { encoded_character } "\"" .
|
||||
integer_literal = digits .
|
||||
real_literal = ( digits "." [ digits ] [ "e" [ sign ] digits ] ) | integer_literal .
|
||||
simple_id = letter { letter | digit | "_" } .
|
||||
simple_string_literal = "'" { ( "'" "'" ) | not_quote } "'" .
|
||||
embedded_remark = "(*" [ remark_tag ] { ( not_paren_star { not_paren_star } ) | lparen_then_not_lparen_star | ( "*" { "*" } ) | not_rparen_star_then_rparen | embedded_remark } "*)" .
|
||||
remark = embedded_remark | tail_remark .
|
||||
remark_tag = "\"" remark_ref { "." remark_ref } "\"" .
|
||||
remark_ref = attribute_ref | constant_ref | entity_ref | enumeration_ref | function_ref | parameter_ref | procedure_ref | rule_label_ref | rule_ref | schema_ref | subtype_constraint_ref | type_label_ref | type_ref | variable_ref .
|
||||
tail_remark = "--" [ remark_tag ] .
|
||||
attribute_ref = attribute_id .
|
||||
constant_ref = constant_id .
|
||||
entity_ref = entity_id .
|
||||
enumeration_ref = enumeration_id .
|
||||
function_ref = function_id .
|
||||
parameter_ref = parameter_id .
|
||||
procedure_ref = procedure_id .
|
||||
rule_label_ref = rule_label_id .
|
||||
rule_ref = rule_id .
|
||||
schema_ref = schema_id .
|
||||
subtype_constraint_ref = subtype_constraint_id .
|
||||
type_label_ref = type_label_id .
|
||||
type_ref = type_id .
|
||||
variable_ref = variable_id .
|
||||
abstract_entity_declaration = ABSTRACT .
|
||||
abstract_supertype = ABSTRACT SUPERTYPE ";" .
|
||||
abstract_supertype_declaration = ABSTRACT SUPERTYPE [ subtype_constraint ] .
|
||||
actual_parameter_list = "(" [ parameter ] { "," parameter } ")" .
|
||||
add_like_op = "+" | "-" | OR | XOR .
|
||||
aggregate_initializer = "[" [ element { "," element } ] "]" .
|
||||
aggregate_source = simple_expression .
|
||||
aggregate_type = AGGREGATE [ ":" type_label ] OF parameter_type .
|
||||
aggregation_types = array_type | bag_type | list_type | set_type .
|
||||
algorithm_head = { declaration } [ constant_decl ] [ local_decl ] .
|
||||
alias_stmt = ALIAS variable_id FOR general_ref { qualifier } ";" stmt { stmt } END_ALIAS ";" .
|
||||
array_type = ARRAY bound_spec OF [ OPTIONAL ] [ UNIQUE ] instantiable_type .
|
||||
assignment_stmt = general_ref { qualifier } ":=" expression ";" .
|
||||
attribute_decl = redeclared_attribute | attribute_id .
|
||||
attribute_id = simple_id .
|
||||
attribute_qualifier = "." attribute_ref .
|
||||
bag_type = BAG [ bound_spec ] OF instantiable_type .
|
||||
binary_type = BINARY [ width_spec ] .
|
||||
boolean_type = BOOLEAN .
|
||||
bound_1 = numeric_expression .
|
||||
bound_2 = numeric_expression .
|
||||
bound_spec = "[" bound_1 ":" bound_2 "]" .
|
||||
built_in_constant = CONST_E | PI | SELF | "?" .
|
||||
built_in_function = ABS | ACOS | ASIN | ATAN | BLENGTH | COS | EXISTS | EXP | FORMAT | HIBOUND | HIINDEX | LENGTH | LOBOUND | LOINDEX | LOG | LOG2 | LOG10 | NVL | ODD | ROLESOF | SIN | SIZEOF | SQRT | TAN | TYPEOF | USEDIN | VALUE | VALUE_IN | VALUE_UNIQUE .
|
||||
built_in_procedure = INSERT | REMOVE .
|
||||
case_action = case_label { "," case_label } ":" stmt .
|
||||
case_label = expression .
|
||||
case_stmt = CASE selector OF { case_action } [ OTHERWISE ":" stmt ] END_CASE ";" .
|
||||
compound_stmt = BEGIN stmt { stmt } END ";" .
|
||||
concrete_types = aggregation_types | simple_types | type_ref .
|
||||
constant_body = constant_id ":" instantiable_type ":=" expression ";" .
|
||||
constant_decl = CONSTANT constant_body { constant_body } END_CONSTANT ";" .
|
||||
constant_factor = built_in_constant | constant_ref .
|
||||
constant_id = simple_id .
|
||||
constructed_types = enumeration_type | select_type .
|
||||
declaration = entity_decl | function_decl | procedure_decl | subtype_constraint_decl | type_decl .
|
||||
derived_attr = attribute_decl ":" parameter_type ":=" expression ";" .
|
||||
derive_clause = DERIVE derived_attr { derived_attr } .
|
||||
domain_rule = rule_label_id ":" expression .
|
||||
element = expression [ ":" repetition ] .
|
||||
entity_body = { explicit_attr } [ derive_clause ] [ inverse_clause ] [ unique_clause ] [ where_clause ] .
|
||||
entity_constructor = entity_ref "(" [ expression { "," expression } ] ")" .
|
||||
entity_decl = entity_head entity_body END_ENTITY ";" .
|
||||
entity_head = ENTITY entity_id subsuper ";" .
|
||||
entity_id = simple_id .
|
||||
enumeration_extension = BASED_ON type_ref [ WITH enumeration_items ] .
|
||||
enumeration_id = simple_id .
|
||||
enumeration_items = "(" enumeration_id { "," enumeration_id } ")" .
|
||||
enumeration_reference = [ type_ref "." ] enumeration_ref .
|
||||
enumeration_type = [ EXTENSIBLE ] ENUMERATION [ ( OF enumeration_items ) | enumeration_extension ] .
|
||||
escape_stmt = ESCAPE ";" .
|
||||
explicit_attr = attribute_decl { "," attribute_decl } ":" [ OPTIONAL ] parameter_type ";" .
|
||||
expression = simple_expression [ rel_op_extended simple_expression ] .
|
||||
factor = simple_factor [ "**" simple_factor ] .
|
||||
formal_parameter = parameter_id { "," parameter_id } ":" parameter_type .
|
||||
function_call = ( built_in_function | function_ref ) actual_parameter_list .
|
||||
function_decl = function_head algorithm_head stmt { stmt } END_FUNCTION ";" .
|
||||
function_head = FUNCTION function_id [ "(" formal_parameter { ";" formal_parameter } ")" ] ":" parameter_type ";" .
|
||||
function_id = simple_id .
|
||||
generalized_types = aggregate_type | general_aggregation_types | generic_entity_type | generic_type .
|
||||
general_aggregation_types = general_array_type | general_bag_type | general_list_type | general_set_type .
|
||||
general_array_type = ARRAY [ bound_spec ] OF [ OPTIONAL ] [ UNIQUE ] parameter_type .
|
||||
general_bag_type = BAG [ bound_spec ] OF parameter_type .
|
||||
general_list_type = LIST [ bound_spec ] OF [ UNIQUE ] parameter_type .
|
||||
general_ref = parameter_ref | variable_ref .
|
||||
general_set_type = SET [ bound_spec ] OF parameter_type .
|
||||
generic_entity_type = GENERIC_ENTITY [ ":" type_label ] .
|
||||
generic_type = GENERIC [ ":" type_label ] .
|
||||
group_qualifier = "\\" entity_ref .
|
||||
if_stmt = IF logical_expression THEN stmt { stmt } [ ELSE stmt { stmt } ] END_IF ";" .
|
||||
increment = numeric_expression .
|
||||
increment_control = variable_id ":=" bound_1 TO bound_2 [ BY increment ] .
|
||||
index = numeric_expression .
|
||||
index_1 = index .
|
||||
index_2 = index .
|
||||
index_qualifier = "[" index_1 [ ":" index_2 ] "]" .
|
||||
instantiable_type = concrete_types | entity_ref .
|
||||
integer_type = INTEGER .
|
||||
interface_specification = reference_clause | use_clause .
|
||||
interval = "{" interval_low interval_op interval_item interval_op interval_high "}" .
|
||||
interval_high = simple_expression .
|
||||
interval_item = simple_expression .
|
||||
interval_low = simple_expression .
|
||||
interval_op = "<=" | "<" .
|
||||
inverse_attr = attribute_decl ":" [ ( SET | BAG ) [ bound_spec ] OF ] entity_ref FOR [ entity_ref "." ] attribute_ref ";" .
|
||||
inverse_clause = INVERSE inverse_attr { inverse_attr } .
|
||||
list_type = LIST [ bound_spec ] OF [ UNIQUE ] instantiable_type .
|
||||
literal = binary_literal | logical_literal | real_literal | string_literal .
|
||||
local_decl = LOCAL local_variable { local_variable } END_LOCAL ";" .
|
||||
local_variable = variable_id { "," variable_id } ":" parameter_type [ ":=" expression ] ";" .
|
||||
logical_expression = expression .
|
||||
logical_literal = FALSE | TRUE | UNKNOWN .
|
||||
logical_type = LOGICAL .
|
||||
multiplication_like_op = "*" | "/" | DIV | MOD | AND | "||" .
|
||||
named_types = entity_ref | type_ref .
|
||||
named_type_or_rename = named_types [ AS ( entity_id | type_id ) ] .
|
||||
null_stmt = ";" .
|
||||
number_type = NUMBER .
|
||||
numeric_expression = simple_expression .
|
||||
one_of = ONEOF "(" supertype_expression { "," supertype_expression } ")" .
|
||||
parameter = expression .
|
||||
parameter_id = simple_id .
|
||||
parameter_type = generalized_types | simple_types | named_types .
|
||||
population = entity_ref .
|
||||
precision_spec = numeric_expression .
|
||||
primary = literal | ( qualifiable_factor { qualifier } ) .
|
||||
procedure_call_stmt = ( built_in_procedure | procedure_ref ) actual_parameter_list ";" .
|
||||
procedure_decl = procedure_head algorithm_head { stmt } END_PROCEDURE ";" .
|
||||
procedure_head = PROCEDURE procedure_id [ "(" [ VAR ] formal_parameter { ";" [ VAR ] formal_parameter } ")" ] ";" .
|
||||
procedure_id = simple_id .
|
||||
qualifiable_factor = function_call | attribute_ref | constant_factor | general_ref | population .
|
||||
qualified_attribute = SELF group_qualifier attribute_qualifier .
|
||||
qualifier = attribute_qualifier | group_qualifier | index_qualifier .
|
||||
query_expression = QUERY "(" variable_id "<*" aggregate_source "|" logical_expression ")" .
|
||||
real_type = REAL [ "(" precision_spec ")" ] .
|
||||
redeclared_attribute = qualified_attribute [ RENAMED attribute_id ] .
|
||||
referenced_attribute = attribute_ref | qualified_attribute .
|
||||
reference_clause = REFERENCE FROM schema_ref [ "(" resource_or_rename { "," resource_or_rename } ")" ] ";" .
|
||||
rel_op = "<=" | ">=" | "<>" | "=" | ":<>:" | ":=:" | "<" | ">" .
|
||||
rel_op_extended = rel_op | IN | LIKE .
|
||||
rename_id = constant_id | entity_id | function_id | procedure_id | type_id .
|
||||
repeat_control = [ increment_control ] [ while_control ] [ until_control ] .
|
||||
repeat_stmt = REPEAT repeat_control ";" stmt { stmt } END_REPEAT ";" .
|
||||
repetition = numeric_expression .
|
||||
resource_or_rename = resource_ref [ AS rename_id ] .
|
||||
resource_ref = constant_ref | entity_ref | function_ref | procedure_ref | type_ref .
|
||||
return_stmt = RETURN [ "(" expression ")" ] ";" .
|
||||
rule_decl = rule_head algorithm_head { stmt } where_clause END_RULE ";" .
|
||||
rule_head = RULE rule_id FOR "(" entity_ref { "," entity_ref } ")" ";" .
|
||||
rule_id = simple_id .
|
||||
rule_label_id = simple_id .
|
||||
schema_body = { interface_specification } [ constant_decl ] { declaration | rule_decl } .
|
||||
schema_decl = SCHEMA schema_id [ schema_version_id ] ";" schema_body END_SCHEMA ";" .
|
||||
schema_id = simple_id .
|
||||
schema_version_id = string_literal .
|
||||
selector = expression .
|
||||
select_extension = BASED_ON type_ref [ WITH select_list ] .
|
||||
select_list = "(" named_types { "," named_types } ")" .
|
||||
select_type = [ EXTENSIBLE [ GENERIC_ENTITY ] ] SELECT [ select_list | select_extension ] .
|
||||
set_type = SET [ bound_spec ] OF instantiable_type .
|
||||
sign = "+" | "-" .
|
||||
simple_expression = term { add_like_op term } .
|
||||
simple_factor = aggregate_initializer | interval | query_expression | ( [ unary_op ] ( "(" expression ")" | primary ) ) | entity_constructor | enumeration_reference .
|
||||
simple_types = binary_type | boolean_type | integer_type | logical_type | number_type | real_type | string_type .
|
||||
skip_stmt = SKIP ";" .
|
||||
stmt = alias_stmt | assignment_stmt | case_stmt | compound_stmt | escape_stmt | if_stmt | null_stmt | procedure_call_stmt | repeat_stmt | return_stmt | skip_stmt .
|
||||
string_literal = simple_string_literal | encoded_string_literal .
|
||||
string_type = STRING [ width_spec ] .
|
||||
subsuper = [ supertype_constraint ] [ subtype_declaration ] .
|
||||
subtype_constraint = OF "(" supertype_expression ")" .
|
||||
subtype_constraint_body = [ abstract_supertype ] [ total_over ] [ supertype_expression ";" ] .
|
||||
subtype_constraint_decl = subtype_constraint_head subtype_constraint_body END_SUBTYPE_CONSTRAINT ";" .
|
||||
subtype_constraint_head = SUBTYPE_CONSTRAINT subtype_constraint_id FOR entity_ref ";" .
|
||||
subtype_constraint_id = simple_id .
|
||||
subtype_declaration = SUBTYPE OF "(" entity_ref { "," entity_ref } ")" .
|
||||
supertype_constraint = abstract_supertype_declaration | abstract_entity_declaration | supertype_rule .
|
||||
supertype_expression = supertype_factor { ANDOR supertype_factor } .
|
||||
supertype_factor = supertype_term { AND supertype_term } .
|
||||
supertype_rule = SUPERTYPE subtype_constraint .
|
||||
supertype_term = one_of | "(" supertype_expression ")" | entity_ref .
|
||||
syntax = schema_decl { schema_decl } .
|
||||
term = factor { multiplication_like_op factor } .
|
||||
total_over = TOTAL_OVER "(" entity_ref { "," entity_ref } ")" ";" .
|
||||
type_decl = TYPE type_id "=" underlying_type ";" [ where_clause ] END_TYPE ";" .
|
||||
type_id = simple_id .
|
||||
type_label = type_label_id | type_label_ref .
|
||||
type_label_id = simple_id .
|
||||
unary_op = "+" | "-" | NOT .
|
||||
underlying_type = constructed_types | concrete_types .
|
||||
unique_clause = UNIQUE unique_rule ";" { unique_rule ";" } .
|
||||
unique_rule = rule_label_id ":" referenced_attribute { "," referenced_attribute } .
|
||||
until_control = UNTIL logical_expression .
|
||||
use_clause = USE FROM schema_ref [ "(" named_type_or_rename { "," named_type_or_rename } ")" ] ";" .
|
||||
variable_id = simple_id .
|
||||
where_clause = WHERE domain_rule ";" { domain_rule ";" } .
|
||||
while_control = WHILE logical_expression .
|
||||
width = numeric_expression .
|
||||
width_spec = "(" width ")" [ FIXED ] .
|
||||
@@ -0,0 +1,129 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# 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 templates
|
||||
import documentation
|
||||
|
||||
class Header:
|
||||
def __init__(self, mapping):
|
||||
declarations = []
|
||||
|
||||
write = lambda str, **kwargs: declarations.append(str%dict({
|
||||
'documentation': templates.multi_line_comment(documentation.description(kwargs['name']))}, **kwargs))
|
||||
|
||||
forward_names = list(mapping.schema.entities.keys()) + list(mapping.schema.simpletypes.keys())
|
||||
forward_definitions = "".join(["class %s; "%n for n in forward_names])
|
||||
|
||||
for name, type in mapping.schema.selects.items():
|
||||
write(templates.select, name=name)
|
||||
|
||||
for name, type in mapping.schema.enumerations.items():
|
||||
short_name = name[:-4] if name.endswith("Enum") else name
|
||||
write(templates.enumeration, name=name, values=", ".join(["%s_%s"%(short_name, v) for v in type.values]))
|
||||
|
||||
emitted_simpletypes = set()
|
||||
while len(emitted_simpletypes) < len(mapping.schema.simpletypes):
|
||||
for name, type in mapping.schema.simpletypes.items():
|
||||
if name in emitted_simpletypes: continue
|
||||
type_str = mapping.make_type_string(mapping.flatten_type_string(type))
|
||||
attr_type = mapping.make_argument_type(type)
|
||||
superclass = mapping.simple_type_parent(name)
|
||||
if superclass is None:
|
||||
superclass = "IfcUtil::IfcBaseType"
|
||||
elif superclass not in emitted_simpletypes:
|
||||
continue
|
||||
emitted_simpletypes.add(name)
|
||||
write(templates.simpletype, name=name, type=type_str, attr_type=attr_type, superclass=superclass)
|
||||
|
||||
class_definitions = []
|
||||
|
||||
write = lambda str, **kwargs: class_definitions.append(str%dict({
|
||||
'documentation': templates.multi_line_comment(documentation.description(kwargs['name']))}, **kwargs))
|
||||
|
||||
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:
|
||||
attr_lines = []
|
||||
def write_method(attr):
|
||||
attr_lines.extend(["/// %s"%d for d in documentation.description((name, attr.name))])
|
||||
type_str = mapping.get_parameter_type(attr, allow_optional=True, allow_entities=True)
|
||||
if mapping.make_argument_type(attr) != "IfcUtil::Argument_UNKNOWN":
|
||||
attr_lines.append("%s %s() const;"%(type_str, attr.name))
|
||||
attr_lines.append("void %s(%s v);"%(attr.name, type_str))
|
||||
|
||||
[write_method(attr) for attr in type.attributes]
|
||||
|
||||
inv_lines = []
|
||||
def write_inverse(attr):
|
||||
inv_lines.append(templates.inverse_attr%{'name':attr.name, 'entity':attr.entity, 'attribute':attr.attribute})
|
||||
|
||||
if type.inverse:
|
||||
[write_inverse(attr) for attr in type.inverse.elements]
|
||||
|
||||
attributes = "\n".join(["%s%s"%(' '*4, a) for a in attr_lines])
|
||||
if len(attributes): attributes += '\n'
|
||||
|
||||
inverse = "\n".join(["%s%s"%(' '*4, a) for a in inv_lines])
|
||||
if len(inverse): inverse += '\n'
|
||||
|
||||
supertypes = type.supertypes if len(type.supertypes) else ['IfcUtil::IfcBaseEntity']
|
||||
superclass = ": %s "%(", ".join(["public %s"%c for c in supertypes]))
|
||||
|
||||
argument_count = mapping.argument_count(type)
|
||||
|
||||
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 = 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 = argument_type_function_body_switch_stmt + argument_type_function_body_tail
|
||||
|
||||
argument_entity_function_body_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return %s; '%(i+argument_start, mapping.make_argument_entity(attr)) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
|
||||
argument_entity_function_body_tail = (" return %s::getArgumentEntity(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcException("argument out of range"); '
|
||||
|
||||
argument_entity_function_body = 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))
|
||||
|
||||
write(templates.entity, **locals())
|
||||
emitted_entities.add(name)
|
||||
|
||||
self.str = templates.header % {
|
||||
'schema_name_upper' : mapping.schema.name.upper(),
|
||||
'schema_name' : mapping.schema.name.capitalize(),
|
||||
'declarations' : ''.join(declarations),
|
||||
'forward_definitions' : forward_definitions,
|
||||
'class_definitions' : ''.join(class_definitions)
|
||||
}
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
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()
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# 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 templates
|
||||
|
||||
class Implementation:
|
||||
def __init__(self, mapping):
|
||||
enumeration_functions = []
|
||||
entity_implementations = []
|
||||
schema_entity_statements = []
|
||||
|
||||
schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
stringify = lambda s: '"%s"'%s
|
||||
cat = lambda vs: "".join(vs)
|
||||
catc = lambda vs: ", ".join(vs)
|
||||
catnl = lambda vs: "\n".join(vs)
|
||||
cator = lambda vs: " || ".join(vs)
|
||||
nl = lambda s: "%s\n"%s if len(s) else s
|
||||
|
||||
write = lambda str, **kwargs: enumeration_functions.append(str%kwargs)
|
||||
|
||||
for name, enum in mapping.schema.enumerations.items():
|
||||
short_name = name[:-4] if name.endswith("Enum") else name
|
||||
context = locals()
|
||||
write(
|
||||
templates.enumeration_function,
|
||||
max_id = len(enum.values),
|
||||
name = name,
|
||||
values = catc(map(stringify, enum.values)),
|
||||
from_string_statements = catnl(templates.enum_from_string_stmt%dict(context,**locals()) for value in enum.values)
|
||||
)
|
||||
|
||||
write = lambda str, **kwargs: entity_implementations.append(str%kwargs)
|
||||
|
||||
for name, type in mapping.schema.entities.items():
|
||||
parent_type_test = "" if not type.supertypes or len(type.supertypes) != 1 \
|
||||
else templates.parent_type_test%(type.supertypes[0])
|
||||
constructor_arguments = mapping.get_assignable_arguments(type, include_derived = True)
|
||||
constructor_arguments_str = catc("%(full_type)s v%(index)d_%(name)s"%a for a in constructor_arguments if not a['is_derived'])
|
||||
attributes = []
|
||||
constructor_implementations = []
|
||||
write_attr = lambda str, **kwargs: attributes.append(str%kwargs)
|
||||
for arg in constructor_arguments:
|
||||
if not arg['is_inherited'] and not arg['is_derived']:
|
||||
|
||||
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_optional']:
|
||||
if arg['is_enum']: return templates.get_attr_stmt_optional_enum
|
||||
elif arg['is_nested']: return templates.get_attr_stmt_optional_nested_array
|
||||
elif arg['is_array'] and not (select or simple or express): return templates.get_attr_stmt_optional_array
|
||||
elif arg['non_optional_type'].endswith('*'): return templates.get_attr_stmt_optional_entity
|
||||
else: return templates.get_attr_stmt_generic
|
||||
else:
|
||||
if arg['is_enum']: return templates.get_attr_stmt_enum
|
||||
elif arg['is_nested']: return templates.get_attr_stmt_nested_array
|
||||
elif arg['is_array'] and not (select or simple or express): return templates.get_attr_stmt_array
|
||||
elif arg['non_optional_type'].endswith('*'): return templates.get_attr_stmt_entity
|
||||
else: return templates.get_attr_stmt_generic
|
||||
|
||||
tmpl = find_template(arg)
|
||||
write_attr(
|
||||
templates.const_function,
|
||||
class_name = name,
|
||||
name = arg['name'],
|
||||
arguments = '',
|
||||
return_type = arg['full_type'],
|
||||
body = tmpl % {'index': arg['index']-1,
|
||||
'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_optional']:
|
||||
if arg['is_enum']: return templates.set_attr_stmt_optional_enum
|
||||
elif arg['is_array'] and not (select or simple or express): return templates.set_attr_stmt_optional_array
|
||||
else: return templates.set_attr_stmt_optional_generic
|
||||
else:
|
||||
if arg['is_enum']: return templates.set_attr_stmt_enum
|
||||
elif arg['is_array'] and not (select or simple or express): return templates.set_attr_stmt_array
|
||||
else: return templates.set_attr_stmt_generic
|
||||
|
||||
tmpl = find_template(arg)
|
||||
write_attr(
|
||||
templates.function,
|
||||
class_name = name,
|
||||
name = arg['name'],
|
||||
arguments = '%s v'%arg['full_type'],
|
||||
return_type = 'void',
|
||||
body = tmpl % {'index': arg['index']-1,
|
||||
'type' : arg['non_optional_type'].split('::')[0]}
|
||||
)
|
||||
|
||||
if arg['is_derived']:
|
||||
constructor_implementations.append(templates.constructor_stmt_derived % {'index' : arg['index']-1})
|
||||
else:
|
||||
arg_name = "v%(index)d_%(name)s"%arg
|
||||
deref_name = ("*%s"%arg_name) if arg['is_optional'] else arg_name
|
||||
|
||||
tmpl = templates.constructor_stmt_array if arg['is_templated_list'] \
|
||||
else templates.constructor_stmt_enum if arg['is_enum'] \
|
||||
else templates.constructor_stmt
|
||||
impl = tmpl % {'name' : deref_name,
|
||||
'index' : arg['index']-1,
|
||||
'type' : arg['non_optional_type'].split('::')[0]}
|
||||
if arg['is_optional']:
|
||||
impl = templates.constructor_stmt_optional%{'name' : arg_name,
|
||||
'index' : arg['index']-1,
|
||||
'stmt' : impl}
|
||||
constructor_implementations.append(impl)
|
||||
|
||||
def get_attribute_index(entity, attr_name):
|
||||
related_entity = mapping.schema.entities[entity]
|
||||
return [a['name'] for a in mapping.get_assignable_arguments(related_entity, include_derived=True)].index(attr_name)
|
||||
|
||||
inverse = [templates.const_function % {
|
||||
'class_name' : name,
|
||||
'name' : i.name,
|
||||
'arguments' : '',
|
||||
'return_type' : '%s::list::ptr' % i.entity,
|
||||
'body' : templates.get_inverse % {'type': i.entity, 'index':get_attribute_index(i.entity, i.attribute)}
|
||||
} for i in (type.inverse.elements if type.inverse else [])]
|
||||
|
||||
superclass = "%s((IfcAbstractEntity*)0)" % type.supertypes[0] if len(type.supertypes) == 1 else 'IfcUtil::IfcBaseEntity()'
|
||||
|
||||
write(
|
||||
templates.entity_implementation,
|
||||
name = name,
|
||||
parent_type_test = parent_type_test,
|
||||
constructor_arguments = constructor_arguments_str,
|
||||
constructor_implementation = cat(constructor_implementations),
|
||||
attributes = nl(catnl(attributes)),
|
||||
inverse = nl(catnl(inverse)),
|
||||
superclass = superclass
|
||||
)
|
||||
|
||||
selectable_simple_types = sorted(set(sum([b.values for a,b in mapping.schema.selects.items()], [])) & set(mapping.schema.types.keys()))
|
||||
schema_entity_statements += [templates.schema_entity_stmt%locals() for name, type in mapping.schema.simpletypes.items()]
|
||||
schema_entity_statements += [templates.schema_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()]))
|
||||
max_len = max(map(len, enumerable_types))
|
||||
type_name_strings = catc(map(stringify, enumerable_types))
|
||||
string_map_statements = [templates.string_map_statement % {
|
||||
'uppercase_name' : name.upper(),
|
||||
'name' : name,
|
||||
'padding' : ' ' * (max_len - len(name))
|
||||
} for name in enumerable_types]
|
||||
|
||||
parent_type_statements = [templates.parent_type_stmt % {
|
||||
'name' : name,
|
||||
'parent' : type.supertypes[0],
|
||||
'padding' : ' ' * (max_len - len(name))
|
||||
} for name, type in mapping.schema.entities.items() if type.supertypes and len(type.supertypes) == 1]
|
||||
|
||||
max_id = len(enumerable_types)
|
||||
|
||||
simple_type_statements = cator("v == Type::%s"%name for name in selectable_simple_types)
|
||||
|
||||
simple_type_impl = []
|
||||
for class_name, type in mapping.schema.simpletypes.items():
|
||||
type_str = mapping.make_type_string(mapping.flatten_type_string(type))
|
||||
attr_type = mapping.make_argument_type(type)
|
||||
superclass = mapping.simple_type_parent(class_name)
|
||||
|
||||
simpletype_impl_is = templates.simpletype_impl_is_with_supertype if superclass \
|
||||
else templates.simpletype_impl_is_without_supertype
|
||||
|
||||
constructor = templates.constructor_single_initlist if superclass \
|
||||
else templates.constructor
|
||||
|
||||
def compose(params):
|
||||
class_name, attr_type, superclass, superclass_init, name, tmpl, return_type, args, body = params
|
||||
arguments = ",".join(args)
|
||||
body = body % locals()
|
||||
return tmpl % locals()
|
||||
|
||||
simple_type_impl.append(templates.simpletype_impl_comment % {'name': class_name})
|
||||
simple_type_impl.extend(map(compose, map(lambda x: (class_name, attr_type, superclass, "(IfcAbstractEntity*)0")+x, (
|
||||
('getArgumentType', templates.const_function, 'IfcUtil::ArgumentType', ('unsigned int i',), templates.simpletype_impl_argument_type ),
|
||||
('getArgument', templates.const_function, 'Argument*', ('unsigned int i',), templates.simpletype_impl_argument ),
|
||||
('is', templates.const_function, 'bool', ('Type::Enum v',), simpletype_impl_is ),
|
||||
('type', templates.const_function, 'Type::Enum', (), templates.simpletype_impl_type ),
|
||||
('Class', templates.function, 'Type::Enum', (), templates.simpletype_impl_class ),
|
||||
('', constructor, '', ('IfcAbstractEntity* e',), templates.simpletype_impl_explicit_constructor),
|
||||
('', constructor, '', ("%s v" % type_str,), templates.simpletype_impl_constructor ),
|
||||
('', templates.cast_function, type_str, (), templates.simpletype_impl_cast )
|
||||
))))
|
||||
simple_type_impl.append('')
|
||||
|
||||
self.str = templates.implementation % {
|
||||
'schema_name_upper' : mapping.schema.name.upper(),
|
||||
'schema_name' : mapping.schema.name.capitalize(),
|
||||
'max_id' : max_id,
|
||||
'enumeration_functions' : cat(enumeration_functions),
|
||||
'schema_entity_statements' : catnl(schema_entity_statements),
|
||||
'type_name_strings' : type_name_strings,
|
||||
'string_map_statements' : catnl(string_map_statements),
|
||||
'simple_type_statement' : simple_type_statements,
|
||||
'parent_type_statements' : catnl(parent_type_statements),
|
||||
'entity_implementations' : catnl(entity_implementations),
|
||||
'simple_type_impl' : catnl(simple_type_impl)
|
||||
}
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
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()
|
||||
|
||||
@@ -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/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
import templates
|
||||
|
||||
class LateBoundHeader:
|
||||
def __init__(self, mapping):
|
||||
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()
|
||||
def __repr__(self):
|
||||
return self.str
|
||||
def emit(self):
|
||||
f = open('%s-latebound.h'%self.schema_name, 'w', encoding='utf-8')
|
||||
f.write(str(self))
|
||||
f.close()
|
||||
@@ -0,0 +1,119 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# 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 templates
|
||||
|
||||
class LateBoundImplementation:
|
||||
def __init__(self, mapping):
|
||||
schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
entity_descriptors = []
|
||||
enumeration_descriptors = []
|
||||
derived_field_statements = []
|
||||
inverse_implementations = []
|
||||
|
||||
for name, type in mapping.schema.simpletypes.items():
|
||||
entity_descriptors.append(templates.entity_descriptor % {
|
||||
'type' : name,
|
||||
'parent_statement' : '0',
|
||||
'entity_descriptor_attributes' : templates.entity_descriptor_attribute_without_entity % {
|
||||
'name' : 'wrappedValue',
|
||||
'optional' : 'false',
|
||||
'type' : mapping.make_argument_type(mapping.schema.types[name].type)
|
||||
}
|
||||
})
|
||||
|
||||
emitted_entities = set()
|
||||
entities_to_emit = mapping.schema.entities.keys()
|
||||
while len(emitted_entities) < len(mapping.schema.entities):
|
||||
for name, type in mapping.schema.entities.items():
|
||||
if name in emitted_entities: continue
|
||||
if len(type.supertypes) == 0 or set(type.supertypes) < emitted_entities:
|
||||
constructor_arguments = mapping.get_assignable_arguments(type, include_derived = True)
|
||||
entity_descriptor_attributes = []
|
||||
for arg in constructor_arguments:
|
||||
if not arg['is_inherited']:
|
||||
is_enumeration = arg['argument_type_enum'] == 'IfcUtil::Argument_ENUMERATION'
|
||||
tmpl = templates.entity_descriptor_attribute_with_entity
|
||||
entity_name = arg['argument_type'] if is_enumeration else arg['argument_entity'].split('::')[1]
|
||||
entity_descriptor_attributes.append(tmpl % {
|
||||
'name' : arg['name'],
|
||||
'optional' : 'true' if arg['is_optional'] else 'false',
|
||||
'type' : arg['argument_type_enum'],
|
||||
'entity_name': entity_name
|
||||
})
|
||||
|
||||
emitted_entities.add(name)
|
||||
parent_statement = '0' if len(type.supertypes) != 1 else templates.entity_descriptor_parent % {
|
||||
'type' : type.supertypes[0]
|
||||
}
|
||||
entity_descriptors.append(templates.entity_descriptor % {
|
||||
'type' : name,
|
||||
'parent_statement' : parent_statement,
|
||||
'entity_descriptor_attributes' : '\n'.join(entity_descriptor_attributes)
|
||||
})
|
||||
|
||||
for name, enum in mapping.schema.enumerations.items():
|
||||
enumeration_descriptor_values = '\n'.join([templates.enumeration_descriptor_value % {
|
||||
'name' : v
|
||||
} for v in enum.values])
|
||||
enumeration_descriptors.append(templates.enumeration_descriptor % {
|
||||
'type' : name,
|
||||
'enumeration_descriptor_values' : enumeration_descriptor_values
|
||||
})
|
||||
|
||||
for name, type in mapping.schema.entities.items():
|
||||
constructor_arguments = mapping.get_assignable_arguments(type, include_derived = True)
|
||||
statements = ''.join(templates.derived_field_statement_attrs % (a['index']-1) for a in constructor_arguments if a['is_derived'])
|
||||
if len(statements):
|
||||
derived_field_statements.append(templates.derived_field_statement % {
|
||||
'type' : name,
|
||||
'statements' : statements
|
||||
})
|
||||
|
||||
for name, type in mapping.schema.entities.items():
|
||||
if type.inverse:
|
||||
for attr in type.inverse.elements:
|
||||
related_entity = mapping.schema.entities[attr.entity]
|
||||
related_attrs = [a['name'] for a in mapping.get_assignable_arguments(related_entity, include_derived=True)]
|
||||
|
||||
inverse_implementations.append(templates.inverse_implementation % {
|
||||
'type' : name,
|
||||
'name' : attr.name,
|
||||
'related_type' : attr.entity,
|
||||
'index' : related_attrs.index(attr.attribute)
|
||||
})
|
||||
|
||||
self.str = templates.lb_implementation % {
|
||||
'schema_name_upper' : mapping.schema.name.upper(),
|
||||
'schema_name' : mapping.schema.name.capitalize(),
|
||||
'entity_descriptors' : '\n'.join(entity_descriptors),
|
||||
'enumeration_descriptors' : '\n'.join(enumeration_descriptors),
|
||||
'derived_field_statements' : '\n'.join(derived_field_statements),
|
||||
'inverse_implementations' : '\n'.join(inverse_implementations)
|
||||
}
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
def __repr__(self):
|
||||
return self.str
|
||||
def emit(self):
|
||||
f = open('%s-latebound.cpp'%self.schema_name, 'w', encoding='utf-8')
|
||||
f.write(str(self))
|
||||
f.close()
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# 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 nodes
|
||||
import templates
|
||||
|
||||
class Mapping:
|
||||
|
||||
express_to_cpp_typemapping = {
|
||||
'boolean' : 'bool',
|
||||
'logical' : 'bool',
|
||||
'integer' : 'int',
|
||||
'real' : 'double',
|
||||
'number' : 'double',
|
||||
'string' : 'std::string'
|
||||
}
|
||||
|
||||
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 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)
|
||||
else:
|
||||
is_list = self.schema.is_entity(type.type)
|
||||
is_nested_list = isinstance(type.type, nodes.AggregationType)
|
||||
tmpl = templates.list_list_type if is_nested_list else templates.list_type if is_list else templates.array_type
|
||||
return tmpl % {
|
||||
'instance_type' : self.make_type_string(type.type),
|
||||
'lower' : type.bounds.lower,
|
||||
'upper' : type.bounds.upper,
|
||||
}
|
||||
|
||||
def is_array(self, type):
|
||||
if isinstance(type, nodes.AggregationType):
|
||||
return True
|
||||
elif isinstance(type, str) and self.schema.is_type(type):
|
||||
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 type in self.express_to_cpp_typemapping or isinstance(type, nodes.BinaryType): 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)
|
||||
elif isinstance(type, nodes.BinaryType):
|
||||
return "UNKNOWN"
|
||||
elif isinstance(type, nodes.EnumerationType):
|
||||
return "ENUMERATION"
|
||||
elif isinstance(type, nodes.SelectType):
|
||||
return "ENTITY"
|
||||
elif isinstance(type, nodes.AggregationType):
|
||||
ty = _make_argument_type(type.type)
|
||||
if ty == "UNKNOWN": return "UNKNOWN"
|
||||
return "%s_LIST"%ty if ty.startswith("ENTITY") else ("VECTOR_%s"%ty)
|
||||
else: raise ValueError
|
||||
supported = {'INT', 'BOOL', 'DOUBLE', 'STRING', 'VECTOR_INT', 'VECTOR_DOUBLE', 'VECTOR_STRING', 'ENTITY', 'ENTITY_LIST', 'ENTITY_LIST_LIST', 'ENUMERATION'}
|
||||
ty = _make_argument_type(attr.type if hasattr(attr, 'type') else attr)
|
||||
if ty not in supported: ty = 'UNKNOWN'
|
||||
return "IfcUtil::Argument_%s" % ty
|
||||
|
||||
def get_type_dep(self, type):
|
||||
if isinstance(type, str):
|
||||
return self.express_to_cpp_typemapping.get(type, type)
|
||||
else:
|
||||
return self.get_type_dep(type.type)
|
||||
|
||||
def get_parameter_type(self, attr, allow_optional, allow_entities, allow_pointer = True):
|
||||
|
||||
attr_type = self.flatten_type(attr.type)
|
||||
type_str = self.express_to_cpp_typemapping.get(str(attr_type), attr_type)
|
||||
|
||||
if self.schema.is_enumeration(attr_type):
|
||||
type_str = '%s::%s'%(attr_type, attr_type)
|
||||
elif isinstance(type_str, nodes.AggregationType):
|
||||
is_nested_list = isinstance(attr_type.type, nodes.AggregationType)
|
||||
ty = self.get_parameter_type(attr_type.type if is_nested_list else attr_type, False, allow_entities, False)
|
||||
if True and 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 % {
|
||||
'instance_type' : ty,
|
||||
'lower' : attr_type.bounds.lower,
|
||||
'upper' : attr_type.bounds.upper
|
||||
}
|
||||
else:
|
||||
tmpl = templates.list_list_type if is_nested_list else templates.list_type
|
||||
type_str = tmpl % {
|
||||
'instance_type': ty
|
||||
}
|
||||
elif allow_pointer and (self.schema.is_entity(type_str) or self.schema.is_select(type_str)):
|
||||
type_str += '*'
|
||||
elif not allow_pointer and self.schema.is_select(type_str):
|
||||
type_str = "IfcUtil::IfcBaseClass*"
|
||||
if allow_optional and attr.optional:# and not is_ptr:
|
||||
type_str = "boost::optional< %s >"%type_str
|
||||
return type_str
|
||||
|
||||
def argument_count(self, t):
|
||||
c = sum([self.argument_count(self.schema.entities[s]) for s in t.supertypes])
|
||||
return c + len(t.attributes)
|
||||
|
||||
def arguments(self, t):
|
||||
c = sum([self.arguments(self.schema.entities[s]) for s in t.supertypes], [])
|
||||
return c + t.attributes
|
||||
|
||||
def derived_in_supertype(self, t):
|
||||
c = sum([self.derived_in_supertype(self.schema.entities[s]) for s in t.supertypes], [])
|
||||
return c + ([str(s) for s in t.derive.elements] if t.derive else [])
|
||||
|
||||
def list_instance_type(self, attr):
|
||||
f = lambda v : 'IfcUtil::IfcBaseClass' if self.schema.is_select(v) else v
|
||||
if self.is_array(attr.type):
|
||||
if not isinstance(attr.type, str) and self.is_array(attr.type.type):
|
||||
if isinstance(attr.type.type, str):
|
||||
return f(attr.type.type)
|
||||
else: return f(attr.type.type.type)
|
||||
else:
|
||||
if isinstance(attr.type, str):
|
||||
return f(attr.type)
|
||||
else: return f(attr.type.type)
|
||||
return None
|
||||
|
||||
def is_templated_list(self, attr):
|
||||
ty = self.list_instance_type(attr)
|
||||
arr = self.is_array(attr.type)
|
||||
simple = self.schema.is_simpletype(ty)
|
||||
express = 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):
|
||||
count = self.argument_count(t)
|
||||
num_inherited = count - len(t.attributes)
|
||||
derived = set(self.derived_in_supertype(t))
|
||||
attrs = enumerate(self.arguments(t))
|
||||
|
||||
def include(attr):
|
||||
not_derived = include_derived or (attr.name not in derived)
|
||||
supported = self.make_argument_type(attr) != "IfcUtil::Argument_UNKNOWN"
|
||||
return not_derived and supported
|
||||
|
||||
return [{
|
||||
'index' : i+1,
|
||||
'name' : attr.name,
|
||||
'full_type' : self.get_parameter_type(attr, allow_optional=True, allow_entities=True),
|
||||
'specialized_type' : self.get_parameter_type(attr, allow_optional=True, allow_entities=False),
|
||||
'non_optional_type' : self.get_parameter_type(attr, allow_optional=False, allow_entities=False),
|
||||
'list_instance_type' : self.list_instance_type(attr),
|
||||
'is_optional' : attr.optional,
|
||||
'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)]
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# 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
|
||||
import collections
|
||||
|
||||
class Node:
|
||||
def __init__(self, tokens):
|
||||
self.tokens = tokens
|
||||
self.init()
|
||||
def tokens_of_type(self, cls):
|
||||
return [t for t in self.tokens if isinstance(t, cls)]
|
||||
def single_token_of_type(self, cls, k = None, v = None):
|
||||
ts = [t for t in self.tokens if isinstance(t, cls) and (k is None or getattr(t, k) == v)]
|
||||
return ts[0] if len(ts) == 1 else None
|
||||
|
||||
|
||||
class TypeDeclaration(Node):
|
||||
name = property(lambda self: self.tokens[1])
|
||||
type = property(lambda self: self.tokens[3])
|
||||
def init(self):
|
||||
assert self.tokens[0] == 'type'
|
||||
assert isinstance(self.type, UnderlyingType)
|
||||
def __repr__(self):
|
||||
return "%s = TypeDeclaration(%s)" % (self.name, self.type)
|
||||
|
||||
|
||||
class EntityDeclaration(Node):
|
||||
name = property(lambda self: self.tokens[1])
|
||||
attributes = property(lambda self: self.tokens_of_type(ExplicitAttribute))
|
||||
def init(self):
|
||||
assert self.tokens[0] == 'entity'
|
||||
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)
|
||||
if len(self.supertypes):
|
||||
builder += "\n Supertypes: %s"%(",".join(self.supertypes))
|
||||
if len(self.attributes):
|
||||
builder += "\n Attributes: %s"%("".join(["\n %s"%a for a in self.attributes]))
|
||||
if self.derive:
|
||||
builder += "\n Derive:"
|
||||
builder += str(self.derive)
|
||||
if self.inverse:
|
||||
builder += "\n Inverse:"
|
||||
builder += str(self.inverse)
|
||||
builder += "\n"
|
||||
return builder
|
||||
|
||||
|
||||
class UnderlyingType(Node):
|
||||
type = property(lambda self: self.tokens[0])
|
||||
def init(self):
|
||||
pass
|
||||
def __repr__(self):
|
||||
return repr(self.type)
|
||||
|
||||
|
||||
class EnumerationType(Node):
|
||||
type = property(lambda self: self.tokens[0])
|
||||
values = property(lambda self: self.tokens[3::2])
|
||||
def init(self):
|
||||
assert self.type == 'enumeration'
|
||||
def __repr__(self):
|
||||
return ",".join(self.values)
|
||||
|
||||
|
||||
class AggregationType(Node):
|
||||
aggregate_type = property(lambda self: self.tokens[0])
|
||||
bounds = property(lambda self: None if self.tokens[1] == 'of' else self.tokens[1])
|
||||
type = property(lambda self: self.tokens[-1])
|
||||
def init(self):
|
||||
assert self.bounds is None or isinstance(self.bounds, BoundSpecification)
|
||||
def __repr__(self):
|
||||
return "%s%s of %s"%(self.aggregate_type, self.bounds, self.type)
|
||||
|
||||
|
||||
class SelectType(Node):
|
||||
type = property(lambda self: self.tokens[0])
|
||||
values = property(lambda self: self.tokens[2::2])
|
||||
def init(self):
|
||||
assert self.type == 'select'
|
||||
def __repr__(self):
|
||||
return ",".join(self.values)
|
||||
|
||||
|
||||
class SubSuperTypeExpression(Node):
|
||||
type = property(lambda self: self.tokens[0])
|
||||
types = property(lambda self: self.tokens[3::2])
|
||||
def init(self):
|
||||
assert self.type == self.class_type
|
||||
|
||||
|
||||
class SubtypeExpression(SubSuperTypeExpression):
|
||||
class_type = 'subtype'
|
||||
|
||||
|
||||
class AttributeList(Node):
|
||||
elements = property(lambda self: self.tokens[1:])
|
||||
def __init__(self, ty, toks):
|
||||
self.type = ty
|
||||
Node.__init__(self, toks)
|
||||
def init(self):
|
||||
assert self.type == self.tokens[0]
|
||||
def __repr__(self):
|
||||
return "".join(["\n %s"%s for s in self.elements])
|
||||
|
||||
|
||||
class InverseAttribute(Node):
|
||||
name = property(lambda self: self.tokens[0])
|
||||
type = property(lambda self: self.tokens[2])
|
||||
bounds = property(lambda self: None if len(self.tokens) == 6 else self.tokens[3])
|
||||
entity = property(lambda self: self.tokens[-4])
|
||||
attribute = property(lambda self: self.tokens[-2])
|
||||
def init(self):
|
||||
assert self.bounds is None or isinstance(self.bounds, BoundSpecification)
|
||||
def __repr__(self):
|
||||
return "%s = %s.%s (%s%s)"%(self.name, self.entity, self.attribute, self.type, self.bounds or "")
|
||||
|
||||
|
||||
class DerivedAttribute(Node):
|
||||
def init(self):
|
||||
name_index = list(self.tokens).index(':') - 1
|
||||
self.name = self.tokens[name_index]
|
||||
def __repr__(self):
|
||||
return str(self.name)
|
||||
|
||||
|
||||
class BinaryType(Node):
|
||||
def init(self):
|
||||
pass
|
||||
def __repr__(self):
|
||||
return "BINARY"
|
||||
|
||||
|
||||
class BoundSpecification(Node):
|
||||
lower = property(lambda self: self.tokens[1])
|
||||
upper = property(lambda self: self.tokens[3])
|
||||
def init(self):
|
||||
# assert self.lower in string.digits or self.lower == '?'
|
||||
# assert self.upper in string.digits or self.upper == '?'
|
||||
pass
|
||||
def __repr__(self):
|
||||
return "[%s:%s]"%(self.lower, self.upper)
|
||||
|
||||
|
||||
class ExplicitAttribute(Node):
|
||||
name = property(lambda self: self.tokens[0])
|
||||
type = property(lambda self: self.tokens[-2])
|
||||
optional = property(lambda self: len(self.tokens) == 5 and self.tokens[-3] == 'optional')
|
||||
def init(self):
|
||||
# NB: This assumes a single name per attribute
|
||||
# definition, which is not necessarily the case.
|
||||
assert self.tokens[1] == ':'
|
||||
def __repr__(self):
|
||||
return "%s : %s%s" % (self.name, self.type, " ?" if self.optional else "")
|
||||
@@ -0,0 +1,46 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# 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 nodes
|
||||
import collections
|
||||
|
||||
class Schema:
|
||||
def is_enumeration(self, v):
|
||||
return v in self.enumerations
|
||||
def is_select(self, v):
|
||||
return v in self.selects
|
||||
def is_simpletype(self, v):
|
||||
return v in self.simpletypes
|
||||
def is_type(self, v):
|
||||
return v in self.types
|
||||
def is_entity(self, v):
|
||||
return v in self.entities
|
||||
def __init__(self, parsetree):
|
||||
self.name = parsetree[1]
|
||||
|
||||
sort = lambda d: collections.OrderedDict(sorted(d.items()))
|
||||
|
||||
self.types = sort({t.name:t for t in parsetree if isinstance(t, nodes.TypeDeclaration)})
|
||||
self.entities = sort({t.name:t for t in parsetree if isinstance(t, nodes.EntityDeclaration)})
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,448 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# 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/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
header = """
|
||||
#ifndef %(schema_name_upper)s_H
|
||||
#define %(schema_name_upper)s_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/%(schema_name)senum.h"
|
||||
|
||||
#define IfcSchema %(schema_name)s
|
||||
|
||||
namespace %(schema_name)s {
|
||||
|
||||
const char* const Identifier = "%(schema_name_upper)s";
|
||||
|
||||
// Forward definitions
|
||||
%(forward_definitions)s
|
||||
|
||||
%(declarations)s
|
||||
|
||||
%(class_definitions)s
|
||||
void InitStringMap();
|
||||
IfcUtil::IfcBaseClass* SchemaEntity(IfcAbstractEntity* e = 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
"""
|
||||
|
||||
enum_header = """
|
||||
#ifndef %(schema_name_upper)sENUM_H
|
||||
#define %(schema_name_upper)sENUM_H
|
||||
|
||||
#define IfcSchema %(schema_name)s
|
||||
|
||||
namespace %(schema_name)s {
|
||||
|
||||
namespace Type {
|
||||
typedef enum {
|
||||
%(types)s, UNDEFINED
|
||||
} Enum;
|
||||
Enum Parent(Enum v);
|
||||
Enum FromString(const std::string& s);
|
||||
std::string ToString(Enum v);
|
||||
bool IsSimple(Enum v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
"""
|
||||
|
||||
lb_header = """
|
||||
#ifndef %(schema_name_upper)sRT_H
|
||||
#define %(schema_name_upper)sRT_H
|
||||
|
||||
#define IfcSchema %(schema_name)s
|
||||
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcEntityDescriptor.h"
|
||||
#include "../ifcparse/IfcWritableEntity.h"
|
||||
|
||||
namespace %(schema_name)s {
|
||||
namespace Type {
|
||||
int GetAttributeCount(Enum t);
|
||||
int GetAttributeIndex(Enum t, const std::string& a);
|
||||
IfcUtil::ArgumentType GetAttributeType(Enum t, unsigned char a);
|
||||
Enum GetAttributeEntity(Enum t, unsigned char a);
|
||||
const std::string& GetAttributeName(Enum t, unsigned char a);
|
||||
bool GetAttributeOptional(Enum t, unsigned char a);
|
||||
bool GetAttributeDerived(Enum t, unsigned char a);
|
||||
std::pair<const char*, int> GetEnumerationIndex(Enum t, const std::string& a);
|
||||
std::pair<Enum, unsigned> GetInverseAttribute(Enum t, const std::string& a);
|
||||
std::set<std::string> GetInverseAttributeNames(Enum t);
|
||||
void PopulateDerivedFields(IfcWrite::IfcWritableEntity* e);
|
||||
}}
|
||||
|
||||
#endif
|
||||
"""
|
||||
|
||||
implementation= """
|
||||
#include "../ifcparse/%(schema_name)s.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/IfcWrite.h"
|
||||
#include "../ifcparse/IfcWritableEntity.h"
|
||||
|
||||
using namespace %(schema_name)s;
|
||||
using namespace IfcParse;
|
||||
using namespace IfcWrite;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Type::ToString(Enum v) {
|
||||
if (v < 0 || v >= %(max_id)d) throw IfcException("Unable to find find keyword in schema");
|
||||
const char* names[] = { %(type_name_strings)s };
|
||||
return names[v];
|
||||
}
|
||||
|
||||
static std::map<std::string,Type::Enum> string_map;
|
||||
void %(schema_name)s::InitStringMap() {
|
||||
%(string_map_statements)s
|
||||
}
|
||||
|
||||
Type::Enum Type::FromString(const std::string& s) {
|
||||
if (string_map.empty()) 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;
|
||||
}
|
||||
|
||||
Type::Enum Type::Parent(Enum v){
|
||||
if (v < 0 || v >= %(max_id)d) return (Enum)-1;
|
||||
%(parent_type_statements)s
|
||||
return (Enum)-1;
|
||||
}
|
||||
|
||||
bool Type::IsSimple(Enum v) {
|
||||
return %(simple_type_statement)s;
|
||||
}
|
||||
|
||||
%(enumeration_functions)s
|
||||
|
||||
%(simple_type_impl)s
|
||||
|
||||
%(entity_implementations)s
|
||||
"""
|
||||
|
||||
lb_implementation = """
|
||||
#include <set>
|
||||
|
||||
#include "../ifcparse/%(schema_name)s.h"
|
||||
#include "../ifcparse/%(schema_name)s-latebound.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/IfcWrite.h"
|
||||
#include "../ifcparse/IfcWritableEntity.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcEntityDescriptor.h"
|
||||
|
||||
using namespace %(schema_name)s;
|
||||
using namespace IfcParse;
|
||||
using namespace IfcWrite;
|
||||
using namespace IfcUtil;
|
||||
|
||||
typedef std::map<Type::Enum,IfcEntityDescriptor*> entity_descriptor_map_t;
|
||||
typedef std::map<Type::Enum,IfcEnumerationDescriptor*> enumeration_descriptor_map_t;
|
||||
typedef std::map<Type::Enum, std::map<std::string, std::pair<Type::Enum, int> > > inverse_map_t;
|
||||
typedef std::map<Type::Enum,std::set<int> > derived_map_t;
|
||||
|
||||
entity_descriptor_map_t entity_descriptor_map;
|
||||
enumeration_descriptor_map_t enumeration_descriptor_map;
|
||||
inverse_map_t inverse_map;
|
||||
derived_map_t derived_map;
|
||||
|
||||
void InitDescriptorMap() {
|
||||
IfcEntityDescriptor* current;
|
||||
%(entity_descriptors)s
|
||||
// Enumerations
|
||||
IfcEnumerationDescriptor* current_enum;
|
||||
std::vector<std::string> values;
|
||||
%(enumeration_descriptors)s
|
||||
}
|
||||
|
||||
void InitInverseMap() {
|
||||
%(inverse_implementations)s
|
||||
}
|
||||
|
||||
void InitDerivedMap() {
|
||||
%(derived_field_statements)s
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
bool Type::GetAttributeDerived(Enum t, unsigned char a) {
|
||||
if (derived_map.empty()) ::InitDerivedMap();
|
||||
std::map<Type::Enum,std::set<int> >::const_iterator i = derived_map.find(t);
|
||||
return i != derived_map.end() && i->second.find(a) != i->second.end();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
std::pair<Type::Enum, unsigned> Type::GetInverseAttribute(Enum t, const std::string& a) {
|
||||
if (inverse_map.empty()) ::InitInverseMap();
|
||||
inverse_map_t::const_iterator it;
|
||||
inverse_map_t::mapped_type::const_iterator jt;
|
||||
while (true) {
|
||||
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");
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
while (true) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
entity_descriptor = """ current = entity_descriptor_map[Type::%(type)s] = new IfcEntityDescriptor(Type::%(type)s,%(parent_statement)s);
|
||||
%(entity_descriptor_attributes)s"""
|
||||
|
||||
entity_descriptor_parent = "entity_descriptor_map.find(Type::%(type)s)->second"
|
||||
entity_descriptor_attribute_without_entity = ' current->add("%(name)s",%(optional)s,%(type)s);'
|
||||
entity_descriptor_attribute_with_entity = ' current->add("%(name)s",%(optional)s,%(type)s,Type::%(entity_name)s);'
|
||||
|
||||
enumeration_descriptor = """ values.clear(); values.reserve(128);
|
||||
%(enumeration_descriptor_values)s
|
||||
current_enum = enumeration_descriptor_map[Type::%(type)s] = new IfcEnumerationDescriptor(Type::%(type)s, values);"""
|
||||
|
||||
enumeration_descriptor_value = ' values.push_back("%(name)s");'
|
||||
|
||||
derived_field_statement = ' {std::set<int> idxs; %(statements)sderived_map[Type::%(type)s] = idxs;}';
|
||||
derived_field_statement_attrs = 'idxs.insert(%d); '
|
||||
|
||||
simpletype = """%(documentation)s
|
||||
class %(name)s : public %(superclass)s {
|
||||
public:
|
||||
virtual IfcUtil::ArgumentType getArgumentType(unsigned int i) const;
|
||||
virtual Argument* getArgument(unsigned int i) const;
|
||||
bool is(Type::Enum v) const;
|
||||
Type::Enum type() const;
|
||||
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::IfcException(\"argument out of range\"); }"
|
||||
simpletype_impl_argument = "return entity->getArgument(i);"
|
||||
simpletype_impl_is_with_supertype = "return v == Type::%(class_name)s || %(superclass)s::is(v);"
|
||||
simpletype_impl_is_without_supertype = "return v == %(class_name)s::Class();"
|
||||
simpletype_impl_type = "return Type::%(class_name)s;"
|
||||
simpletype_impl_class = "return Type::%(class_name)s;"
|
||||
simpletype_impl_explicit_constructor = "entity = e;"
|
||||
simpletype_impl_constructor = "IfcWritableEntity* e = new IfcWritableEntity(Type::%(class_name)s); e->setArgument(0, v); entity = e;"
|
||||
simpletype_impl_cast = "return *entity->getArgument(0);"
|
||||
|
||||
select = """%(documentation)s
|
||||
typedef IfcUtil::IfcBaseClass %(name)s;
|
||||
"""
|
||||
|
||||
enumeration = """namespace %(name)s {
|
||||
%(documentation)s
|
||||
typedef enum {%(values)s} %(name)s;
|
||||
const char* ToString(%(name)s v);
|
||||
%(name)s FromString(const std::string& s);
|
||||
}
|
||||
"""
|
||||
|
||||
entity = """%(documentation)s
|
||||
class %(name)s %(superclass)s{
|
||||
public:
|
||||
%(attributes)s virtual unsigned int getArgumentCount() const { return %(argument_count)d; }
|
||||
virtual IfcUtil::ArgumentType getArgumentType(unsigned int i) const {%(argument_type_function_body)s}
|
||||
virtual Type::Enum getArgumentEntity(unsigned int i) const {%(argument_entity_function_body)s}
|
||||
virtual const char* getArgumentName(unsigned int i) const {%(argument_name_function_body)s}
|
||||
virtual Argument* getArgument(unsigned int i) const { return entity->getArgument(i); }
|
||||
%(inverse)s bool is(Type::Enum v) const;
|
||||
Type::Enum type() const;
|
||||
static Type::Enum Class();
|
||||
%(name)s (IfcAbstractEntity* e);
|
||||
%(name)s (%(constructor_arguments)s);
|
||||
typedef IfcTemplatedEntityList< %(name)s > list;
|
||||
};
|
||||
"""
|
||||
|
||||
enumeration_function="""
|
||||
const char* %(name)s::ToString(%(name)s v) {
|
||||
if ( v < 0 || v >= %(max_id)d ) throw IfcException("Unable to find find keyword in schema");
|
||||
const char* names[] = { %(values)s };
|
||||
return names[v];
|
||||
}
|
||||
|
||||
%(name)s::%(name)s %(name)s::FromString(const std::string& s) {
|
||||
%(from_string_statements)s
|
||||
throw IfcException("Unable to find find keyword in schema");
|
||||
}
|
||||
"""
|
||||
|
||||
entity_implementation = """// Function implementations for %(name)s
|
||||
%(attributes)s%(inverse)sbool %(name)s::is(Type::Enum v) const { return v == Type::%(name)s%(parent_type_test)s; }
|
||||
Type::Enum %(name)s::type() const { return Type::%(name)s; }
|
||||
Type::Enum %(name)s::Class() { return Type::%(name)s; }
|
||||
%(name)s::%(name)s(IfcAbstractEntity* e) : %(superclass)s { if (!e) return; if (!e->is(Type::%(name)s)) throw IfcException("Unable to find find keyword in schema"); entity = e; }
|
||||
%(name)s::%(name)s(%(constructor_arguments)s) : %(superclass)s { IfcWritableEntity* e = new IfcWritableEntity(Class());%(constructor_implementation)s entity = e; EntityBuffer::Add(this); }
|
||||
"""
|
||||
|
||||
optional_attribute_description = "/// Whether the optional attribute %s is defined for this %s"
|
||||
|
||||
function = "%(return_type)s %(class_name)s::%(name)s(%(arguments)s) { %(body)s }"
|
||||
const_function = "%(return_type)s %(class_name)s::%(name)s(%(arguments)s) const { %(body)s }"
|
||||
constructor = "%(class_name)s::%(class_name)s(%(arguments)s) { %(body)s }"
|
||||
constructor_single_initlist = "%(class_name)s::%(class_name)s(%(arguments)s) : %(superclass)s(%(superclass_init)s) { %(body)s }"
|
||||
cast_function = "%(class_name)s::operator %(return_type)s() const { %(body)s }"
|
||||
|
||||
array_type = "std::vector< %(instance_type)s > /*[%(lower)s:%(upper)s]*/"
|
||||
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)"
|
||||
|
||||
get_attr_stmt_generic = "return *entity->getArgument(%(index)d);"
|
||||
get_attr_stmt_enum = "return %(type)s::FromString(*entity->getArgument(%(index)d));"
|
||||
get_attr_stmt_entity = "return (%(type)s)((IfcUtil::IfcBaseClass*)(*entity->getArgument(%(index)d)));"
|
||||
get_attr_stmt_array = "IfcEntityList::ptr es = *entity->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
|
||||
get_attr_stmt_nested_array = "IfcEntityListList::ptr es = *entity->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
|
||||
get_attr_stmt_optional = "Argument* arg = entity->getArgument(%%(index)d); if (arg->isNull()) { return boost::none; } else { %s }"
|
||||
get_attr_stmt_optional_generic = get_attr_stmt_optional % "return *arg;"
|
||||
get_attr_stmt_optional_enum = get_attr_stmt_optional % "return %(type)s::FromString(*arg);"
|
||||
get_attr_stmt_optional_entity = get_attr_stmt_optional % "return (%(type)s)((IfcUtil::IfcBaseClass*)(*arg));"
|
||||
get_attr_stmt_optional_array = get_attr_stmt_optional % "IfcEntityList::ptr es = *arg; return es->as<%(list_instance_type)s>();"
|
||||
get_attr_stmt_optional_nested_array = get_attr_stmt_optional % "IfcEntityListList::ptr es = *arg; return es->as<%(list_instance_type)s>();"
|
||||
|
||||
set_attr_stmt = "IfcWritableEntity* w = entity->isWritable(); if (!w) { entity = w = new IfcWritableEntity(entity); } %s;"
|
||||
set_attr_stmt_optional = "IfcWritableEntity* w = entity->isWritable(); if (!w) { entity = w = new IfcWritableEntity(entity); } if (v) { %s; } else { w->setArgument(%%(index)d); }"
|
||||
set_attr_stmt_generic = set_attr_stmt % "w->setArgument(%(index)d,v)"
|
||||
set_attr_stmt_enum = set_attr_stmt % "w->setArgument(%(index)d,v,%(type)s::ToString(v));"
|
||||
set_attr_stmt_array = set_attr_stmt % "w->setArgument(%(index)d,v->generalize());"
|
||||
set_attr_stmt_optional_generic = set_attr_stmt_optional % "w->setArgument(%(index)d,*v)"
|
||||
set_attr_stmt_optional_enum = set_attr_stmt_optional % "w->setArgument(%(index)d,*v,%(type)s::ToString(*v));"
|
||||
set_attr_stmt_optional_array = set_attr_stmt_optional % "w->setArgument(%(index)d,(*v)->generalize());"
|
||||
|
||||
get_inverse = "return entity->getInverse(Type::%(type)s, %(index)d)->as<%(type)s>();"
|
||||
|
||||
constructor_stmt = " e->setArgument(%(index)d,(%(name)s));"
|
||||
constructor_stmt_enum = " e->setArgument(%(index)d,%(name)s,%(type)s::ToString(%(name)s));"
|
||||
constructor_stmt_array = " e->setArgument(%(index)d,(%(name)s)->generalize());"
|
||||
constructor_stmt_optional = " if (%(name)s) {%(stmt)s } else { e->setArgument(%(index)d); }"
|
||||
constructor_stmt_derived = " e->setArgumentDerived(%(index)d);"
|
||||
|
||||
inverse_implementation = " inverse_map[Type::%(type)s].insert(std::make_pair(\"%(name)s\", std::make_pair(Type::%(related_type)s, %(index)d)));"
|
||||
|
||||
def multi_line_comment(li):
|
||||
return ("/// %s"%("\n/// ".join(li))) if len(li) else ""
|
||||
|
||||
+123
-24
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -36,36 +36,79 @@
|
||||
#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/IfcShapeList.h"
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
#include "../ifcgeom/IfcGeomRepresentation.h"
|
||||
#include "../ifcgeom/IfcRepresentationShapeItem.h"
|
||||
|
||||
// Tolerances for various geometrical operations:
|
||||
// Specifies the deflection of the mesher
|
||||
#define DEFLECTION_TOLERANCE 0.001
|
||||
// Specifies the tolerance of the wire builder, most notably for trimmed curves
|
||||
#define WIRE_CREATION_TOLERANCE 0.0001
|
||||
// Specifies the minimal area of a face to be included in an IfcConnectedFaceset
|
||||
#define MINIMAL_FACE_AREA 0.000001
|
||||
// Specifies the treshold distance under which cartesian points are deemed equal
|
||||
#define POINT_EQUALITY_TOLERANCE 0.00001
|
||||
|
||||
// Specifies maximum number of faces for a shell to be sewed. Sewing shells
|
||||
// that consist of many faces is really detrimental for the performance.
|
||||
#define MAX_FACES_TO_SEW 1000
|
||||
#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;
|
||||
|
||||
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
|
||||
// Default: 0.001m / 1mm
|
||||
GV_DEFLECTION_TOLERANCE,
|
||||
// Specifies the tolerance of the wire builder, most notably for trimmed curves
|
||||
// Defailt: 0.0001m / 0.1mm
|
||||
GV_WIRE_CREATION_TOLERANCE,
|
||||
// Specifies the minimal area of a face to be included in an IfcConnectedFaceset
|
||||
// Default: 0.000001m 0.01cm2
|
||||
GV_MINIMAL_FACE_AREA,
|
||||
// Specifies the treshold distance under which cartesian points are deemed equal
|
||||
// Default: 0.00001m / 0.01mm
|
||||
GV_POINT_EQUALITY_TOLERANCE,
|
||||
// Specifies maximum number of faces for a shell to be sewed. Sewing shells
|
||||
// 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
|
||||
GV_LENGTH_UNIT,
|
||||
// The plane angle unit used for the creation of TopoDS_Shapes, primarily affects
|
||||
// the interpretation of IfcParamaterValues of IfcTrimmedCurves
|
||||
// Default: -1.0 (= not set, fist try degrees, then radians)
|
||||
GV_PLANEANGLE_UNIT,
|
||||
// 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
|
||||
};
|
||||
|
||||
bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face);
|
||||
bool convert_shapes(const IfcUtil::IfcBaseClass* L, ShapeList& result);
|
||||
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);
|
||||
const TopoDS_Shape* convert_shape(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
|
||||
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_Face& result);
|
||||
bool convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcRelVoidsElement::list& openings, const ShapeList& entity_shapes, const gp_Trsf& entity_trsf, ShapeList& cut_shapes);
|
||||
bool convert_openings_fast(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcRelVoidsElement::list& openings, const ShapeList& entity_shapes, const gp_Trsf& entity_trsf, ShapeList& cut_shapes);
|
||||
bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
|
||||
bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
|
||||
bool convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
|
||||
IfcSchema::IfcSurfaceStyleShading* get_surface_style(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);
|
||||
@@ -73,13 +116,69 @@ namespace IfcGeom {
|
||||
gp_Pln plane_from_face(const TopoDS_Face& face);
|
||||
gp_Pnt point_above_plane(const gp_Pln& pln, bool agree=true);
|
||||
const TopoDS_Shape& ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid);
|
||||
bool profile_helper(int numVerts, double* verts, int numFillets, int* filletIndices, double* filletRadii, gp_Trsf2d trsf, TopoDS_Face& face);
|
||||
bool profile_helper(int numVerts, double* verts, int numFillets, int* filletIndices, double* filletRadii, gp_Trsf2d trsf, TopoDS_Shape& face);
|
||||
double shape_volume(const TopoDS_Shape& s);
|
||||
double face_area(const TopoDS_Face& f);
|
||||
namespace Cache {
|
||||
void Purge();
|
||||
void PurgeShapeCache();
|
||||
void apply_tolerance(TopoDS_Shape& s, double t);
|
||||
void setValue(GeomValue var, double value);
|
||||
double getValue(GeomValue var);
|
||||
bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape);
|
||||
void remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
|
||||
|
||||
std::pair<std::string, double> initializeUnits(IfcSchema::IfcUnitAssignment*);
|
||||
|
||||
IfcSchema::IfcObjectDefinition* get_decomposing_entity(IfcSchema::IfcProduct*);
|
||||
|
||||
template <typename P>
|
||||
IfcGeom::BRepElement<P>* create_brep_for_representation_and_product(const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*);
|
||||
|
||||
const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem* representation_item);
|
||||
|
||||
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) {
|
||||
IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem();
|
||||
for (IfcSchema::IfcStyledItem::list::it jt = styled_items->begin(); jt != styled_items->end(); ++jt) {
|
||||
#ifdef USE_IFC4
|
||||
IfcUtil::IfcAbstractSelect::list::ptr style_assignments = (*jt)->Styles();
|
||||
for (IfcUtil::IfcAbstractSelect::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
if (!(*kt)->is(IfcSchema::Type::IfcPresentationStyleAssignment)) {
|
||||
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->is(IfcSchema::Type::IfcSurfaceStyle)) {
|
||||
IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style;
|
||||
if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) {
|
||||
IfcEntityList::ptr styles_elements = surface_style->Styles();
|
||||
for (IfcEntityList::it mt = styles_elements->begin(); mt != styles_elements->end(); ++mt) {
|
||||
if ((*mt)->is(T::Class())) {
|
||||
return std::make_pair(surface_style, (T*) *mt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -23,6 +23,8 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Vec.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
@@ -77,43 +79,60 @@
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcCircle::ptr l, Handle(Geom_Curve)& curve) {
|
||||
const double r = l->Radius() * Ifc::LengthUnit;
|
||||
if ( r <= 0.0f ) { return false; }
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
gp_Trsf trsf;
|
||||
Ifc2x3::IfcAxis2Placement placement = l->Position();
|
||||
if (placement->is(Ifc2x3::Type::IfcAxis2Placement3D)) {
|
||||
IfcGeom::convert((Ifc2x3::IfcAxis2Placement3D*)placement,trsf);
|
||||
IfcSchema::IfcAxis2Placement* placement = l->Position();
|
||||
if (placement->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 Ifc2x3::IfcEllipse::ptr l, Handle(Geom_Curve)& curve) {
|
||||
double x = l->SemiAxis1() * Ifc::LengthUnit;
|
||||
double y = l->SemiAxis2() * Ifc::LengthUnit;
|
||||
if ( x == 0.0f || y == 0.0f || y > x ) { return false; }
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
// Open Cascade does not allow ellipses of which the minor radius
|
||||
// is greater than the major radius. Hence, in this case, the
|
||||
// ellipse is rotated. Note that special care needs to be taken
|
||||
// when creating a trimmed curve off of an ellipse like this.
|
||||
const bool rotated = y > x;
|
||||
gp_Trsf trsf;
|
||||
Ifc2x3::IfcAxis2Placement placement = l->Position();
|
||||
if (placement->is(Ifc2x3::Type::IfcAxis2Placement3D)) {
|
||||
IfcGeom::convert((Ifc2x3::IfcAxis2Placement3D*)placement,trsf);
|
||||
IfcSchema::IfcAxis2Placement* placement = l->Position();
|
||||
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
} else {
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::convert((Ifc2x3::IfcAxis2Placement2D*)placement,trsf2d);
|
||||
convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d);
|
||||
trsf = trsf2d;
|
||||
}
|
||||
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
|
||||
gp_Ax2 ax = gp_Ax2();
|
||||
if (rotated) {
|
||||
ax.Rotate(ax.Axis(), M_PI / 2.);
|
||||
std::swap(x, y);
|
||||
}
|
||||
ax.Transform(trsf);
|
||||
curve = new Geom_Ellipse(ax, x, y);
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::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;
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 "../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;
|
||||
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 Transformation<P>& transformation() const { return _transformation; }
|
||||
Element(const ElementSettings& settings, int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf)
|
||||
: _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _transformation(settings, trsf)
|
||||
{}
|
||||
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 gp_Trsf& trsf, Representation::BRep* geometry)
|
||||
: Element<P>(geometry->settings(),id,parent_id,name,type,guid,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
|
||||
+700
-88
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -50,23 +50,27 @@
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include <Geom_TrimmedCurve.hxx>
|
||||
#include <Geom_OffsetCurve.hxx>
|
||||
|
||||
#include <BRepPrimAPI_MakePrism.hxx>
|
||||
#include <BRepPrimAPI_MakeHalfSpace.hxx>
|
||||
|
||||
#include <BRepOffsetAPI_Sewing.hxx>
|
||||
#include <BRepOffsetAPI_MakeOffset.hxx>
|
||||
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <BRepBuilderAPI_MakePolygon.hxx>
|
||||
#include <BRepBuilderAPI_MakeVertex.hxx>
|
||||
#include <BRepBuilderAPI_MakeShell.hxx>
|
||||
#include <BRepBuilderAPI_MakeSolid.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 <BRepAlgoAPI_Cut.hxx>
|
||||
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
@@ -74,32 +78,48 @@
|
||||
#include <ShapeFix_Solid.hxx>
|
||||
|
||||
#include <TopLoc_Location.hxx>
|
||||
#include <BRepGProp_Face.hxx>
|
||||
|
||||
#include <Standard_Failure.hxx>
|
||||
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include <Geom_BSplineSurface.hxx>
|
||||
#include <TColgp_Array2OfPnt.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <BRepCheck_Face.hxx>
|
||||
#endif
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcFace::ptr l, TopoDS_Face& face) {
|
||||
Ifc2x3::IfcFaceBound::list bounds = l->Bounds();
|
||||
Ifc2x3::IfcFaceBound::it it = bounds->begin();
|
||||
Ifc2x3::IfcLoop::ptr loop = (*it)->Bound();
|
||||
TopoDS_Wire wire;
|
||||
if ( ! IfcGeom::convert_wire(loop,wire) ) return false;
|
||||
BRepBuilderAPI_MakeFace mf (wire);
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
|
||||
IfcSchema::IfcFaceBound::list::it it = bounds->begin();
|
||||
IfcSchema::IfcLoop* loop = (*it)->Bound();
|
||||
TopoDS_Wire outer_wire;
|
||||
if ( ! convert_wire(loop,outer_wire) ) return false;
|
||||
BRepBuilderAPI_MakeFace mf (outer_wire);
|
||||
BRepBuilderAPI_FaceError er = mf.Error();
|
||||
if ( er == BRepBuilderAPI_NotPlanar ) {
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
FTol.SetTolerance(wire, 0.01, TopAbs_WIRE);
|
||||
FTol.SetTolerance(outer_wire, 0.01, TopAbs_WIRE);
|
||||
mf.~BRepBuilderAPI_MakeFace();
|
||||
new (&mf) BRepBuilderAPI_MakeFace(wire);
|
||||
new (&mf) BRepBuilderAPI_MakeFace(outer_wire);
|
||||
er = mf.Error();
|
||||
}
|
||||
if ( er != BRepBuilderAPI_FaceDone ) return false;
|
||||
if ( bounds->Size() == 1 ) {
|
||||
if ( bounds->size() == 1 ) {
|
||||
face = mf.Face();
|
||||
} else {
|
||||
for( ++it; it != bounds->end(); ++ it) {
|
||||
Ifc2x3::IfcLoop::ptr loop = (*it)->Bound();
|
||||
IfcSchema::IfcLoop* loop = (*it)->Bound();
|
||||
TopoDS_Wire wire;
|
||||
if ( ! IfcGeom::convert_wire(loop,wire) ) return false;
|
||||
if ( ! convert_wire(loop,wire) ) return false;
|
||||
mf.Add(wire);
|
||||
}
|
||||
if ( mf.IsDone() ) {
|
||||
@@ -116,6 +136,68 @@ bool IfcGeom::convert(const Ifc2x3::IfcFace::ptr l, TopoDS_Face& face) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( getValue(GV_FORCE_CCW_FACE_ORIENTATION)>0 ) {
|
||||
// Check the orientation of the face by comparing the
|
||||
// normal of the topological surface to the Newell's Method's
|
||||
// normal. Newell's Method is used for the normal calculation
|
||||
// as a simple edge cross product can give opposite results
|
||||
// for a concave face boundary.
|
||||
// Reference: Graphics Gems III p. 231
|
||||
BRepGProp_Face prop(TopoDS::Face(face));
|
||||
gp_Vec normal_direction;
|
||||
gp_Pnt center;
|
||||
double u1,u2,v1,v2;
|
||||
prop.Bounds(u1,u2,v1,v2);
|
||||
prop.Normal((u1+u2)/2.0,(v1+v2)/2.0,center,normal_direction);
|
||||
gp_Dir face_normal1 = gp_Dir(normal_direction.XYZ());
|
||||
|
||||
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 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_normal2.Magnitude() > ALMOST_ZERO) {
|
||||
if ( face_normal1.Dot(face_normal2) < 0 ) {
|
||||
TopAbs_Orientation o = face.Orientation();
|
||||
face.Orientation(o == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -123,19 +205,25 @@ bool IfcGeom::convert(const Ifc2x3::IfcFace::ptr l, TopoDS_Face& face) {
|
||||
// return face_area(face) > 0.0001;
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcArbitraryClosedProfileDef::ptr l, TopoDS_Face& face) {
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, TopoDS_Shape& face) {
|
||||
TopoDS_Wire wire;
|
||||
if ( ! IfcGeom::convert_wire(l->OuterCurve(),wire) ) return false;
|
||||
return IfcGeom::convert_wire_to_face(wire,face);
|
||||
if ( ! convert_wire(l->OuterCurve(),wire) ) return false;
|
||||
|
||||
TopoDS_Face f;
|
||||
bool success = convert_wire_to_face(wire, f);
|
||||
if (success) face = f;
|
||||
return success;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcArbitraryProfileDefWithVoids::ptr l, TopoDS_Face& 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);
|
||||
Ifc2x3::IfcCurve::list voids = l->InnerCurves();
|
||||
for( Ifc2x3::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);
|
||||
}
|
||||
}
|
||||
@@ -144,124 +232,432 @@ bool IfcGeom::convert(const Ifc2x3::IfcArbitraryProfileDefWithVoids::ptr l, Topo
|
||||
face = TopoDS::Face(sfs.Shape());
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcRectangleProfileDef::ptr l, TopoDS_Face& face) {
|
||||
const double x = l->XDim() / 2.0f * Ifc::LengthUnit;
|
||||
const double y = l->YDim() / 2.0f * Ifc::LengthUnit;
|
||||
|
||||
if ( x == 0.0f || y == 0.0f ) {
|
||||
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
|
||||
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);
|
||||
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 Ifc2x3::IfcIShapeProfileDef::ptr l, TopoDS_Face& face) {
|
||||
const double x = l->OverallWidth() / 2.0f * Ifc::LengthUnit;
|
||||
const double y = l->OverallDepth() / 2.0f * Ifc::LengthUnit;
|
||||
const double d1 = l->WebThickness() / 2.0f * Ifc::LengthUnit;
|
||||
const double d2 = l->FlangeThickness() * Ifc::LengthUnit;
|
||||
bool doFillet = l->hasFilletRadius();
|
||||
double f;
|
||||
if ( doFillet ) {
|
||||
f = l->FilletRadius() * Ifc::LengthUnit;
|
||||
}
|
||||
|
||||
if ( x == 0.0f || y == 0.0f || d1 == 0.0f || d2 == 0.0f ) {
|
||||
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::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};
|
||||
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);
|
||||
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 profile_helper(4,coords,4,fillets,radii,trsf2d,face);
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcCShapeProfileDef::ptr l, TopoDS_Face& face) {
|
||||
const double x = l->Depth() / 2.0f * Ifc::LengthUnit;
|
||||
const double y = l->Width() / 2.0f * Ifc::LengthUnit;
|
||||
const double d1 = l->WallThickness() * Ifc::LengthUnit;
|
||||
const double d2 = l->Girth() * Ifc::LengthUnit;
|
||||
bool doFillet = l->hasInternalFilletRadius();
|
||||
double f1,f2;
|
||||
|
||||
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->OuterFilletRadius() ? true : false;
|
||||
const bool fr2 = l->InnerFilletRadius() ? true : false;
|
||||
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
||||
TopoDS_Face f1;
|
||||
TopoDS_Face f2;
|
||||
|
||||
gp_Trsf2d 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 = 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;
|
||||
|
||||
TopExp_Explorer exp1(f1, TopAbs_WIRE);
|
||||
TopExp_Explorer exp2(f2, TopAbs_WIRE);
|
||||
|
||||
TopoDS_Wire w1 = TopoDS::Wire(exp1.Current());
|
||||
TopoDS_Wire w2 = TopoDS::Wire(exp2.Current());
|
||||
|
||||
BRepBuilderAPI_MakeFace mf(w1, false);
|
||||
mf.Add(w2);
|
||||
|
||||
ShapeFix_Shape sfs(mf.Face());
|
||||
sfs.Perform();
|
||||
face = TopoDS::Face(sfs.Shape());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrapeziumProfileDef* l, TopoDS_Shape& face) {
|
||||
const double x1 = l->BottomXDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double w = l->TopXDim() * getValue(GV_LENGTH_UNIT);
|
||||
const double dx = l->TopXOffset() * getValue(GV_LENGTH_UNIT);
|
||||
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( x1 < ALMOST_ZERO || w < ALMOST_ZERO || y < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf2d);
|
||||
double coords[8] = {-x1,-y, x1,-y, dx+w-x1,y, dx-x1,y};
|
||||
return profile_helper(4,coords,0,0,0,trsf2d,face);
|
||||
}
|
||||
|
||||
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->FilletRadius() ? true : false;
|
||||
double f1 = 0.;
|
||||
if ( doFillet1 ) {
|
||||
f1 = *l->FilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
|
||||
bool doFillet2 = doFillet1;
|
||||
double x2 = x1, dy2 = dy1, f2 = f1;
|
||||
|
||||
if (l->is(IfcSchema::Type::IfcAsymmetricIShapeProfileDef)) {
|
||||
IfcSchema::IfcAsymmetricIShapeProfileDef* assym = (IfcSchema::IfcAsymmetricIShapeProfileDef*) l;
|
||||
x2 = assym->TopFlangeWidth() / 2. * getValue(GV_LENGTH_UNIT);
|
||||
doFillet2 = assym->TopFlangeFilletRadius() ? true : false;
|
||||
if (doFillet2) {
|
||||
f2 = *assym->TopFlangeFilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
if (assym->TopFlangeThickness()) {
|
||||
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->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
convert(l->Position(),trsf2d);
|
||||
|
||||
double coords[24] = {-x1,-y, x1,-y, x1,-y+dy1, d1,-y+dy1, d1,y-dy2, x2,y-dy2, x2,y, -x2,y, -x2,y-dy2, -d1,y-dy2, -d1,-y+dy1, -x1,-y+dy1};
|
||||
int fillets[4] = {3,4,9,10};
|
||||
double radii[4] = {f1,f1,f2,f2};
|
||||
return profile_helper(12,coords,(doFillet1||doFillet2) ? 4 : 0,fillets,radii,trsf2d,face);
|
||||
}
|
||||
|
||||
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->FilletRadius() ? true : false;
|
||||
bool doEdgeFillet = l->EdgeRadius() ? true : false;
|
||||
|
||||
double f1 = 0.;
|
||||
double f2 = 0.;
|
||||
|
||||
if ( doFillet ) {
|
||||
f1 = l->InternalFilletRadius() * Ifc::LengthUnit;
|
||||
f1 = *l->FilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
if ( doEdgeFillet ) {
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d 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 profile_helper(8,coords,(doFillet || doEdgeFillet) ? 4 : 0,fillets,radii,trsf2d,face);
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCShapeProfileDef* l, TopoDS_Shape& face) {
|
||||
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double x = l->Width() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double d1 = l->WallThickness() * getValue(GV_LENGTH_UNIT);
|
||||
const double d2 = l->Girth() * getValue(GV_LENGTH_UNIT);
|
||||
bool doFillet = l->InternalFilletRadius() ? true : false;
|
||||
double f1 = 0;
|
||||
double f2 = 0;
|
||||
if ( doFillet ) {
|
||||
f1 = *l->InternalFilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
f2 = f1 + d1;
|
||||
}
|
||||
|
||||
if ( x == 0.0f || y == 0.0f || d1 == 0.0f || d2 == 0.0f ) {
|
||||
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
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 Ifc2x3::IfcLShapeProfileDef::ptr l, TopoDS_Face& face) {
|
||||
const double y = l->Depth() / 2.0f * Ifc::LengthUnit;
|
||||
const double x = l->Width() / 2.0f * Ifc::LengthUnit;
|
||||
const double d = l->Thickness() * Ifc::LengthUnit;
|
||||
bool doEdgeFillet = l->hasEdgeRadius();
|
||||
bool doFillet = l->hasFilletRadius();
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Shape& face) {
|
||||
const bool hasSlope = l->LegSlope() ? true : false;
|
||||
const bool doEdgeFillet = l->EdgeRadius() ? true : false;
|
||||
const bool doFillet = l->FilletRadius() ? true : false;
|
||||
|
||||
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double x = (l->Width() ? *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() * Ifc::LengthUnit;
|
||||
f1 = *l->FilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
if ( doEdgeFillet) {
|
||||
f2 = l->EdgeRadius() * Ifc::LengthUnit;
|
||||
f2 = *l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
if ( x == 0.0f || y == 0.0f || d == 0.0f ) {
|
||||
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
double xx = -x+d;
|
||||
double xy = -y+d;
|
||||
double dy1 = 0.;
|
||||
double dy2 = 0.;
|
||||
double dx1 = 0.;
|
||||
double dx2 = 0.;
|
||||
if (hasSlope) {
|
||||
dy1 = tan(slope) * x;
|
||||
dy2 = tan(slope) * (x - d);
|
||||
dx1 = tan(slope) * y;
|
||||
dx2 = tan(slope) * (y - d);
|
||||
|
||||
const double x1s = x; const double y1s = -y + d - dy1;
|
||||
const double x1e = -x + d; const double y1e = -y + d + dy2;
|
||||
const double x2s = -x + d - dx1; const double y2s = y;
|
||||
const double x2e = -x + d + dx2; const double y2e = -y + d;
|
||||
|
||||
const double a1 = y1e - y1s;
|
||||
const double b1 = x1s - x1e;
|
||||
const double c1 = a1*x1s + b1*y1s;
|
||||
|
||||
const double a2 = y2e - y2s;
|
||||
const double b2 = x2s - x2e;
|
||||
const double c2 = a2*x2s + b2*y2s;
|
||||
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
||||
xx = (b2*c1 - b1*c2) / det;
|
||||
xy = (a1*c2 - a2*c1) / det;
|
||||
}
|
||||
|
||||
gp_Trsf2d 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 profile_helper(6,coords,doFillet ? 3 : 0,fillets,radii,trsf2d,face);
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcUShapeProfileDef* l, TopoDS_Shape& face) {
|
||||
const bool doEdgeFillet = l->EdgeRadius() ? true : false;
|
||||
const bool doFillet = l->FilletRadius() ? true : false;
|
||||
const bool hasSlope = l->FlangeSlope() ? true : false;
|
||||
|
||||
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;
|
||||
double f1 = 0.0f;
|
||||
double f2 = 0.0f;
|
||||
|
||||
if (doFillet) {
|
||||
f1 = *l->FilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
if (doEdgeFillet) {
|
||||
f2 = *l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
|
||||
if (hasSlope) {
|
||||
dy1 = (x - d1) * tan(slope);
|
||||
dy2 = x * tan(slope);
|
||||
}
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::convert(l->Position(),trsf2d);
|
||||
convert(l->Position(),trsf2d);
|
||||
|
||||
double coords[12] = {-x,-y,x,-y,x,-y+d,-x+d,-y+d,-x+d,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);
|
||||
double coords[16] = {-x,-y, x,-y, x,-y+d2-dy2, -x+d1,-y+d2+dy1, -x+d1,y-d2-dy1, x,y-d2+dy2, x,y, -x,y};
|
||||
int fillets[4] = {2,3,4,5};
|
||||
double radii[4] = {f2,f1,f1,f2};
|
||||
return profile_helper(8, coords, (doFillet || doEdgeFillet) ? 4 : 0, fillets, radii, trsf2d, face);
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcCircleProfileDef::ptr l, TopoDS_Face& face) {
|
||||
const double r = l->Radius() * Ifc::LengthUnit;
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Shape& face) {
|
||||
const bool doFlangeEdgeFillet = l->FlangeEdgeRadius() ? true : false;
|
||||
const bool doWebEdgeFillet = l->WebEdgeRadius() ? true : false;
|
||||
const bool doFillet = l->FilletRadius() ? true : false;
|
||||
const bool hasFlangeSlope = l->FlangeSlope() ? true : false;
|
||||
const bool hasWebSlope = l->WebSlope() ? true : false;
|
||||
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
||||
double dy1 = 0.0f;
|
||||
double dy2 = 0.0f;
|
||||
double dx1 = 0.0f;
|
||||
double dx2 = 0.0f;
|
||||
double f1 = 0.0f;
|
||||
double f2 = 0.0f;
|
||||
double f3 = 0.0f;
|
||||
|
||||
if (doFillet) {
|
||||
f1 = *l->FilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
if (doWebEdgeFillet) {
|
||||
f2 = *l->WebEdgeRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
if (doFlangeEdgeFillet) {
|
||||
f3 = *l->FlangeEdgeRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
|
||||
double xx, xy;
|
||||
if (hasFlangeSlope) {
|
||||
dy1 = (x / 2. - d1) * tan(flangeSlope);
|
||||
dy2 = x / 2. * tan(flangeSlope);
|
||||
}
|
||||
if (hasWebSlope) {
|
||||
dx1 = (y - d2) * tan(webSlope);
|
||||
dx2 = y * tan(webSlope);
|
||||
}
|
||||
if (hasWebSlope || hasFlangeSlope) {
|
||||
const double x1s = d1/2. - dx2; const double y1s = -y;
|
||||
const double x1e = d1/2. + dx1; const double y1e = y - d2;
|
||||
const double x2s = x; const double y2s = y - d2 + dy2;
|
||||
const double x2e = d1/2.; const double y2e = y - d2 - dy1;
|
||||
|
||||
const double a1 = y1e - y1s;
|
||||
const double b1 = x1s - x1e;
|
||||
const double c1 = a1*x1s + b1*y1s;
|
||||
|
||||
const double a2 = y2e - y2s;
|
||||
const double b2 = x2s - x2e;
|
||||
const double c2 = a2*x2s + b2*y2s;
|
||||
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
||||
xx = (b2*c1 - b1*c2) / det;
|
||||
xy = (a1*c2 - a2*c1) / det;
|
||||
} else {
|
||||
xx = d1 / 2;
|
||||
xy = y - d2;
|
||||
}
|
||||
|
||||
gp_Trsf2d 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 profile_helper(8, coords, (doFillet || doWebEdgeFillet || doFlangeEdgeFillet) ? 6 : 0, fillets, radii, trsf2d, face);
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleProfileDef* l, TopoDS_Shape& face) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
if ( r == 0.0f ) {
|
||||
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf;
|
||||
IfcGeom::convert(l->Position(),trsf);
|
||||
convert(l->Position(),trsf);
|
||||
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
|
||||
Handle(Geom_Circle) circle = new Geom_Circle(ax, r);
|
||||
TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(circle);
|
||||
w.Add(edge);
|
||||
return IfcGeom::convert_wire_to_face(w,face);
|
||||
|
||||
TopoDS_Face f;
|
||||
bool success = convert_wire_to_face(w, f);
|
||||
if (success) face = f;
|
||||
return success;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcCircleHollowProfileDef::ptr l, TopoDS_Face& face) {
|
||||
const double r = l->Radius() * Ifc::LengthUnit;
|
||||
const double t = l->WallThickness() * Ifc::LengthUnit;
|
||||
|
||||
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 ) {
|
||||
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Trsf2d trsf;
|
||||
IfcGeom::convert(l->Position(),trsf);
|
||||
convert(l->Position(),trsf);
|
||||
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
|
||||
|
||||
BRepBuilderAPI_MakeWire outer;
|
||||
@@ -278,4 +674,220 @@ bool IfcGeom::convert(const Ifc2x3::IfcCircleHollowProfileDef::ptr l, TopoDS_Fac
|
||||
sfs.Perform();
|
||||
face = TopoDS::Face(sfs.Shape());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipseProfileDef* l, TopoDS_Shape& face) {
|
||||
double rx = l->SemiAxis1() * getValue(GV_LENGTH_UNIT);
|
||||
double ry = l->SemiAxis2() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( rx < ALMOST_ZERO || ry < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool rotated = ry > rx;
|
||||
gp_Trsf2d trsf;
|
||||
convert(l->Position(),trsf);
|
||||
|
||||
gp_Ax2 ax = gp_Ax2();
|
||||
if (rotated) {
|
||||
ax.Rotate(ax.Axis(), M_PI / 2.);
|
||||
std::swap(rx, ry);
|
||||
}
|
||||
ax.Transform(trsf);
|
||||
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
Handle(Geom_Ellipse) ellipse = new Geom_Ellipse(ax, rx, ry);
|
||||
TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(ellipse);
|
||||
w.Add(edge);
|
||||
|
||||
TopoDS_Face f;
|
||||
bool success = convert_wire_to_face(w, f);
|
||||
if (success) face = f;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCenterLineProfileDef* l, TopoDS_Shape& face) {
|
||||
const double d = l->Thickness() * getValue(GV_LENGTH_UNIT) / 2.;
|
||||
|
||||
TopoDS_Wire wire;
|
||||
if (!convert_wire(l->Curve(), wire)) return false;
|
||||
|
||||
// BRepOffsetAPI_MakeOffset insists on creating circular arc
|
||||
// segments for joining the curves that constitute the center
|
||||
// line. This is probably not in accordance with the IFC spec.
|
||||
// Although it does not specify a method to join segments
|
||||
// explicitly, it does dictate 'a constant thickness along the
|
||||
// curve'. Therefore for simple singular wires a quick
|
||||
// alternative is provided that uses a straight join.
|
||||
|
||||
TopExp_Explorer exp(wire, TopAbs_EDGE);
|
||||
TopoDS_Edge edge = TopoDS::Edge(exp.Current());
|
||||
exp.Next();
|
||||
|
||||
if (!exp.More()) {
|
||||
double u1, u2;
|
||||
Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, u1, u2);
|
||||
|
||||
Handle(Geom_TrimmedCurve) trim = new Geom_TrimmedCurve(curve, u1, u2);
|
||||
|
||||
Handle(Geom_OffsetCurve) c1 = new Geom_OffsetCurve(trim, d, gp::DZ());
|
||||
Handle(Geom_OffsetCurve) c2 = new Geom_OffsetCurve(trim, -d, gp::DZ());
|
||||
|
||||
gp_Pnt c1a, c1b, c2a, c2b;
|
||||
c1->D0(c1->FirstParameter(), c1a);
|
||||
c1->D0(c1->LastParameter(), c1b);
|
||||
c2->D0(c2->FirstParameter(), c2a);
|
||||
c2->D0(c2->LastParameter(), c2b);
|
||||
|
||||
BRepBuilderAPI_MakeWire mw;
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(c1));
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(c1a, c2a));
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(c2));
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(c2b, c1b));
|
||||
|
||||
face = BRepBuilderAPI_MakeFace(mw.Wire());
|
||||
} else {
|
||||
BRepOffsetAPI_MakeOffset offset(BRepBuilderAPI_MakeFace(gp_Pln(gp::Origin(), gp::DZ())));
|
||||
offset.AddWire(wire);
|
||||
offset.Perform(d);
|
||||
face = BRepBuilderAPI_MakeFace(TopoDS::Wire(offset));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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::ptr profiles = l->Profiles();
|
||||
bool first = true;
|
||||
for (IfcSchema::IfcProfileDef::list::it it = profiles->begin(); it != profiles->end(); ++it) {
|
||||
TopoDS_Face f;
|
||||
if (convert_face(*it, f)) {
|
||||
builder.Add(compound, f);
|
||||
/* TopExp_Explorer exp(f, TopAbs_WIRE);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
const TopoDS_Wire& wire = TopoDS::Wire(exp.Current());
|
||||
if (first) {
|
||||
mf.Init(BRepBuilderAPI_MakeFace(wire));
|
||||
} else {
|
||||
mf.Add(wire);
|
||||
}
|
||||
first = false;
|
||||
} */
|
||||
}
|
||||
}
|
||||
|
||||
face = compound;
|
||||
return !face.IsNull();
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcDerivedProfileDef* l, TopoDS_Shape& face) {
|
||||
TopoDS_Face f;
|
||||
gp_Trsf2d 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;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_IFC4
|
||||
|
||||
bool convert_surf(IfcSchema::IfcBSplineSurfaceWithKnots* l, Handle_Geom_Surface& surf) {
|
||||
SHARED_PTR< IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint> > cps = l->ControlPointsList();
|
||||
std::vector<double> uknots = l->UKnots();
|
||||
std::vector<double> vknots = l->VKnots();
|
||||
std::vector<int> umults = l->UMultiplicities();
|
||||
std::vector<int> vmults = l->VMultiplicities();
|
||||
|
||||
TColgp_Array2OfPnt Poles (0, cps->size() - 1, 0, (*cps->begin()).size() - 1);
|
||||
TColStd_Array1OfReal UKnots(0, uknots.size() - 1);
|
||||
TColStd_Array1OfReal VKnots(0, vknots.size() - 1);
|
||||
TColStd_Array1OfInteger UMults(0, umults.size() - 1);
|
||||
TColStd_Array1OfInteger VMults(0, vmults.size() - 1);
|
||||
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;
|
||||
}
|
||||
surf = new Geom_BSplineSurface(Poles, UKnots, VKnots, UMults, VMults, UDegree, VDegree);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool convert_surf(IfcSchema::IfcPlane* l, Handle_Geom_Surface& surf) {
|
||||
gp_Pln pln;
|
||||
convert(l, pln);
|
||||
surf = new Geom_Plane(pln);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAdvancedFace* l, TopoDS_Shape& face) {
|
||||
IfcSchema::IfcSurface* s = l->FaceSurface();
|
||||
Handle_Geom_Surface surf(0);
|
||||
if (s->is(IfcSchema::Type::IfcBSplineSurfaceWithKnots)) {
|
||||
convert_surf((IfcSchema::IfcBSplineSurfaceWithKnots*)s, surf);
|
||||
} else if (s->is(IfcSchema::Type::IfcPlane)) {
|
||||
convert_surf((IfcSchema::IfcPlane*)s, surf);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeFace mf(surf, Precision::Confusion());
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
|
||||
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
|
||||
IfcSchema::IfcLoop* loop = (*it)->Bound();
|
||||
TopoDS_Wire outer_wire;
|
||||
if (!convert_wire(loop, outer_wire)) return false;
|
||||
|
||||
TopoDS_Face temp = BRepBuilderAPI_MakeFace(surf, outer_wire);
|
||||
|
||||
if (BRepCheck_Face(temp).OrientationOfWires() == BRepCheck_BadOrientationOfSubshape) {
|
||||
outer_wire.Reverse();
|
||||
ShapeFix_Face fix(BRepBuilderAPI_MakeFace(surf, outer_wire).Face());
|
||||
fix.FixOrientation();
|
||||
fix.Perform();
|
||||
TopoDS_Face temp = fix.Face();
|
||||
TopExp_Explorer exp(temp, TopAbs_WIRE);
|
||||
outer_wire = TopoDS::Wire(exp.Current());
|
||||
}
|
||||
|
||||
mf.Add(outer_wire);
|
||||
}
|
||||
|
||||
face = mf.Face();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
+734
-104
File diff suppressed because it is too large
Load Diff
+120
-77
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -77,28 +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 Ifc2x3::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]*Ifc::LengthUnit) : 0.0f,
|
||||
xyz.size() > 1 ? (xyz[1]*Ifc::LengthUnit) : 0.0f,
|
||||
xyz.size() > 2 ? (xyz[2]*Ifc::LengthUnit) : 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 Ifc2x3::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(
|
||||
@@ -109,21 +100,23 @@ bool IfcGeom::convert(const Ifc2x3::IfcDirection::ptr l, gp_Dir& dir) {
|
||||
CACHE(IfcDirection,l,dir)
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::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() * Ifc::LengthUnit * 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 Ifc2x3::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);
|
||||
bool hasRef = l->hasRefDirection();
|
||||
if ( l->hasAxis() ) IfcGeom::convert(l->Axis(),axis);
|
||||
if ( hasRef ) IfcGeom::convert(l->RefDirection(),refDirection);
|
||||
IfcGeom::Kernel::convert(l->Location(),o);
|
||||
bool hasRef = l->RefDirection() ? true : false;
|
||||
if ( l->Axis() ) 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);
|
||||
@@ -131,57 +124,88 @@ bool IfcGeom::convert(const Ifc2x3::IfcAxis2Placement3D::ptr l, gp_Trsf& trsf) {
|
||||
CACHE(IfcAxis2Placement3D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcCartesianTransformationOperator3D::ptr l, gp_Trsf& trsf) {
|
||||
|
||||
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::Kernel::convert(l->Location(),o);
|
||||
if ( l->Axis() ) IfcGeom::Kernel::convert(*l->Axis(), axis);
|
||||
ax = gp_Ax1(o, axis);
|
||||
CACHE(IfcAxis1Placement,l,ax)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator3D* l, gp_Trsf& trsf) {
|
||||
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->Axis1() ) IfcGeom::Kernel::convert(*l->Axis1(),axis1);
|
||||
if ( l->Axis2() ) IfcGeom::Kernel::convert(*l->Axis2(),axis2);
|
||||
if ( l->Axis3() ) IfcGeom::Kernel::convert(*l->Axis3(),axis3);
|
||||
gp_Ax3 ax3 (origin,axis3,axis1);
|
||||
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
|
||||
trsf.SetTransformation(ax3);
|
||||
trsf.Invert();
|
||||
if ( l->hasScale() ) trsf.SetScaleFactor(l->Scale());
|
||||
if ( l->Scale() ) trsf.SetScaleFactor(*l->Scale());
|
||||
CACHE(IfcCartesianTransformationOperator3D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::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;
|
||||
IfcGeom::convert(l->LocalOrigin(),origin);
|
||||
gp_Dir axis1 (1.,0.,0.);
|
||||
if ( l->hasAxis1() ) IfcGeom::convert(l->Axis1(),axis1);
|
||||
const gp_Ax2d ax2d (gp_Pnt2d(origin.X(),origin.Y()),gp_Dir2d(axis1.X(),axis1.Y()));
|
||||
gp_Dir axis2 (0.,1.,0.);
|
||||
|
||||
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
|
||||
if ( l->Axis1() ) IfcGeom::Kernel::convert(*l->Axis1(),axis1);
|
||||
if ( l->Axis2() ) IfcGeom::Kernel::convert(*l->Axis2(),axis2);
|
||||
|
||||
const gp_Pnt2d origin2d(origin.X(), origin.Y());
|
||||
const gp_Dir2d axis12d(axis1.X(), axis1.Y());
|
||||
const gp_Dir2d axis22d(axis2.X(), axis2.Y());
|
||||
|
||||
// A better match to represent the IfcCartesianTransformationOperator2D would
|
||||
// be the gp_Ax22d, but to my knowledge no easy way exists to convert it into
|
||||
// a gp_Trsf2d. Easiest would probably be to simply update the underlying
|
||||
// gp_Mat2d directly.
|
||||
|
||||
const gp_Ax2d ax2d (origin2d, axis12d);
|
||||
trsf.SetTransformation(ax2d);
|
||||
|
||||
if ( ax2d.Direction().Rotated(M_PI / 2.).Dot(axis22d) < 0. ) {
|
||||
gp_Trsf2d mirror; mirror.SetMirror(ax2d);
|
||||
trsf.Multiply(mirror);
|
||||
}
|
||||
|
||||
trsf.Invert();
|
||||
if ( l->hasScale() ) trsf.SetScaleFactor(l->Scale());
|
||||
if ( l->Scale() ) trsf.SetScaleFactor(*l->Scale());
|
||||
CACHE(IfcCartesianTransformationOperator2D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::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->Axis1() ) IfcGeom::Kernel::convert(*l->Axis1(),axis1);
|
||||
if ( l->Axis2() ) IfcGeom::Kernel::convert(*l->Axis2(),axis2);
|
||||
if ( l->Axis3() ) IfcGeom::Kernel::convert(*l->Axis3(),axis3);
|
||||
gp_Ax3 ax3 (origin,axis3,axis1);
|
||||
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
|
||||
trsf.SetTransformation(ax3);
|
||||
trsf.Invert();
|
||||
const double scale1 = l->hasScale() ? l->Scale() : 1.0f;
|
||||
const double scale2 = l->hasScale2() ? l->Scale2() : scale1;
|
||||
const double scale3 = l->hasScale3() ? l->Scale3() : scale1;
|
||||
const double scale1 = l->Scale() ? *l->Scale() : 1.0f;
|
||||
const double scale2 = l->Scale2() ? *l->Scale2() : scale1;
|
||||
const double scale3 = l->Scale3() ? *l->Scale3() : scale1;
|
||||
gtrsf = gp_GTrsf();
|
||||
gtrsf.SetValue(1,1,scale1);
|
||||
gtrsf.SetValue(2,2,scale2);
|
||||
@@ -190,18 +214,35 @@ bool IfcGeom::convert(const Ifc2x3::IfcCartesianTransformationOperator3DnonUnifo
|
||||
CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gtrsf)
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::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;
|
||||
gp_Pnt origin;
|
||||
IfcGeom::convert(l->LocalOrigin(),origin);
|
||||
gp_Dir axis1 (1.,0.,0.);
|
||||
if ( l->hasAxis1() ) IfcGeom::convert(l->Axis1(),axis1);
|
||||
const gp_Ax2d ax2d (gp_Pnt2d(origin.X(),origin.Y()),gp_Dir2d(axis1.X(),axis1.Y()));
|
||||
gp_Dir axis2 (0.,1.,0.);
|
||||
|
||||
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
|
||||
if ( l->Axis1() ) IfcGeom::Kernel::convert(*l->Axis1(),axis1);
|
||||
if ( l->Axis2() ) IfcGeom::Kernel::convert(*l->Axis2(),axis2);
|
||||
|
||||
const gp_Pnt2d origin2d(origin.X(), origin.Y());
|
||||
const gp_Dir2d axis12d(axis1.X(), axis1.Y());
|
||||
const gp_Dir2d axis22d(axis2.X(), axis2.Y());
|
||||
|
||||
const gp_Ax2d ax2d (origin2d, axis12d);
|
||||
trsf.SetTransformation(ax2d);
|
||||
|
||||
if ( ax2d.Direction().Rotated(M_PI / 2.).Dot(axis22d) < 0. ) {
|
||||
gp_Trsf2d mirror; mirror.SetMirror(ax2d);
|
||||
trsf.Multiply(mirror);
|
||||
}
|
||||
|
||||
trsf.Invert();
|
||||
const double scale1 = l->hasScale() ? l->Scale() : 1.0f;
|
||||
const double scale2 = l->hasScale2() ? l->Scale2() : scale1;
|
||||
|
||||
const double scale1 = l->Scale() ? *l->Scale() : 1.0f;
|
||||
const double scale2 = l->Scale2() ? *l->Scale2() : scale1;
|
||||
gtrsf = gp_GTrsf2d();
|
||||
gtrsf.SetValue(1,1,scale1);
|
||||
gtrsf.SetValue(2,2,scale2);
|
||||
@@ -209,14 +250,15 @@ bool IfcGeom::convert(const Ifc2x3::IfcCartesianTransformationOperator2DnonUnifo
|
||||
CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gtrsf)
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcPlane::ptr pln, gp_Pln& plane) {
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPlane* pln, gp_Pln& plane) {
|
||||
IN_CACHE(IfcPlane,pln,gp_Pln,plane)
|
||||
Ifc2x3::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);
|
||||
bool hasRef = l->hasRefDirection();
|
||||
if ( l->hasAxis() ) IfcGeom::convert(l->Axis(),axis);
|
||||
if ( hasRef ) IfcGeom::convert(l->RefDirection(),refDirection);
|
||||
IfcGeom::Kernel::convert(l->Location(),o);
|
||||
bool hasRef = l->RefDirection();
|
||||
if ( l->Axis() ) 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);
|
||||
@@ -224,40 +266,41 @@ bool IfcGeom::convert(const Ifc2x3::IfcPlane::ptr pln, gp_Pln& plane) {
|
||||
CACHE(IfcPlane,pln,plane)
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::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);
|
||||
if ( l->hasRefDirection() )
|
||||
IfcGeom::convert(l->RefDirection(),V);
|
||||
IfcGeom::Kernel::convert(l->Location(),P);
|
||||
if ( l->RefDirection() )
|
||||
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());
|
||||
CACHE(IfcAxis2Placement2D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::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(Ifc2x3::Type::IfcLocalPlacement) ) return false;
|
||||
Ifc2x3::IfcLocalPlacement::ptr current = reinterpret_pointer_cast<Ifc2x3::IfcObjectPlacement,Ifc2x3::IfcLocalPlacement>(l);
|
||||
if ( ! l->is(IfcSchema::Type::IfcLocalPlacement) ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity);
|
||||
return false;
|
||||
}
|
||||
IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l;
|
||||
while (1) {
|
||||
gp_Trsf trsf2;
|
||||
Ifc2x3::IfcAxis2Placement relplacement = current->RelativePlacement();
|
||||
if ( relplacement->is(Ifc2x3::Type::IfcAxis2Placement3D) ) {
|
||||
IfcGeom::convert((Ifc2x3::IfcAxis2Placement3D*)relplacement,trsf2);
|
||||
IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement();
|
||||
if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2);
|
||||
trsf.PreMultiply(trsf2);
|
||||
}
|
||||
if ( current->hasPlacementRelTo() ) {
|
||||
Ifc2x3::IfcObjectPlacement::ptr relto = current->PlacementRelTo();
|
||||
if ( relto->is(Ifc2x3::Type::IfcLocalPlacement) )
|
||||
current = reinterpret_pointer_cast<Ifc2x3::IfcObjectPlacement,Ifc2x3::IfcLocalPlacement>(current->PlacementRelTo());
|
||||
if ( current->PlacementRelTo() ) {
|
||||
IfcSchema::IfcObjectPlacement* relto = *current->PlacementRelTo();
|
||||
if ( relto->is(IfcSchema::Type::IfcLocalPlacement) )
|
||||
current = (IfcSchema::IfcLocalPlacement*) relto;
|
||||
else break;
|
||||
} else break;
|
||||
}
|
||||
CACHE(IfcObjectPlacement,l,trsf)
|
||||
return true;
|
||||
}
|
||||
void IfcGeom::Cache::Purge() {
|
||||
#include "IfcRegisterPurgeCache.h"
|
||||
IfcGeom::Cache::PurgeShapeCache();
|
||||
}
|
||||
@@ -0,0 +1,493 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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::findContext() *
|
||||
* 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 <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) {
|
||||
std::string uppercase_type = *it;
|
||||
for (std::string::iterator c = uppercase_type.begin(); c != uppercase_type.end(); ++c) {
|
||||
*c = toupper(*c);
|
||||
}
|
||||
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 findContext() {
|
||||
try {
|
||||
initUnits();
|
||||
} catch (...) {}
|
||||
|
||||
// Really this should only be 'Model', as per
|
||||
// the standard 'Design' is deprecated. So,
|
||||
// just for backwards compatibility:
|
||||
std::set<std::string> context_types;
|
||||
context_types.insert("model");
|
||||
context_types.insert("design");
|
||||
// DDS likes to output 'model view'
|
||||
context_types.insert("model view");
|
||||
|
||||
double lowest_precision_encountered = std::numeric_limits<double>::infinity();
|
||||
bool any_precision_encountered = false;
|
||||
|
||||
representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
|
||||
|
||||
IfcSchema::IfcGeometricRepresentationContext::list::it it;
|
||||
IfcSchema::IfcGeometricRepresentationSubContext::list::it jt;
|
||||
IfcSchema::IfcGeometricRepresentationContext::list::ptr contexts =
|
||||
ifc_file->entitiesByType<IfcSchema::IfcGeometricRepresentationContext>();
|
||||
|
||||
IfcSchema::IfcGeometricRepresentationContext::list::ptr filtered_contexts (new IfcSchema::IfcGeometricRepresentationContext::list);
|
||||
|
||||
for (it = contexts->begin(); it != contexts->end(); ++it) {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
if (context->is(IfcSchema::Type::IfcGeometricRepresentationSubContext)) {
|
||||
// Continue, as the list of subcontexts will be considered
|
||||
// by the parent's context inverse attributes.
|
||||
continue;
|
||||
}
|
||||
if (context->ContextType()) {
|
||||
std::string context_type_lc = *context->ContextType();
|
||||
for (std::string::iterator c = context_type_lc.begin(); c != context_type_lc.end(); ++c) {
|
||||
*c = tolower(*c);
|
||||
}
|
||||
if (context_types.find(context_type_lc) != context_types.end()) {
|
||||
filtered_contexts->push(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (filtered_contexts->size() == 0) {
|
||||
filtered_contexts = contexts;
|
||||
}
|
||||
|
||||
for (it = filtered_contexts->begin(); it != filtered_contexts->end(); ++it) {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
|
||||
representations->push(context->RepresentationsInContext());
|
||||
if (context->Precision() && *context->Precision() < lowest_precision_encountered) {
|
||||
lowest_precision_encountered = *context->Precision();
|
||||
any_precision_encountered = true;
|
||||
}
|
||||
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() {
|
||||
while ( true ) {
|
||||
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)->is(IfcSchema::Type::IfcProductDefinitionShape) ) {
|
||||
IfcSchema::IfcProductDefinitionShape* pds = (IfcSchema::IfcProductDefinitionShape*)*it;
|
||||
unfiltered_products->push(pds->ShapeOfProduct());
|
||||
} else {
|
||||
// http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm
|
||||
// IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards.
|
||||
// It will be changed into an ABSTRACT supertype in future releases of IFC.
|
||||
|
||||
// IfcProductRepresentation also lacks the INVERSE relation to IfcProduct
|
||||
// Let's find the IfcProducts that reference the IfcProductRepresentation anyway
|
||||
unfiltered_products->push((*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>());
|
||||
}
|
||||
|
||||
// Filter the products based on the set of entities being included or excluded for
|
||||
// processing. The set is iterated over te able to filter on subtypes.
|
||||
for ( IfcSchema::IfcProduct::list::it it = unfiltered_products->begin(); it != unfiltered_products->end(); ++it ) {
|
||||
bool found = false;
|
||||
for (std::set<IfcSchema::Type::Enum>::const_iterator jt = entities_to_include_or_exclude.begin(); jt != entities_to_include_or_exclude.end(); ++jt) {
|
||||
if ((*it)->is(*jt)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found == include_entities_in_processing) {
|
||||
ifcproducts->push(*it);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// 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->type());
|
||||
if ( ifc_entity->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->entity->id();
|
||||
}
|
||||
} catch (...) {}
|
||||
|
||||
try {
|
||||
kernel.convert(ifc_product->ObjectPlacement(), trsf);
|
||||
} catch (...) {}
|
||||
}
|
||||
} catch(...) {}
|
||||
|
||||
ElementSettings element_settings(settings, unit_magnitude, instance_type);
|
||||
Element<P>* ifc_object = new Element<P>(element_settings, id, parent_id, product_name, instance_type, product_guid, trsf);
|
||||
|
||||
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_FORCE_CCW_FACE_ORIENTATION, settings.force_ccw_face_orientation() ? 1 : -1);
|
||||
}
|
||||
public:
|
||||
Iterator(const IteratorSettings& settings, IfcParse::IfcFile* file)
|
||||
: settings(settings)
|
||||
, ifc_file(file)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
Iterator(const IteratorSettings& settings, const std::string& filename)
|
||||
: settings(settings)
|
||||
, ifc_file(new IfcParse::IfcFile)
|
||||
{
|
||||
ifc_file->Init(filename);
|
||||
initialize();
|
||||
}
|
||||
Iterator(const IteratorSettings& settings, void* data, int length)
|
||||
: settings(settings)
|
||||
, ifc_file(new IfcParse::IfcFile)
|
||||
{
|
||||
ifc_file->Init(data, length);
|
||||
initialize();
|
||||
}
|
||||
Iterator(const IteratorSettings& settings, std::istream& filestream, int length)
|
||||
: settings(settings)
|
||||
, ifc_file(new IfcParse::IfcFile)
|
||||
{
|
||||
ifc_file->Init(filestream, length);
|
||||
initialize();
|
||||
}
|
||||
|
||||
~Iterator() {
|
||||
// TODO: Correctly implement destructor for IfcFile
|
||||
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,172 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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;
|
||||
// By default singular faces have no explicitly defined orientation, to
|
||||
// force faces to be defined CounterClockWise set this to true.
|
||||
static const int FORCE_CCW_FACE_ORIENTATION = 7;
|
||||
// Disables the subtraction of IfcOpeningElement representations from
|
||||
// the related building element representations.
|
||||
static const int DISABLE_OPENING_SUBTRACTIONS = 8;
|
||||
// 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;
|
||||
|
||||
// End of settings enumeration.
|
||||
|
||||
private:
|
||||
bool _weld_vertices, _use_world_coords, _convert_back_units, _use_brep_data, _sew_shells, _faster_booleans, _force_ccw_face_orientation, _disable_opening_subtractions, _disable_triangulation, _apply_default_materials;
|
||||
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)
|
||||
, _force_ccw_face_orientation(false)
|
||||
, _disable_opening_subtractions(false)
|
||||
, _disable_triangulation(false)
|
||||
, _apply_default_materials(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& force_ccw_face_orientation() const { return _force_ccw_face_orientation; }
|
||||
bool& force_ccw_face_orientation() { return _force_ccw_face_orientation; }
|
||||
const bool& disable_opening_subtractions() const { return _disable_opening_subtractions; }
|
||||
bool& disable_opening_subtractions() { return _disable_opening_subtractions; }
|
||||
const bool& disable_triangulation() const { return _disable_triangulation; }
|
||||
bool& disable_triangulation() { return _disable_triangulation; }
|
||||
const bool& apply_default_materials() const { return _apply_default_materials; }
|
||||
bool& apply_default_materials() { return _apply_default_materials; }
|
||||
|
||||
const 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 FORCE_CCW_FACE_ORIENTATION:
|
||||
_force_ccw_face_orientation = 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;
|
||||
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; }
|
||||
@@ -17,64 +17,34 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
namespace IfcGeomObjects {
|
||||
#ifndef IFCGEOMMATERIAL_H
|
||||
#define IFCGEOMMATERIAL_H
|
||||
|
||||
const int WELD_VERTICES = 1;
|
||||
const int USE_WORLD_COORDS = 2;
|
||||
const int CONVERT_BACK_UNITS = 3;
|
||||
const int USE_BREP_DATA = 4;
|
||||
const int SEW_SHELLS = 5;
|
||||
#include <string>
|
||||
|
||||
class IfcMesh {
|
||||
#include "../ifcgeom/IfcGeomRenderStyles.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
class Material {
|
||||
private:
|
||||
const IfcGeom::SurfaceStyle* style;
|
||||
public:
|
||||
int id;
|
||||
std::vector<float> verts;
|
||||
std::vector<int> faces;
|
||||
std::vector<int> edges;
|
||||
std::vector<float> normals;
|
||||
std::string brep_data;
|
||||
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;
|
||||
};
|
||||
|
||||
class IfcObject {
|
||||
public:
|
||||
int id;
|
||||
int parent_id;
|
||||
std::string name;
|
||||
std::string type;
|
||||
std::string guid;
|
||||
std::vector<float> matrix;
|
||||
const std::vector<int> name_as_intvector() {
|
||||
std::vector<int> r;
|
||||
for ( std::string::const_iterator it = name.begin(); it != name.end(); ++ it ) r.push_back(*it);
|
||||
return r;
|
||||
}
|
||||
const std::vector<int> type_as_intvector() {
|
||||
std::vector<int> r;
|
||||
for ( std::string::const_iterator it = type.begin(); it != type.end(); ++ it ) r.push_back(*it);
|
||||
return r;
|
||||
}
|
||||
const std::vector<int> guid_as_intvector() {
|
||||
std::vector<int> r;
|
||||
for ( std::string::const_iterator it = guid.begin(); it != guid.end(); ++ it ) r.push_back(*it);
|
||||
return r;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class IfcGeomObject : public IfcObject {
|
||||
public:
|
||||
IfcMesh* mesh;
|
||||
};
|
||||
|
||||
bool Next();
|
||||
const IfcGeomObject* Get();
|
||||
bool Init(const std::string fn);
|
||||
bool InitUCS2(const char* fn) {
|
||||
return Init(std::string(fn+1));
|
||||
}
|
||||
void Settings(int setting, bool value);
|
||||
int Progress();
|
||||
const IfcObject* GetObject(int id);
|
||||
bool CleanUp();
|
||||
std::string GetLog();
|
||||
|
||||
};
|
||||
#endif
|
||||
@@ -1,550 +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 <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 "../ifcgeom/IfcGeomObjects.h"
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
// Welds vertices that belong to different faces
|
||||
bool weld_vertices = true;
|
||||
bool convert_back_units = false;
|
||||
bool use_faster_booleans = false;
|
||||
|
||||
int IfcGeomObjects::IfcMesh::addvert(const gp_XYZ& p) {
|
||||
const float X = convert_back_units ? (float) (p.X() / Ifc::LengthUnit) : (float)p.X();
|
||||
const float Y = convert_back_units ? (float) (p.Y() / Ifc::LengthUnit) : (float)p.Y();
|
||||
const float Z = convert_back_units ? (float) (p.Z() / Ifc::LengthUnit) : (float)p.Z();
|
||||
int i = (int) verts.size() / 3;
|
||||
if ( weld_vertices ) {
|
||||
const VertKey key = VertKey(X,std::pair<float,float>(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;
|
||||
}
|
||||
|
||||
bool use_world_coords = false;
|
||||
bool use_brep_data = false;
|
||||
|
||||
IfcGeomObjects::IfcMesh::IfcMesh(int i, const IfcGeom::ShapeList& shapes) {
|
||||
id = i;
|
||||
|
||||
if ( use_brep_data ) {
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
for ( IfcGeom::ShapeList::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) {
|
||||
const TopoDS_Shape& s = *(*it).second;
|
||||
const gp_GTrsf& trsf = *(*it).first;
|
||||
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();
|
||||
} else
|
||||
for ( IfcGeom::ShapeList::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) {
|
||||
|
||||
const TopoDS_Shape& s = *(*it).second;
|
||||
const gp_GTrsf& trsf = *(*it).first;
|
||||
|
||||
// Triangulate the shape
|
||||
try {
|
||||
//BRepTools::Clean(s);
|
||||
BRepMesh::Mesh(s,DEFLECTION_TOLERANCE);
|
||||
} catch(...) {
|
||||
Ifc::LogMessage("Error","Failed to triangulate mesh:",Ifc::EntityById(i)->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(*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_Dir 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]);
|
||||
|
||||
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 my_id,
|
||||
int p_id,
|
||||
const std::string& n,
|
||||
const std::string& t,
|
||||
const std::string& g,
|
||||
const gp_Trsf& trsf) {
|
||||
|
||||
// Convert the gp_Trsf into a 4x3 Matrix
|
||||
for( int i = 1; i < 5; ++ i )
|
||||
for ( int j = 1; j < 4; ++ j )
|
||||
matrix.push_back((float)trsf.Value(j,i));
|
||||
|
||||
id = my_id;
|
||||
parent_id = p_id;
|
||||
name = n;
|
||||
type = t;
|
||||
guid = g;
|
||||
}
|
||||
|
||||
IfcGeomObjects::IfcGeomObject::IfcGeomObject(int my_id,
|
||||
int p_id,
|
||||
const std::string& n,
|
||||
const std::string& t,
|
||||
const std::string& g,
|
||||
const gp_Trsf& trsf,
|
||||
IfcMesh* m) : IfcObject(my_id,p_id,n,t,g,trsf) {
|
||||
|
||||
mesh = m;
|
||||
}
|
||||
|
||||
// A container and iterator for IfcShapeRepresentations
|
||||
Ifc2x3::IfcShapeRepresentation::list shapereps;
|
||||
Ifc2x3::IfcShapeRepresentation::it outer;
|
||||
|
||||
// The object is fetched beforehand to be positive an entity actually exists
|
||||
IfcGeomObjects::IfcGeomObject* current_geom_obj;
|
||||
|
||||
// A container and iterator for IfcBuildingElements for the current IfcShapeRepresentation referenced by *outer
|
||||
Ifc2x3::IfcProduct::list entities;
|
||||
Ifc2x3::IfcProduct::it inner;
|
||||
|
||||
int done;
|
||||
int total;
|
||||
|
||||
// Move the the next IfcShapeRepresentation
|
||||
void _nextShape() {
|
||||
entities.reset();
|
||||
++ outer;
|
||||
++ done;
|
||||
}
|
||||
|
||||
int _getParentId(const Ifc2x3::IfcProduct::ptr ifc_product) {
|
||||
int parent_id = -1;
|
||||
// In case of an opening element, parent to the RelatingBuildingElement
|
||||
if ( ifc_product->is(Ifc2x3::Type::IfcOpeningElement ) ) {
|
||||
Ifc2x3::IfcOpeningElement::ptr opening = reinterpret_pointer_cast<Ifc2x3::IfcProduct,Ifc2x3::IfcOpeningElement>(ifc_product);
|
||||
Ifc2x3::IfcRelVoidsElement::list voids = opening->VoidsElements();
|
||||
if ( voids->Size() ) {
|
||||
Ifc2x3::IfcRelVoidsElement::ptr ifc_void = *voids->begin();
|
||||
parent_id = ifc_void->RelatingBuildingElement()->entity->id();
|
||||
}
|
||||
} else if ( ifc_product->is(Ifc2x3::Type::IfcElement ) ) {
|
||||
Ifc2x3::IfcElement::ptr element = reinterpret_pointer_cast<Ifc2x3::IfcProduct,Ifc2x3::IfcElement>(ifc_product);
|
||||
Ifc2x3::IfcRelFillsElement::list fills = element->FillsVoids();
|
||||
// Incase of a RelatedBuildingElement parent to the opening element
|
||||
if ( fills->Size() ) {
|
||||
for ( Ifc2x3::IfcRelFillsElement::it it = fills->begin(); it != fills->end(); ++ it ) {
|
||||
Ifc2x3::IfcRelFillsElement::ptr fill = *it;
|
||||
Ifc2x3::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 ) {
|
||||
Ifc2x3::IfcRelContainedInSpatialStructure::list parents = element->ContainedInStructure();
|
||||
if ( parents->Size() ) {
|
||||
Ifc2x3::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(Ifc2x3::Type::IfcRelAggregates);
|
||||
parents->push(ifc_product->entity->getInverse(Ifc2x3::Type::IfcRelNests));
|
||||
for ( IfcEntityList::it it = parents->begin(); it != parents->end(); ++ it ) {
|
||||
Ifc2x3::IfcRelDecomposes::ptr decompose = reinterpret_pointer_cast<IfcBaseClass,Ifc2x3::IfcRelDecomposes>(*it);
|
||||
Ifc2x3::IfcObjectDefinition* ifc_objectdef = decompose->RelatingObject();
|
||||
if ( ifc_product == ifc_objectdef ) continue;
|
||||
parent_id = ifc_objectdef->entity->id();
|
||||
}
|
||||
}
|
||||
return parent_id;
|
||||
}
|
||||
|
||||
// Returns the current IfcGeomObject*
|
||||
IfcGeomObjects::IfcGeomObject* _get() {
|
||||
while ( true ) {
|
||||
Ifc2x3::IfcShapeRepresentation::ptr shaperep;
|
||||
|
||||
// Have we reached the end of our list of representations?
|
||||
if ( outer == shapereps->end() ) {
|
||||
shapereps.reset();
|
||||
return 0;
|
||||
}
|
||||
shaperep = *outer;
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
Ifc2x3::IfcProductRepresentation::list prodreps = shaperep->OfProductRepresentation();
|
||||
entities = Ifc2x3::IfcProduct::list( new IfcTemplatedEntityList<Ifc2x3::IfcProduct>() );
|
||||
for ( Ifc2x3::IfcProductRepresentation::it it = prodreps->begin(); it != prodreps->end(); ++it ) {
|
||||
if ( (*it)->is(Ifc2x3::Type::IfcProductDefinitionShape) ) {
|
||||
Ifc2x3::IfcProductDefinitionShape::ptr pds = reinterpret_pointer_cast<Ifc2x3::IfcProductRepresentation,Ifc2x3::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(Ifc2x3::Type::IfcProduct);
|
||||
for ( IfcEntityList::it it = products->begin(); it != products->end(); ++ it ) {
|
||||
entities->push(reinterpret_pointer_cast<IfcBaseClass,Ifc2x3::IfcProduct>(*it));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Does this representation have any IfcProducts?
|
||||
if ( ! entities->Size() ) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
inner = entities->begin();
|
||||
}
|
||||
// Have we reached the end of our list of IfcProducts?
|
||||
if ( inner == entities->end() ) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
IfcGeomObjects::IfcMesh* shape;
|
||||
IfcGeom::ShapeList shapes;
|
||||
|
||||
if ( !IfcGeom::convert_shapes(shaperep,shapes) ) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
Ifc2x3::IfcProduct::ptr ifc_product = *inner;
|
||||
|
||||
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
|
||||
Ifc2x3::IfcRelVoidsElement::list openings = Ifc2x3::IfcRelVoidsElement::list();
|
||||
if ( ifc_product->is(Ifc2x3::Type::IfcElement) && !ifc_product->is(Ifc2x3::Type::IfcOpeningElement) ) {
|
||||
Ifc2x3::IfcElement::ptr element = reinterpret_pointer_cast<Ifc2x3::IfcProduct,Ifc2x3::IfcElement>(ifc_product);
|
||||
openings = element->HasOpenings();
|
||||
}
|
||||
// Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements?
|
||||
if ( ifc_product->is(Ifc2x3::Type::IfcBuildingElementPart ) ) {
|
||||
Ifc2x3::IfcBuildingElementPart::ptr part = reinterpret_pointer_cast<Ifc2x3::IfcProduct,Ifc2x3::IfcBuildingElementPart>(ifc_product);
|
||||
Ifc2x3::IfcRelDecomposes::list decomposes = part->Decomposes();
|
||||
for ( Ifc2x3::IfcRelDecomposes::it it = decomposes->begin(); it != decomposes->end(); ++ it ) {
|
||||
Ifc2x3::IfcObjectDefinition::ptr obdef = (*it)->RelatingObject();
|
||||
if ( obdef->is(Ifc2x3::Type::IfcElement) ) {
|
||||
Ifc2x3::IfcElement::ptr element = reinterpret_pointer_cast<Ifc2x3::IfcObjectDefinition,Ifc2x3::IfcElement>(obdef);
|
||||
openings->push(element->HasOpenings());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( openings && openings->Size() ) {
|
||||
IfcGeom::ShapeList opened_shapes;
|
||||
try {
|
||||
if ( use_faster_booleans ) {
|
||||
bool succes = IfcGeom::convert_openings_fast(ifc_product,openings,shapes,trsf,opened_shapes);
|
||||
if ( ! succes ) {
|
||||
for ( IfcGeom::ShapeList::const_iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) {
|
||||
delete it->first;
|
||||
delete it->second;
|
||||
}
|
||||
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(...) {
|
||||
Ifc::LogMessage("Error","Error processing openings for:",ifc_product->entity);
|
||||
}
|
||||
if ( use_world_coords ) {
|
||||
for ( IfcGeom::ShapeList::const_iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) {
|
||||
it->first->PreMultiply(trsf);
|
||||
}
|
||||
trsf = gp_Trsf();
|
||||
}
|
||||
shape = new IfcGeomObjects::IfcMesh(shaperep->entity->id(),opened_shapes);
|
||||
for ( IfcGeom::ShapeList::const_iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) {
|
||||
delete it->first;
|
||||
delete it->second;
|
||||
}
|
||||
} else if ( use_world_coords ) {
|
||||
for ( IfcGeom::ShapeList::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) {
|
||||
it->first->PreMultiply(trsf);
|
||||
}
|
||||
trsf = gp_Trsf();
|
||||
shape = new IfcGeomObjects::IfcMesh(shaperep->entity->id(),shapes);
|
||||
} else {
|
||||
shape = new IfcGeomObjects::IfcMesh(shaperep->entity->id(),shapes);
|
||||
}
|
||||
|
||||
IfcGeomObjects::IfcGeomObject* geom_obj = new IfcGeomObjects::IfcGeomObject(ifc_product->entity->id(), parent_id, name,
|
||||
Ifc2x3::Type::ToString(ifc_product->type()), guid, trsf, shape);
|
||||
|
||||
for ( IfcGeom::ShapeList::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) {
|
||||
delete it->first;
|
||||
}
|
||||
|
||||
return geom_obj;
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeomObjects::Next() {
|
||||
if ( current_geom_obj ) {
|
||||
delete current_geom_obj->mesh;
|
||||
delete current_geom_obj;
|
||||
}
|
||||
if ( entities ) {
|
||||
++inner;
|
||||
}
|
||||
current_geom_obj = _get();
|
||||
if ( ! current_geom_obj ) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
std::vector<IfcGeomObjects::IfcObject*> returned_objects;
|
||||
bool IfcGeomObjects::CleanUp() {
|
||||
Ifc::Dispose();
|
||||
IfcGeom::Cache::Purge();
|
||||
for ( std::vector<IfcGeomObjects::IfcObject*>::const_iterator 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 IfcEntity& ifc_entity = Ifc::EntityById(id);
|
||||
if ( ifc_entity->is(Ifc2x3::Type::IfcProduct) ) {
|
||||
Ifc2x3::IfcProduct::ptr ifc_product = reinterpret_pointer_cast<IfcUtil::IfcBaseClass,Ifc2x3::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,
|
||||
Ifc2x3::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() {
|
||||
return current_geom_obj;
|
||||
}
|
||||
bool IfcGeomObjects::Init(const std::string fn) {
|
||||
return IfcGeomObjects::Init(fn, 0, 0);
|
||||
}
|
||||
bool _Init() {
|
||||
shapereps = Ifc::EntitiesByType<Ifc2x3::IfcShapeRepresentation>();
|
||||
if ( ! shapereps ) return false;
|
||||
|
||||
outer = shapereps->begin();
|
||||
entities.reset();
|
||||
current_geom_obj = _get();
|
||||
|
||||
if ( ! current_geom_obj ) return false;
|
||||
|
||||
done = 0;
|
||||
total = shapereps->Size();
|
||||
return true;
|
||||
}
|
||||
bool IfcGeomObjects::Init(const std::string fn, std::ostream* log1, std::ostream* log2) {
|
||||
Ifc::SetOutput(log1,log2);
|
||||
if ( !Ifc::Init(fn) ) return false;
|
||||
return _Init();
|
||||
}
|
||||
bool IfcGeomObjects::Init(std::istream& f, int len, std::ostream* log1, std::ostream* log2) {
|
||||
Ifc::SetOutput(log1,log2);
|
||||
if ( !Ifc::Init(f, len) ) return false;
|
||||
return _Init();
|
||||
}
|
||||
bool IfcGeomObjects::Init(void* data, int len) {
|
||||
Ifc::SetOutput(0,0);
|
||||
if ( !Ifc::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:
|
||||
Ifc::SewShells = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int IfcGeomObjects::Progress() {
|
||||
return 100 * done / total;
|
||||
}
|
||||
std::string IfcGeomObjects::GetLog() {
|
||||
return Ifc::GetLog();
|
||||
}
|
||||
@@ -1,160 +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/IfcShapeList.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;
|
||||
|
||||
// End of settings enumeration.
|
||||
|
||||
// Some typedefs for convenience
|
||||
typedef std::vector<int>::const_iterator IntIt;
|
||||
typedef std::vector<float>::const_iterator FltIt;
|
||||
// A nested pair of doubles to be able to store an XYZ coordinate in a map.
|
||||
typedef std::pair< float,std::pair<float,float> > VertKey;
|
||||
typedef std::map<VertKey,int> VertKeyMap;
|
||||
typedef std::pair<int,int> Edge;
|
||||
|
||||
class IfcMesh {
|
||||
public:
|
||||
int id;
|
||||
std::vector<float> verts;
|
||||
std::vector<int> faces;
|
||||
std::vector<int> edges;
|
||||
std::vector<float> normals;
|
||||
std::string brep_data;
|
||||
VertKeyMap welds;
|
||||
|
||||
IfcMesh(int i, const IfcGeom::ShapeList& s);
|
||||
private:
|
||||
int addvert(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);
|
||||
}
|
||||
};
|
||||
|
||||
class IfcObject {
|
||||
public:
|
||||
int id;
|
||||
int parent_id;
|
||||
std::string name;
|
||||
std::string type;
|
||||
std::string guid;
|
||||
std::vector<float> matrix;
|
||||
IfcObject(int my_id, int p_id, const std::string& n, const std::string& t, const std::string& g, const gp_Trsf& trsf);
|
||||
};
|
||||
|
||||
class IfcGeomObject : public IfcObject {
|
||||
public:
|
||||
IfcMesh* mesh;
|
||||
IfcGeomObject(int my_id, int p_id, const std::string& n, const std::string& t, const std::string& g, const gp_Trsf& trsf, IfcMesh* m);
|
||||
};
|
||||
|
||||
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);
|
||||
bool CleanUp();
|
||||
const IfcGeomObject* Get();
|
||||
bool Next();
|
||||
int Progress();
|
||||
const IfcObject* GetObject(int id);
|
||||
std::string GetLog();
|
||||
|
||||
}
|
||||
|
||||
#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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "IfcGeom.h"
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourRgb* colour, std::tr1::array<double, 3>& rgb) {
|
||||
if (colour != 0) {
|
||||
rgb[0] = colour->Red();
|
||||
rgb[1] = colour->Green();
|
||||
rgb[2] = colour->Blue();
|
||||
}
|
||||
return colour != 0;
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, std::tr1::array<double, 3>& rgb) {
|
||||
if (factor != 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) {
|
||||
if (colour_or_factor == 0) {
|
||||
return false;
|
||||
} else if (colour_or_factor->is(IfcSchema::Type::IfcColourRgb)) {
|
||||
return process_colour(static_cast<IfcSchema::IfcColourRgb*>(colour_or_factor), rgb);
|
||||
} else if (colour_or_factor->is(IfcSchema::Type::IfcNormalisedRatioMeasure)) {
|
||||
return process_colour(static_cast<IfcSchema::IfcNormalisedRatioMeasure*>(colour_or_factor), rgb);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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()) {
|
||||
return &(it->second);
|
||||
}
|
||||
SurfaceStyle surface_style;
|
||||
if (shading_styles.first->Name()) {
|
||||
surface_style = SurfaceStyle(surface_style_id, *shading_styles.first->Name());
|
||||
} else {
|
||||
surface_style = SurfaceStyle(surface_style_id);
|
||||
}
|
||||
std::tr1::array<double, 3> rgb;
|
||||
if (process_colour(shading_styles.second->SurfaceColour(), rgb)) {
|
||||
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
|
||||
}
|
||||
if (shading_styles.second->is(IfcSchema::Type::IfcSurfaceStyleRendering)) {
|
||||
IfcSchema::IfcSurfaceStyleRendering* rendering_style = static_cast<IfcSchema::IfcSurfaceStyleRendering*>(shading_styles.second);
|
||||
if (rendering_style->DiffuseColour() && process_colour(*rendering_style->DiffuseColour(), rgb)) {
|
||||
SurfaceStyle::ColorComponent diffuse = surface_style.Diffuse().get_value_or(SurfaceStyle::ColorComponent(1,1,1));
|
||||
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(diffuse.R() * rgb[0], diffuse.G() * rgb[1], diffuse.B() * rgb[2]));
|
||||
}
|
||||
if (rendering_style->DiffuseTransmissionColour()) {
|
||||
// Not supported
|
||||
}
|
||||
if (rendering_style->ReflectionColour()) {
|
||||
// Not supported
|
||||
}
|
||||
if (rendering_style->SpecularColour() && process_colour(*rendering_style->SpecularColour(), rgb)) {
|
||||
surface_style.Specular().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
|
||||
}
|
||||
if (rendering_style->SpecularHighlight()) {
|
||||
IfcSchema::IfcSpecularHighlightSelect* highlight = *rendering_style->SpecularHighlight();
|
||||
if (highlight->is(IfcSchema::Type::IfcSpecularRoughness)) {
|
||||
double roughness = *((IfcSchema::IfcSpecularRoughness*)highlight);
|
||||
if (roughness >= 1e-9) {
|
||||
surface_style.Specularity().reset(1.0 / roughness);
|
||||
}
|
||||
} else if (highlight->is(IfcSchema::Type::IfcSpecularExponent)) {
|
||||
surface_style.Specularity().reset(*((IfcSchema::IfcSpecularExponent*)highlight));
|
||||
}
|
||||
}
|
||||
if (rendering_style->TransmissionColour()) {
|
||||
// Not supported
|
||||
}
|
||||
if (rendering_style->Transparency()) {
|
||||
const double d = *rendering_style->Transparency();
|
||||
surface_style.Transparency().reset(d);
|
||||
}
|
||||
}
|
||||
return &(cache.Style[surface_style_id] = surface_style);
|
||||
}
|
||||
|
||||
static std::map<std::string, IfcGeom::SurfaceStyle> default_materials;
|
||||
static IfcGeom::SurfaceStyle default_material;
|
||||
static bool default_materials_initialized = false;
|
||||
|
||||
void InitDefaultMaterials() {
|
||||
default_materials.insert(std::make_pair("IfcSite", IfcGeom::SurfaceStyle("IfcSite")));
|
||||
default_materials["IfcSite" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.8, 0.65));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcSlab", IfcGeom::SurfaceStyle("IfcSlab")));
|
||||
default_materials["IfcSlab" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.4 , 0.4, 0.4 ));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcWallStandardCase", IfcGeom::SurfaceStyle("IfcWallStandardCase")));
|
||||
default_materials["IfcWallStandardCase"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.9 , 0.9, 0.9 ));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcWall", IfcGeom::SurfaceStyle("IfcWall")));
|
||||
default_materials["IfcWall" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.9 , 0.9, 0.9 ));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcWindow", IfcGeom::SurfaceStyle("IfcWindow")));
|
||||
default_materials["IfcWindow" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.8, 0.75));
|
||||
default_materials["IfcWindow" ].Transparency().reset(0.3);
|
||||
|
||||
default_materials.insert(std::make_pair("IfcDoor", IfcGeom::SurfaceStyle("IfcDoor")));
|
||||
default_materials["IfcDoor" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.55, 0.3, 0.15));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcBeam", IfcGeom::SurfaceStyle("IfcBeam")));
|
||||
default_materials["IfcBeam" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.7, 0.7 ));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcRailing", IfcGeom::SurfaceStyle("IfcRailing")));
|
||||
default_materials["IfcRailing" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.65, 0.6, 0.6 ));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcMember", IfcGeom::SurfaceStyle("IfcMember")));
|
||||
default_materials["IfcMember" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.65, 0.6, 0.6 ));
|
||||
|
||||
default_materials.insert(std::make_pair("IfcPlate", IfcGeom::SurfaceStyle("IfcPlate")));
|
||||
default_materials["IfcPlate" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.8 , 0.8, 0.8 ));
|
||||
|
||||
default_material = IfcGeom::SurfaceStyle("DefaultMaterial");
|
||||
default_material.Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.7, 0.7, 0.7));
|
||||
|
||||
default_materials_initialized = true;
|
||||
}
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::get_default_style(const std::string& s) {
|
||||
if (!default_materials_initialized) InitDefaultMaterials();
|
||||
std::map<std::string, IfcGeom::SurfaceStyle>::const_iterator it = default_materials.find(s);
|
||||
if (it == default_materials.end()) {
|
||||
default_materials.insert(std::make_pair(s, IfcGeom::SurfaceStyle(s)));
|
||||
default_materials[s].Diffuse().reset(*default_material.Diffuse());
|
||||
it = default_materials.find(s);
|
||||
}
|
||||
const IfcGeom::SurfaceStyle& surface_style = it->second;
|
||||
return &surface_style;
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 IFCGEOMRENDERSTYLES_H
|
||||
#define IFCGEOMRENDERSTYLES_H
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <tr1/array>
|
||||
#else
|
||||
#include <array>
|
||||
#endif
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include "../ifcparse/Ifc4.h"
|
||||
#else
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#endif
|
||||
|
||||
namespace IfcGeom {
|
||||
class SurfaceStyle {
|
||||
public:
|
||||
class ColorComponent {
|
||||
private:
|
||||
std::tr1::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:
|
||||
boost::optional<std::string> name;
|
||||
boost::optional<int> id;
|
||||
boost::optional<ColorComponent> diffuse, specular;
|
||||
boost::optional<double> transparency;
|
||||
boost::optional<double> specularity;
|
||||
public:
|
||||
SurfaceStyle() {
|
||||
this->name = "IfcSurfaceStyleShading";
|
||||
}
|
||||
SurfaceStyle(int id) : id(id) {
|
||||
std::stringstream sstr;
|
||||
sstr << "IfcSurfaceStyleShading_" << id;
|
||||
this->name = sstr.str();
|
||||
}
|
||||
SurfaceStyle(const std::string& name) : name(name) {}
|
||||
SurfaceStyle(int id, const std::string& name) : id(id) {
|
||||
std::stringstream sstr;
|
||||
sstr << id << "_" << name;
|
||||
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
|
||||
// pointer addresses of the styles, as they are always referenced
|
||||
// from out of a global map of some sort.
|
||||
bool operator==(const SurfaceStyle& other) {
|
||||
if (name && other.name) {
|
||||
return *name == *other.name;
|
||||
} else if (id && other.id) {
|
||||
return *id == *other.id;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& Name() const { return *name; }
|
||||
|
||||
const boost::optional<ColorComponent>& Diffuse() const { return diffuse; }
|
||||
const boost::optional<ColorComponent>& Specular() const { return specular; }
|
||||
const boost::optional<double>& Transparency() const { return transparency; }
|
||||
const boost::optional<double>& Specularity() const { return specularity; }
|
||||
boost::optional<ColorComponent>& Diffuse() { return diffuse; }
|
||||
boost::optional<ColorComponent>& Specular() { return specular; }
|
||||
boost::optional<double>& Transparency() { return transparency; }
|
||||
boost::optional<double>& Specularity() { return specularity; }
|
||||
};
|
||||
|
||||
const SurfaceStyle* get_default_style(const std::string& ifc_type);
|
||||
}
|
||||
|
||||
#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,272 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 "../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
#include "../ifcgeom/IfcGeomMaterial.h"
|
||||
#include "../ifcgeom/IfcRepresentationShapeItem.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
namespace Representation {
|
||||
|
||||
class Representation {
|
||||
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 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 it = shape_model.begin(); it != shape_model.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();
|
||||
}
|
||||
}
|
||||
|
||||
if (settings().apply_default_materials() && surface_style_id == -1) {
|
||||
Material material(IfcGeom::get_default_style(settings().element_type()));
|
||||
std::vector<Material>::const_iterator it = std::find(_materials.begin(), _materials.end(), material);
|
||||
if (it == _materials.end()) {
|
||||
surface_style_id = _materials.size();
|
||||
_materials.push_back(material);
|
||||
} else {
|
||||
surface_style_id = it - _materials.begin();
|
||||
}
|
||||
}
|
||||
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
const gp_GTrsf& trsf = it->Placement();
|
||||
|
||||
// Triangulate the shape
|
||||
try {
|
||||
BRepMesh_IncrementalMesh(s, settings().deflection_tolerance());
|
||||
} catch(...) {
|
||||
|
||||
// TODO: Catch outside
|
||||
// Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape:",ifc_file->entityById(_id)->entity);
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape");
|
||||
continue;
|
||||
}
|
||||
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 = !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((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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
+617
-185
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <gp_GTrsf2d.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
#include <gp_Ax1.hxx>
|
||||
#include <gp_Ax3.hxx>
|
||||
#include <gp_Ax2d.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
@@ -44,12 +45,17 @@
|
||||
#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 <Geom_CylindricalSurface.hxx>
|
||||
|
||||
#include <BRepOffsetAPI_Sewing.hxx>
|
||||
#include <BRepOffsetAPI_MakePipe.hxx>
|
||||
#include <BRepOffsetAPI_MakePipeShell.hxx>
|
||||
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
@@ -62,10 +68,21 @@
|
||||
#include <TopExp_Explorer.hxx>
|
||||
|
||||
#include <BRepPrimAPI_MakePrism.hxx>
|
||||
#include <BRepPrimAPI_MakeRevol.hxx>
|
||||
#include <BRepPrimAPI_MakeBox.hxx>
|
||||
#include <BRepPrimAPI_MakeCone.hxx>
|
||||
#include <BRepPrimAPI_MakeCylinder.hxx>
|
||||
#include <BRepPrimAPI_MakeSphere.hxx>
|
||||
#include <BRepPrimAPI_MakeWedge.hxx>
|
||||
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
#include <BRepBuilderAPI_MakeShell.hxx>
|
||||
#include <BRepBuilderAPI_MakeSolid.hxx>
|
||||
#include <BRepPrimAPI_MakeHalfSpace.hxx>
|
||||
|
||||
#include <BRepAlgoAPI_Cut.hxx>
|
||||
#include <BRepAlgoAPI_Fuse.hxx>
|
||||
#include <BRepAlgoAPI_Common.hxx>
|
||||
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
#include <ShapeFix_ShapeTolerance.hxx>
|
||||
@@ -74,259 +91,365 @@
|
||||
#include <TopLoc_Location.hxx>
|
||||
|
||||
#include <BRepCheck_Analyzer.hxx>
|
||||
#include <BRepAlgoAPI_Common.hxx>
|
||||
#include <BRepClass3d_SolidClassifier.hxx>
|
||||
|
||||
#include <Standard_Version.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcExtrudedAreaSolid::ptr l, TopoDS_Shape& shape) {
|
||||
TopoDS_Face face;
|
||||
if ( ! IfcGeom::convert_face(l->SweptArea(),face) ) return false;
|
||||
const double height = l->Depth() * Ifc::LengthUnit;
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_Shape& shape) {
|
||||
TopoDS_Shape face;
|
||||
if ( !convert_face(l->SweptArea(),face) ) return false;
|
||||
|
||||
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);
|
||||
|
||||
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 Ifc2x3::IfcFacetedBrep::ptr l, ShapeList& shape) {
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion* l, TopoDS_Shape& shape) {
|
||||
TopoDS_Wire wire;
|
||||
if ( !convert_wire(l->SweptCurve(), wire) ) {
|
||||
TopoDS_Face face;
|
||||
if ( !convert_face(l->SweptCurve(),face) ) return false;
|
||||
TopExp_Explorer exp(face, TopAbs_WIRE);
|
||||
wire = TopoDS::Wire(exp.Current());
|
||||
}
|
||||
const double height = l->Depth() * getValue(GV_LENGTH_UNIT);
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
|
||||
gp_Dir dir;
|
||||
convert(l->ExtrudedDirection(),dir);
|
||||
|
||||
shape = BRepPrimAPI_MakePrism(wire, height*dir);
|
||||
shape.Move(trsf);
|
||||
return !shape.IsNull();
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfRevolution* l, TopoDS_Shape& shape) {
|
||||
TopoDS_Wire wire;
|
||||
if ( !convert_wire(l->SweptCurve(), wire) ) {
|
||||
TopoDS_Face face;
|
||||
if ( !convert_face(l->SweptCurve(),face) ) return false;
|
||||
TopExp_Explorer exp(face, TopAbs_WIRE);
|
||||
wire = TopoDS::Wire(exp.Current());
|
||||
}
|
||||
|
||||
gp_Ax1 ax1;
|
||||
IfcGeom::Kernel::convert(l->AxisPosition(), ax1);
|
||||
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
|
||||
shape = BRepPrimAPI_MakeRevol(wire, ax1);
|
||||
|
||||
shape.Move(trsf);
|
||||
return !shape.IsNull();
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRevolvedAreaSolid* l, TopoDS_Shape& shape) {
|
||||
const double ang = l->Angle() * getValue(GV_PLANEANGLE_UNIT);
|
||||
|
||||
TopoDS_Face face;
|
||||
if ( ! convert_face(l->SweptArea(),face) ) return false;
|
||||
|
||||
gp_Ax1 ax1;
|
||||
IfcGeom::Kernel::convert(l->Axis(), ax1);
|
||||
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
|
||||
if (ang >= M_PI * 2. - ALMOST_ZERO) {
|
||||
shape = BRepPrimAPI_MakeRevol(face, ax1);
|
||||
} else {
|
||||
shape = BRepPrimAPI_MakeRevol(face, ax1, ang);
|
||||
}
|
||||
|
||||
shape.Move(trsf);
|
||||
return !shape.IsNull();
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFacetedBrep* l, IfcRepresentationShapeItems& shape) {
|
||||
TopoDS_Shape s;
|
||||
if ( const TopoDS_Shape* shape_id = IfcGeom::convert_shape(l->Outer(),s) ) {
|
||||
shape.push_back(LocationShape(new gp_GTrsf(),shape_id));
|
||||
const SurfaceStyle* collective_style = get_style(l);
|
||||
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;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcFaceBasedSurfaceModel::ptr l, ShapeList& shapes) {
|
||||
Ifc2x3::IfcConnectedFaceSet::list facesets = l->FbsmFaces();
|
||||
for( Ifc2x3::IfcConnectedFaceSet::it it = facesets->begin(); it != facesets->end(); ++ it ) {
|
||||
|
||||
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::list::it it = facesets->begin(); it != facesets->end(); ++ it ) {
|
||||
TopoDS_Shape s;
|
||||
if ( const TopoDS_Shape* shape_id = IfcGeom::convert_shape(*it,s) ) {
|
||||
shapes.push_back(LocationShape(new gp_GTrsf(),shape_id));
|
||||
const SurfaceStyle* shell_style = get_style(*it);
|
||||
if (convert_shape(*it,s)) {
|
||||
shapes.push_back(IfcRepresentationShapeItem(s, shell_style ? shell_style : collective_style));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcHalfSpaceSolid::ptr l, TopoDS_Shape& shape) {
|
||||
Ifc2x3::IfcSurface::ptr surface = l->BaseSurface();
|
||||
if ( ! surface->is(Ifc2x3::Type::IfcPlane) ) {
|
||||
// Not implemented
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, TopoDS_Shape& shape) {
|
||||
IfcSchema::IfcSurface* surface = l->BaseSurface();
|
||||
if ( ! surface->is(IfcSchema::Type::IfcPlane) ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface->entity);
|
||||
return false;
|
||||
}
|
||||
gp_Pln pln;
|
||||
IfcGeom::convert(reinterpret_pointer_cast<Ifc2x3::IfcSurface,Ifc2x3::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 Ifc2x3::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<Ifc2x3::IfcPolygonalBoundedHalfSpace,Ifc2x3::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);
|
||||
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(down*trsf);
|
||||
prism.Move(trsf*down);
|
||||
shape = BRepAlgoAPI_Common(halfspace,prism);
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcShellBasedSurfaceModel::ptr l, ShapeList& shapes) {
|
||||
IfcUtil::IfcAbstractSelect::list shells = l->SbsmBoundary();
|
||||
for( IfcUtil::IfcAbstractSelect::it it = shells->begin(); it != shells->end(); ++ it ) {
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, IfcRepresentationShapeItems& shapes) {
|
||||
IfcEntityList::ptr shells = l->SbsmBoundary();
|
||||
const SurfaceStyle* collective_style = get_style(l);
|
||||
for( IfcEntityList::it it = shells->begin(); it != shells->end(); ++ it ) {
|
||||
TopoDS_Shape s;
|
||||
if ( const TopoDS_Shape* shape_id = IfcGeom::convert_shape(*it,s) ) {
|
||||
shapes.push_back(LocationShape(new gp_GTrsf(),shape_id));
|
||||
const SurfaceStyle* shell_style = 0;
|
||||
if ((*it)->is(IfcSchema::Type::IfcRepresentationItem)) {
|
||||
shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it);
|
||||
}
|
||||
if (convert_shape(*it,s)) {
|
||||
shapes.push_back(IfcRepresentationShapeItem(s, shell_style ? shell_style : collective_style));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcBooleanClippingResult::ptr l, TopoDS_Shape& shape) {
|
||||
TopoDS_Shape s1, s2;
|
||||
TopoDS_Wire boundary_wire;
|
||||
Ifc2x3::IfcBooleanOperand operand2 = l->SecondOperand();
|
||||
bool is_halfspace = operand2->is(Ifc2x3::Type::IfcHalfSpaceSolid);
|
||||
bool is_bounded = operand2->is(Ifc2x3::Type::IfcPolygonalBoundedHalfSpace);
|
||||
bool is_convex_bound = false;
|
||||
|
||||
if ( ! IfcGeom::convert_shape(l->FirstOperand(),s1) )
|
||||
return false;
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) {
|
||||
TopoDS_Shape s1, s2;
|
||||
IfcRepresentationShapeItems items1, items2;
|
||||
TopoDS_Wire boundary_wire;
|
||||
IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand();
|
||||
IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand();
|
||||
bool is_halfspace = operand2->is(IfcSchema::Type::IfcHalfSpaceSolid);
|
||||
|
||||
if ( is_shape_collection(operand1) ) {
|
||||
if (!(convert_shapes(operand1, items1) && flatten_shape_list(items1, s1, true))) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if ( ! convert_shape(operand1, s1) ) {
|
||||
return false;
|
||||
}
|
||||
{ TopoDS_Solid temp_solid;
|
||||
s1 = ensure_fit_for_subtraction(s1, temp_solid); }
|
||||
}
|
||||
|
||||
const double first_operand_volume = shape_volume(s1);
|
||||
if ( first_operand_volume <= ALMOST_ZERO )
|
||||
Ifc::LogMessage("Warning","Empty solid for:",l->FirstOperand()->entity);
|
||||
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand()->entity);
|
||||
|
||||
if ( !IfcGeom::convert_shape(l->SecondOperand(),s2) ) {
|
||||
bool shape2_processed = false;
|
||||
if ( is_shape_collection(operand2) ) {
|
||||
shape2_processed = convert_shapes(operand2, items2) && flatten_shape_list(items2, s2, true);
|
||||
} else {
|
||||
shape2_processed = convert_shape(operand2,s2);
|
||||
if (shape2_processed && !is_halfspace) {
|
||||
TopoDS_Solid temp_solid;
|
||||
s2 = ensure_fit_for_subtraction(s2, temp_solid);
|
||||
}
|
||||
}
|
||||
|
||||
if (!shape2_processed) {
|
||||
shape = s1;
|
||||
Ifc::LogMessage("Error","Failed to convert SecondOperand of:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l->entity);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( is_bounded ) {
|
||||
Ifc2x3::IfcPolygonalBoundedHalfSpace::ptr ifc_bounded_halfspace =
|
||||
(Ifc2x3::IfcPolygonalBoundedHalfSpace::ptr) operand2;
|
||||
IfcGeom::convert_wire(ifc_bounded_halfspace->PolygonalBoundary(),boundary_wire);
|
||||
is_convex_bound = is_convex(boundary_wire);
|
||||
}
|
||||
|
||||
if ( ! is_halfspace ) {
|
||||
if (!is_halfspace) {
|
||||
const double second_operand_volume = shape_volume(s2);
|
||||
if ( second_operand_volume <= ALMOST_ZERO )
|
||||
Ifc::LogMessage("Warning","Empty solid for:",operand2->entity);
|
||||
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2->entity);
|
||||
}
|
||||
|
||||
bool valid_cut = false;
|
||||
if ( !is_bounded || !is_convex_bound ) {
|
||||
const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator();
|
||||
|
||||
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
|
||||
|
||||
bool valid_cut = false;
|
||||
BRepAlgoAPI_Cut brep_cut(s1,s2);
|
||||
if ( brep_cut.IsDone() ) {
|
||||
TopoDS_Shape result = brep_cut;
|
||||
|
||||
ShapeFix_Shape fix(result);
|
||||
try {
|
||||
fix.Perform();
|
||||
result = fix.Shape();
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Shape healing failed on boolean result", l->entity);
|
||||
}
|
||||
|
||||
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
|
||||
if ( is_valid ) {
|
||||
shape = result;
|
||||
valid_cut = true;
|
||||
}
|
||||
}
|
||||
if ( !valid_cut && !is_bounded ) {
|
||||
Ifc2x3::IfcHalfSpaceSolid::ptr ifc_halfspace = (Ifc2x3::IfcHalfSpaceSolid::ptr) operand2;
|
||||
Ifc2x3::IfcSurface::ptr surface = ifc_halfspace->BaseSurface();
|
||||
if ( surface->is(Ifc2x3::Type::IfcPlane) ) {
|
||||
gp_Pln pln;
|
||||
IfcGeom::convert(reinterpret_pointer_cast<Ifc2x3::IfcSurface,Ifc2x3::IfcPlane>(surface),pln);
|
||||
gp_Pnt pnt = pln.Location();
|
||||
bool reverse = ifc_halfspace->AgreementFlag();
|
||||
gp_Vec direction = pln.Axis().Direction();
|
||||
if ( reverse ) direction *= -1;
|
||||
pnt.Translate(direction);
|
||||
pln.SetLocation(pln.Location().Translated(direction * -0.0001));
|
||||
TopoDS_Shape halfspace = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln),pnt).Solid();
|
||||
|
||||
BRepAlgoAPI_Cut brep_cut(s1,halfspace);
|
||||
if ( brep_cut.IsDone() ) {
|
||||
TopoDS_Shape result = brep_cut;
|
||||
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
|
||||
if ( is_valid ) {
|
||||
shape = result;
|
||||
valid_cut = true;
|
||||
Ifc::LogMessage("Warning","Slightly nudged the SecondOperand of:",l->entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",l->entity);
|
||||
shape = s1;
|
||||
}
|
||||
} else {
|
||||
Ifc2x3::IfcPolygonalBoundedHalfSpace::ptr ifc_bounded_halfspace =
|
||||
(Ifc2x3::IfcPolygonalBoundedHalfSpace::ptr) operand2;
|
||||
gp_Trsf trsf;
|
||||
convert(ifc_bounded_halfspace->Position(),trsf);
|
||||
TopoDS_Shape face = BRepBuilderAPI_MakeFace(boundary_wire).Face();
|
||||
TopoDS_Shape prism = BRepPrimAPI_MakePrism (boundary_wire,gp_Vec(0,0,1),1);
|
||||
prism.Move(trsf);
|
||||
face.Move(trsf);
|
||||
|
||||
gp_Pln pln = plane_from_face(TopoDS::Face(face));
|
||||
gp_Pnt pnt = point_above_plane(pln,ifc_bounded_halfspace->AgreementFlag());
|
||||
return true;
|
||||
|
||||
TopoDS_Shape halfspace;
|
||||
Ifc2x3::IfcHalfSpaceSolid::ptr ifc_halfspace = (Ifc2x3::IfcHalfSpaceSolid::ptr) operand2;
|
||||
if ( ! IfcGeom::convert(ifc_halfspace,halfspace) ) return false;
|
||||
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) {
|
||||
|
||||
TopoDS_Shape subtraction_volume = s1;
|
||||
double subtraction_volume_volume = shape_volume(subtraction_volume);
|
||||
BRepAlgoAPI_Fuse brep_fuse(s1,s2);
|
||||
if ( brep_fuse.IsDone() ) {
|
||||
TopoDS_Shape result = brep_fuse;
|
||||
|
||||
const double minimal_substraction_difference = subtraction_volume_volume * 0.0001;
|
||||
ShapeFix_Shape fix(result);
|
||||
fix.Perform();
|
||||
result = fix.Shape();
|
||||
|
||||
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
|
||||
if ( is_valid ) {
|
||||
shape = result;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
BRepAlgoAPI_Common brep_common(subtraction_volume,halfspace);
|
||||
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) {
|
||||
|
||||
BRepAlgoAPI_Common brep_common(s1,s2);
|
||||
if ( brep_common.IsDone() ) {
|
||||
TopoDS_Shape brep_common_shape = brep_common;
|
||||
bool is_valid = BRepCheck_Analyzer(brep_common_shape).IsValid() != 0;
|
||||
double new_subtraction_volume_volume = shape_volume(brep_common_shape);
|
||||
double subtraction_volume_difference = subtraction_volume_volume - new_subtraction_volume_volume;
|
||||
if ( is_valid && subtraction_volume_difference > minimal_substraction_difference ) {
|
||||
subtraction_volume = brep_common_shape;
|
||||
subtraction_volume_volume = new_subtraction_volume_volume;
|
||||
}
|
||||
}
|
||||
TopoDS_Shape result = brep_common;
|
||||
|
||||
TopExp_Explorer exp(prism,TopAbs_FACE);
|
||||
while ( exp.More() ) {
|
||||
TopoDS_Shape halfspace = halfspace_from_plane(plane_from_face(TopoDS::Face(exp.Current())),pnt);
|
||||
BRepAlgoAPI_Common brep_common(subtraction_volume,halfspace);
|
||||
if ( brep_common.IsDone() ) {
|
||||
TopoDS_Shape brep_common_shape = brep_common;
|
||||
bool is_valid = BRepCheck_Analyzer(brep_common_shape).IsValid() != 0;
|
||||
double new_subtraction_volume_volume = shape_volume(brep_common_shape);
|
||||
double subtraction_volume_difference = subtraction_volume_volume - new_subtraction_volume_volume;
|
||||
if ( is_valid && subtraction_volume_difference > minimal_substraction_difference ) {
|
||||
subtraction_volume = brep_common_shape;
|
||||
subtraction_volume_volume = new_subtraction_volume_volume;
|
||||
}
|
||||
}
|
||||
exp.Next();
|
||||
}
|
||||
|
||||
BRepAlgoAPI_Cut brep_cut(s1,subtraction_volume);
|
||||
if ( brep_cut.IsDone() ) {
|
||||
TopoDS_Shape result = brep_cut;
|
||||
ShapeFix_Shape fix(result);
|
||||
fix.Perform();
|
||||
result = fix.Shape();
|
||||
|
||||
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
|
||||
if ( is_valid ) {
|
||||
shape = result;
|
||||
valid_cut = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( valid_cut ) {
|
||||
const double volume_after_subtraction = shape_volume(shape);
|
||||
if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) )
|
||||
Ifc::LogMessage("Warning","Subtraction yields unchanged volume:",l->entity);
|
||||
} else {
|
||||
Ifc::LogMessage("Error","Failed to process subtraction:",l->entity);
|
||||
shape = s1;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& shape) {
|
||||
Ifc2x3::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 ( Ifc::SewShells && num_faces < MAX_FACES_TO_SEW ) {
|
||||
const unsigned int num_faces = faces->size();
|
||||
bool valid_shell = false;
|
||||
if ( num_faces < getValue(GV_MAX_FACES_TO_SEW) ) {
|
||||
BRepOffsetAPI_Sewing builder;
|
||||
builder.SetTolerance(POINT_EQUALITY_TOLERANCE);
|
||||
builder.SetMaxTolerance(POINT_EQUALITY_TOLERANCE);
|
||||
builder.SetMinTolerance(POINT_EQUALITY_TOLERANCE);
|
||||
for( Ifc2x3::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) > 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 {
|
||||
Ifc::LogMessage("Warning","Invalid face:",(*it)->entity);
|
||||
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
|
||||
}
|
||||
}
|
||||
if ( ! facesAdded ) return false;
|
||||
builder.Perform();
|
||||
shape = builder.SewedShape();
|
||||
try {
|
||||
ShapeFix_Solid solid;
|
||||
solid.LimitTolerance(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->entity);
|
||||
}
|
||||
}
|
||||
if (!valid_shell) {
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
for( Ifc2x3::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) > 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 {
|
||||
Ifc::LogMessage("Warning","Invalid face:",(*it)->entity);
|
||||
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
|
||||
}
|
||||
}
|
||||
if ( ! facesAdded ) return false;
|
||||
@@ -334,53 +457,362 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcMappedItem::ptr l, ShapeList& shapes) {
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentationShapeItems& shapes) {
|
||||
gp_GTrsf gtrsf;
|
||||
Ifc2x3::IfcCartesianTransformationOperator::ptr transform = l->MappingTarget();
|
||||
if ( transform->is(Ifc2x3::Type::IfcCartesianTransformationOperator3DnonUniform) ) {
|
||||
IfcGeom::convert(reinterpret_pointer_cast<Ifc2x3::IfcCartesianTransformationOperator,
|
||||
Ifc2x3::IfcCartesianTransformationOperator3DnonUniform>(transform),gtrsf);
|
||||
} else if ( transform->is(Ifc2x3::Type::IfcCartesianTransformationOperator2DnonUniform) ) {
|
||||
IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget();
|
||||
if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf);
|
||||
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity);
|
||||
return false;
|
||||
} else if ( transform->is(Ifc2x3::Type::IfcCartesianTransformationOperator3D) ) {
|
||||
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) {
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::convert(reinterpret_pointer_cast<Ifc2x3::IfcCartesianTransformationOperator,
|
||||
Ifc2x3::IfcCartesianTransformationOperator3D>(transform),trsf);
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf);
|
||||
gtrsf = trsf;
|
||||
} else if ( transform->is(Ifc2x3::Type::IfcCartesianTransformationOperator2D) ) {
|
||||
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) {
|
||||
gp_Trsf2d trsf_2d;
|
||||
IfcGeom::convert(reinterpret_pointer_cast<Ifc2x3::IfcCartesianTransformationOperator,
|
||||
Ifc2x3::IfcCartesianTransformationOperator2D>(transform),trsf_2d);
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,trsf_2d);
|
||||
gtrsf = (gp_Trsf) trsf_2d;
|
||||
}
|
||||
Ifc2x3::IfcRepresentationMap::ptr map = l->MappingSource();
|
||||
Ifc2x3::IfcAxis2Placement placement = map->MappingOrigin();
|
||||
IfcSchema::IfcRepresentationMap* map = l->MappingSource();
|
||||
IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin();
|
||||
gp_Trsf trsf;
|
||||
if (placement->is(Ifc2x3::Type::IfcAxis2Placement3D)) {
|
||||
IfcGeom::convert((Ifc2x3::IfcAxis2Placement3D*)placement,trsf);
|
||||
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
} else {
|
||||
gp_Trsf2d trsf_2d;
|
||||
IfcGeom::convert((Ifc2x3::IfcAxis2Placement2D*)placement,trsf_2d);
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf_2d);
|
||||
trsf = trsf_2d;
|
||||
}
|
||||
gtrsf.Multiply(trsf);
|
||||
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].first->Multiply(gtrsf);
|
||||
shapes[i].append(gtrsf);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcShapeRepresentation::ptr l, ShapeList& shapes) {
|
||||
Ifc2x3::IfcRepresentationItem::list items = l->Items();
|
||||
if ( ! items->Size() ) return false;
|
||||
for ( Ifc2x3::IfcRepresentationItem::it it = items->begin(); it != items->end(); ++ it ) {
|
||||
if ( IfcGeom::is_shape_collection(*it) ) IfcGeom::convert_shapes(*it,shapes);
|
||||
else {
|
||||
TopoDS_Shape s;
|
||||
if ( const TopoDS_Shape* shape_id = IfcGeom::convert_shape(*it,s))
|
||||
shapes.push_back(LocationShape(new gp_GTrsf(),shape_id));
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcShapeRepresentation* l, IfcRepresentationShapeItems& shapes) {
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items = l->Items();
|
||||
bool part_succes = false;
|
||||
if ( items->size() ) {
|
||||
for ( IfcSchema::IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++ it ) {
|
||||
IfcSchema::IfcRepresentationItem* representation_item = *it;
|
||||
if ( is_shape_collection(representation_item) ) {
|
||||
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 part_succes;
|
||||
}
|
||||
|
||||
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 ( IfcEntityList::it it = elements->begin(); it != elements->end(); ++ it ) {
|
||||
IfcSchema::IfcGeometricSetSelect* element = *it;
|
||||
if (element->is(IfcSchema::Type::IfcSurface)) {
|
||||
IfcSchema::IfcSurface* surface = (IfcSchema::IfcSurface*) element;
|
||||
TopoDS_Shape s;
|
||||
if (convert_shape(surface, s)) {
|
||||
part_succes = true;
|
||||
const IfcGeom::SurfaceStyle* style = get_style(surface);
|
||||
shapes.push_back(IfcRepresentationShapeItem(s, style ? style : parent_style));
|
||||
}
|
||||
}
|
||||
}
|
||||
return part_succes;
|
||||
}
|
||||
|
||||
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::Kernel::convert(l->Position(),trsf);
|
||||
shape = builder.Solid().Moved(trsf);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularPyramid* l, TopoDS_Shape& shape) {
|
||||
const double dx = l->XLength() * getValue(GV_LENGTH_UNIT);
|
||||
const double dy = l->YLength() * getValue(GV_LENGTH_UNIT);
|
||||
const double dz = l->Height() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
BRepPrimAPI_MakeWedge builder(dx, dz, dy, dx / 2., dy / 2., dx / 2., dy / 2.);
|
||||
|
||||
gp_Trsf trsf1, trsf2;
|
||||
trsf2.SetValues(
|
||||
1, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 1, 0, 0
|
||||
#if OCC_VERSION_HEX < 0x60800
|
||||
, Precision::Angular(), Precision::Confusion()
|
||||
#endif
|
||||
);
|
||||
|
||||
IfcGeom::Kernel::convert(l->Position(), trsf1);
|
||||
shape = BRepBuilderAPI_Transform(builder.Solid(), trsf1 * trsf2);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRightCircularCylinder* l, TopoDS_Shape& shape) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
const double h = l->Height() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
BRepPrimAPI_MakeCylinder builder(r, h);
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
shape = builder.Solid().Moved(trsf);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRightCircularCone* l, TopoDS_Shape& shape) {
|
||||
const double r = l->BottomRadius() * getValue(GV_LENGTH_UNIT);
|
||||
const double h = l->Height() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
BRepPrimAPI_MakeCone builder(r, 0., h);
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
shape = builder.Solid().Moved(trsf);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSphere* l, TopoDS_Shape& shape) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
BRepPrimAPI_MakeSphere builder(r);
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
shape = builder.Solid().Moved(trsf);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCsgSolid* l, TopoDS_Shape& shape) {
|
||||
return convert_shape(l->TreeRootExpression(), shape);
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_Shape& face) {
|
||||
gp_Pln pln;
|
||||
IfcGeom::Kernel::convert(l->BasisSurface(), pln);
|
||||
|
||||
gp_Trsf trsf;
|
||||
trsf.SetTransformation(pln.Position());
|
||||
|
||||
TopoDS_Wire outer;
|
||||
convert_wire(l->OuterBoundary(), outer);
|
||||
|
||||
BRepBuilderAPI_MakeFace mf (outer);
|
||||
mf.Add(outer);
|
||||
|
||||
IfcSchema::IfcCurve::list::ptr inner = l->InnerBoundaries();
|
||||
|
||||
for (IfcSchema::IfcCurve::list::it it = inner->begin(); it != inner->end(); ++it) {
|
||||
TopoDS_Wire inner;
|
||||
convert_wire(*it, inner);
|
||||
|
||||
mf.Add(inner);
|
||||
}
|
||||
|
||||
ShapeFix_Shape sfs(mf.Face());
|
||||
sfs.Perform();
|
||||
face = TopoDS::Face(sfs.Shape()).Moved(trsf);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularTrimmedSurface* l, TopoDS_Shape& face) {
|
||||
if (!l->BasisSurface()->is(IfcSchema::Type::IfcPlane)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported BasisSurface:", l->BasisSurface()->entity);
|
||||
return false;
|
||||
}
|
||||
gp_Pln pln;
|
||||
IfcGeom::Kernel::convert((IfcSchema::IfcPlane*) l->BasisSurface(), pln);
|
||||
|
||||
BRepBuilderAPI_MakeFace mf(pln, l->U1(), l->U2(), l->V1(), l->V2());
|
||||
|
||||
face = mf.Face();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IfcGeom::Kernel::convert(l->Position(), position) ||
|
||||
!convert_face(l->SweptArea(), face) ||
|
||||
!convert_wire(l->Directrix(), wire) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Pln pln;
|
||||
gp_Pnt directrix_origin;
|
||||
gp_Vec directrix_tangent;
|
||||
bool directrix_on_plane = true;
|
||||
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
|
||||
// how to deal with this and whether my interpretation of the propositions is
|
||||
// correct. However, if it has been asserted that the vertices of the directrix do
|
||||
// not conform to the ReferenceSurface, the ReferenceSurface is ignored.
|
||||
{
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
TopExp_Explorer exp(wire, TopAbs_EDGE);
|
||||
TopoDS_Edge edge = TopoDS::Edge(exp.Current());
|
||||
double u0, u1;
|
||||
Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u0, u1);
|
||||
crv->D1(u0, directrix_origin, directrix_tangent);
|
||||
}
|
||||
|
||||
if (pln.Axis().Direction().IsNormal(directrix_tangent, Precision::Approximation()) && directrix_on_plane) {
|
||||
directrix.SetTransformation(gp_Ax3(directrix_origin, directrix_tangent, pln.Axis().Direction()), gp::XOY());
|
||||
} else {
|
||||
directrix.SetTransformation(gp_Ax3(directrix_origin, directrix_tangent), gp::XOY());
|
||||
}
|
||||
face = BRepBuilderAPI_Transform(face, directrix);
|
||||
|
||||
// NB: Note that StartParam and EndParam param are ignored and the assumption is
|
||||
// made that the parametric range over which to be swept matches the IfcCurve in
|
||||
// its entirety.
|
||||
BRepOffsetAPI_MakePipeShell builder(wire);
|
||||
|
||||
{ TopExp_Explorer exp(face, TopAbs_WIRE);
|
||||
section = TopoDS::Wire(exp.Current()); }
|
||||
|
||||
builder.Add(section);
|
||||
builder.SetTransitionMode(BRepBuilderAPI_RightCorner);
|
||||
if (directrix_on_plane) {
|
||||
builder.SetMode(pln.Axis().Direction());
|
||||
}
|
||||
builder.Build();
|
||||
builder.MakeSolid();
|
||||
shape = builder.Shape();
|
||||
shape.Move(position);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shape& shape) {
|
||||
TopoDS_Wire wire, section1, section2;
|
||||
|
||||
bool hasInnerRadius = l->InnerRadius() ? true : false;
|
||||
|
||||
if (!convert_wire(l->Directrix(), wire)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Ax2 directrix;
|
||||
{
|
||||
gp_Pnt directrix_origin;
|
||||
gp_Vec directrix_tangent;
|
||||
TopExp_Explorer exp(wire, TopAbs_EDGE);
|
||||
TopoDS_Edge edge = TopoDS::Edge(exp.Current());
|
||||
double u0, u1;
|
||||
Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u0, u1);
|
||||
crv->D1(u0, directrix_origin, directrix_tangent);
|
||||
directrix = gp_Ax2(directrix_origin, directrix_tangent);
|
||||
}
|
||||
|
||||
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()) * getValue(GV_LENGTH_UNIT);
|
||||
if (r2 < getValue(GV_PRECISION)) {
|
||||
// Subtraction of pipes with small radii is unstable.
|
||||
hasInnerRadius = false;
|
||||
} else {
|
||||
Handle(Geom_Circle) circle = new Geom_Circle(directrix, r2);
|
||||
section2 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle));
|
||||
}
|
||||
}
|
||||
|
||||
// NB: Note that StartParam and EndParam param are ignored and the assumption is
|
||||
// made that the parametric range over which to be swept matches the IfcCurve in
|
||||
// its entirety.
|
||||
// NB2: Contrary to IfcSurfaceCurveSweptAreaSolid the transition mode has been
|
||||
// set to create round corners as this has proven to work better with the types
|
||||
// of directrices encountered, which do not necessarily conform to a surface.
|
||||
{ BRepOffsetAPI_MakePipeShell builder(wire);
|
||||
builder.Add(section1);
|
||||
builder.SetTransitionMode(BRepBuilderAPI_RoundCorner);
|
||||
builder.Build();
|
||||
builder.MakeSolid();
|
||||
shape = builder.Shape(); }
|
||||
|
||||
if (hasInnerRadius) {
|
||||
BRepOffsetAPI_MakePipeShell builder(wire);
|
||||
builder.Add(section2);
|
||||
builder.SetTransitionMode(BRepBuilderAPI_RoundCorner);
|
||||
builder.Build();
|
||||
builder.MakeSolid();
|
||||
TopoDS_Shape inner = builder.Shape();
|
||||
|
||||
BRepAlgoAPI_Cut brep_cut(shape, inner);
|
||||
bool is_valid = false;
|
||||
if (brep_cut.IsDone()) {
|
||||
TopoDS_Shape result = brep_cut;
|
||||
|
||||
ShapeFix_Shape fix(result);
|
||||
fix.Perform();
|
||||
result = fix.Shape();
|
||||
|
||||
is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
|
||||
if (is_valid) {
|
||||
shape = result;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_valid) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Failed to subtract inner radius void for:", l->entity);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef USE_IFC4
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCylindricalSurface* l, TopoDS_Shape& face) {
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::Kernel::convert(l->Position(),trsf);
|
||||
|
||||
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius()), getValue(GV_PRECISION)).Face().Moved(trsf);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAdvancedBrep* l, TopoDS_Shape& shape) {
|
||||
return convert(l->Outer(), shape);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+317
-117
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -47,15 +47,18 @@
|
||||
#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>
|
||||
|
||||
@@ -63,61 +66,92 @@
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopLoc_Location.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
|
||||
#include <BRepPrimAPI_MakePrism.hxx>
|
||||
#include <BRepBuilderAPI_MakeShell.hxx>
|
||||
#include <BRepBuilderAPI_MakeSolid.hxx>
|
||||
#include <BRepPrimAPI_MakeHalfSpace.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 Ifc2x3::IfcCompositeCurve::ptr l, TopoDS_Wire& wire) {
|
||||
if ( ! Ifc::hasPlaneAngleUnit ) {
|
||||
Ifc::LogMessage("Warning","Creating a composite curve without unit information:",l->entity);
|
||||
Ifc::hasPlaneAngleUnit = true;
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire& wire) {
|
||||
if ( getValue(GV_PLANEANGLE_UNIT)<0 ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l->entity);
|
||||
|
||||
// Temporarily pretend we do have unit information
|
||||
setValue(GV_PLANEANGLE_UNIT,1.0);
|
||||
|
||||
bool succes_radians = false;
|
||||
bool succes_degrees = false;
|
||||
bool use_radians = false;
|
||||
bool use_degrees = false;
|
||||
|
||||
// First try radians
|
||||
Ifc::PlaneAngleUnit = 1.0f;
|
||||
bool succes_radians = IfcGeom::convert(l,wire);
|
||||
bool succes_degrees;
|
||||
if ( succes_radians ) {
|
||||
Ifc::LogMessage("Notice","Used radians to create composite curve");
|
||||
} else {
|
||||
// Now try degrees
|
||||
Ifc::PlaneAngleUnit = 0.0174532925199433f;
|
||||
succes_degrees = IfcGeom::convert(l,wire);
|
||||
if ( succes_degrees ) {
|
||||
Ifc::LogMessage("Notice","Used degrees to create composite curve");
|
||||
TopoDS_Wire wire_radians, wire_degrees;
|
||||
try {
|
||||
succes_radians = IfcGeom::Kernel::convert(l,wire_radians);
|
||||
} catch (...) {}
|
||||
|
||||
// Now try degrees
|
||||
setValue(GV_PLANEANGLE_UNIT,0.0174532925199433);
|
||||
try {
|
||||
succes_degrees = IfcGeom::Kernel::convert(l,wire_degrees);
|
||||
} catch (...) {}
|
||||
|
||||
// Restore to unknown unit state
|
||||
setValue(GV_PLANEANGLE_UNIT,-1.0);
|
||||
|
||||
if ( succes_degrees && ! succes_radians ) {
|
||||
use_degrees = true;
|
||||
} else if ( succes_radians && ! succes_degrees ) {
|
||||
use_radians = true;
|
||||
} else if ( succes_radians && succes_degrees ) {
|
||||
if ( wire_degrees.Closed() && ! wire_radians.Closed() ) {
|
||||
use_degrees = true;
|
||||
} else if ( wire_radians.Closed() && ! wire_degrees.Closed() ) {
|
||||
use_radians = true;
|
||||
} else {
|
||||
// No heuristic left to prefer the one over the other,
|
||||
// apparently both variants are equally succesful.
|
||||
// The curve might be composed of only straight segments.
|
||||
// Let's go with the wire created using radians as that
|
||||
// at least is a SI unit.
|
||||
use_radians = true;
|
||||
}
|
||||
// Restore to radians
|
||||
Ifc::PlaneAngleUnit = 1.0f;
|
||||
}
|
||||
Ifc::hasPlaneAngleUnit = false;
|
||||
return succes_radians || succes_degrees;
|
||||
|
||||
if ( use_radians ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Used radians to create composite curve");
|
||||
wire = wire_radians;
|
||||
} else if ( use_degrees ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Used degrees to create composite curve");
|
||||
wire = wire_degrees;
|
||||
}
|
||||
|
||||
return use_radians || use_degrees;
|
||||
}
|
||||
Ifc2x3::IfcCompositeCurveSegment::list segments = l->Segments();
|
||||
IfcSchema::IfcCompositeCurveSegment::list::ptr segments = l->Segments();
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
//TopoDS_Vertex last_vertex;
|
||||
for( Ifc2x3::IfcCompositeCurveSegment::it it = segments->begin(); it != segments->end(); ++ it ) {
|
||||
const Ifc2x3::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) ) {
|
||||
Ifc::LogMessage("Error","Failed to convert curve:",curve->entity);
|
||||
if ( !convert_wire(curve,wire2) ) {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve->entity);
|
||||
continue;
|
||||
}
|
||||
if ( ! (*it)->SameSense() ) wire2.Reverse();
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
FTol.SetTolerance(wire2, 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());
|
||||
@@ -131,107 +165,273 @@ bool IfcGeom::convert(const Ifc2x3::IfcCompositeCurve::ptr l, TopoDS_Wire& wire)
|
||||
w.Add(wire2);
|
||||
//last_vertex = w.Vertex();
|
||||
if ( w.Error() != BRepBuilderAPI_WireDone ) {
|
||||
Ifc::LogMessage("Error","Failed to join curve segments:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to join curve segments:",l->entity);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
wire = w.Wire();
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcTrimmedCurve::ptr l, TopoDS_Wire& wire) {
|
||||
Ifc2x3::IfcCurve::ptr basis_curve = l->BasisCurve();
|
||||
bool isConic = basis_curve->is(Ifc2x3::Type::IfcConic);
|
||||
double parameterFactor = isConic ? Ifc::PlaneAngleUnit : Ifc::LengthUnit;
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& wire) {
|
||||
IfcSchema::IfcCurve* basis_curve = l->BasisCurve();
|
||||
bool isConic = basis_curve->is(IfcSchema::Type::IfcConic);
|
||||
double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT);
|
||||
Handle(Geom_Curve) curve;
|
||||
if ( ! IfcGeom::convert_curve(basis_curve,curve) ) return false;
|
||||
bool trim_cartesian = l->MasterRepresentation() == Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN;
|
||||
IfcUtil::IfcAbstractSelect::list trims1 = l->Trim1();
|
||||
IfcUtil::IfcAbstractSelect::list trims2 = l->Trim2();
|
||||
if ( !convert_curve(basis_curve,curve) ) return false;
|
||||
bool trim_cartesian = l->MasterRepresentation() == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN;
|
||||
IfcEntityList::ptr trims1 = l->Trim1();
|
||||
IfcEntityList::ptr trims2 = l->Trim2();
|
||||
bool trimmed1 = false;
|
||||
bool trimmed2 = false;
|
||||
bool sense_agreement = l->SenseAgreement();
|
||||
double flt1;
|
||||
gp_Pnt pnt1;
|
||||
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(Ifc2x3::Type::IfcCartesianPoint) && trim_cartesian ) {
|
||||
IfcGeom::convert(reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,Ifc2x3::IfcCartesianPoint>(i), pnt1 );
|
||||
trimmed1 = true;
|
||||
} else if ( i->is(Ifc2x3::Type::IfcParameterValue) && !trim_cartesian ) {
|
||||
const double value = *reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,IfcUtil::IfcArgumentSelect>(i)->wrappedValue();
|
||||
flt1 = value * parameterFactor;
|
||||
trimmed1 = true;
|
||||
for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) {
|
||||
IfcUtil::IfcBaseClass* i = *it;
|
||||
if ( i->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 = *((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(Ifc2x3::Type::IfcCartesianPoint) && trim_cartesian && trimmed1 ) {
|
||||
gp_Pnt pnt2;
|
||||
IfcGeom::convert(reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,Ifc2x3::IfcCartesianPoint>(i), pnt2 );
|
||||
BRepBuilderAPI_MakeEdge e (curve,sense_agreement ? pnt1 : pnt2,sense_agreement ? pnt2 : pnt1);
|
||||
if ( ! e.IsDone() ) {
|
||||
BRepBuilderAPI_EdgeError err = e.Error();
|
||||
if ( err == BRepBuilderAPI_PointProjectionFailed ) {
|
||||
w.Add(BRepBuilderAPI_MakeEdge(sense_agreement ? pnt1 : pnt2,sense_agreement ? pnt2 : pnt1));
|
||||
Ifc::LogMessage("Warning","Point projection failed for:",l->entity);
|
||||
}
|
||||
} else {
|
||||
w.Add(e.Edge());
|
||||
}
|
||||
trimmed2 = true;
|
||||
break;
|
||||
} else if ( i->is(Ifc2x3::Type::IfcParameterValue) && !trim_cartesian && trimmed1 ) {
|
||||
const double value = *reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,IfcUtil::IfcArgumentSelect>(i)->wrappedValue();
|
||||
double flt2 = value * parameterFactor;
|
||||
if ( isConic && ALMOST_THE_SAME(fmod(flt2-flt1,(double)(M_PI*2.0)),0.0f) ) {
|
||||
w.Add(BRepBuilderAPI_MakeEdge(curve));
|
||||
} else {
|
||||
BRepBuilderAPI_MakeEdge e (curve,sense_agreement ? flt1 : flt2,sense_agreement ? flt2 : flt1);
|
||||
w.Add(e.Edge());
|
||||
}
|
||||
trimmed2 = true;
|
||||
break;
|
||||
for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) {
|
||||
IfcUtil::IfcBaseClass* i = *it;
|
||||
if ( i->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 = *((IfcSchema::IfcParameterValue*)i);
|
||||
flts[1-sense_agreement] = value * parameterFactor;
|
||||
has_flts[1-sense_agreement] = true;
|
||||
}
|
||||
}
|
||||
if ( trimmed2 ) wire = w.Wire();
|
||||
return trimmed2;
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
trim_cartesian_failed = true;
|
||||
}
|
||||
} else {
|
||||
w.Add(e.Edge());
|
||||
}
|
||||
}
|
||||
if ( (!trim_cartesian || trim_cartesian_failed) && (has_flts[0] && has_flts[1]) ) {
|
||||
// The Geom_Line is constructed from a gp_Pnt and gp_Dir, whereas the IfcLine
|
||||
// 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) ) {
|
||||
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) ) {
|
||||
IfcSchema::IfcEllipse* ellipse = static_cast<IfcSchema::IfcEllipse*>(basis_curve);
|
||||
double x = ellipse->SemiAxis1() * getValue(GV_LENGTH_UNIT);
|
||||
double y = ellipse->SemiAxis2() * getValue(GV_LENGTH_UNIT);
|
||||
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) ) {
|
||||
w.Add(BRepBuilderAPI_MakeEdge(curve));
|
||||
} else {
|
||||
BRepBuilderAPI_MakeEdge e (curve,flts[0],flts[1]);
|
||||
w.Add(e.Edge());
|
||||
}
|
||||
} else if ( trim_cartesian_failed && (has_pnts[0] && has_pnts[1]) ) {
|
||||
w.Add(BRepBuilderAPI_MakeEdge(pnts[0],pnts[1]));
|
||||
}
|
||||
if ( w.IsDone() ) {
|
||||
wire = w.Wire();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool IfcGeom::convert(const Ifc2x3::IfcPolyline::ptr l, TopoDS_Wire& result) {
|
||||
Ifc2x3::IfcCartesianPoint::list points = l->Points();
|
||||
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
gp_Pnt P1;gp_Pnt P2;
|
||||
for( Ifc2x3::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it ) {
|
||||
IfcGeom::convert(*it,P2);
|
||||
if ( it != points->begin() && ( !P1.IsEqual(P2,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_redundant_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 Ifc2x3::IfcPolyLoop::ptr l, TopoDS_Wire& result) {
|
||||
Ifc2x3::IfcCartesianPoint::list points = l->Polygon();
|
||||
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
gp_Pnt P1;gp_Pnt P2;gp_Pnt F;
|
||||
int count = 0;
|
||||
for( Ifc2x3::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it ) {
|
||||
IfcGeom::convert(*it,P2);
|
||||
if ( it != points->begin() && ( !P1.IsEqual(P2,POINT_EQUALITY_TOLERANCE) ) ) {
|
||||
w.Add(BRepBuilderAPI_MakeEdge(P1,P2));
|
||||
count ++;
|
||||
} else if ( ! count ) F = P2;
|
||||
P1 = P2;
|
||||
}
|
||||
if ( !P1.IsEqual(F,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->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove points that are too close to one another
|
||||
remove_redundant_points_from_loop(polygon, true);
|
||||
|
||||
int count = polygon.Length();
|
||||
if (original_count - count != 0) {
|
||||
std::stringstream ss; ss << (original_count - count) << " edges removed for:";
|
||||
Logger::Message(Logger::LOG_WARNING, ss.str(), l->entity);
|
||||
}
|
||||
|
||||
if (count < 3) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakePolygon w;
|
||||
for (int i = 1; i <= polygon.Length(); ++i) {
|
||||
w.Add(polygon.Value(i));
|
||||
}
|
||||
w.Close();
|
||||
|
||||
result = w.Wire();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Pnt p1, p2;
|
||||
if (!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
|
||||
!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeWire mw;
|
||||
Handle_Geom_Curve crv;
|
||||
|
||||
// The lack of a clear separation between topological and geometrical entities
|
||||
// is starting to get problematic. If the underlying curve is bounded it is
|
||||
// assumed that a topological wire can be crafted from it. After which an
|
||||
// attempt is made to reconstruct it from the individual curves and the vertices
|
||||
// of the IfcEdgeCurve.
|
||||
const bool is_bounded = l->EdgeGeometry()->is(IfcSchema::Type::IfcBoundedCurve);
|
||||
|
||||
if (!is_bounded && convert_curve(l->EdgeGeometry(), crv)) {
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(crv, p1, p2));
|
||||
result = mw;
|
||||
return true;
|
||||
} else if (is_bounded && convert_wire(l->EdgeGeometry(), result)) {
|
||||
if (!l->SameSense()) 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) {
|
||||
IfcSchema::IfcOrientedEdge* e = *it;
|
||||
|
||||
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) e->EdgeStart())->VertexGeometry();
|
||||
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) e->EdgeEnd())->VertexGeometry();
|
||||
if (!pnt1->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Pnt p1, p2;
|
||||
if (!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
|
||||
!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(p1, p2));
|
||||
continue;
|
||||
|
||||
IfcSchema::IfcEdge* base = e->EdgeElement();
|
||||
TopoDS_Wire w;
|
||||
if (convert_wire(e->EdgeElement(), w)) {
|
||||
if (!e->Orientation()) w.Reverse();
|
||||
mw.Add(w);
|
||||
}
|
||||
}
|
||||
result = mw;
|
||||
return true;
|
||||
}
|
||||
|
||||
+33
-25
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -19,47 +19,55 @@
|
||||
|
||||
#include "IfcGeom.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
namespace Cache {
|
||||
std::map<int,TopoDS_Shape> Shape;
|
||||
void PurgeShapeCache() {
|
||||
Shape.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using namespace Ifc2x3;
|
||||
using namespace IfcSchema;
|
||||
using namespace IfcUtil;
|
||||
|
||||
bool IfcGeom::convert_shapes(const IfcBaseClass* l, ShapeList& r) {
|
||||
bool IfcGeom::Kernel::convert_shapes(const IfcBaseClass* l, IfcRepresentationShapeItems& r) {
|
||||
#include "IfcRegisterConvertShapes.h"
|
||||
Ifc::LogMessage("Error","No operation defined for:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
return false;
|
||||
}
|
||||
bool IfcGeom::is_shape_collection(const IfcBaseClass* l) {
|
||||
|
||||
bool IfcGeom::Kernel::is_shape_collection(const IfcBaseClass* l) {
|
||||
#include "IfcRegisterIsShapeCollection.h"
|
||||
return false;
|
||||
}
|
||||
const TopoDS_Shape* IfcGeom::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) {
|
||||
|
||||
bool IfcGeom::Kernel::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) {
|
||||
const unsigned int id = l->entity->id();
|
||||
std::map<int,TopoDS_Shape>::const_iterator it = Cache::Shape.find(id);
|
||||
if ( it != Cache::Shape.end() ) { r = it->second; return &(it->second); }
|
||||
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; }
|
||||
#include "IfcRegisterConvertShape.h"
|
||||
Ifc::LogMessage("Error","No operation defined for:",l->entity);
|
||||
return 0;
|
||||
if ( processed ) {
|
||||
const double precision = getValue(GV_PRECISION);
|
||||
apply_tolerance(r, precision);
|
||||
cache.Shape[id] = r;
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
}
|
||||
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"
|
||||
Ifc::LogMessage("Error","No operation defined for:",l->entity);
|
||||
Handle(Geom_Curve) curve;
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
bool IfcGeom::convert_face(const IfcBaseClass* l, TopoDS_Face& r) {
|
||||
|
||||
bool IfcGeom::Kernel::convert_face(const IfcBaseClass* l, TopoDS_Shape& r) {
|
||||
#include "IfcRegisterConvertFace.h"
|
||||
Ifc::LogMessage("Error","No operation defined for:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
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"
|
||||
Ifc::LogMessage("Error","No operation defined for:",l->entity);
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
return false;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -38,36 +38,70 @@
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcParse.h"
|
||||
|
||||
using namespace Ifc2x3;
|
||||
|
||||
SHAPES(IfcShellBasedSurfaceModel);
|
||||
SHAPES(IfcFaceBasedSurfaceModel);
|
||||
SHAPES(IfcShapeRepresentation);
|
||||
SHAPES(IfcMappedItem);
|
||||
SHAPES(IfcFacetedBrep);
|
||||
SHAPES(IfcGeometricSet);
|
||||
|
||||
#ifdef USE_IFC4
|
||||
SHAPE(IfcCylindricalSurface);
|
||||
SHAPE(IfcAdvancedBrep);
|
||||
#endif
|
||||
SHAPE(IfcExtrudedAreaSolid);
|
||||
SHAPE(IfcRevolvedAreaSolid);
|
||||
SHAPE(IfcConnectedFaceSet);
|
||||
SHAPE(IfcBooleanClippingResult);
|
||||
SHAPE(IfcBooleanResult);
|
||||
SHAPE(IfcPolygonalBoundedHalfSpace);
|
||||
SHAPE(IfcHalfSpaceSolid);
|
||||
SHAPE(IfcSurfaceOfLinearExtrusion);
|
||||
SHAPE(IfcSurfaceOfRevolution);
|
||||
SHAPE(IfcBlock);
|
||||
SHAPE(IfcRectangularPyramid);
|
||||
SHAPE(IfcRightCircularCylinder);
|
||||
SHAPE(IfcRightCircularCone);
|
||||
SHAPE(IfcSphere);
|
||||
SHAPE(IfcCsgSolid);
|
||||
SHAPE(IfcCurveBoundedPlane);
|
||||
SHAPE(IfcRectangularTrimmedSurface);
|
||||
SHAPE(IfcSurfaceCurveSweptAreaSolid);
|
||||
SHAPE(IfcSweptDiskSolid);
|
||||
|
||||
#ifdef USE_IFC4
|
||||
FACE(IfcAdvancedFace);
|
||||
#endif
|
||||
FACE(IfcArbitraryProfileDefWithVoids);
|
||||
FACE(IfcArbitraryClosedProfileDef);
|
||||
FACE(IfcRoundedRectangleProfileDef);
|
||||
FACE(IfcRectangleHollowProfileDef);
|
||||
FACE(IfcRectangleProfileDef);
|
||||
FACE(IfcIShapeProfileDef);
|
||||
FACE(IfcTrapeziumProfileDef)
|
||||
FACE(IfcCShapeProfileDef);
|
||||
// IfcAsymmetricIShapeProfileDef included
|
||||
FACE(IfcIShapeProfileDef);
|
||||
FACE(IfcLShapeProfileDef);
|
||||
FACE(IfcTShapeProfileDef);
|
||||
FACE(IfcUShapeProfileDef);
|
||||
FACE(IfcZShapeProfileDef);
|
||||
FACE(IfcCircleHollowProfileDef);
|
||||
FACE(IfcCircleProfileDef);
|
||||
FACE(IfcEllipseProfileDef);
|
||||
FACE(IfcCenterLineProfileDef);
|
||||
FACE(IfcCompositeProfileDef);
|
||||
FACE(IfcDerivedProfileDef);
|
||||
FACE(IfcFace);
|
||||
|
||||
WIRE(IfcEdgeCurve);
|
||||
WIRE(IfcEdgeLoop);
|
||||
WIRE(IfcPolyline);
|
||||
WIRE(IfcPolyLoop);
|
||||
WIRE(IfcCompositeCurve);
|
||||
WIRE(IfcTrimmedCurve);
|
||||
WIRE(IfcArbitraryOpenProfileDef);
|
||||
|
||||
CURVE(IfcCircle);
|
||||
CURVE(IfcEllipse);
|
||||
@@ -77,6 +111,7 @@ CLASS(IfcCartesianPoint,gp_Pnt);
|
||||
CLASS(IfcDirection,gp_Dir);
|
||||
CLASS(IfcAxis2Placement2D,gp_Trsf2d);
|
||||
CLASS(IfcAxis2Placement3D,gp_Trsf);
|
||||
CLASS(IfcAxis1Placement,gp_Ax1);
|
||||
CLASS(IfcCartesianTransformationOperator2DnonUniform,gp_GTrsf2d);
|
||||
CLASS(IfcCartesianTransformationOperator3DnonUniform,gp_GTrsf);
|
||||
CLASS(IfcCartesianTransformationOperator2D,gp_Trsf2d);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define CURVE(T) \
|
||||
if ( l->is(T::Class()) ) return convert((T*)l,r);
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define FACE(T) \
|
||||
if ( l->is(T::Class()) ) return convert((T*)l,r);
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define SHAPE(T) \
|
||||
if ( l->is(T::Class()) ) { \
|
||||
if ( !processed && l->is(T::Class()) ) { \
|
||||
processed = true; \
|
||||
try { \
|
||||
if ( convert((T*)l,r) ) { \
|
||||
Cache::Shape[id] = r; \
|
||||
return &(Cache::Shape[id]); \
|
||||
success = true; \
|
||||
} \
|
||||
} catch(...) { } \
|
||||
Ifc::LogMessage("Error","Failed to convert:",l->entity); \
|
||||
return false; \
|
||||
if ( !success) { \
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
|
||||
return false; \
|
||||
} \
|
||||
}
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define SHAPES(T) \
|
||||
if ( l->is(T::Class()) ) { \
|
||||
try { \
|
||||
return IfcGeom::convert((T*)l,r); \
|
||||
return convert((T*)l,r); \
|
||||
} catch (...) { } \
|
||||
Ifc::LogMessage("Error","Failed to convert:",l->entity); \
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
|
||||
return false; \
|
||||
}
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define WIRE(T) \
|
||||
if ( l->is(T::Class()) ) return convert((T*)l,r);
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define CLASS(T,V) \
|
||||
std::map<int,V> T;
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#ifndef SHAPES
|
||||
#ifndef SHAPES
|
||||
#define SHAPES(T)
|
||||
#endif
|
||||
#ifndef SHAPE
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define CLASS(T,V) bool convert(const T::ptr L, V& r);
|
||||
#define SHAPES(T) CLASS(T,ShapeList)
|
||||
#include "IfcRegisterUndef.h"
|
||||
#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)
|
||||
#define FACE(T) CLASS(T,TopoDS_Face)
|
||||
#define FACE(T) CLASS(T,TopoDS_Shape)
|
||||
#define CURVE(T) CLASS(T,Handle(Geom_Curve))
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define SHAPES(T) \
|
||||
if ( l->is(T::Class()) ) return true;
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define CLASS(T,V) \
|
||||
T.clear();
|
||||
#include "IfcRegisterDef.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#ifdef SHAPES
|
||||
#ifdef SHAPES
|
||||
#undef SHAPES
|
||||
#endif
|
||||
#ifdef SHAPE
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 IFCSHAPELIST_H
|
||||
#define IFCSHAPELIST_H
|
||||
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeomRenderStyles.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
class IfcRepresentationShapeItem {
|
||||
private:
|
||||
gp_GTrsf placement;
|
||||
TopoDS_Shape shape;
|
||||
const SurfaceStyle* style;
|
||||
public:
|
||||
IfcRepresentationShapeItem(const gp_GTrsf& placement, const TopoDS_Shape& shape, const SurfaceStyle* style)
|
||||
: placement(placement), shape(shape), style(style) {}
|
||||
IfcRepresentationShapeItem(const gp_GTrsf& placement, const TopoDS_Shape& shape)
|
||||
: placement(placement), shape(shape), style(0) {}
|
||||
IfcRepresentationShapeItem(const TopoDS_Shape& shape, const SurfaceStyle* style)
|
||||
: shape(shape), style(style) {}
|
||||
IfcRepresentationShapeItem(const TopoDS_Shape& shape)
|
||||
: shape(shape), style(0) {}
|
||||
void append(const gp_GTrsf& trsf) { placement.Multiply(trsf); }
|
||||
void prepend(const gp_GTrsf& trsf) { placement.PreMultiply(trsf); }
|
||||
const TopoDS_Shape& Shape() const { return shape; }
|
||||
const gp_GTrsf& Placement() const { return placement; }
|
||||
bool hasStyle() const { return style != 0; }
|
||||
const SurfaceStyle& Style() const { return *style; }
|
||||
};
|
||||
typedef std::vector<IfcRepresentationShapeItem> IfcRepresentationShapeItems;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,345 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 examples exposes the IfcOpenShell API through a command-based stdin *
|
||||
* interface *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
#define SET_BINARY_STREAMS
|
||||
#endif
|
||||
#ifdef SET_BINARY_STREAMS
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
using namespace boost;
|
||||
|
||||
template <typename T>
|
||||
T sread(std::istream& s) {
|
||||
char buf[sizeof(T)];
|
||||
s.read(buf, sizeof(T));
|
||||
return *((T*)buf);
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string sread(std::istream& s) {
|
||||
int32_t len = sread<int32_t>(s);
|
||||
char* buf = new char[len + 1];
|
||||
s.read(buf, len);
|
||||
buf[len] = 0;
|
||||
while (len++ % 4) s.get();
|
||||
std::string str(buf);
|
||||
delete buf;
|
||||
return str;
|
||||
}
|
||||
|
||||
static std::streambuf *stdout_orig, *stdout_redir;
|
||||
|
||||
template <typename T>
|
||||
void swrite(std::ostream& s, T t) {
|
||||
char buf[sizeof(T)];
|
||||
memcpy(buf, &t, sizeof(T));
|
||||
s.write(buf, sizeof(T));
|
||||
}
|
||||
|
||||
template <>
|
||||
void swrite(std::ostream& s, std::string t) {
|
||||
int32_t len = t.size();
|
||||
swrite(s, len);
|
||||
s.write(t.c_str(), len);
|
||||
while (len++ % 4) s.put(0);
|
||||
}
|
||||
|
||||
class Command {
|
||||
protected:
|
||||
virtual void read_content(std::istream& s) = 0;
|
||||
virtual void write_content(std::ostream& s) = 0;
|
||||
int32_t iden;
|
||||
int32_t len;
|
||||
public:
|
||||
void read(std::istream& s) {
|
||||
len = sread<int32_t>(s);
|
||||
read_content(s);
|
||||
}
|
||||
|
||||
void write(std::ostream& s) {
|
||||
std::cout.rdbuf(stdout_orig);
|
||||
swrite(s, iden);
|
||||
std::ostringstream oss;
|
||||
write_content(oss);
|
||||
swrite(s, oss.str());
|
||||
s.flush();
|
||||
std::cout.rdbuf(stdout_redir);
|
||||
}
|
||||
|
||||
Command(int32_t iden) : iden(iden) {}
|
||||
};
|
||||
|
||||
const int32_t HELLO = 0xff00;
|
||||
const int32_t IFC_MODEL = HELLO + 1;
|
||||
const int32_t GET = IFC_MODEL + 1;
|
||||
const int32_t ENTITY = GET + 1;
|
||||
const int32_t MORE = ENTITY + 1;
|
||||
const int32_t NEXT = MORE + 1;
|
||||
const int32_t BYE = NEXT + 1;
|
||||
const int32_t GET_LOG = BYE + 1;
|
||||
const int32_t LOG = GET_LOG + 1;
|
||||
|
||||
class Hello : public Command {
|
||||
private:
|
||||
std::string str;
|
||||
protected:
|
||||
void read_content(std::istream& s) {
|
||||
str = sread<std::string>(s);
|
||||
}
|
||||
void write_content(std::ostream& s) {
|
||||
swrite(s, str);
|
||||
}
|
||||
public:
|
||||
const std::string& string() { return str; }
|
||||
Hello() : Command(HELLO), str("IfcOpenShell-" IFCOPENSHELL_VERSION) {}
|
||||
};
|
||||
|
||||
class More : public Command {
|
||||
private:
|
||||
bool more;
|
||||
protected:
|
||||
void read_content(std::istream& s) {
|
||||
more = sread<int32_t>(s) == 1;
|
||||
}
|
||||
void write_content(std::ostream& s) {
|
||||
swrite<int32_t>(s, more ? 1 : 0);
|
||||
}
|
||||
public:
|
||||
More(bool more) : Command(MORE), more(more) {}
|
||||
};
|
||||
|
||||
class IfcModel : public Command {
|
||||
private:
|
||||
std::string str;
|
||||
protected:
|
||||
void read_content(std::istream& s) {
|
||||
str = sread<std::string>(s);
|
||||
}
|
||||
void write_content(std::ostream& s) {
|
||||
swrite(s, str);
|
||||
}
|
||||
public:
|
||||
const std::string& string() { return str; }
|
||||
IfcModel() : Command(IFC_MODEL) {};
|
||||
};
|
||||
|
||||
class Get : public Command {
|
||||
protected:
|
||||
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) {}
|
||||
public:
|
||||
GetLog() : Command(GET_LOG) {};
|
||||
};
|
||||
|
||||
class WriteLog : public Command {
|
||||
private:
|
||||
std::string str;
|
||||
protected:
|
||||
void read_content(std::istream& s) {
|
||||
str = sread<std::string>(s);
|
||||
}
|
||||
void write_content(std::ostream& s) {
|
||||
swrite(s, str);
|
||||
}
|
||||
public:
|
||||
WriteLog(const std::string& str) : Command(LOG), str(str) {};
|
||||
};
|
||||
|
||||
class Entity : public Command {
|
||||
private:
|
||||
const IfcGeom::TriangulationElement<float>* geom;
|
||||
protected:
|
||||
void read_content(std::istream& s) {}
|
||||
void write_content(std::ostream& s) {
|
||||
swrite<int32_t>(s, geom->id());
|
||||
swrite(s, geom->guid());
|
||||
swrite(s, geom->name());
|
||||
swrite(s, geom->type());
|
||||
swrite<int32_t>(s, geom->parent_id());
|
||||
const std::vector<float>& m = geom->transformation().matrix().data();
|
||||
const float matrix_array[16] = {
|
||||
m[0], m[3], m[6], m[ 9],
|
||||
m[1], m[4], m[7], m[10],
|
||||
m[2], m[5], m[8], m[11],
|
||||
0, 0, 0, 1
|
||||
};
|
||||
swrite(s, std::string((char*)matrix_array, 16 * sizeof(float)));
|
||||
swrite<int32_t>(s, geom->geometry().id());
|
||||
swrite(s, std::string((char*)geom->geometry().verts().data(), geom->geometry().verts().size() * sizeof(float)));
|
||||
swrite(s, std::string((char*)geom->geometry().normals().data(), geom->geometry().normals().size() * sizeof(float)));
|
||||
{ std::vector<int32_t> indices;
|
||||
for (std::vector<int>::const_iterator it = geom->geometry().faces().begin(); it != geom->geometry().faces().end(); ++it) {
|
||||
indices.push_back(*it);
|
||||
}
|
||||
swrite(s, std::string((char*) indices.data(), indices.size() * sizeof(int32_t))); }
|
||||
{ std::vector<float> diffuse_color_array;
|
||||
for (std::vector<IfcGeom::Material>::const_iterator it = geom->geometry().materials().begin(); it != geom->geometry().materials().end(); ++it) {
|
||||
const IfcGeom::Material& m = *it;
|
||||
if (m.hasDiffuse()) {
|
||||
const double* color = m.diffuse();
|
||||
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]));
|
||||
} else {
|
||||
diffuse_color_array.push_back(0.f);
|
||||
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()));
|
||||
} else {
|
||||
diffuse_color_array.push_back(1.f);
|
||||
}
|
||||
}
|
||||
swrite(s, std::string((char*) diffuse_color_array.data(), diffuse_color_array.size() * sizeof(float))); }
|
||||
{ std::vector<int32_t> material_indices;
|
||||
for (std::vector<int>::const_iterator it = geom->geometry().material_ids().begin(); it != geom->geometry().material_ids().end(); ++it) {
|
||||
material_indices.push_back(*it);
|
||||
}
|
||||
swrite(s, std::string((char*) material_indices.data(), material_indices.size() * sizeof(int32_t))); }
|
||||
}
|
||||
public:
|
||||
Entity(const IfcGeom::TriangulationElement<float>* geom) : Command(ENTITY), geom(geom) {};
|
||||
};
|
||||
|
||||
class Next : public Command {
|
||||
protected:
|
||||
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) {}
|
||||
public:
|
||||
Bye() : Command(BYE) {};
|
||||
};
|
||||
|
||||
int main (int argc, char** argv) {
|
||||
if (sizeof(float) != 4 || sizeof(int32_t) != 4) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Redirect stdout to this stream, so that involuntary
|
||||
// writes to stdout do not interfere with our protocol.
|
||||
std::ostringstream oss;
|
||||
stdout_redir = oss.rdbuf();
|
||||
stdout_orig = std::cout.rdbuf();
|
||||
std::cout.rdbuf(stdout_redir);
|
||||
|
||||
#ifdef SET_BINARY_STREAMS
|
||||
_setmode(_fileno(stdout), _O_BINARY);
|
||||
std::cout.setf(std::ios_base::binary);
|
||||
_setmode(_fileno(stdin), _O_BINARY);
|
||||
std::cin.setf(std::ios_base::binary);
|
||||
#endif
|
||||
|
||||
bool has_more = false;
|
||||
|
||||
IfcGeom::Iterator<float>* iterator = 0;
|
||||
|
||||
Hello().write(std::cout);
|
||||
|
||||
int exit_code = 0;
|
||||
while (1) {
|
||||
const int32_t msg_type = sread<int32_t>(std::cin);
|
||||
switch (msg_type) {
|
||||
case IFC_MODEL: {
|
||||
IfcModel m; m.read(std::cin);
|
||||
std::string::size_type len = m.string().size();
|
||||
char* data = new char[len];
|
||||
memcpy(data, m.string().c_str(), len);
|
||||
|
||||
IfcGeom::IteratorSettings settings;
|
||||
settings.use_world_coords() = false;
|
||||
settings.weld_vertices() = false;
|
||||
settings.convert_back_units() = true;
|
||||
settings.force_ccw_face_orientation() = true;
|
||||
|
||||
iterator = new IfcGeom::Iterator<float>(settings, data, len);
|
||||
has_more = iterator->findContext();
|
||||
|
||||
More(has_more).write(std::cout);
|
||||
continue;
|
||||
}
|
||||
case GET: {
|
||||
Get g; g.read(std::cin);
|
||||
if (!has_more) {
|
||||
exit_code = 1;
|
||||
break;
|
||||
}
|
||||
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 = iterator->next();
|
||||
if (!has_more) {
|
||||
delete iterator;
|
||||
iterator = 0;
|
||||
}
|
||||
More(has_more).write(std::cout);
|
||||
continue;
|
||||
}
|
||||
case GET_LOG: {
|
||||
GetLog gl; gl.read(std::cin);
|
||||
WriteLog(iterator->getLog()).write(std::cout);
|
||||
continue;
|
||||
}
|
||||
case BYE: {
|
||||
Bye().write(std::cout);
|
||||
exit_code = 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
exit_code = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
std::cout.rdbuf(stdout_orig);
|
||||
return exit_code;
|
||||
}
|
||||
+12
-12
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "org_ifcopenshell_IfcOpenShellModel.h"
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
|
||||
bool has_more = false;
|
||||
static bool has_more = false;
|
||||
|
||||
JNIEXPORT jobject JNICALL Java_org_ifcopenshell_IfcOpenShellModel_getGeometry (JNIEnv * env, jobject) {
|
||||
if ( ! has_more ) return 0;
|
||||
@@ -37,19 +37,19 @@ JNIEXPORT jobject JNICALL Java_org_ifcopenshell_IfcOpenShellModel_getGeometry (J
|
||||
if ( ! jconstructor ) return 0;
|
||||
const IfcGeomObjects::IfcGeomObject* o = IfcGeomObjects::Get();
|
||||
|
||||
jstring name = env->NewStringUTF(o->name.c_str());
|
||||
jstring type = env->NewStringUTF(o->type.c_str());
|
||||
jstring guid = env->NewStringUTF(o->guid.c_str());
|
||||
jstring name = env->NewStringUTF(o->name().c_str());
|
||||
jstring type = env->NewStringUTF(o->type().c_str());
|
||||
jstring guid = env->NewStringUTF(o->guid().c_str());
|
||||
|
||||
jintArray indices = env->NewIntArray(o->mesh->faces.size());
|
||||
jfloatArray positions = env->NewFloatArray(o->mesh->verts.size());
|
||||
jfloatArray normals = env->NewFloatArray(o->mesh->normals.size());
|
||||
jintArray indices = env->NewIntArray(o->mesh().faces().size());
|
||||
jfloatArray positions = env->NewFloatArray(o->mesh().verts().size());
|
||||
jfloatArray normals = env->NewFloatArray(o->mesh().normals().size());
|
||||
|
||||
env->SetIntArrayRegion(indices,0,o->mesh->faces.size(),(jint*) &o->mesh->faces[0]);
|
||||
env->SetFloatArrayRegion(positions,0,o->mesh->verts.size(),(jfloat*) &o->mesh->verts[0]);
|
||||
env->SetFloatArrayRegion(normals,0,o->mesh->normals.size(),(jfloat*) &o->mesh->normals[0]);
|
||||
env->SetIntArrayRegion(indices,0,o->mesh().faces().size(),(jint*) &o->mesh().faces()[0]);
|
||||
env->SetFloatArrayRegion(positions,0,o->mesh().verts().size(),(jfloat*) &o->mesh().verts()[0]);
|
||||
env->SetFloatArrayRegion(normals,0,o->mesh().normals().size(),(jfloat*) &o->mesh().normals()[0]);
|
||||
|
||||
jobject return_obj = env->NewObject(class_def, jconstructor, o->id, name, type, guid, indices, positions, normals);
|
||||
jobject return_obj = env->NewObject(class_def, jconstructor, o->id(), name, type, guid, indices, positions, normals);
|
||||
|
||||
env->DeleteLocalRef(name);
|
||||
env->DeleteLocalRef(type);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class org_ifcopenshell_IfcOpenShellModel */
|
||||
|
||||
|
||||
+164
-67
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -17,13 +17,14 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "Max.h"
|
||||
#include "stdmat.h"
|
||||
#include "istdplug.h"
|
||||
#include <Max.h>
|
||||
#include <stdmat.h>
|
||||
#include <istdplug.h>
|
||||
|
||||
#include "../ifcmax/IfcMax.h"
|
||||
#include "../ifcmax/MaxMaterials.h"
|
||||
#include "../ifcgeom/IfcGeomObjects.h"
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
static const int NUM_MATERIAL_SLOTS = 24;
|
||||
|
||||
int controlsInit = false;
|
||||
|
||||
@@ -101,85 +102,181 @@ void IFCImp::ShowAbout(HWND hWnd) {}
|
||||
|
||||
DWORD WINAPI fn(LPVOID arg) { return 0; }
|
||||
|
||||
#if MAX_RELEASE > 14000
|
||||
# define S(x) (TSTR::FromCStr(x.c_str()))
|
||||
#elif defined(_UNICODE)
|
||||
# define S(x) (WStr(x.c_str()))
|
||||
#else
|
||||
# define S(x) (CStr(x.c_str()))
|
||||
#endif
|
||||
|
||||
Mtl* FindMaterialByName(MtlBaseLib* library, const std::string& material_name) {
|
||||
const int mat_index = library->FindMtlByName(S(material_name));
|
||||
Mtl* m = 0;
|
||||
if (mat_index != -1) {
|
||||
m = static_cast<Mtl*>((*library)[mat_index]);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
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();
|
||||
const TimeValue t = -1;
|
||||
if (material.hasDiffuse()) {
|
||||
const double* diffuse = material.diffuse();
|
||||
stdm->SetDiffuse(Color(diffuse[0], diffuse[1], diffuse[2]),t);
|
||||
}
|
||||
if (material.hasSpecular()) {
|
||||
const double* specular = material.specular();
|
||||
stdm->SetSpecular(Color(specular[0], specular[1], specular[2]),t);
|
||||
}
|
||||
if (material.hasSpecularity()) {
|
||||
stdm->SetShininess(material.specularity(), t);
|
||||
}
|
||||
if (material.hasTransparency()) {
|
||||
stdm->SetOpacity(1.0 - material.transparency(), t);
|
||||
}
|
||||
m = stdm;
|
||||
m->SetName(S(material.name()));
|
||||
library->Add(m);
|
||||
if (slot < NUM_MATERIAL_SLOTS) {
|
||||
max_interface->PutMtlToMtlEditor(m,slot++);
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi_mats, MtlBaseLib* library, Interface* max_interface, int& slot, const std::vector<IfcGeom::Material>& materials, const std::string& object_type, const std::vector<int>& material_ids) {
|
||||
std::vector<std::string> material_names;
|
||||
bool needs_default = std::find(material_ids.begin(), material_ids.end(), -1) != material_ids.end();
|
||||
if (needs_default) {
|
||||
material_names.push_back(object_type);
|
||||
}
|
||||
for (auto it = materials.begin(); it != materials.end(); ++it) {
|
||||
material_names.push_back(it->name());
|
||||
}
|
||||
Mtl* default_material = 0;
|
||||
if (needs_default) {
|
||||
default_material = FindMaterialByName(library, object_type);
|
||||
if (default_material == 0) {
|
||||
default_material = NewDefaultStdMat();
|
||||
default_material->SetName(S(object_type));
|
||||
library->Add(default_material);
|
||||
if (slot < NUM_MATERIAL_SLOTS) {
|
||||
max_interface->PutMtlToMtlEditor(default_material, slot++);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (material_names.size() == 1) {
|
||||
if (needs_default) {
|
||||
return default_material;
|
||||
} else {
|
||||
return FindOrCreateMaterial(library, max_interface, slot, *materials.begin());
|
||||
}
|
||||
}
|
||||
std::map<std::vector<std::string>, Mtl*>::const_iterator i = multi_mats.find(material_names);
|
||||
if (i != multi_mats.end()) {
|
||||
return i->second;
|
||||
}
|
||||
MultiMtl* multi_mat = NewDefaultMultiMtl();
|
||||
multi_mat->SetNumSubMtls(material_names.size());
|
||||
int mtl_id = 0;
|
||||
if (needs_default) {
|
||||
multi_mat->SetSubMtlAndName(mtl_id ++, default_material, default_material->GetName());
|
||||
}
|
||||
for (auto it = materials.begin(); it != materials.end(); ++it) {
|
||||
Mtl* mtl = FindOrCreateMaterial(library, max_interface, slot, *it);
|
||||
multi_mat->SetSubMtl(mtl_id ++, mtl);
|
||||
}
|
||||
library->Add(multi_mat);
|
||||
if (slot < NUM_MATERIAL_SLOTS) {
|
||||
max_interface->PutMtlToMtlEditor(multi_mat,slot++);
|
||||
}
|
||||
multi_mats.insert(std::pair<std::vector<std::string>, Mtl*>(material_names, multi_mat));
|
||||
return multi_mat;
|
||||
}
|
||||
|
||||
int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, BOOL suppressPrompts) {
|
||||
|
||||
itfc->ProgressStart("Importing file...", TRUE, fn, NULL);
|
||||
IfcGeom::IteratorSettings settings;
|
||||
settings.use_world_coords() = false;
|
||||
settings.weld_vertices() = true;
|
||||
settings.sew_shells() = true;
|
||||
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS,false);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::WELD_VERTICES,true);
|
||||
IfcGeomObjects::Settings(IfcGeomObjects::SEW_SHELLS,true);
|
||||
#ifdef _UNICODE
|
||||
int fn_buffer_size = WideCharToMultiByte(CP_UTF8, 0, name, -1, 0, 0, 0, 0);
|
||||
char* fn_mb = new char[fn_buffer_size];
|
||||
WideCharToMultiByte(CP_UTF8, 0, name, -1, fn_mb, fn_buffer_size, 0, 0);
|
||||
#else
|
||||
const char* fn_mb = name;
|
||||
#endif
|
||||
|
||||
if ( ! IfcGeomObjects::Init((char*)name,0,0) ) return false;
|
||||
IfcGeom::Iterator<float> iterator(settings, fn_mb);
|
||||
|
||||
if (!iterator.findContext()) return false;
|
||||
|
||||
itfc->ProgressStart(_T("Importing file..."), TRUE, fn, NULL);
|
||||
|
||||
//std::map<int, TriObject*> dict;
|
||||
MtlBaseLib* mats = itfc->GetSceneMtls();
|
||||
int slot = mats->Count();
|
||||
|
||||
std::map<std::vector<std::string>, Mtl*> material_cache;
|
||||
|
||||
do{
|
||||
const IfcGeom::TriangulationElement<float>* o = static_cast<const IfcGeom::TriangulationElement<float>*>(iterator.get());
|
||||
|
||||
const IfcGeomObjects::IfcGeomObject* o = IfcGeomObjects::Get();
|
||||
|
||||
Mtl *m;
|
||||
const int matIndex = mats->FindMtlByName(MSTR(o->type.c_str()));
|
||||
if ( matIndex == -1 ) {
|
||||
StdMat2* stdm = GetMaterial(o->type);
|
||||
m = stdm;
|
||||
m->SetName(o->type.c_str());
|
||||
mats->Add(m);
|
||||
itfc->PutMtlToMtlEditor(m,slot++);
|
||||
} else {
|
||||
m = static_cast<Mtl*>((*mats)[matIndex]);
|
||||
}
|
||||
|
||||
// This mapping is useless for now, because this even in case
|
||||
// meshes entities in IFC share the same representation elements
|
||||
// they will never be given the same id.
|
||||
// TODO: Fix this!
|
||||
// std::map<int, TriObject*>::const_iterator it = dict.find(o->mesh->id);
|
||||
TSTR o_type = S(o->type());
|
||||
TSTR o_guid = S(o->guid());
|
||||
|
||||
TriObject* tri;
|
||||
// if ( it == dict.end() ) {
|
||||
tri = CreateNewTriObject();
|
||||
const int numVerts = o->mesh->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]);
|
||||
}
|
||||
const int numFaces = o->mesh->faces.size()/3;
|
||||
tri->mesh.setNumFaces(numFaces);
|
||||
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]);
|
||||
}
|
||||
Mtl *m = ComposeMultiMaterial(material_cache, mats, itfc, slot, o->geometry().materials(), o->type(), o->geometry().material_ids());
|
||||
|
||||
TriObject* tri = CreateNewTriObject();
|
||||
|
||||
const int numVerts = o->geometry().verts().size()/3;
|
||||
tri->mesh.setNumVerts(numVerts);
|
||||
for( int i = 0; i < numVerts; i ++ ) {
|
||||
tri->mesh.setVert(i,o->geometry().verts()[3*i+0],o->geometry().verts()[3*i+1],o->geometry().verts()[3*i+2]);
|
||||
}
|
||||
const int numFaces = o->geometry().faces().size()/3;
|
||||
tri->mesh.setNumFaces(numFaces);
|
||||
|
||||
bool needs_default = std::find(o->geometry().material_ids().begin(), o->geometry().material_ids().end(), -1) != o->geometry().material_ids().end();
|
||||
|
||||
for( int i = 0; i < numFaces; i ++ ) {
|
||||
tri->mesh.faces[i].setVerts(o->geometry().faces()[3*i+0],o->geometry().faces()[3*i+1],o->geometry().faces()[3*i+2]);
|
||||
tri->mesh.faces[i].setEdgeVisFlags(o->geometry().edges()[3*i+0],o->geometry().edges()[3*i+1],o->geometry().edges()[3*i+2]);
|
||||
MtlID mtlid = o->geometry().material_ids()[i];
|
||||
if (needs_default) mtlid ++;
|
||||
tri->mesh.faces[i].setMatID(mtlid);
|
||||
}
|
||||
|
||||
tri->mesh.buildNormals();
|
||||
// Either use this or undefine the FACESETS_AS_COMPOUND option in IfcGeom.h to have
|
||||
// properly oriented normals. Using only the line below will result in a consistent
|
||||
// orientation of normals accross shells, but not always oriented towards the
|
||||
// outside.
|
||||
// tri->mesh.UnifyNormals(false);
|
||||
tri->mesh.BuildStripsAndEdges();
|
||||
tri->mesh.InvalidateTopologyCache();
|
||||
tri->mesh.InvalidateGeomCache();
|
||||
|
||||
// dict[o->mesh->id] = tri;
|
||||
// } else {
|
||||
// tri = (*it).second;
|
||||
// }
|
||||
tri->mesh.buildNormals();
|
||||
// Either use this or undefine the FACESETS_AS_COMPOUND option in IfcGeom.h to have
|
||||
// properly oriented normals. Using only the line below will result in a consistent
|
||||
// orientation of normals accross shells, but not always oriented towards the
|
||||
// outside.
|
||||
// tri->mesh.UnifyNormals(false);
|
||||
tri->mesh.BuildStripsAndEdges();
|
||||
tri->mesh.InvalidateTopologyCache();
|
||||
tri->mesh.InvalidateGeomCache();
|
||||
|
||||
ImpNode* node = impitfc->CreateNode();
|
||||
node->Reference(tri);
|
||||
node->SetName(o->guid.c_str());
|
||||
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]) ));
|
||||
node->SetName(o_guid);
|
||||
node->GetINode()->Hide(o->type() == "IfcOpeningElement" || o->type() == "IfcSpace");
|
||||
if (m) {
|
||||
node->GetINode()->SetMtl(m);
|
||||
}
|
||||
const std::vector<float>& matrix_data = o->transformation().matrix().data();
|
||||
node->SetTransform(0,Matrix3 ( Point3(matrix_data[0],matrix_data[1],matrix_data[2]),Point3(matrix_data[3],matrix_data[4],matrix_data[5]),
|
||||
Point3(matrix_data[6],matrix_data[7],matrix_data[8]),Point3(matrix_data[9],matrix_data[10],matrix_data[11]) ));
|
||||
impitfc->AddNodeToScene(node);
|
||||
|
||||
itfc->ProgressUpdate(IfcGeomObjects::Progress(),true,"");
|
||||
itfc->ProgressUpdate(iterator.progress(), true, _T(""));
|
||||
|
||||
} while ( IfcGeomObjects::Next() );
|
||||
|
||||
IfcGeomObjects::CleanUp();
|
||||
} while (iterator.next());
|
||||
|
||||
itfc->ProgressEnd();
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
|
||||
@@ -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,133 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# 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 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):
|
||||
try: return entity_instance.wrap_value(self.wrapped_data.get_argument(self.wrapped_data.get_argument_index(name)))
|
||||
except:
|
||||
try: return entity_instance.wrap_value(self.wrapped_data.get_inverse(name))
|
||||
except: raise AttributeError("entity instance of type '%s' has no attribute '%s'"%(self.wrapped_data.is_a(), name))
|
||||
@staticmethod
|
||||
def map_value(v):
|
||||
if isinstance(v, entity_instance): return v.wrapped_data
|
||||
elif isinstance(v, (tuple, list)) and len(v):
|
||||
classes = list(map(type, v))
|
||||
if float in classes: return ifcopenshell_wrapper.double_vector(v)
|
||||
elif int in classes: return ifcopenshell_wrapper.int_vector(v)
|
||||
elif str in classes: return ifcopenshell_wrapper.string_vector(v)
|
||||
elif entity_instance in classes: return list(map(lambda e: e.wrapped_data, v))
|
||||
return v
|
||||
@staticmethod
|
||||
def wrap_value(v):
|
||||
wrap = lambda e: entity_instance(e)
|
||||
if isinstance(v, ifcopenshell_wrapper.entity_instance): return wrap(v)
|
||||
elif isinstance(v, (tuple, list)) and len(v):
|
||||
classes = list(map(type, v))
|
||||
if ifcopenshell_wrapper.entity_instance in classes: return list(map(wrap, v))
|
||||
return v
|
||||
def attribute_type(self, attr):
|
||||
attr_idx = attr if isinstance(attr, int) 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):
|
||||
self.wrapped_data.set_argument(idx, entity_instance.map_value(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, int):
|
||||
return entity_instance(self.wrapped_data.by_id(key))
|
||||
elif isinstance(key, str):
|
||||
return entity_instance(self.wrapped_data.by_guid(key))
|
||||
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
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# 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:
|
||||
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):
|
||||
return wrap_shape_creation(settings, ifcopenshell_wrapper.create_shape(settings, inst.wrapped_data))
|
||||
|
||||
|
||||
def iterate(settings, filename):
|
||||
it = iterator(settings, filename)
|
||||
if it.findContext():
|
||||
while True:
|
||||
yield it.get()
|
||||
if not it.next(): break
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
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
|
||||
|
||||
try: brep_data = brep_object.geometry.brep_data
|
||||
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
|
||||
|
||||
return tuple(brep_object, 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:])
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,30 +19,33 @@
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file defines materials for use in 3ds Max for several IFC datatypes *
|
||||
* This file has been generated from IFC2X3_TC1.exp. Do not make modifications *
|
||||
* but instead modify the python script that has been used to generate this. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#ifndef IFC2X3RT_H
|
||||
#define IFC2X3RT_H
|
||||
|
||||
#include "Max.h"
|
||||
#include "stdmat.h"
|
||||
#define IfcSchema Ifc2x3
|
||||
|
||||
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;
|
||||
}
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcEntityDescriptor.h"
|
||||
#include "../ifcparse/IfcWritableEntity.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);
|
||||
Enum GetAttributeEntity(Enum t, unsigned char a);
|
||||
const std::string& GetAttributeName(Enum t, unsigned char a);
|
||||
bool GetAttributeOptional(Enum t, unsigned char a);
|
||||
bool GetAttributeDerived(Enum t, unsigned char a);
|
||||
std::pair<const char*, int> GetEnumerationIndex(Enum t, const std::string& a);
|
||||
std::pair<Enum, unsigned> GetInverseAttribute(Enum t, const std::string& a);
|
||||
std::set<std::string> GetInverseAttributeNames(Enum t);
|
||||
void PopulateDerivedFields(IfcWrite::IfcWritableEntity* e);
|
||||
}}
|
||||
|
||||
#endif
|
||||
+8315
-4542
File diff suppressed because one or more lines are too long
+11845
-10407
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,51 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 has been generated from IFC4.exp. Do not make modifications *
|
||||
* but instead modify the python script that has been used to generate this. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFC4RT_H
|
||||
#define IFC4RT_H
|
||||
|
||||
#define IfcSchema Ifc4
|
||||
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcEntityDescriptor.h"
|
||||
#include "../ifcparse/IfcWritableEntity.h"
|
||||
|
||||
namespace Ifc4 {
|
||||
namespace Type {
|
||||
int GetAttributeCount(Enum t);
|
||||
int GetAttributeIndex(Enum t, const std::string& a);
|
||||
IfcUtil::ArgumentType GetAttributeType(Enum t, unsigned char a);
|
||||
Enum GetAttributeEntity(Enum t, unsigned char a);
|
||||
const std::string& GetAttributeName(Enum t, unsigned char a);
|
||||
bool GetAttributeOptional(Enum t, unsigned char a);
|
||||
bool GetAttributeDerived(Enum t, unsigned char a);
|
||||
std::pair<const char*, int> GetEnumerationIndex(Enum t, const std::string& a);
|
||||
std::pair<Enum, unsigned> GetInverseAttribute(Enum t, const std::string& a);
|
||||
std::set<std::string> GetInverseAttributeNames(Enum t);
|
||||
void PopulateDerivedFields(IfcWrite::IfcWritableEntity* e);
|
||||
}}
|
||||
|
||||
#endif
|
||||
+16212
File diff suppressed because one or more lines are too long
+53504
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -30,7 +30,7 @@
|
||||
|
||||
#include "../ifcparse/IfcCharacterDecoder.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcparse/IfcSpfStream.h"
|
||||
|
||||
#define FIRST_SOLIDUS (1 << 1)
|
||||
#define PAGE (1 << 2)
|
||||
@@ -67,6 +67,7 @@
|
||||
#define CLEAR_HEX(C) (C &= ~(HEX(1)&HEX(2)&HEX(3)&HEX(4)&HEX(5)&HEX(6)&HEX(7)&HEX(8)))
|
||||
|
||||
using namespace IfcParse;
|
||||
using namespace IfcWrite;
|
||||
|
||||
void IfcCharacterDecoder::addChar(std::stringstream& s,const UChar32& ch) {
|
||||
#ifdef HAVE_ICU
|
||||
@@ -87,20 +88,35 @@ void IfcCharacterDecoder::addChar(std::stringstream& s,const UChar32& ch) {
|
||||
s.put(substitution_character);
|
||||
#endif
|
||||
}
|
||||
IfcCharacterDecoder::IfcCharacterDecoder(IfcParse::File* f) {
|
||||
file = f;
|
||||
IfcCharacterDecoder::IfcCharacterDecoder(IfcParse::IfcSpfStream* f) {
|
||||
file = f;
|
||||
#ifdef HAVE_ICU
|
||||
if ( ! destination && mode == UTF8 ) {
|
||||
destination = ucnv_open("utf-8", &status);
|
||||
} else if ( ! destination && mode == LATIN ) {
|
||||
destination = ucnv_open("iso-8859-1", &status);
|
||||
}
|
||||
if (destination) ucnv_close(destination);
|
||||
if (compatibility_converter) ucnv_close(compatibility_converter);
|
||||
destination = 0;
|
||||
compatibility_converter = 0;
|
||||
|
||||
if (mode == DEFAULT) {
|
||||
destination = ucnv_open(0, &status);
|
||||
} else if (mode == UTF8) {
|
||||
destination = ucnv_open("utf-8", &status);
|
||||
} else if (mode == LATIN) {
|
||||
destination = ucnv_open("iso-8859-1", &status);
|
||||
}
|
||||
if (compatibility_charset.empty()) {
|
||||
compatibility_charset = ucnv_getDefaultName();
|
||||
}
|
||||
compatibility_converter = ucnv_open(compatibility_charset.c_str(), &status);
|
||||
#endif
|
||||
}
|
||||
IfcCharacterDecoder::~IfcCharacterDecoder() {
|
||||
#ifdef HAVE_ICU
|
||||
if ( destination ) ucnv_close(destination);
|
||||
if ( converter ) ucnv_close(converter);
|
||||
if ( destination ) ucnv_close(destination);
|
||||
if ( converter ) ucnv_close(converter);
|
||||
if ( compatibility_converter ) ucnv_close(compatibility_converter);
|
||||
destination = 0;
|
||||
converter = 0;
|
||||
compatibility_converter = 0;
|
||||
#endif
|
||||
}
|
||||
IfcCharacterDecoder::operator std::string() {
|
||||
@@ -111,6 +127,9 @@ IfcCharacterDecoder::operator std::string() {
|
||||
int codepage = 1;
|
||||
unsigned int hex = 0;
|
||||
unsigned int hex_count = 0;
|
||||
#ifdef HAVE_ICU
|
||||
unsigned int old_hex = 0; // for compatibility_mode
|
||||
#endif
|
||||
while ( current_char = file->Peek() ) {
|
||||
if ( EXPECTS_CHARACTER(parse_state) ) {
|
||||
#ifdef HAVE_ICU
|
||||
@@ -164,7 +183,24 @@ IfcCharacterDecoder::operator std::string() {
|
||||
if ( (hex_count == 2 && !(parse_state & EXTENDED2)) ||
|
||||
(hex_count == 4 && !(parse_state & EXTENDED4)) ||
|
||||
(hex_count == 8) ) {
|
||||
addChar(s,(UChar32) hex);
|
||||
#ifdef HAVE_ICU
|
||||
if (compatibility_mode) {
|
||||
if (old_hex == 0) {
|
||||
old_hex = hex;
|
||||
} else {
|
||||
char characters[3] = { old_hex, hex };
|
||||
const char* char_array = &characters[0];
|
||||
UChar32 ch = ucnv_getNextUChar(compatibility_converter,&char_array,char_array+2,&status);
|
||||
addChar(s,ch);
|
||||
old_hex = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
addChar(s,(UChar32) hex);
|
||||
#ifdef HAVE_ICU
|
||||
}
|
||||
#endif
|
||||
if ( hex_count == 2 ) parse_state = 0;
|
||||
else CLEAR_HEX(parse_state);
|
||||
hex = hex_count = 0;
|
||||
@@ -177,8 +213,8 @@ IfcCharacterDecoder::operator std::string() {
|
||||
throw IfcException("Invalid character encountered");
|
||||
} else {
|
||||
parse_state = hex = hex_count = 0;
|
||||
// NOTE: this is in fact wrong, this ought to be the representation of the character.
|
||||
// In UTF-8 this is the same, but we should not rely on that.
|
||||
// NOTE: this is in fact wrong, this ought to be the representation of the character.
|
||||
// In UTF-8 this is the same, but we should not rely on that.
|
||||
s.put(current_char);
|
||||
}
|
||||
file->Inc();
|
||||
@@ -246,9 +282,86 @@ void IfcCharacterDecoder::dryRun() {
|
||||
#ifdef HAVE_ICU
|
||||
UConverter* IfcCharacterDecoder::destination = 0;
|
||||
UConverter* IfcCharacterDecoder::converter = 0;
|
||||
UConverter* IfcCharacterDecoder::compatibility_converter = 0;
|
||||
int IfcCharacterDecoder::previous_codepage = -1;
|
||||
UErrorCode IfcCharacterDecoder::status = U_ZERO_ERROR;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ICU
|
||||
IfcCharacterDecoder::ConversionMode IfcCharacterDecoder::mode = IfcCharacterDecoder::JSON;
|
||||
|
||||
// Many BIM software (eg. Revit, ArchiCAD, ...) has wrong behavior
|
||||
bool IfcCharacterDecoder::compatibility_mode = false;
|
||||
std::string IfcCharacterDecoder::compatibility_charset = "";
|
||||
|
||||
#else
|
||||
char IfcCharacterDecoder::substitution_character = '_';
|
||||
#endif
|
||||
|
||||
|
||||
IfcCharacterEncoder::IfcCharacterEncoder(const std::string& input) {
|
||||
#ifdef HAVE_ICU
|
||||
if ( !converter) converter = ucnv_open("utf-8", &status);
|
||||
#endif
|
||||
str = input;
|
||||
}
|
||||
|
||||
IfcCharacterEncoder::~IfcCharacterEncoder() {
|
||||
#ifdef HAVE_ICU
|
||||
if ( !converter) ucnv_close(converter);
|
||||
converter = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
IfcCharacterEncoder::operator std::string() {
|
||||
std::ostringstream oss;
|
||||
oss.put('\'');
|
||||
#ifdef HAVE_ICU
|
||||
// Either 2 or 4 to uses \X2 or \X4 respectively.
|
||||
// Currently hardcoded to 4, but \X2 might be
|
||||
// sufficient for nearly all purposes.
|
||||
const int num_bytes = 4;
|
||||
const std::string num_bytes_str = std::string(1,num_bytes + 0x30);
|
||||
|
||||
|
||||
UChar32 ch;
|
||||
|
||||
const char* source = str.c_str();
|
||||
const char* limit = source + str.size();
|
||||
|
||||
bool in_extended = false;
|
||||
|
||||
while(source < limit) {
|
||||
ch = ucnv_getNextUChar(converter, &source, limit, &status);
|
||||
const bool within_spf_range = ch >= 0x20 && ch <= 0x7e;
|
||||
if ( in_extended && within_spf_range ) {
|
||||
oss << "\\X0\\";
|
||||
} else if ( !in_extended && !within_spf_range ) {
|
||||
oss << "\\X" << num_bytes_str << "\\";
|
||||
}
|
||||
if ( within_spf_range ) {
|
||||
oss.put(ch);
|
||||
if ( ch == '\\' || ch == '\'' ) oss.put(ch);
|
||||
} else {
|
||||
oss << std::hex << std::setw(num_bytes*2) << std::uppercase << std::setfill('0') << (int) ch;
|
||||
}
|
||||
in_extended = !within_spf_range;
|
||||
}
|
||||
|
||||
if ( in_extended ) oss << "\\X0\\";
|
||||
#else
|
||||
for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) {
|
||||
char ch = *i;
|
||||
if ( ch == '\\' || ch == '\'' ) oss.put(ch);
|
||||
oss.put(ch);
|
||||
}
|
||||
#endif
|
||||
oss.put('\'');
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_ICU
|
||||
UErrorCode IfcCharacterEncoder::status = U_ZERO_ERROR;
|
||||
UConverter* IfcCharacterEncoder::converter = 0;
|
||||
#endif
|
||||
@@ -1,29 +1,29 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Implementation of character decoding as described in ISO 10303-21 table 2 and *
|
||||
* table 4 *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
* *
|
||||
* Implementation of character decoding as described in ISO 10303-21 table 2 and *
|
||||
* table 4 *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCCHARACTERDECODER_H
|
||||
#define IFCCHARACTERDECODER_H
|
||||
|
||||
@@ -36,28 +36,36 @@
|
||||
typedef unsigned int UChar32;
|
||||
#endif
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcparse/IfcSpfStream.h"
|
||||
|
||||
namespace IfcParse {
|
||||
|
||||
class IfcCharacterDecoder {
|
||||
private:
|
||||
IfcParse::File* file;
|
||||
IfcParse::IfcSpfStream* file;
|
||||
#ifdef HAVE_ICU
|
||||
static UConverter* destination;
|
||||
static UConverter* converter;
|
||||
static UConverter* compatibility_converter;
|
||||
static int previous_codepage;
|
||||
static UErrorCode status;
|
||||
#endif
|
||||
void addChar(std::stringstream& s,const UChar32& ch);
|
||||
public:
|
||||
#ifdef HAVE_ICU
|
||||
enum ConversionMode {UTF8,LATIN,JSON,PYTHON};
|
||||
enum ConversionMode {DEFAULT,UTF8,LATIN,JSON,PYTHON};
|
||||
static ConversionMode mode;
|
||||
|
||||
// Many BIM software (eg. Revit, ArchiCAD, ...) has wrong behavior to encode characters.
|
||||
// It just translate to extended string in system default code page, not unicode.
|
||||
// If you want to process these strings, set true.
|
||||
static bool compatibility_mode;
|
||||
static std::string compatibility_charset;
|
||||
|
||||
#else
|
||||
static char substitution_character;
|
||||
#endif
|
||||
IfcCharacterDecoder(IfcParse::File* file);
|
||||
IfcCharacterDecoder(IfcParse::IfcSpfStream* file);
|
||||
~IfcCharacterDecoder();
|
||||
void dryRun();
|
||||
operator std::string();
|
||||
@@ -65,4 +73,21 @@ namespace IfcParse {
|
||||
|
||||
}
|
||||
|
||||
namespace IfcWrite {
|
||||
|
||||
class IfcCharacterEncoder {
|
||||
private:
|
||||
std::string str;
|
||||
#ifdef HAVE_ICU
|
||||
static UErrorCode status;
|
||||
static UConverter* converter;
|
||||
#endif
|
||||
public:
|
||||
IfcCharacterEncoder(const std::string& input);
|
||||
~IfcCharacterEncoder();
|
||||
operator std::string();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 IFCENTITYDESCRIPTOR_H
|
||||
#define IFCENTITYDESCRIPTOR_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../ifcparse/SharedPointer.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include "../ifcparse/Ifc4enum.h"
|
||||
#else
|
||||
#include "../ifcparse/Ifc2x3enum.h"
|
||||
#endif
|
||||
|
||||
namespace IfcUtil {
|
||||
|
||||
class IfcEnumerationDescriptor {
|
||||
private:
|
||||
IfcSchema::Type::Enum type;
|
||||
std::vector<std::string> values;
|
||||
public:
|
||||
IfcEnumerationDescriptor(IfcSchema::Type::Enum type, const std::vector<std::string>& values)
|
||||
: type(type), values(values) {}
|
||||
std::pair<const char*, int> getIndex(const std::string& value) const {
|
||||
std::vector<std::string>::const_iterator it = std::find(values.begin(), values.end(), value);
|
||||
if (it != values.end()) {
|
||||
return std::make_pair(it->c_str(), std::distance(it, values.begin()));
|
||||
} else {
|
||||
throw IfcParse::IfcException("Invalid enumeration value");
|
||||
}
|
||||
}
|
||||
const std::vector<std::string>& getValues() {
|
||||
return values;
|
||||
}
|
||||
IfcSchema::Type::Enum getType() {
|
||||
return type;
|
||||
}
|
||||
};
|
||||
|
||||
class IfcEntityDescriptor {
|
||||
public:
|
||||
class IfcArgumentDescriptor
|
||||
{
|
||||
public:
|
||||
std::string name;
|
||||
bool optional;
|
||||
ArgumentType argument_type;
|
||||
IfcSchema::Type::Enum data_type;
|
||||
IfcArgumentDescriptor(const std::string& name, bool optional, ArgumentType argument_type, IfcSchema::Type::Enum data_type)
|
||||
: name(name), optional(optional), argument_type(argument_type), data_type(data_type) {}
|
||||
};
|
||||
private:
|
||||
IfcSchema::Type::Enum type;
|
||||
IfcEntityDescriptor* parent;
|
||||
std::vector<IfcArgumentDescriptor> arguments;
|
||||
unsigned argument_start() const {
|
||||
return parent ? parent->getArgumentCount() : 0;
|
||||
}
|
||||
const IfcArgumentDescriptor& get_argument(unsigned i) const {
|
||||
if (i < arguments.size()) return arguments[i];
|
||||
else throw IfcParse::IfcException("Argument out of range");
|
||||
}
|
||||
public:
|
||||
IfcEntityDescriptor(IfcSchema::Type::Enum type, IfcEntityDescriptor* parent)
|
||||
: type(type), parent(parent) {}
|
||||
void add(const std::string& name, bool optional, ArgumentType argument_type, IfcSchema::Type::Enum data_type = IfcSchema::Type::UNDEFINED) {
|
||||
arguments.push_back(IfcArgumentDescriptor(name, optional, argument_type, data_type));
|
||||
}
|
||||
unsigned getArgumentCount() const {
|
||||
return (parent ? parent->getArgumentCount() : 0) + arguments.size();
|
||||
}
|
||||
const std::string& getArgumentName(unsigned i) const {
|
||||
const unsigned a = argument_start();
|
||||
return i < a
|
||||
? parent->getArgumentName(i)
|
||||
: get_argument(i-a).name;
|
||||
}
|
||||
ArgumentType getArgumentType(unsigned i) const {
|
||||
const unsigned a = argument_start();
|
||||
return i < a
|
||||
? parent->getArgumentType(i)
|
||||
: get_argument(i-a).argument_type;
|
||||
}
|
||||
bool getArgumentOptional(unsigned i) const {
|
||||
const unsigned a = argument_start();
|
||||
return i < a
|
||||
? parent->getArgumentOptional(i)
|
||||
: get_argument(i-a).optional;
|
||||
}
|
||||
IfcSchema::Type::Enum getArgumentEntity(unsigned i) const {
|
||||
const unsigned a = argument_start();
|
||||
return i < a
|
||||
? parent->getArgumentEntity(i)
|
||||
: get_argument(i-a).data_type;
|
||||
}
|
||||
unsigned getArgumentIndex(const std::string& s) const {
|
||||
unsigned a = argument_start();
|
||||
for(std::vector<IfcArgumentDescriptor>::const_iterator i = arguments.begin(); i != arguments.end(); ++i) {
|
||||
if (i->name == s) return a;
|
||||
a++;
|
||||
}
|
||||
if (parent) return parent->getArgumentIndex(s);
|
||||
throw IfcParse::IfcException(std::string("Argument ") + s + " not found on " + IfcSchema::Type::ToString(type));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
|
||||
+112
-55
@@ -16,66 +16,123 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Reads a file in chunks of BUF_SIZE and provides functions to access its *
|
||||
* contents randomly and character by character *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
#ifndef IFCFILE_H
|
||||
#define IFCFILE_H
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
// As of IfcOpenShell version 0.3.0 the paging functionality, which
|
||||
// loads a file on disk into multiple chunks, has been disabled.
|
||||
// It proved to be an inefficient way of working with large files,
|
||||
// as often these did not facilitate to be parsed in a sequential
|
||||
// manner efficiently, to enable the paging functionality uncomment
|
||||
// the following statement.
|
||||
//const int BUF_SIZE = (128 * 1024 * 1024);
|
||||
#include "../ifcparse/IfcParse.h"
|
||||
#include "../ifcparse/IfcSpfHeader.h"
|
||||
|
||||
namespace IfcParse {
|
||||
/// The File class represents a ISO 10303-21 IFC-SPF file in memory.
|
||||
/// The file is interpreted as a sequence of tokens which are lazily
|
||||
/// interpreted only when requested. If the size of the file is
|
||||
/// larger than BUF_SIZE, the file is split into seperate pages, of
|
||||
/// which only one is simultaneously kept in memory, for files
|
||||
/// that define their entities not in a sequential nature, this is
|
||||
/// detrimental for the performance of the parser.
|
||||
class File {
|
||||
private:
|
||||
std::ifstream stream;
|
||||
char* buffer;
|
||||
unsigned int ptr;
|
||||
unsigned int len;
|
||||
void ReadBuffer(bool inc=true);
|
||||
#ifdef BUF_SIZE
|
||||
unsigned int offset;
|
||||
bool paging;
|
||||
#endif
|
||||
public:
|
||||
bool valid;
|
||||
bool eof;
|
||||
unsigned int size;
|
||||
File(const std::string& fn);
|
||||
File(std::istream& f, int len);
|
||||
File(void* data, int len);
|
||||
/// Returns the character at the cursor
|
||||
char Peek();
|
||||
/// Returns the character at specified offset
|
||||
char Read(unsigned int offset);
|
||||
/// Increment the file cursor and reads new page if necessary
|
||||
void Inc();
|
||||
void Close();
|
||||
/// Moves the file cursor to an arbitrary offset in the file
|
||||
void Seek(unsigned int offset);
|
||||
/// Returns the cursor position
|
||||
unsigned int Tell();
|
||||
};
|
||||
|
||||
/// This class provides several static convenience functions and variables
|
||||
/// and provide access to the entities in an IFC file
|
||||
class IfcFile {
|
||||
public:
|
||||
typedef std::map<IfcSchema::Type::Enum, IfcEntityList::ptr> entities_by_type_t;
|
||||
typedef std::map<unsigned int, IfcUtil::IfcBaseClass*> entity_by_id_t;
|
||||
typedef std::map<std::string, IfcSchema::IfcRoot*> entity_by_guid_t;
|
||||
typedef std::map<unsigned int, IfcEntityList::ptr> entities_by_ref_t;
|
||||
typedef std::map<unsigned int, unsigned int> offset_by_id_t;
|
||||
typedef entity_by_id_t::const_iterator const_iterator;
|
||||
private:
|
||||
typedef std::map<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*> entity_entity_map_t;
|
||||
|
||||
bool _create_latebound_entities;
|
||||
|
||||
entity_by_id_t byid;
|
||||
entities_by_type_t bytype;
|
||||
entities_by_ref_t byref;
|
||||
entity_by_guid_t byguid;
|
||||
offset_by_id_t offsets;
|
||||
|
||||
entity_entity_map_t entity_file_map;
|
||||
|
||||
unsigned int lastId;
|
||||
unsigned int MaxId;
|
||||
|
||||
IfcSpfHeader _header;
|
||||
|
||||
void setDefaultHeaderValues();
|
||||
void traverse(IfcUtil::IfcBaseClass*, std::set<IfcUtil::IfcBaseClass*>& visited, IfcEntityList::ptr list, int level, int max_level);
|
||||
public:
|
||||
IfcParse::IfcSpfLexer* tokens;
|
||||
IfcParse::IfcSpfStream* stream;
|
||||
|
||||
IfcFile(bool create_latebound_entities = false);
|
||||
~IfcFile();
|
||||
|
||||
/// Returns the first entity in the file, this probably is the entity
|
||||
/// with the lowest id (EXPRESS ENTITY_INSTANCE_NAME)
|
||||
const_iterator begin() const;
|
||||
/// Returns the last entity in the file, this probably is the entity
|
||||
/// with the highest id (EXPRESS ENTITY_INSTANCE_NAME)
|
||||
const_iterator end() const;
|
||||
|
||||
/// Returns all entities in the file that match the template argument.
|
||||
/// NOTE: This also returns subtypes of the requested type, for example:
|
||||
/// IfcWall will also return IfcWallStandardCase entities
|
||||
template <class T>
|
||||
typename T::list::ptr entitiesByType() {
|
||||
IfcEntityList::ptr untyped_list = entitiesByType(T::Class());
|
||||
if (untyped_list) {
|
||||
return untyped_list->as<T>();
|
||||
} else {
|
||||
return typename T::list::ptr(new typename T::list);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns all entities in the file that match the positional argument.
|
||||
/// NOTE: This also returns subtypes of the requested type, for example:
|
||||
/// IfcWall will also return IfcWallStandardCase entities
|
||||
IfcEntityList::ptr entitiesByType(IfcSchema::Type::Enum t);
|
||||
|
||||
/// Returns all entities in the file that match the positional argument.
|
||||
/// NOTE: This also returns subtypes of the requested type, for example:
|
||||
/// IfcWall will also return IfcWallStandardCase entities
|
||||
IfcEntityList::ptr entitiesByType(const std::string& t);
|
||||
|
||||
/// Returns all entities in the file that reference the id
|
||||
IfcEntityList::ptr entitiesByReference(int id);
|
||||
|
||||
/// Returns the entity with the specified id
|
||||
IfcUtil::IfcBaseClass* entityById(int id);
|
||||
|
||||
/// Returns the entity with the specified GlobalId
|
||||
IfcSchema::IfcRoot* entityByGuid(const std::string& guid);
|
||||
|
||||
/// Performs a depth-first traversal, returning all entity instance
|
||||
/// attributes as a flat list. NB: includes the root instance specified
|
||||
/// in the first function argument.
|
||||
IfcEntityList::ptr traverse(IfcUtil::IfcBaseClass* instance, int max_level=-1);
|
||||
|
||||
bool Init(const std::string& fn);
|
||||
bool Init(std::istream& fn, int len);
|
||||
bool Init(void* data, int len);
|
||||
bool Init(IfcParse::IfcSpfStream* f);
|
||||
|
||||
IfcEntityList::ptr getInverse(int instance_id, IfcSchema::Type::Enum type, int attribute_index);
|
||||
|
||||
unsigned int FreshId() { return ++MaxId; }
|
||||
|
||||
IfcUtil::IfcBaseClass* addEntity(IfcUtil::IfcBaseClass* entity);
|
||||
void addEntities(IfcEntityList::ptr es);
|
||||
|
||||
void removeEntity(IfcUtil::IfcBaseClass* entity);
|
||||
|
||||
const IfcSpfHeader& header() const { return _header; }
|
||||
IfcSpfHeader& header() { return _header; }
|
||||
|
||||
std::string createTimestamp() const;
|
||||
|
||||
bool create_latebound_entities() const { return _create_latebound_entities; }
|
||||
|
||||
std::pair<IfcSchema::IfcNamedUnit*, double> getUnit(IfcSchema::IfcUnitEnum::IfcUnitEnum);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,107 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Please consider this a placeholder for an actual GlobalId generation *
|
||||
* algorithm. A real implementation could for example be based on Boost::uuid *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
|
||||
#include "../ifcparse/IfcWrite.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
|
||||
static const char* chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$";
|
||||
|
||||
// Converts an unsigned integer into a base64 string of length l
|
||||
std::string base64(unsigned v, int l) {
|
||||
std::string r;
|
||||
r.reserve(l);
|
||||
while ( v ) {
|
||||
r.push_back(chars[v%64]);
|
||||
v /= 64;
|
||||
}
|
||||
while ( r.size() != l ) r.push_back('0');
|
||||
std::reverse(r.begin(),r.end());
|
||||
return r;
|
||||
}
|
||||
|
||||
// Converts a base64 string into an unsigned integer
|
||||
unsigned from_base64(const std::string& s) {
|
||||
std::string::size_type zeros = s.find_first_not_of('0');
|
||||
unsigned r = 0;
|
||||
if ( zeros != std::string::npos )
|
||||
for ( std::string::const_iterator i = s.begin()+zeros; i != s.end(); ++ i ) {
|
||||
r *= 64;
|
||||
const char* c = strchr(chars,*i);
|
||||
if ( !c ) throw IfcParse::IfcException("Failed to decode GlobalId");
|
||||
r += (c-chars);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Compresses the UUID byte array into a base64 representation
|
||||
std::string compress(unsigned char* v) {
|
||||
std::string r;
|
||||
r.reserve(22);
|
||||
r += base64(v[0],2);
|
||||
for ( unsigned i = 1; i < 16; i += 3 ) {
|
||||
r += base64((v[i]<<16) + (v[i+1]<<8) + v[i+2],4);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Expands the base64 representation into a UUID byte array
|
||||
void expand(const std::string& s, std::vector<unsigned char>& v) {
|
||||
v.push_back(from_base64(s.substr(0,2)));
|
||||
for( unsigned i = 0; i < 5; ++i ) {
|
||||
unsigned d = from_base64(s.substr(2+4*i,4));
|
||||
for ( unsigned j = 0; j < 3; ++ j ) {
|
||||
v.push_back((d>>(8*(2-j))) % 256);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A random number generator for the UUID
|
||||
static boost::uuids::basic_random_generator<boost::mt19937> gen;
|
||||
|
||||
IfcWrite::IfcGuidHelper::IfcGuidHelper() {
|
||||
boost::uuids::uuid u = gen();
|
||||
std::vector<unsigned char> v(u.size());
|
||||
std::copy(u.begin(), u.end(), v.begin());
|
||||
data = compress(&v[0]);
|
||||
|
||||
std::vector<unsigned char> v2;
|
||||
expand(data,v2);
|
||||
boost::uuids::uuid u2;
|
||||
std::copy(v2.begin(), v2.end(), u2.begin());
|
||||
}
|
||||
IfcWrite::IfcGuidHelper::operator std::string() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
bool IfcWrite::IfcGuidHelper::seeded = false;
|
||||
@@ -0,0 +1,533 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 class is a subclass of the regular IfcFile class that implements *
|
||||
* several convenience functions for creating geometrical representations and *
|
||||
* spatial containers. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
IfcSchema::IfcAxis2Placement3D* IfcHierarchyHelper::addPlacement3d(
|
||||
double ox, double oy, double oz,
|
||||
double zx, double zy, double zz,
|
||||
double xx, double xy, double xz)
|
||||
{
|
||||
IfcSchema::IfcDirection* x = addTriplet<IfcSchema::IfcDirection>(xx, xy, xz);
|
||||
IfcSchema::IfcDirection* z = addTriplet<IfcSchema::IfcDirection>(zx, zy, zz);
|
||||
IfcSchema::IfcCartesianPoint* o = addTriplet<IfcSchema::IfcCartesianPoint>(ox, oy, oz);
|
||||
IfcSchema::IfcAxis2Placement3D* p3d = new IfcSchema::IfcAxis2Placement3D(o, z, x);
|
||||
addEntity(p3d);
|
||||
return p3d;
|
||||
}
|
||||
|
||||
IfcSchema::IfcAxis2Placement2D* IfcHierarchyHelper::addPlacement2d(
|
||||
double ox, double oy,
|
||||
double xx, double xy)
|
||||
{
|
||||
IfcSchema::IfcDirection* x = addDoublet<IfcSchema::IfcDirection>(xx, xy);
|
||||
IfcSchema::IfcCartesianPoint* o = addDoublet<IfcSchema::IfcCartesianPoint>(ox, oy);
|
||||
IfcSchema::IfcAxis2Placement2D* p2d = new IfcSchema::IfcAxis2Placement2D(o, x);
|
||||
addEntity(p2d);
|
||||
return p2d;
|
||||
}
|
||||
|
||||
IfcSchema::IfcLocalPlacement* IfcHierarchyHelper::addLocalPlacement(IfcSchema::IfcObjectPlacement* parent,
|
||||
double ox, double oy, double oz,
|
||||
double zx, double zy, double zz,
|
||||
double xx, double xy, double xz)
|
||||
{
|
||||
IfcSchema::IfcLocalPlacement* lp = new IfcSchema::IfcLocalPlacement(parent,
|
||||
addPlacement3d(ox, oy, oz, zx, zy, zz, xx, xy, xz));
|
||||
|
||||
addEntity(lp);
|
||||
return lp;
|
||||
}
|
||||
|
||||
IfcSchema::IfcOwnerHistory* IfcHierarchyHelper::addOwnerHistory() {
|
||||
IfcSchema::IfcPerson* person = new IfcSchema::IfcPerson(boost::none, boost::none, std::string(""),
|
||||
boost::none, boost::none, boost::none, boost::none, boost::none);
|
||||
|
||||
IfcSchema::IfcOrganization* organization = new IfcSchema::IfcOrganization(boost::none,
|
||||
"IfcOpenShell", boost::none, boost::none, boost::none);
|
||||
|
||||
IfcSchema::IfcPersonAndOrganization* person_and_org = new IfcSchema::IfcPersonAndOrganization(person, organization, boost::none);
|
||||
IfcSchema::IfcApplication* application = new IfcSchema::IfcApplication(organization,
|
||||
IFCOPENSHELL_VERSION, "IfcOpenShell", "IfcOpenShell");
|
||||
|
||||
int timestamp = (int) time(0);
|
||||
IfcSchema::IfcOwnerHistory* owner_hist = new IfcSchema::IfcOwnerHistory(person_and_org, application,
|
||||
boost::none, IfcSchema::IfcChangeActionEnum::IfcChangeAction_ADDED, timestamp, person_and_org, application, timestamp);
|
||||
|
||||
addEntity(person);
|
||||
addEntity(organization);
|
||||
addEntity(person_and_org);
|
||||
addEntity(application);
|
||||
addEntity(owner_hist);
|
||||
|
||||
return owner_hist;
|
||||
}
|
||||
|
||||
IfcSchema::IfcProject* IfcHierarchyHelper::addProject(IfcSchema::IfcOwnerHistory* owner_hist) {
|
||||
IfcSchema::IfcRepresentationContext::list::ptr rep_contexts (new IfcSchema::IfcRepresentationContext::list);
|
||||
|
||||
IfcEntityList::ptr units (new IfcEntityList);
|
||||
IfcSchema::IfcDimensionalExponents* dimexp = new IfcSchema::IfcDimensionalExponents(0, 0, 0, 0, 0, 0, 0);
|
||||
IfcSchema::IfcSIUnit* unit1 = new IfcSchema::IfcSIUnit(IfcSchema::IfcUnitEnum::IfcUnit_LENGTHUNIT,
|
||||
IfcSchema::IfcSIPrefix::IfcSIPrefix_MILLI, IfcSchema::IfcSIUnitName::IfcSIUnitName_METRE);
|
||||
IfcSchema::IfcSIUnit* unit2a = new IfcSchema::IfcSIUnit(IfcSchema::IfcUnitEnum::IfcUnit_PLANEANGLEUNIT,
|
||||
boost::none, IfcSchema::IfcSIUnitName::IfcSIUnitName_RADIAN);
|
||||
IfcSchema::IfcMeasureWithUnit* unit2b = new IfcSchema::IfcMeasureWithUnit(
|
||||
new IfcSchema::IfcPlaneAngleMeasure(0.017453293), unit2a);
|
||||
IfcSchema::IfcConversionBasedUnit* unit2 = new IfcSchema::IfcConversionBasedUnit(dimexp,
|
||||
IfcSchema::IfcUnitEnum::IfcUnit_PLANEANGLEUNIT, "Degrees", unit2b);
|
||||
|
||||
units->push(unit1);
|
||||
units->push(unit2);
|
||||
|
||||
IfcSchema::IfcUnitAssignment* unit_assignment = new IfcSchema::IfcUnitAssignment(units);
|
||||
|
||||
IfcSchema::IfcProject* project = new IfcSchema::IfcProject(IfcWrite::IfcGuidHelper(), owner_hist, boost::none, boost::none,
|
||||
boost::none, boost::none, boost::none, rep_contexts, unit_assignment);
|
||||
|
||||
addEntity(dimexp);
|
||||
addEntity(unit1);
|
||||
addEntity(unit2a);
|
||||
addEntity(unit2b);
|
||||
addEntity(unit2);
|
||||
addEntity(unit_assignment);
|
||||
addEntity(project);
|
||||
|
||||
return project;
|
||||
}
|
||||
|
||||
void IfcHierarchyHelper::relatePlacements(IfcSchema::IfcProduct* parent, IfcSchema::IfcProduct* product) {
|
||||
IfcSchema::IfcObjectPlacement* place = product->ObjectPlacement() ? (*product->ObjectPlacement()) : 0;
|
||||
if (place && place->is(IfcSchema::Type::IfcLocalPlacement)) {
|
||||
IfcSchema::IfcLocalPlacement* local_place = (IfcSchema::IfcLocalPlacement*) place;
|
||||
if (parent->ObjectPlacement()) {
|
||||
local_place->PlacementRelTo(*parent->ObjectPlacement());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IfcSchema::IfcSite* IfcHierarchyHelper::addSite(IfcSchema::IfcProject* proj, IfcSchema::IfcOwnerHistory* owner_hist) {
|
||||
if (! owner_hist) {
|
||||
owner_hist = getSingle<IfcSchema::IfcOwnerHistory>();
|
||||
}
|
||||
if (! owner_hist) {
|
||||
owner_hist = addOwnerHistory();
|
||||
}
|
||||
if (! proj) {
|
||||
proj = getSingle<IfcSchema::IfcProject>();
|
||||
}
|
||||
if (! proj) {
|
||||
proj = addProject(owner_hist);
|
||||
}
|
||||
|
||||
IfcSchema::IfcSite* site = new IfcSchema::IfcSite(IfcWrite::IfcGuidHelper(), owner_hist, boost::none,
|
||||
boost::none, boost::none, addLocalPlacement(), boost::none, boost::none,
|
||||
IfcSchema::IfcElementCompositionEnum::IfcElementComposition_ELEMENT,
|
||||
boost::none, boost::none, boost::none, boost::none, boost::none);
|
||||
|
||||
addEntity(site);
|
||||
addRelatedObject<IfcSchema::IfcRelAggregates>(proj, site);
|
||||
return site;
|
||||
}
|
||||
|
||||
IfcSchema::IfcBuilding* IfcHierarchyHelper::addBuilding(IfcSchema::IfcSite* site, IfcSchema::IfcOwnerHistory* owner_hist) {
|
||||
if (! owner_hist) {
|
||||
owner_hist = getSingle<IfcSchema::IfcOwnerHistory>();
|
||||
}
|
||||
if (! owner_hist) {
|
||||
owner_hist = addOwnerHistory();
|
||||
}
|
||||
if (! site) {
|
||||
site = getSingle<IfcSchema::IfcSite>();
|
||||
}
|
||||
if (! site) {
|
||||
site = addSite(0, owner_hist);
|
||||
}
|
||||
IfcSchema::IfcBuilding* building = new IfcSchema::IfcBuilding(IfcWrite::IfcGuidHelper(), owner_hist, boost::none, boost::none, boost::none,
|
||||
addLocalPlacement(), boost::none, boost::none, IfcSchema::IfcElementCompositionEnum::IfcElementComposition_ELEMENT,
|
||||
boost::none, boost::none, boost::none);
|
||||
|
||||
addEntity(building);
|
||||
addRelatedObject<IfcSchema::IfcRelAggregates>(site, building);
|
||||
relatePlacements(site, building);
|
||||
|
||||
return building;
|
||||
}
|
||||
|
||||
IfcSchema::IfcBuildingStorey* IfcHierarchyHelper::addBuildingStorey(IfcSchema::IfcBuilding* building,
|
||||
IfcSchema::IfcOwnerHistory* owner_hist)
|
||||
{
|
||||
if (! owner_hist) {
|
||||
owner_hist = getSingle<IfcSchema::IfcOwnerHistory>();
|
||||
}
|
||||
if (! owner_hist) {
|
||||
owner_hist = addOwnerHistory();
|
||||
}
|
||||
if (! building) {
|
||||
building = getSingle<IfcSchema::IfcBuilding>();
|
||||
}
|
||||
if (! building) {
|
||||
building = addBuilding(0, owner_hist);
|
||||
}
|
||||
IfcSchema::IfcBuildingStorey* storey = new IfcSchema::IfcBuildingStorey(IfcWrite::IfcGuidHelper(),
|
||||
owner_hist, boost::none, boost::none, boost::none, addLocalPlacement(), boost::none, boost::none,
|
||||
IfcSchema::IfcElementCompositionEnum::IfcElementComposition_ELEMENT, boost::none);
|
||||
|
||||
addEntity(storey);
|
||||
addRelatedObject<IfcSchema::IfcRelAggregates>(building, storey);
|
||||
relatePlacements(building, storey);
|
||||
|
||||
return storey;
|
||||
}
|
||||
|
||||
IfcSchema::IfcBuildingStorey* IfcHierarchyHelper::addBuildingProduct(IfcSchema::IfcProduct* product,
|
||||
IfcSchema::IfcBuildingStorey* storey, IfcSchema::IfcOwnerHistory* owner_hist)
|
||||
{
|
||||
if (! owner_hist) {
|
||||
owner_hist = getSingle<IfcSchema::IfcOwnerHistory>();
|
||||
}
|
||||
if (! owner_hist) {
|
||||
owner_hist = addOwnerHistory();
|
||||
}
|
||||
if (! storey) {
|
||||
storey = getSingle<IfcSchema::IfcBuildingStorey>();
|
||||
}
|
||||
if (! storey) {
|
||||
storey = addBuildingStorey(0, owner_hist);
|
||||
}
|
||||
addEntity(product);
|
||||
// CV-2x3-158: Don't add decompositions directly to a building storey
|
||||
bool is_decomposition = false;
|
||||
#ifdef USE_IFC4
|
||||
IfcSchema::IfcRelAggregates::list::ptr decomposes = product->Decomposes();
|
||||
for (IfcSchema::IfcRelAggregates::list::it it = decomposes->begin(); it != decomposes->end(); ++it) {
|
||||
#else
|
||||
IfcSchema::IfcRelDecomposes::list::ptr decomposes = product->Decomposes();
|
||||
for (IfcSchema::IfcRelDecomposes::list::it it = decomposes->begin(); it != decomposes->end(); ++it) {
|
||||
#endif
|
||||
if ((*it)->RelatingObject() != product) {
|
||||
is_decomposition = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!is_decomposition) {
|
||||
addRelatedObject<IfcSchema::IfcRelContainedInSpatialStructure>(storey, product);
|
||||
relatePlacements(storey, product);
|
||||
}
|
||||
return storey;
|
||||
}
|
||||
|
||||
void IfcHierarchyHelper::addExtrudedPolyline(IfcSchema::IfcShapeRepresentation* rep, const std::vector<std::pair<double, double> >& points, double h,
|
||||
IfcSchema::IfcAxis2Placement2D* place, IfcSchema::IfcAxis2Placement3D* place2,
|
||||
IfcSchema::IfcDirection* dir, IfcSchema::IfcRepresentationContext* context)
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint::list::ptr cartesian_points (new IfcSchema::IfcCartesianPoint::list);
|
||||
for (std::vector<std::pair<double, double> >::const_iterator i = points.begin(); i != points.end(); ++i) {
|
||||
cartesian_points->push(addDoublet<IfcSchema::IfcCartesianPoint>(i->first, i->second));
|
||||
}
|
||||
if (cartesian_points->size()) cartesian_points->push(*cartesian_points->begin());
|
||||
IfcSchema::IfcPolyline* line = new IfcSchema::IfcPolyline(cartesian_points);
|
||||
IfcSchema::IfcArbitraryClosedProfileDef* profile = new IfcSchema::IfcArbitraryClosedProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, boost::none, line);
|
||||
|
||||
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(
|
||||
profile, place2 ? place2 : addPlacement3d(), dir ? dir : addTriplet<IfcSchema::IfcDirection>(0, 0, 1), h);
|
||||
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items = rep->Items();
|
||||
items->push(solid);
|
||||
rep->Items(items);
|
||||
|
||||
addEntity(line);
|
||||
addEntity(profile);
|
||||
addEntity(solid);
|
||||
}
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* IfcHierarchyHelper::addExtrudedPolyline(const std::vector<std::pair<double, double> >& points, double h,
|
||||
IfcSchema::IfcAxis2Placement2D* place, IfcSchema::IfcAxis2Placement3D* place2, IfcSchema::IfcDirection* dir,
|
||||
IfcSchema::IfcRepresentationContext* context)
|
||||
{
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(context
|
||||
? context
|
||||
: getRepresentationContext("Model"), std::string("Body"), std::string("SweptSolid"), items);
|
||||
reps->push(rep);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
addEntity(rep);
|
||||
addEntity(shape);
|
||||
addExtrudedPolyline(rep, points, h, place, place2, dir, context);
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
void IfcHierarchyHelper::addBox(IfcSchema::IfcShapeRepresentation* rep, double w, double d, double h,
|
||||
IfcSchema::IfcAxis2Placement2D* place, IfcSchema::IfcAxis2Placement3D* place2,
|
||||
IfcSchema::IfcDirection* dir, IfcSchema::IfcRepresentationContext* context)
|
||||
{
|
||||
if (false) {
|
||||
IfcSchema::IfcRectangleProfileDef* profile = new IfcSchema::IfcRectangleProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, boost::none, place ? place : addPlacement2d(), w, d);
|
||||
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(profile,
|
||||
place2 ? place2 : addPlacement3d(), dir ? dir : addTriplet<IfcSchema::IfcDirection>(0, 0, 1), h);
|
||||
|
||||
addEntity(profile);
|
||||
addEntity(solid);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items = rep->Items();
|
||||
items->push(solid);
|
||||
rep->Items(items);
|
||||
} else {
|
||||
std::vector<std::pair<double, double> > points;
|
||||
points.push_back(std::pair<double, double>(-w/2, -d/2));
|
||||
points.push_back(std::pair<double, double>(w/2, -d/2));
|
||||
points.push_back(std::pair<double, double>(w/2, d/2));
|
||||
points.push_back(std::pair<double, double>(-w/2, d/2));
|
||||
// The call to addExtrudedPolyline() closes the polyline
|
||||
addExtrudedPolyline(rep, points, h, place, place2, dir, context);
|
||||
}
|
||||
}
|
||||
|
||||
void IfcHierarchyHelper::addAxis(IfcSchema::IfcShapeRepresentation* rep, double l, IfcSchema::IfcRepresentationContext* context) {
|
||||
IfcSchema::IfcCartesianPoint* p1 = addDoublet<IfcSchema::IfcCartesianPoint>(-l / 2., 0.);
|
||||
IfcSchema::IfcCartesianPoint* p2 = addDoublet<IfcSchema::IfcCartesianPoint>(+l / 2., 0.);
|
||||
IfcSchema::IfcCartesianPoint::list::ptr pts(new IfcSchema::IfcCartesianPoint::list);
|
||||
pts->push(p1); pts->push(p2);
|
||||
IfcSchema::IfcPolyline* poly = new IfcSchema::IfcPolyline(pts);
|
||||
addEntity(poly);
|
||||
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items = rep->Items();
|
||||
items->push(poly);
|
||||
rep->Items(items);
|
||||
}
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* IfcHierarchyHelper::addBox(double w, double d, double h, IfcSchema::IfcAxis2Placement2D* place,
|
||||
IfcSchema::IfcAxis2Placement3D* place2, IfcSchema::IfcDirection* dir, IfcSchema::IfcRepresentationContext* context)
|
||||
{
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
context ? context : getRepresentationContext("Model"), std::string("Body"), std::string("SweptSolid"), items);
|
||||
reps->push(rep);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
addEntity(rep);
|
||||
addEntity(shape);
|
||||
addBox(rep, w, d, h, place, place2, dir, context);
|
||||
return shape;
|
||||
}
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* IfcHierarchyHelper::addAxisBox(double w, double d, double h, IfcSchema::IfcRepresentationContext* context)
|
||||
{
|
||||
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr body_items(new IfcSchema::IfcRepresentationItem::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr axis_items(new IfcSchema::IfcRepresentationItem::list);
|
||||
IfcSchema::IfcShapeRepresentation* body_rep = new IfcSchema::IfcShapeRepresentation(
|
||||
context ? context : getRepresentationContext("Model"), std::string("Body"), std::string("SweptSolid"), body_items);
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* axis_rep = new IfcSchema::IfcShapeRepresentation(
|
||||
context ? context : getRepresentationContext("Plan"), std::string("Axis"), std::string("Curve2D"), axis_items);
|
||||
|
||||
reps->push(axis_rep);
|
||||
reps->push(body_rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
addEntity(shape);
|
||||
addEntity(body_rep);
|
||||
addBox(body_rep, w, d, h, 0, 0, 0, context);
|
||||
addEntity(axis_rep);
|
||||
addAxis(axis_rep, w);
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
void IfcHierarchyHelper::clipRepresentation(IfcSchema::IfcProductRepresentation* shape,
|
||||
IfcSchema::IfcAxis2Placement3D* place, bool agree)
|
||||
{
|
||||
IfcSchema::IfcRepresentation::list::ptr reps = shape->Representations();
|
||||
for (IfcSchema::IfcRepresentation::list::it j = reps->begin(); j != reps->end(); ++j) {
|
||||
clipRepresentation(*j, place, agree);
|
||||
}
|
||||
}
|
||||
|
||||
void IfcHierarchyHelper::clipRepresentation(IfcSchema::IfcRepresentation* rep,
|
||||
IfcSchema::IfcAxis2Placement3D* place, bool agree)
|
||||
{
|
||||
if (!rep->RepresentationIdentifier() || *rep->RepresentationIdentifier() != "Body") return;
|
||||
IfcSchema::IfcPlane* plane = new IfcSchema::IfcPlane(place);
|
||||
IfcSchema::IfcHalfSpaceSolid* half_space = new IfcSchema::IfcHalfSpaceSolid(plane, agree);
|
||||
addEntity(plane);
|
||||
addEntity(half_space);
|
||||
rep->RepresentationType(std::string("Clipping"));
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items = rep->Items();
|
||||
IfcSchema::IfcRepresentationItem::list::ptr new_items (new IfcSchema::IfcRepresentationItem::list);
|
||||
for (IfcSchema::IfcRepresentationItem::list::it i = items->begin(); i != items->end(); ++i) {
|
||||
IfcSchema::IfcRepresentationItem* item = *i;
|
||||
IfcSchema::IfcBooleanClippingResult* clip = new IfcSchema::IfcBooleanClippingResult(
|
||||
IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE, item, half_space);
|
||||
addEntity(clip);
|
||||
new_items->push(clip);
|
||||
}
|
||||
rep->Items(new_items);
|
||||
}
|
||||
|
||||
IfcSchema::IfcPresentationStyleAssignment* IfcHierarchyHelper::addStyleAssignment(double r, double g, double b, double a) {
|
||||
IfcSchema::IfcColourRgb* colour = new IfcSchema::IfcColourRgb(boost::none, r, g, b);
|
||||
IfcSchema::IfcSurfaceStyleRendering* rendering = a == 1.0
|
||||
? new IfcSchema::IfcSurfaceStyleRendering(colour, boost::none, boost::none, boost::none, boost::none, boost::none,
|
||||
boost::none, boost::none, IfcSchema::IfcReflectanceMethodEnum::IfcReflectanceMethod_FLAT)
|
||||
: new IfcSchema::IfcSurfaceStyleRendering(colour, 1.0-a, boost::none, boost::none, boost::none, boost::none,
|
||||
boost::none, boost::none, IfcSchema::IfcReflectanceMethodEnum::IfcReflectanceMethod_FLAT);
|
||||
|
||||
IfcEntityList::ptr styles(new IfcEntityList());
|
||||
styles->push(rendering);
|
||||
IfcSchema::IfcSurfaceStyle* surface_style = new IfcSchema::IfcSurfaceStyle(
|
||||
boost::none, IfcSchema::IfcSurfaceSide::IfcSurfaceSide_BOTH, styles);
|
||||
IfcEntityList::ptr surface_styles(new IfcEntityList());
|
||||
surface_styles->push(surface_style);
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment =
|
||||
new IfcSchema::IfcPresentationStyleAssignment(surface_styles);
|
||||
addEntity(colour);
|
||||
addEntity(rendering);
|
||||
addEntity(surface_style);
|
||||
addEntity(style_assignment);
|
||||
return style_assignment;
|
||||
}
|
||||
|
||||
IfcSchema::IfcPresentationStyleAssignment* IfcHierarchyHelper::setSurfaceColour(
|
||||
IfcSchema::IfcProductRepresentation* shape, double r, double g, double b, double a)
|
||||
{
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment = addStyleAssignment(r, g, b, a);
|
||||
setSurfaceColour(shape, style_assignment);
|
||||
return style_assignment;
|
||||
}
|
||||
|
||||
IfcSchema::IfcPresentationStyleAssignment* IfcHierarchyHelper::setSurfaceColour(
|
||||
IfcSchema::IfcRepresentation* shape, double r, double g, double b, double a)
|
||||
{
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment = addStyleAssignment(r, g, b, a);
|
||||
setSurfaceColour(shape, style_assignment);
|
||||
return style_assignment;
|
||||
}
|
||||
|
||||
void IfcHierarchyHelper::setSurfaceColour(IfcSchema::IfcProductRepresentation* shape,
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment)
|
||||
{
|
||||
IfcSchema::IfcRepresentation::list::ptr reps = shape->Representations();
|
||||
for (IfcSchema::IfcRepresentation::list::it j = reps->begin(); j != reps->end(); ++j) {
|
||||
setSurfaceColour(*j, style_assignment);
|
||||
}
|
||||
}
|
||||
|
||||
void IfcHierarchyHelper::setSurfaceColour(IfcSchema::IfcRepresentation* rep,
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment)
|
||||
{
|
||||
#ifdef USE_IFC4
|
||||
IfcEntityList::ptr style_assignments (new IfcEntityList);
|
||||
#else
|
||||
IfcSchema::IfcPresentationStyleAssignment::list::ptr style_assignments (new IfcSchema::IfcPresentationStyleAssignment::list);
|
||||
#endif
|
||||
style_assignments->push(style_assignment);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items = rep->Items();
|
||||
for (IfcSchema::IfcRepresentationItem::list::it i = items->begin(); i != items->end(); ++i) {
|
||||
IfcSchema::IfcRepresentationItem* item = *i;
|
||||
IfcSchema::IfcStyledItem* styled_item = new IfcSchema::IfcStyledItem(item, style_assignments, boost::none);
|
||||
addEntity(styled_item);
|
||||
}
|
||||
}
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* IfcHierarchyHelper::addMappedItem(
|
||||
IfcSchema::IfcShapeRepresentation* rep,
|
||||
IfcSchema::IfcCartesianTransformationOperator3D* transform,
|
||||
IfcSchema::IfcProductDefinitionShape* def)
|
||||
{
|
||||
IfcSchema::IfcRepresentationMap::list::ptr maps = rep->RepresentationMap();
|
||||
IfcSchema::IfcRepresentationMap* map;
|
||||
if (maps->size() == 1) {
|
||||
map = *maps->begin();
|
||||
} else {
|
||||
map = new IfcSchema::IfcRepresentationMap(addPlacement3d(), rep);
|
||||
addEntity(map);
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr representations(new IfcSchema::IfcRepresentation::list);
|
||||
if (def) representations = def->Representations();
|
||||
|
||||
if (!transform) {
|
||||
transform = new IfcSchema::IfcCartesianTransformationOperator3D(boost::none, boost::none, addTriplet<IfcSchema::IfcCartesianPoint>(0,0,0), boost::none, boost::none);
|
||||
addEntity(transform);
|
||||
}
|
||||
IfcSchema::IfcMappedItem* item = new IfcSchema::IfcMappedItem(map, transform);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
|
||||
items->push(item);
|
||||
IfcSchema::IfcRepresentation* new_rep = new IfcSchema::IfcShapeRepresentation(rep->ContextOfItems(), boost::none, std::string("MappedRepresentation"), items);
|
||||
if (rep->RepresentationIdentifier()) {
|
||||
new_rep->RepresentationIdentifier(*rep->RepresentationIdentifier());
|
||||
}
|
||||
addEntity(item);
|
||||
addEntity(new_rep);
|
||||
representations->push(new_rep);
|
||||
if (!def) {
|
||||
def = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, representations);
|
||||
addEntity(def);
|
||||
} else {
|
||||
def->Representations(representations);
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* IfcHierarchyHelper::addMappedItem(
|
||||
IfcSchema::IfcShapeRepresentation::list::ptr reps,
|
||||
IfcSchema::IfcCartesianTransformationOperator3D* transform)
|
||||
{
|
||||
IfcSchema::IfcProductDefinitionShape* def = 0;
|
||||
for (IfcSchema::IfcShapeRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) {
|
||||
def = addMappedItem(*it, transform, def);
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* IfcHierarchyHelper::addEmptyRepresentation(const std::string& repid, const std::string& reptype) {
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
|
||||
IfcSchema::IfcShapeRepresentation* shape_rep = new IfcSchema::IfcShapeRepresentation(getRepresentationContext(reptype == "Curve2D" ? "Plan" : "Model"), repid, reptype, items);
|
||||
addEntity(shape_rep);
|
||||
return shape_rep;
|
||||
}
|
||||
|
||||
IfcSchema::IfcGeometricRepresentationContext* IfcHierarchyHelper::getRepresentationContext(const std::string& s) {
|
||||
std::map<std::string, IfcSchema::IfcGeometricRepresentationContext*>::const_iterator it = contexts.find(s);
|
||||
if (it != contexts.end()) return it->second;
|
||||
else {
|
||||
IfcSchema::IfcProject* project = getSingle<IfcSchema::IfcProject>();
|
||||
IfcSchema::IfcRepresentationContext::list::ptr project_contexts = project->RepresentationContexts();
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = new IfcSchema::IfcGeometricRepresentationContext(
|
||||
boost::none, s, 3, 1e-5, addPlacement3d(), addDoublet<IfcSchema::IfcDirection>(0, 1));
|
||||
addEntity(context);
|
||||
project_contexts->push(context);
|
||||
project->RepresentationContexts(project_contexts);
|
||||
return contexts[s] = context;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user