Compare commits

..

425 Commits

Author SHA1 Message Date
Thomas Krijnen 16f2b0a0d2 Renumber instances, add comments, update federate for group structure 2018-02-13 14:50:39 +01:00
Thomas Krijnen 6dd22fda82 Consistent IFC4 schema 2018-02-06 14:45:22 +01:00
Thomas Krijnen 1e772a7ea9 Inverse attributes 2018-02-06 13:31:00 +01:00
Thomas Krijnen 7e14d4389e Fixes for reading proper select types 2018-02-05 15:19:38 +01:00
Thomas Krijnen 852e3e28ee Create objects group, separate some string definitions 2018-02-02 16:44:35 +01:00
Thomas Krijnen e962872549 Only *ambiguous* selects with type path, numeric code in padded profile 2018-02-02 14:12:14 +01:00
Thomas Krijnen f16b2e59ae Fix set_unset_bitmap_value 2018-01-26 11:53:04 +01:00
Thomas Krijnen 844428fefd Fix IfcBinary default instantiation as part of select 2018-01-23 11:59:24 +01:00
Thomas Krijnen a53ffd2662 Fix padded serialization of aggregate of IfcInteger 2018-01-18 18:05:32 +01:00
Thomas Krijnen fd02665e5e Add missing ifc4 schema 2018-01-18 14:15:42 +01:00
Thomas Krijnen fa3fdcd273 Fix for IfcPropertyEnumeratedValue padded profile 2018-01-18 13:56:38 +01:00
Thomas Krijnen e6499ef3b1 gcc compatibility 2018-01-17 17:00:27 +01:00
Thomas Krijnen cf1de365e7 Fix federation example 2018-01-12 17:05:39 +01:00
Thomas Krijnen 3bdf429c30 Correct bounding boxes on LOD case 2018-01-12 12:39:39 +01:00
Thomas Krijnen 1bef19a87a Update types for LOD segmentation 2018-01-08 12:17:28 +01:00
Thomas Krijnen e07189e6b1 Work on LOD use case 2017-12-08 13:26:23 +01:00
Thomas Krijnen f851a7188f Fix set_unset mask on padded profile 2017-12-07 19:26:51 +01:00
Thomas Krijnen d8d82eb6ec Work on LOD example 2017-12-06 17:51:18 +01:00
Thomas Krijnen 89e97e5d7c Separate properties 2017-12-04 18:14:52 +01:00
Thomas Krijnen 388c717317 Work on LOD use case 2017-12-04 17:20:04 +01:00
Thomas Krijnen 20eb913b65 Work on LOD use case 2017-12-04 17:19:31 +01:00
Thomas Krijnen 6ca5c90517 Work around for H5cpp memory leak 2017-12-04 16:49:03 +01:00
Thomas Krijnen 5e2d5129bb Work on LOD use case 2017-12-01 15:38:28 +01:00
Thomas Krijnen 226a02adfc Work on LOD use case 2017-11-25 09:47:42 +01:00
Thomas Krijnen 03a82fe301 Start working on LOD example 2017-11-24 15:20:21 +01:00
Thomas Krijnen b40a21743b Separate h file 2017-11-24 15:19:58 +01:00
Thomas Krijnen 2562d6c208 Rename federation use case example 2017-11-24 13:20:46 +01:00
Thomas Krijnen cab7716bdf No mounting in federation example 2017-11-24 13:15:24 +01:00
Thomas Krijnen 83af36dc60 common prefix and postfix 2017-11-24 13:14:46 +01:00
Thomas Krijnen 34fd334fcb Check dereference error 2017-11-24 12:15:30 +01:00
Thomas Krijnen 839dd9aed6 Specify mount points from command line 2017-11-24 12:15:08 +01:00
Thomas Krijnen 0f0d060177 Option to renumber instances 2017-11-21 15:45:42 +01:00
Thomas Krijnen 6dc9ff6fa3 Mount: Create new owner history 2017-11-21 13:24:20 +01:00
Thomas Krijnen c2da3b9e82 Write populations to distinct groups 2017-11-20 14:48:40 +01:00
Thomas Krijnen 621859453a Configurable instance locator 2017-11-20 14:38:54 +01:00
Thomas Krijnen 01ab21a69a Incrementing id when enumerating arbitrary instances 2017-11-18 10:40:10 +01:00
Thomas Krijnen 9c81735cbd Begin working on some hdf5 use cases 2017-11-17 14:58:13 +01:00
Thomas Krijnen 659f05bda3 attempts to make hdf5 generation process more configurable 2017-11-17 14:57:33 +01:00
Thomas Krijnen 59020a22ee set_default() on spf header 2017-11-17 14:57:03 +01:00
Thomas Krijnen 693444d4d2 Fix traversal 2017-11-13 14:58:02 +01:00
Thomas Krijnen 93a33a8507 Quotes in comment 2017-11-12 08:30:02 +01:00
Thomas Krijnen e1b1940d83 Conversion back from hdf to spf, referenced profile 2017-11-11 09:43:45 +01:00
Thomas Krijnen 9a2e5d698a Conversion back from hdf to spf, padded profile 2017-11-09 13:49:49 +01:00
Thomas Krijnen 71dcc96ac2 Hacky support for LOGICAL 2017-10-13 14:51:09 +02:00
Thomas Krijnen 2422da4048 Run codegen 2017-10-13 13:12:43 +02:00
Thomas Krijnen f6403c81e1 Ignore line comment in express parser 2017-10-13 13:11:08 +02:00
Thomas Krijnen de78c6c5dc Map LOGICAL to separate type 2017-10-13 13:09:08 +02:00
Thomas Krijnen f24c996bc1 Backport some codegen fixes wrt unicode 2017-10-13 13:08:50 +02:00
Thomas Krijnen 3dbb52a4f3 Read and write header fields in HDF; clean-up 2017-10-13 12:19:50 +02:00
Thomas Krijnen d9c4920d37 Conversion back from hdf to spf, standard profile only ftm 2017-10-11 16:15:27 +02:00
Thomas Krijnen dcf331a78d Correct instance lookup 2017-10-09 15:43:51 +02:00
Thomas Krijnen 09679050c2 Fix iso_10303_26_data_set_names 2017-10-09 14:57:14 +02:00
Thomas Krijnen d13a7b613b Work on padded and referenced profiles 2017-10-09 13:58:29 +02:00
Thomas Krijnen 61fba3f406 Work on padded profile 2017-09-24 13:48:16 +02:00
Thomas Krijnen b8001ea05d Refactor 2017-09-20 17:08:11 +02:00
Thomas Krijnen 4163f817a6 Update win build script and cmake for HDF5 library 2017-08-18 15:29:05 +02:00
aothms 2a0471ec27 Add support for storing aggregate values in separate datasets 2016-02-24 11:26:47 +01:00
aothms 418b78cdd5 Fix wrapper code 2016-02-24 11:26:15 +01:00
aothms c1c738390f Add support for aggregate of bool 2016-02-24 11:25:45 +01:00
aothms 766d45e0cb Add missing include 2016-02-19 14:25:56 +01:00
aothms df88474bc5 Merge remote-tracking branch 'origin/master' into hdf5
Conflicts:
	src/ifcexpressparser/bootstrap.py
	src/ifcexpressparser/templates.py
	src/ifcgeom/IfcGeomFaces.cpp
	src/ifcgeom/IfcGeomFunctions.cpp
	src/ifcgeom/IfcGeomIterator.h
	src/ifcgeom/IfcGeomWires.cpp
	src/ifcparse/Ifc2x3.h
	src/ifcparse/Ifc4.h
	src/ifcparse/IfcLateBoundEntity.cpp
	src/ifcparse/IfcParse.cpp
	src/ifcparse/IfcUtil.h
2016-02-19 14:19:57 +01:00
aothms 481515f5ae Add missing include 2016-02-18 16:57:22 +01:00
Thomas Krijnen a33f5b6e17 Merge pull request #31 from aothms/cmake_compile_schema
Add option to compile (external) schema by cmake + general improvements
2016-02-18 15:43:52 +01:00
aothms 10bec3eee0 Replace PYTHONPATH with PYTHONHOME 2016-02-18 14:57:57 +01:00
aothms da0af77570 Compatibility for older versions of cmake, python, open cascade, boost 2016-02-18 13:17:15 +01:00
aothms a6094f50b9 Let CMake find python interpreter for schema compilation and installation dir
Remove unused compiled schema in cpp installation target
2016-02-17 12:03:38 +01:00
aothms c3f1b41860 Fix https://github.com/IfcOpenShell/IfcOpenShell/issues/30 2016-02-15 17:59:31 +01:00
aothms 4122759f1a Add option to compile (external) schema by cmake 2016-02-15 16:59:47 +01:00
Thomas Krijnen a583339492 Merge pull request #29 from Tridify/win_build_script_improvements
Windows build script improvements
2016-02-15 16:14:51 +01:00
Stinkfist0 f12e980bfe build-all.cmd: simplify "yes" trick 2016-02-15 15:08:13 +02:00
Stinkfist0 4979deb111 CMakeLists.txt: Remove sources specific to an IFC release we are not using from the project 2016-02-09 15:51:18 +02:00
Stinkfist0 c575352d20 ~IfcCharacterDecoder: call ucnv_flushCache() to fix two ICU mem leaks. 2016-02-07 23:01:34 +02:00
Stinkfist0 2f8fa3282b Fix mem leak in IfcSpfStream (not closed upon destruction), make Entity's dtor virtual. 2016-02-07 22:45:42 +02:00
Stinkfist0 993e322a8e Fix memory leakage from IfcSpfHeader 2016-02-07 13:14:14 +02:00
Stinkfist0 61ccd8a7cf VLD, not VLC... 2016-02-07 12:28:05 +02:00
Stinkfist0 450baf224f Remove accidentally committed lines 2016-02-07 00:51:10 +02:00
Stinkfist0 7b2197fa37 add /test/__pycache__ to ignore list 2016-02-07 00:31:29 +02:00
Stinkfist0 cde1c5f2ee Add build option for using Visual Leak Detector for debugging memory leaks. Initial report:
- IfcConvert (no arguments): 2 leaks (140 bytes) (from OCE)
- IfcConvert (acad2010_objects.ifc): 47 memory leaks (6,158 bytes)
- IfcGeomServer: 2 leaks (from OCE)
- IfcOpenHouse: 11,952 leaks (1,169,658 bytes)!
- IfcParseExamples (acad2010_objects.ifc): 40 memory leaks (4,564 bytes)
2016-02-07 00:30:08 +02:00
Stinkfist0 33772a4710 run-cmake.bat & build-all.cmd: fix cmake arguments parsing when arguments passed for the batch scripts 2016-02-06 18:48:18 +02:00
Stinkfist0 178c34fb22 README.md: document the supported IFC releases with links 2016-02-05 14:48:51 +02:00
Stinkfist0 17ecc43f78 vs-cfg.cmd: remove if-clause, an erroneous syntax print comes if this script is called when VS env vars not set but that's OK. 2016-02-04 11:46:53 +02:00
Stinkfist0 72999e04d9 vs-cfg.cmd: clean up output when used wrongly (VS tools not in path and empty/no generator argument passed). 2016-02-04 00:43:52 +02:00
Stinkfist0 f191b1fdd2 Fix warning regarding shadowing variable names. 2016-02-03 22:34:50 +02:00
Stinkfist0 d095bfecde Fix command-line argument parsing in run-cmake.bat and build-all.cmd 2016-02-03 22:16:50 +02:00
Stinkfist0 2e1699beea build-all.cmd: support for passing arguments, e.g. build-all.cmd vs2015-x64 RelWithDebInfo -DUSE_IFC4=1 -DENABLE_BUILD_OPTIMIZATIONS=1 2016-02-03 16:36:07 +02:00
Stinkfist0 5c07c8dc95 run-cmake.bat print tweak 2016-02-03 16:15:40 +02:00
Stinkfist0 0fa05faee8 Simplify run-cmake.bat, the script can now be used e.g. run-cmake.bat vs2015-x64 -UDUSE_IFC4=1 -DCMAKE_INSTALL_PREFIX=C:/IfcOpenShell/Ifc4 2016-02-03 16:12:52 +02:00
Stinkfist0 21e8a1e8e6 vs-cfg.cmd: provide support for user-friendly VS generators, e.g. vs2013-x86, and converted them to the appropriate CMake ones. 2016-02-03 16:10:55 +02:00
Stinkfist0 2e6601b3e7 build-deps.cmd: do not print build times if build did not even start properly. 2016-02-03 16:10:55 +02:00
Stinkfist0 634932e6e7 run-cmake.bat: set CMAKE_INSTALL_PREFIX also when passing extra parameters for the script 2016-02-03 16:10:55 +02:00
Stinkfist0 a041d289c6 Add build-all.cmd script for convenience. 2016-02-03 16:10:55 +02:00
Stinkfist0 01f8882311 adjust build-ifcopenshell & install-ifcopenshell to the build cfg batch file change 2016-02-03 16:10:54 +02:00
Stinkfist0 f2bdfbd049 Windows build scripts: move build configuration type to a separate file. 2016-02-03 16:10:32 +02:00
Stinkfist0 c7bf03e8f8 Add set-python-to-path.bat helper, add instructions for using preinstalled Python. 2016-02-03 16:10:32 +02:00
Stinkfist0 18e451b874 Windows build scripts: detect case where user installed Visual Studio but not the C++ toolset. Also detect case where user's CMake version is too old for the desired generator. 2016-02-03 16:10:32 +02:00
aothms f4d58b3969 Fix for IfcAdvancedFace when compiling for 2x3 2016-02-01 14:58:42 +01:00
aothms 76a3146b70 Fix one statement deleted too much in https://github.com/IfcOpenShell/IfcOpenShell/commit/f3af39546be9ecd485737ff0954cfb92807fca1d 2016-01-29 15:25:18 +01:00
aothms fe70acb541 Fix https://github.com/IfcOpenShell/IfcOpenShell/issues/26 2016-01-26 16:45:39 +01:00
Stinkfist0 a52901344c build-deps.cmd: print start, end, and elapsed time + .gitignore doc tweak 2016-01-26 13:41:19 +02:00
Thomas Krijnen d0e26f07fc Merge pull request #25 from aothms/master
Refactoring shared_ptr and array usage
2016-01-25 16:00:49 +01:00
aothms 5270710fc2 Use vanilla C arrays instead of std::tr::array
Fixes https://github.com/IfcOpenShell/IfcOpenShell/issues/17
2016-01-25 14:44:35 +01:00
aothms ed8cc620ea Use boost::shared_ptr
Fixes https://github.com/IfcOpenShell/IfcOpenShell/issues/17
2016-01-25 14:42:41 +01:00
aothms 9b13ed3f38 Emit more debug information when failing to join curve segments 2016-01-25 14:25:24 +01:00
aothms 801c7da40f Use multiple argument boolean operands for IfcOpeningElement subtractions 2016-01-25 13:30:33 +01:00
aothms 4be7da1a43 Use fuzzy boolean subtraction if available
Remove collinear points from polygonal halfspace boundary
Lookup styled items on boolean operation operands

Fixes https://github.com/IfcOpenShell/IfcOpenShell/issues/6
Fixes https://sourceforge.net/p/ifcopenshell/discussion/1782717/thread/a7f99e41/?limit=25#5c36
2016-01-22 17:27:28 +01:00
aothms a0db3a3406 chmod +x on *nix build script 2016-01-09 06:42:35 +01:00
aothms 18f8d7b3a3 Add *nix build script
Set paths by CMake cache entries or env vars
Windows build script: Don't fail on non-zero exit code returned by `git fetch`
2016-01-09 06:38:33 +01:00
Thomas Krijnen 010e05308d Merge pull request #19 from aothms/master
Fixes for sequences of extended control directives
2016-01-08 09:20:50 +01:00
aothms 973fa9ccb5 Fixes for sequences of extended control directives 2016-01-08 09:17:49 +01:00
aothms 0d42a293ad Add license header to occ_utils 2016-01-08 08:38:21 +01:00
aothms 6716423a68 Sort instances on name rather than on std::map occurrence. Add chunk-size command line argument. 2016-01-08 06:35:53 +01:00
Thomas Krijnen a02a06a0e3 Merge pull request #16 from Tridify/win_oce_update
Windows build scripts: OCE & OpenCOLLADA updates
2016-01-06 07:29:06 +01:00
Stinkfist0 d3438335a2 Work around https://github.com/KhronosGroup/OpenCOLLADA/issues/377 2015-12-30 16:26:16 +02:00
Stinkfist0 a0bb589ed3 build-deps.cmd: use OCE and oce-win-bundle from the official repos. 2015-12-30 13:32:22 +02:00
Thomas Krijnen 056bcd12d0 Merge pull request #14 from aothms/master
Various fixes
2015-12-21 11:51:45 +01:00
aothms fe699e0a81 Fix python module import 2015-12-21 11:47:38 +01:00
aothms 4eee9a1936 Merge remote-tracking branch 'official/master'
Conflicts:
	src/ifcconvert/IfcConvert.cpp
	src/ifcgeom/IfcGeomIterator.h
2015-12-21 11:36:23 +01:00
Thomas Krijnen 8c1710cae1 Merge pull request #11 from Tridify/windows_build_scripts
build-ifcopenshell & install-ifcopenshell batch files
2015-12-07 19:21:24 +01:00
Stinkfist0 e2d3b3734f Use IFCOS_NUM_BUILD_PROCS also in build-ifcopenshell.cmd and install-ifcopenshell.cmd. 2015-12-07 16:30:08 +02:00
aothms b243572d23 Don't fail on opening elements lacking representation or placement 2015-12-05 17:14:10 +01:00
Stinkfist0 3224a2cf83 build-ifcopenshell & install-ifcopenshell batch files 2015-12-04 17:33:13 +02:00
aothms a2d91f9331 Fix compilation error reported by bezumenez 2015-12-04 11:56:54 +01:00
aothms 0301e2fb1b Emit an error message on extrusions with negative height or under model precision 2015-12-02 10:17:59 +01:00
Thomas Krijnen 0036bd2dc2 Merge pull request #9 from Tridify/windows_build_scripts
Windows & Visual Studio build scripts continued
2015-12-01 14:27:34 +01:00
Stinkfist0 0877bb0ac3 Windows build scripts: if CMake generator not passed, deduce the generator from VS env vars. 2015-12-01 14:53:16 +02:00
aothms e62ce005dc Work on unit issues with step and iges files 2015-12-01 11:14:50 +01:00
aothms b6e2d78bfa Catch syntax errors during iterator initialization 2015-11-30 23:41:27 +01:00
aothms bf292cccd0 Precision fixes 2015-11-30 22:59:21 +01:00
aothms 83c4b6a642 More serialization options for HDF5 2015-11-30 22:34:48 +01:00
Stinkfist0 2dc5cd44b7 Enable warning C4100 ("'identifier' : unreferenced formal parameter") and fix warnings. 2015-11-23 15:52:12 +02:00
Stinkfist0 fcbe93c4c2 vs-cfg.cmd: support CMake pre-3.0 Visual Studio generator strings. 2015-11-23 15:27:58 +02:00
Stinkfist0 89b3b96f1e .gitignore: add /src/ifcexpressparser/__pycache__ & /src/ifcexpressparser/express_parser.py 2015-11-22 02:39:45 +02:00
Stinkfist0 16a82f035f templates.py: disable C4100 warnings for headers created by this file + move <map> inclusion to .cpp as it's not needed in .h + use spaces instead of tabs consistently for these files as seems to be the convention. 2015-11-22 02:26:28 +02:00
Stinkfist0 b562508f5b win/readme.md tweak 2015-11-22 00:04:21 +02:00
Stinkfist0 a13042f227 Fix warnings: unused variables, shadowing variable names, constant conditional expressions, integer conversions, inability to generate copy-ctor and/or assignment operator, etc. 2015-11-21 23:05:28 +02:00
Stinkfist0 3cbb47a831 Bump up MSVC warning level. 2015-11-21 23:01:29 +02:00
Stinkfist0 7d806296c1 vs-cfg.cmd: use the longer generator names for all generator so that VS version can be identified in generic fashion 2015-11-21 13:16:47 +02:00
Stinkfist0 d6bd0c861b README.md formatting fix 2015-11-21 13:15:31 +02:00
Thomas Krijnen 8164c90ba0 Merge pull request #5 from Tridify/windows_build_scripts
Windows & Visual Studio build scripts
2015-11-20 13:38:45 +01:00
Stinkfist0 fff6f97651 build-deps: when building OpenCOLLADA, enforce that the embedded LibXml2 and PCRE are used as there might be problems with arbitrary versions of the libraries. 2015-11-20 12:45:56 +02:00
Stinkfist0 6a5d5dcb12 Further cleanup for the batch scripts. 2015-11-20 12:34:31 +02:00
Stinkfist0 bb3dc351b8 Batch file tweaks, fix printing of the used generator 2015-11-20 11:44:17 +02:00
Stinkfist0 90946e0877 Windows build scripts: TODO & indentation tweaks. 2015-11-20 00:45:01 +02:00
Stinkfist0 7895835ca3 build-deps.cmd: check that powershell, git and cmake are in path using where.exe. Print instructions upon missing VS env vars or tools in PATH. 2015-11-19 18:01:03 +02:00
Stinkfist0 7caa4e3e1d Replace cecho.exe with PowerShell snippet, fix exit bug in vs-cfg.cmd, fix Visual Studio download URL, rename IFCOS_NUM_BUILD_PROCESSES -> IFCOS_NUM_BUILD_PROCS 2015-11-19 17:30:55 +02:00
Stinkfist0 d721dabf3b Replace wget usage with PowerShell. 2015-11-17 16:02:06 +02:00
aothms ac8cf298fa Commit override types for efficiency 2015-11-16 10:37:02 +01:00
Stinkfist0 9087bc65a7 win/readme.md tweaks 2015-11-14 20:18:29 +02:00
Stinkfist0 ccf4e84e18 CMakeLists.txt: Clean up addition of debug lib variants on MSVC. 2015-11-14 19:19:55 +02:00
Stinkfist0 0f1db1267b Rename readme.txt to readme.md, link to the Windows readme.md from the main README.md. 2015-11-11 17:41:38 +02:00
Stinkfist0 431e993ba3 CMake biz: Instead of providing elusive prints of missing dependencies for required features and continuing the build configuration, fail fast instead; user can easily disable the feature or fix the paths for the dependency. 2015-11-11 13:30:30 +02:00
Stinkfist0 d912e73282 Allow both debug and release variants of dependencies to co-exist allowing effortless switching between IfcOpenShell debug and release builds. 2015-11-10 23:18:02 +02:00
Stinkfist0 106da12444 build-deps.cmd: make debug libs of OpenCOLADA and ICU to have "d" postfix so that release and debug variants can co-exist in the same dir as is the default with OCE. 2015-11-10 20:05:11 +02:00
aothms 579d3713fd hdf5 2015-11-10 11:16:00 +01:00
Stinkfist0 89a015724b CMake biz: rename OCE_LIBRARIES to OPENCASCADE_LIBRARIES, use this variable also in examples & qtviewer CMakeLists.txt 2015-11-09 17:42:46 +02:00
Stinkfist0 8b63959509 Use separate BuildDepsCache.txt for x86 and x64 builds. 2015-11-09 16:04:06 +02:00
Stinkfist0 0a8791e04e Clean up CMake biz by using OCE_LIBRARIES variable for defining OCE libs + fix setting of PYTHON_INCLUDE_DIR + PYTHON_LIBRARY vars + small README.md cleanup. 2015-11-09 15:36:57 +02:00
Stinkfist0 318779196b Use BuildDepsCache.txt to store information about used Python version so that it's available for "autonomic" run-cmake.bat runs. 2015-11-05 18:05:20 +02:00
aothms d076fa588b Work on runtime representation of schema 2015-11-05 11:55:19 +01:00
Stinkfist0 6190771817 Fix/suppress signed-unsigned int conversion warnings on Windows x64. 2015-11-04 18:27:46 +02:00
Stinkfist0 206a9cf5d0 Work around https://github.com/swig/swig/issues/325 2015-11-04 16:25:13 +02:00
Stinkfist0 d4b51a82e7 Fix/suppress plethora of integer conversion warnings on x64 Visual Studio build. 2015-11-03 17:58:08 +02:00
Stinkfist0 a749775045 build-deps.cmd: use OpenCOLLADA from the official repo now that it has the static MSVC run-time option. 2015-11-03 16:55:33 +02:00
Stinkfist0 26ed16ba52 Make possible to switch between Python 2 & 3 easily. Fixes also possible confusion when having both 32-bit and 64-bit Python installations side by side. 2015-11-03 16:28:30 +02:00
Stinkfist0 7b4d8734ed run-cmake.bat: ensure Python packages are installed to the right direction. 2015-10-30 22:49:52 +02:00
Stinkfist0 455d382a9e build-deps.cmd: add option to use Python 2 instead of 3, fix Boost build variant (for some reason error did not manifest itself until clean build) 2015-10-30 21:12:08 +02:00
Stinkfist0 c9313c8e02 build-deps.cmd: update SWIG, build Boost as debug or release, not both, each run. 2015-10-29 00:23:19 +02:00
Stinkfist0 b44a88d203 CMakeLists.txt: install IfcGeomServer executable. 2015-10-28 21:25:48 +02:00
Stinkfist0 921c3eb2d3 SvgSerializer.cpp: add missing #include <Standard_Version.hxx> 2015-10-28 21:25:23 +02:00
Stinkfist0 d5efe45b0b Update READMEs. 2015-10-28 21:21:23 +02:00
Stinkfist0 b8a7b5426d build-deps.cmd: fix Python installation. Also uninstall Python if build type is Clean or Rebuild. 2015-10-28 21:08:08 +02:00
Stinkfist0 89bea19b75 Enhanced CMakeLists.txt for Windows build scripts. 2015-10-28 19:45:45 +02:00
Stinkfist0 5c0eb05482 Add Windows build scripts from https://github.com/Tridify/IfcOpenShell-SourceForge 2015-10-28 19:43:10 +02:00
Stinkfist0 c9ff455812 Move Visual Studio solution files from win\ to win\sln 2015-10-28 19:41:59 +02:00
aothms fdf1b29682 Return shape for arbitrary representation items in ifcopenshell.geom.create_shape() 2015-10-22 12:04:49 +02:00
aothms f3af39546b Don't construct transformation from matrix, but use original data. 2015-10-13 11:15:45 +02:00
aothms 44ddc5e6dc Don't use IfcMappedItems for IfcOpenHouse walls, as suggested by Ian Clévy in https://sourceforge.net/p/ifcopenshell/discussion/1782716/thread/f9b586ca/?limit=25#ab87 2015-10-09 14:23:38 +02:00
aothms c7ddc0643e Fixes to flatten_shape_list() 2015-10-07 16:14:34 +02:00
aothms 3a9e90f94f Mark IfcGeom::Kernel::getValue as const 2015-10-07 16:13:25 +02:00
aothms db6630c1f8 Use boost::to_lower() 2015-10-05 13:34:43 +02:00
aothms c20afd24a5 Remove unnecessary precision cast 2015-10-05 13:09:16 +02:00
aothms 7b82bfb477 Update log messages in parser 2015-10-05 13:08:24 +02:00
aothms 3e00139a87 Add const pointer cast to IfcBaseClass 2015-10-05 13:07:40 +02:00
Thomas Krijnen 23beb5691c Detect abstract entities in schema parser 2015-09-17 10:33:19 +02:00
Thomas Krijnen c6a265adf8 Merge pull request #2 from aothms/master
Assorted fixes
2015-09-13 15:05:46 +02:00
aothms 94d214808e Use boost::to_upper() and -::to_upper_copy() for string manipulation throughout codebase 2015-09-13 15:00:21 +02:00
aothms a58b2ede63 Fixes for unicode handling in Python 2015-09-13 14:43:42 +02:00
aothms e5c20a009d Add convenience method for relating objects to types. As suggested by Cadline St2. 2015-09-12 14:27:58 +02:00
aothms b590747db9 Add version information and schema identifier to Python wrapper 2015-09-10 15:53:59 +02:00
aothms 2532ba30e4 Fix addRelatedObject, fix by Cadline St2 2015-09-10 13:58:27 +02:00
aothms 9096895bdb Support for schemas using TYPE definitions to redeclare BINARY types 2015-09-08 15:27:05 +02:00
aothms 82143f226e Small changes to SVG serialization 2015-09-06 14:50:07 +02:00
aothms 22a8d9a17b Don't leave MakeFace in an invalid state when one of the face boundaries cannot be processed or is not planar 2015-09-04 11:48:53 +02:00
aothms 4385f3b14d Revert some of the typemap work in b96cf38e17 and rely on a general mapping from const vector to tuple 2015-09-04 11:46:52 +02:00
aothms 3cba242295 When built without ICU filter characters outside of unencoded range 2015-08-14 22:11:32 +02:00
aothms 822fa91f4d Work on a C++ representation of the parsed EXPRESS schema 2015-08-13 14:28:50 +02:00
aothms 266d6f4c97 Cache the output of the parsed express schema as a Python pickle stream for speedier code generation 2015-08-13 14:26:14 +02:00
Thomas Krijnen 8406c5243c Merge pull request #1 from aothms/master
Ignore tail remarks in the express schema parser
2015-08-13 14:20:12 +02:00
aothms 810d3eab1e Ignore tail remarks in the express schema parser 2015-08-13 14:18:59 +02:00
aothms 17f6e67706 Update README 2015-08-10 11:38:43 +02:00
Thomas Krijnen f5c32adff1 Be sure to flush fstream when finalizing SVG export 2015-07-26 17:59:52 +00:00
Thomas Krijnen bb43dec90f Fix typos 2015-07-26 17:58:08 +00:00
Thomas Krijnen 0e5edbcd84 Reverse preprocessor statement to work without definition, defaulting to 2x3 2015-07-26 15:26:34 +00:00
Thomas Krijnen 68fc361d96 Add SvgSerializer developed in collaboration with ROOT B.V. 2015-07-26 14:26:13 +00:00
Thomas Krijnen 06b4fcb066 Remove orphaned file. Thanks Stinkfist 2015-07-26 14:22:50 +00:00
Thomas Krijnen 85d5d86c84 Update code examples for recent changes 2015-07-09 13:52:55 +00:00
Thomas Krijnen 78f4d7d592 Fix build with Boost 1.58.0. Patch by stinkfist0. Thanks. 2015-07-09 13:23:40 +00:00
Thomas Krijnen 92bc7b13cb Use custom typemaps for geometry related classes as well 2015-06-26 13:06:28 +00:00
Thomas Krijnen e518146bd6 Fix IfcCurveBoundedPlane implementation 2015-06-21 16:15:15 +00:00
Thomas Krijnen e9eb7db620 Fix ensure_fit_for_subtraction() function when input shape is a solid 2015-06-21 16:14:37 +00:00
Thomas Krijnen 1068070037 Do not free the IFC file if it has not been constructed by the iterator 2015-06-20 14:23:59 +00:00
Thomas Krijnen 3d302619c5 Check for numbers.Integral instead of int, to catch py2.7's long type as well 2015-06-20 14:22:54 +00:00
Thomas Krijnen 48febb7eff Check for null values when setting attributes in IfcOpenShell-Python, also return value being set 2015-06-18 13:15:33 +00:00
Thomas Krijnen feaa13a809 gcc compatibility 2015-06-18 08:55:29 +00:00
Thomas Krijnen 76cbb79c75 Correctly wrap arbitrarily nested aggregates of entity instance attributes in IfcOpenShell-Python 2015-06-17 19:46:11 +00:00
Thomas Krijnen 6aabbd4a55 Correctly interpret SWIG return code of type check 2015-06-17 19:44:15 +00:00
Thomas Krijnen 48676a733f Rework SWIG python binding not to rely on polymorhpic functions. Use hand-written typemaps that map vectors to tuples and iterables to vectors. Add support for multidimensional aggregates in Python. 2015-06-17 11:27:02 +00:00
Thomas Krijnen f8c45b2a99 Fix serialization of binary values 2015-06-17 11:22:43 +00:00
Thomas Krijnen 1ec14118fe Introduce specific exception for out of range attribute indexing 2015-06-17 11:04:28 +00:00
Thomas Krijnen 381f711103 Update string representation of ArgumentTypeToString 2015-06-16 14:47:03 +00:00
Thomas Krijnen b748c0a573 Add source code for generation of IfcTriangulatedFaceSet test case 2015-06-16 13:00:19 +00:00
Thomas Krijnen c4e8a409de Add another IfcTriangulatedFaceSet test case 2015-06-16 12:59:49 +00:00
Thomas Krijnen 28863f90b9 Add support for IFC4.IfcTriangulatedFaceSet 2015-06-16 12:58:51 +00:00
Thomas Krijnen 4f60c7d48c Provide concrete C++ implementations for all multidimensional aggregate types in IFC4 2015-06-16 12:58:07 +00:00
Thomas Krijnen f70b37137d Emit an error message rather than exception for GlobalId parsing inconsistencies to accomodate files with invalid GlobalIds. 2015-06-04 14:33:13 +00:00
Thomas Krijnen 49d491704e Add support for IfcBSplineCurveWithKnots 2015-06-02 15:56:09 +00:00
Thomas Krijnen a3f17cd4e7 Enable passing explicit IfcRepresentation in IfcOpenShell-Python create_shape() 2015-06-02 13:30:02 +00:00
Thomas Krijnen b96cf38e17 Minimize passing STL objects past dynamic library boundaries to improve stability of IfcOpenShell-Python 2015-06-02 13:29:08 +00:00
Thomas Krijnen 5a994ebe28 vc9 compatibility 2015-05-26 12:56:00 +00:00
Thomas Krijnen ffc008228d gcc compatibility 2015-05-26 12:55:00 +00:00
Thomas Krijnen 77ba3f5a80 Perform shape healing after opening subtraction 2015-05-22 15:41:56 +00:00
Thomas Krijnen 04d4095ffe Correctly mark face boundary edges in case of vertex welding 2015-05-22 13:13:48 +00:00
Thomas Krijnen 569fa49796 Prevent an issue with obtaining precision from sub contexts 2015-05-22 13:13:16 +00:00
Thomas Krijnen 7abe2df066 Update implementation of IfcBSplineSurfaceWithKnots for IfcAdvancedFace in IFC4 2015-05-21 13:02:10 +00:00
Thomas Krijnen 9b64c6f4b9 Check for orientation of wires when creating outer boundary of face 2015-05-21 13:01:01 +00:00
Thomas Krijnen 771f78a671 Fix surface style association when compiling with IFC4 2015-05-21 12:55:54 +00:00
Thomas Krijnen 3d6b330366 Reintroduce binary type in express parser 2015-05-21 12:53:17 +00:00
Thomas Krijnen 37d4e9bcbd Fix express parser for simple types that redefine aggregates of entities 2015-05-21 12:09:57 +00:00
Thomas Krijnen 7390faa654 Adapt XML serializer for changes in IFC4 decomposition and property set types 2015-05-21 12:06:38 +00:00
Thomas Krijnen b7d4eb62d5 Add IfcFaceSurface example 2015-05-21 12:05:23 +00:00
Thomas Krijnen 40a60386c8 Brand new implementation of IfcFace(Surface) 2015-05-20 08:55:02 +00:00
Thomas Krijnen 9bf9f82b3b Format obj and dae output predictably based on rfc notation of GlobalId. As discussed in https://sourceforge.net/p/ifcopenshell/discussion/1782717/thread/cbb0c8ca/ 2015-05-13 14:30:21 +00:00
Thomas Krijnen b37a684eb9 Append line segment indices in the IfcGeomServer 2015-04-25 09:13:14 +00:00
Thomas Krijnen c97cf661a2 1. Also emit Plan and Axis shape representations and IfcTopologyRepresentations if requested. 2. Add serialization for curves. 3. In Python add option to specify representation for which to generate shape. 2015-04-22 09:15:48 +00:00
Thomas Krijnen 53f625346f Fix compilation with gcc 2015-04-07 19:26:01 +00:00
Thomas Krijnen 608c7d9841 Don't rely on exceptions for testing whether a Python attribute names a valid (inverse) IFC attribute 2015-04-07 15:49:38 +00:00
Thomas Krijnen 955190b517 Add support for reading and writing BINARY attributes. Rename members of the IfcUtil::ArgumentType enumeration. 2015-04-07 15:06:56 +00:00
Thomas Krijnen 462425f61d Update README 2015-03-22 20:06:04 +00:00
Thomas Krijnen 0a0f44b674 Reduce link time for MSVC release builds. Patch by ch0kee. 2015-03-22 19:52:29 +00:00
Thomas Krijnen 9f9a0ea3dc Update generated code for IFC4 2015-03-20 20:58:05 +00:00
Thomas Krijnen a28b5517e8 Fix compilation with gcc. Thanks Ivano. 2015-03-13 10:40:31 +00:00
Thomas Krijnen df1805921b Create writable argument copies when duplicating entity instances 2015-03-12 17:54:52 +00:00
Thomas Krijnen 5ea13970c8 Instantiate xml_writer_settings based on boost version. Thanks Liam. 2015-03-06 15:49:46 +00:00
Thomas Krijnen aad6c77d00 Skip IfcSweptDiskSolid.InnerRadii under IfcGeometricRepresentationContext.Precision. Thanks Stefan. 2015-03-03 19:18:51 +00:00
Thomas Krijnen 9bbbc6e7d9 Extend Python's dir() function on entity instances with attribute and inverse attribute names of entities 2015-02-27 13:41:33 +00:00
Thomas Krijnen d41dbc386e DISABLE_TRIANGULATION for serializers that operate on Open Cascade's BRep format 2015-02-23 22:01:21 +00:00
Thomas Krijnen 9cd0a76f84 Update bl_info structure in blender addon 2015-02-23 19:13:47 +00:00
Thomas Krijnen dada40735b #include <xlocale.h> header on OS X 2015-02-20 22:02:22 +00:00
Thomas Krijnen 2ce89c8b22 Properly read the CONVERT_BACK_UNITS setting for serialized elements 2015-02-20 18:06:52 +00:00
Thomas Krijnen 0552c336df Correct omitted initialization list item from IfcGeom::IteratorSettings 2015-02-20 17:16:01 +00:00
Thomas Krijnen 349e7ddaa7 USE_WORLD_COORDS by default when USE_PYTHON_OPENCASCADE is set. 2015-02-20 16:03:20 +00:00
Thomas Krijnen f20ae8e25e create a setting to produce pythonOCC shapes for ifcopenshell.geom.iterator and -create_shape() 2015-02-19 21:45:17 +00:00
Thomas Krijnen 8f853ac5af Initialize the attributes of IfcLateBoundEntity to NULL upon construction.
Make sure IfcWritableEntity does not return null pointers, since getArgumentCount() is unreliable for instances being created from keyword arguments in Python.
2015-02-19 20:20:47 +00:00
Thomas Krijnen 6822e84849 Initialize IfcGeomIterator so that no entities are skipped by default 2015-02-19 20:17:53 +00:00
Thomas Krijnen 73266ea216 transfer ownership from Python to C++ when adding an instance to a file 2015-02-19 18:11:09 +00:00
Thomas Krijnen b0ccf69870 Don't add inverse references to the entity being added itself. 2015-02-19 14:42:19 +00:00
Thomas Krijnen 573655e5ef Add the possibility to bundle binary modules for different architectures with the python-ifcopenshell module 2015-02-19 13:37:37 +00:00
Thomas Krijnen 2a7135f347 Correct visibility of IfcBaseType methods. Thanks Ian. 2015-02-19 10:53:41 +00:00
Thomas Krijnen a57a305e9d Correctly cast writable enumeration attributes to string, as reported in: https://sourceforge.net/p/ifcopenshell/discussion/1782717/thread/53b70ea0 2015-02-17 22:14:09 +00:00
Thomas Krijnen e6ff1126ad Catch errors in entity traversal while adding a new entity. In particular for late bound instances having unset attributes. 2015-02-17 22:02:06 +00:00
Thomas Krijnen 6c8a60db6e Fixes related to r312: gcc refuses to erase a const_iterator 2015-02-17 21:24:18 +00:00
Thomas Krijnen b5c9de8d64 Changes related to r312 2015-02-17 20:36:23 +00:00
Thomas Krijnen 5fe4cfab63 More fixes related to locales 2015-02-17 20:23:21 +00:00
Thomas Krijnen b3e5264aa9 WARNING: more function renames 2015-02-17 20:07:09 +00:00
Thomas Krijnen e3d5b6220d Rename AddEntity to addEntity 2015-02-17 19:55:27 +00:00
Thomas Krijnen 846e881cf4 Update build files 2015-02-17 19:52:18 +00:00
Thomas Krijnen ee87466521 1) Implement a breadth-first traversal of forward references 2) implement entity instance deletion from a file 3) recursively copy entity instances to another file 2015-02-17 19:48:41 +00:00
Thomas Krijnen def1328a91 Some more checks and fixes in the IfcBooleanResult code. Most notably set the result to FirstOperand in case healing the result fails. 2015-02-06 17:14:05 +00:00
Thomas Krijnen a7c0c08725 Remove macro redefinition warning 2015-02-06 15:56:07 +00:00
Thomas Krijnen 63e9b706c1 Add missing #includes for OCC 6.8.0 specific #if 2015-02-06 14:20:33 +00:00
Thomas Krijnen 16d400e192 Stricter template syntax in latest commit 2015-02-06 13:37:50 +00:00
Thomas Krijnen 3801e52bff Add an XML serializer (NB: Not ifcXML / 10303-28) that describes property set data, decomposition relations and SPF header fields 2015-02-06 13:07:50 +00:00
Thomas Krijnen c597404dfe Increase the severity of the 'different schema' message 2015-02-06 12:59:36 +00:00
Thomas Krijnen 47b9ed4482 Add a cast in templated list conversion 2015-02-06 12:58:59 +00:00
Thomas Krijnen d23dee551c #ifdef away the two trailing precision arguments for gp_Trsf::SetValues() when OCC >= 6.8.0 2015-02-06 12:49:53 +00:00
Thomas Krijnen 79817341e0 Ignore entity types earlier in IfcConvert so that representations are not processed in vain 2015-02-05 11:55:25 +00:00
Thomas Krijnen 0124034803 Fix typo in locale code 2015-02-04 15:31:01 +00:00
Thomas Krijnen 2da6f5428d Make real number parsing and serializing locale-independent, as suggested by Ian Clevy. 2015-02-03 13:53:36 +00:00
Thomas Krijnen 5f677baf63 Fixes #30. Thanks to Ian Clevy. 2015-02-03 09:40:17 +00:00
Thomas Krijnen b5f055e54b Fix repr() of ifcopenshell.geom.settings 2015-01-29 11:34:11 +00:00
Thomas Krijnen 4c79f713ed Make sure C++ exceptions do not crash the Python interpreter 2015-01-26 18:11:48 +00:00
Thomas Krijnen b789839e4a Fix errors in serialization 2015-01-25 10:50:12 +00:00
Thomas Krijnen 23d5827229 Zero exit code when printing help and version information in IfcConvert 2015-01-23 16:10:49 +00:00
Thomas Krijnen f0425b16d1 Have a peek at a representation's context in the geometry wrapper as well to determine suitability for processing 2015-01-22 10:39:48 +00:00
Thomas Krijnen e1edda588e Properly test for the optional IfcGeometricRepresentationContext.ContextType being null in IfcGeomIterator.h 2015-01-22 10:38:35 +00:00
Thomas Krijnen 6c7c88d7a5 Python wrapper: enable iteration over all entities, get attribute optionality information 2015-01-21 17:01:22 +00:00
Thomas Krijnen 3503c8c933 Fix typo in wrapper generator 2015-01-20 14:39:52 +00:00
Thomas Krijnen e37b062757 python 2/3 compatibility: from functools import reduce 2015-01-20 13:52:08 +00:00
Thomas Krijnen 97b6f444d1 Use BRepMesh_IncrementalMesh rather than BRepMesh::Mesh. Thanks lorinma. 2015-01-19 16:02:34 +00:00
Thomas Krijnen 418dabaff2 Fix typo 2015-01-18 15:32:50 +00:00
Thomas Krijnen 7b17c2dccd Make header values writable 2015-01-16 16:26:40 +00:00
Thomas Krijnen f6f541ee3b Use BRepMesh_IncrementalMesh rather than BRepMesh::Mesh. Thanks lorinma. 2015-01-16 14:32:50 +00:00
Thomas Krijnen 09168d8910 Don't rely on operator bool() but on bool operator!() for truthiness of boost::optionals. Fixes compilation with boost 1.56+. 2015-01-16 13:24:40 +00:00
Thomas Krijnen e57f20f5f2 Small compilation fix 2015-01-14 09:39:52 +00:00
Thomas Krijnen 511e83c2c6 Shuffle around wrapper statements to fix setting arguments 2015-01-10 23:01:52 +00:00
Thomas Krijnen 8581fed39b Track inverse attributes more correctly
Rename Size() to size() on EntityList and friends
2015-01-10 22:13:52 +00:00
Thomas Krijnen 1d319f7ac4 Compilation fixes and python 2 compatibility. Thanks Yorik. 2015-01-07 10:22:55 +00:00
Thomas Krijnen 9780c047e9 Improvements for precision handling 2015-01-06 14:09:28 +00:00
Thomas Krijnen 1c757c351b Fix compilation of IfcOpenHouse, move IfcGeom::tesselate back directly in IfcGeom namespace 2015-01-06 10:19:24 +00:00
Thomas Krijnen f3c26c372d Parse the spf header and check schema_identifiers against compiled schema 2015-01-05 17:46:23 +00:00
Thomas Krijnen 4d5d749255 Merge developments from the python_wrapper branch into master 2015-01-05 14:11:42 +00:00
Thomas Krijnen 8872affe54 Update CMake build script 2014-12-19 12:37:31 +00:00
Thomas Krijnen 3236218aba Compilation fixes related to previous commit 2014-12-19 12:36:06 +00:00
Thomas Krijnen 2a403e240d *** See: https://sourceforge.net/p/ifcopenshell/discussion/1782718/thread/6bd0f843/ ***
Massive refactor of the IfcGeomObjects module, which is now the IfcGeom::Iterator class.
2014-12-19 12:14:36 +00:00
Thomas Krijnen 3f285ea639 Prevent another exception being thrown upon adding entity instances to a file, as reported by ch0kee 2014-11-27 09:22:58 +00:00
Thomas Krijnen 4c976c8b70 Track the surface style of an IfcBooleanResult 2014-11-26 14:32:54 +00:00
Thomas Krijnen d88d4d5951 Add support for IfcAsymmetricIShapeProfileDef 2014-11-26 14:01:31 +00:00
Thomas Krijnen eb815120dc Take unit information into account when applying precision. Thanks Stefan 2014-11-26 13:08:47 +00:00
Thomas Krijnen 7f8d84a1af Fix omitted return statement in previous commit 2014-11-17 15:32:00 +00:00
Thomas Krijnen 24044fb92a Catch all errors when parsing boost program_options in IfcConvert 2014-11-04 12:45:20 +00:00
Thomas Krijnen cd366bf8c2 Reconstruct the form of the transformation to improve the output of the OpenCascade-based serializers 2014-11-04 12:36:59 +00:00
Thomas Krijnen 96ce5f6b25 Don't compare smart pointers to zero, but convert to bool 2014-11-04 12:02:28 +00:00
Thomas Krijnen 120de2f601 Remove erroneous qualifier 2014-11-02 18:50:12 +00:00
Thomas Krijnen 872dd4e831 Rewrite IfcFile::AddEntity() not to rely on exceptions, as suggested by ch0kee. 2014-11-02 18:36:51 +00:00
Thomas Krijnen 6e44683b5d Add another IfcFacetedBrep test case 2014-07-28 20:12:52 +00:00
Thomas Krijnen e77216d41c More robust processing of IfcPolyline and IfcPolyLoop 2014-07-28 20:03:53 +00:00
Thomas Krijnen cf2e82e8f5 Create a compsolid shape for an extrusion of a IfcCompositeProfileDef and process the opening subtraction individually 2014-07-24 11:22:31 +00:00
Thomas Krijnen 9a1c7af953 Fixes for IfcRectangleHollowProfileDef and filleted profile generation. 2014-07-24 11:14:54 +00:00
Thomas Krijnen 5648b8d8bc Correct an invalid default value for IfcCartesianTransformationOperator3D.Axis3. Thanks Stefan. 2014-07-19 10:30:13 +00:00
Thomas Krijnen 1837b79ac3 Add faceted_brep_csg test case 2014-07-06 14:38:48 +00:00
Thomas Krijnen e6aa449ef8 Accept IfcBooleanResult operands that convert to set of shapes in IfcOpenShell rather than a single shape (i.e IfcShellBasedSurfaceModel, IfcFaceBasedSurfaceModel, IfcFacetedBrep, IfcGeometricSet) 2014-07-06 14:21:56 +00:00
Thomas Krijnen aa1ff90241 Remove a duplicated cartesian point from the closed polyline created by the addBox() function as seen in IfcOpenHouse. Thanks Bernd. 2014-06-28 12:39:40 +00:00
Thomas Krijnen 1c39eba3f7 Fix typo 2014-06-27 12:24:49 +00:00
Thomas Krijnen 92c5bb637b - Check the validity of solids created from sewed shells and potentially revert to a shell or compound of faces
- Flag shape representations, for which no item succeeds, as failed
2014-06-27 12:00:41 +00:00
Thomas Krijnen d45056f9c5 Increase precision for writing floats 2014-06-11 10:24:11 +00:00
Thomas Krijnen 83b6ce9083 Apply the same precision value when merging a compound of faces into a solid just-in-time for subtraction 2014-06-09 12:56:47 +00:00
Thomas Krijnen 81292f1adc Detect cases where Newell's Method returns a zero-length vector and make no attempt to normalize it in order to prevent an exception. In this case the face will be flagged as invalid down the road, because its perimeter doesn't span any area. 2014-06-07 17:49:21 +00:00
Thomas Krijnen 49e4ff31ca Fix header of IfcReinforcingBar.ifc 2014-05-14 09:01:33 +00:00
Thomas Krijnen 7066337449 Update IfcParseExamples 2014-05-12 13:56:41 +00:00
Thomas Krijnen 948d7675f0 - Take better care of inverse cardinalities and respect more CoordinationView agreements in IfcOpenHouse
- Track inverse relationships in an IfcWrite context as well
- Fix for lists of SELECT types
2014-05-05 16:17:28 +00:00
Thomas Krijnen 1b54ba039d - Add support for IFC4 nurbs surfaces (IfcBSplineSurfaceWithKnots and IfcAdvancedFace)
- Remove unnecessary typedefs
2014-05-04 14:42:55 +00:00
Thomas Krijnen e87b8988cd Add Test Files from http://www.buildingsmart-tech.org/ifc/IFC4/final/html/annex/annex-e/ifc/ 2014-04-30 14:14:05 +00:00
Thomas Krijnen bd83259d2b More fixes for parsing files with comments 2014-04-19 09:35:08 +00:00
Thomas Krijnen 604d6b032d Add test file with IfcSweptDiskSolids. Thanks Bernd. 2014-04-17 17:50:19 +00:00
Thomas Krijnen b30fbf73ae Add support for IfcSweptDiskSolid 2014-04-16 16:51:03 +00:00
Thomas Krijnen ed1db3dc68 Process IfcStyledItems directly applied to an IfcFacetedBrep 2014-04-09 10:57:45 +00:00
Thomas Krijnen 68740367a5 Account for unit magnitude in matrix translation part when CONVERT_BACK_UNITS is enabled 2014-04-08 07:28:07 +00:00
Thomas Krijnen 365b5f5d48 Fix product's 4x4 matrix on the IfcGeomServer 2014-04-07 17:59:20 +00:00
Thomas Krijnen b406d1c100 When writing collada files, postfix geometry instance nodes to make them distinct from their geometry library references 2014-04-07 14:01:16 +00:00
Thomas Krijnen 95a1332228 IfcGeomServer, small fixes: refrain from using auto type and restore std::cout rdbuf on exit so implicit flush doesn't segfault 2014-04-06 12:50:51 +00:00
Thomas Krijnen a0d74bdf83 Revamp the 'IfcGeomServer' idea to have an executable rather than a library to interface with. This way IFC processing runs in a separate process from the client application, so that crashes or out of memory issues do not bring down the client application. 2014-04-06 11:16:20 +00:00
Thomas Krijnen 24279776ab Increased verbosity in unsupported entity instances 2014-04-02 15:28:04 +00:00
Thomas Krijnen aebb9469a9 Fixes for parsing files with comments 2014-04-02 15:04:09 +00:00
Thomas Krijnen 0ecaf28e3e Measure conversion time of IfcConvert more faithfully 2014-03-31 14:03:06 +00:00
Thomas Krijnen 3e7c0cfd55 IfcSurfaceCurveSweptAreaSolid improvements 2014-03-31 14:00:02 +00:00
Thomas Krijnen aae576aae2 Take into account face location when serializing shape as tesselated faceset. 2014-03-22 21:13:02 +00:00
Thomas Krijnen 1aab95459b IfcConvert: Handle invalid command line options gracefully and notify user 2014-03-22 13:12:22 +00:00
Thomas Krijnen 80b39c0d22 No longer accept and silently convert invalid REAL tokens to zero 2014-03-22 13:02:21 +00:00
Thomas Krijnen bc801d00ba Handle missing or invalid unit and precision information more gracefully during IfcGeomObject initialization 2014-03-22 12:56:08 +00:00
Thomas Krijnen 54ecdb8295 For .obj conversion terminate lines with "\n" rather than std::endl causing a significant speed increase due to longer intermittently flushing the stream 2014-03-22 11:12:50 +00:00
Thomas Krijnen 71ea636206 Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
Add CSG example.
2014-03-22 10:31:51 +00:00
Thomas Krijnen 2f16bb42ed Add missing header to installation files. Thanks Fred. 2014-03-22 09:22:27 +00:00
Thomas Krijnen 268109875f Update build scripts to include TKOffset 2014-03-19 09:47:24 +00:00
Thomas Krijnen dab6e1d220 Add example file to generate file with IfcCompositeProfileDef and IfcDerivedProfileDef 2014-03-16 13:35:14 +00:00
Thomas Krijnen 220b36b09c Support for IfcCompositeProfileDef and IfcDerivedProfileDef 2014-03-16 13:34:01 +00:00
Thomas Krijnen 4c17d153f4 Add support for IfcGeometricSet IfcRevolvedAreaSolid IfcSurfaceOfLinearExtrusion IfcSurfaceOfRevolution IfcCenterLineProfileDef IfcArbitraryOpenProfileDef 2014-03-15 11:51:23 +00:00
Thomas Krijnen 7597f25db0 Implementations for more parameterized profile definitions 2014-03-08 17:21:39 +00:00
Thomas Krijnen ec2ed06272 Add support for ellipses with SemiAxis2 > SemiAxis1 2014-03-03 19:07:39 +00:00
Thomas Krijnen 05c98de100 Add parameterized profile test files and script to generate them 2014-02-23 11:25:35 +00:00
Thomas Krijnen 17f873b486 First stab at a new express parser to have some more luck with Ifc4 2014-02-17 22:13:55 +00:00
Thomas Krijnen 87259c0cab Bump version numbers 2014-01-12 11:03:50 +00:00
Thomas Krijnen 5615c70952 IfcBlender: Assign material ids to mesh polygons rather than to derived tessellation data which is not persistent 2014-01-05 09:50:30 +00:00
Thomas Krijnen 11b877f925 Update IfcJni for updated IfcGeomObjects interface 2014-01-03 14:08:25 +00:00
Thomas Krijnen 60963acd3f Ability to use OpenCOLLADA when building from CMake 2014-01-02 15:52:20 +00:00
Thomas Krijnen 7748a6ef0f Change some auto keywords into fully qualified type names to make it easier on some of the older compilers 2014-01-02 13:57:34 +00:00
Thomas Krijnen c47a43caf7 IfcGeomObjects: No longer implicitly turn off the availability of triangulated data when USE_BREP_DATA is set. Use DISABLE_TRIANGULATION to explicitly disable the generation of triangulated data to gain performance when only OCC brep data is needed. 2014-01-02 13:33:54 +00:00
Thomas Krijnen 3fa934a056 Fix from https://github.com/yorikvanhavre/IfcOpenShell/commit/1cd23609369d4f6165648a55c39ad268af9cae33 2014-01-01 11:14:39 +00:00
Thomas Krijnen 2bd37fd088 IfcConvert: Unit names and magnitudes + cosmetic fixes 2013-12-31 14:10:38 +00:00
Thomas Krijnen 6b2dc3683a IfcConvert: Propagate all settings from the command line to the IfcGeomObjects kernel 2013-12-27 09:39:20 +00:00
Thomas Krijnen 8653e59403 Cosmetic changes to IfcConvert 2013-12-27 09:37:51 +00:00
Thomas Krijnen 586ad14013 #28 USE_BREP_DATA setting does not respect CONVERT_BACK_UNITS setting 2013-12-27 09:36:14 +00:00
Thomas Krijnen 3c2cf1bb08 Fix for Collada export of transparency and material libraries 2013-12-27 09:33:57 +00:00
Thomas Krijnen 71b173a494 IfcOpenHouse: Don't use a single opening element to create multiple openings 2013-12-13 10:41:22 +00:00
Jang Myeongho 06958a02a4 Fix cmake install scripts.
- fix renamed file: "IfcShapeList.h" -> "IfcRepresentationShapeItem.h"
 - IfcImport target object file.
2013-12-11 03:17:05 +00:00
Thomas Krijnen 30804b4232 Support for surface styles, Multi/Sub-Object materials and material indices in the 3ds max importer 2013-12-08 09:45:14 +00:00
Thomas Krijnen 0f088f02b3 Improvements to Wavefront OBJ serialization, patch by Ivano Ras 2013-11-27 09:13:18 +00:00
Thomas Krijnen 9577778573 Fix for gcc thanks to Ivano Ras 2013-11-25 21:20:07 +00:00
Thomas Krijnen bffb19a92f Use the precision from the IfcGeometricRepresentationContext to dictate OCC modeler tolerances 2013-11-24 15:44:27 +00:00
Thomas Krijnen 0f53a877c7 Add file to test case execution 2013-11-24 14:51:04 +00:00
Thomas Krijnen bbf80bedaa Make .dae support in IfcConvert using OpenCOLLADA optional 2013-11-22 08:23:11 +00:00
Thomas Krijnen eb433ff8e2 Link to Boost.Program_options library from CMake 2013-11-22 08:04:32 +00:00
Thomas Krijnen 03beb42d2e Cosmetic changes 2013-08-12 00:26:15 +00:00
Thomas Krijnen 714bf5eb8d Add revit2014_multiple_bounded_halfspaces.ifc test file 2013-08-11 21:43:18 +00:00
Thomas Krijnen b4059cc340 Tweak processing of IfcBooleanClippingResult and IfcPolygonalBoundedHalfSpace 2013-08-09 05:13:02 +00:00
Thomas Krijnen 27962701b9 Use boost::variant for writable arguments in the IFC serializer 2013-08-04 04:49:08 +00:00
Thomas Krijnen 14a3f80c59 Correct a regression in matrix multiplication order 2013-07-20 22:12:40 +00:00
Thomas Krijnen 063f498066 Additional compatibility for std::tr1::array 2013-07-20 22:00:12 +00:00
Thomas Krijnen 2e0e5862f6 Fix for empty material list in the ColladaSerializer 2013-07-20 21:43:08 +00:00
Thomas Krijnen d6693ff931 Representation surface style initialization fix submitted by ckimmig 2013-07-20 21:41:26 +00:00
Thomas Krijnen 17ebefa158 Fix a bug in the processing of an IfcTrimmedCurve with an IfcLine as a basis constructed from an IfcVector with non-unit length. 2013-06-10 15:47:41 +00:00
Thomas Krijnen 12a0571bf4 Prefix array with tr1 to accomodate older compilers 2013-05-13 07:12:42 +00:00
Thomas Krijnen 1d1fd49608 Added missing files 2013-05-13 06:40:30 +00:00
Thomas Krijnen 259cfa895e Support for styled items in the Blender addon and make use of material indices 2013-05-11 17:14:47 +00:00
Thomas Krijnen 3f048efc79 Add an adapter for IfcGeom::SurfaceStyle so that IfcGeomObjects (and most notably the Python wrapper) need not to be aware of boost::optional
Expose shading and rendering styles to the Python wrapper as well
2013-05-11 15:26:35 +00:00
Thomas Krijnen dccbccfa06 A limited attempt at some const correctness in the IfcGeomObjects interface 2013-05-11 10:03:20 +00:00
Thomas Krijnen 80bc1b5dab [Work in progress] Start adding support for IfcSurfaceStyleShading and -Rendering 2013-05-05 08:49:25 +00:00
Thomas Krijnen 5d4ff0b54a First push of a more all-round geometrical file conversion utility 2013-03-24 10:48:39 +00:00
Thomas Krijnen 852cb7d8c4 Fix 3ds max API version detection 2013-01-13 12:01:20 +00:00
Thomas Krijnen 24b03330ef Update version numbers 2013-01-01 15:11:04 +00:00
Thomas Krijnen e4749147d6 Better Unicode handling in the 3ds max importer
Don't initiate progress handler until valid file is opened
2013-01-01 15:10:14 +00:00
Thomas Krijnen 4f26622e03 Do revert to unknown plane angle unit state after guessing when creating an IfcCompositeCurve 2012-12-31 15:48:04 +00:00
Thomas Krijnen 71b5cd12a8 - Getting ready for Blender 2.65 and Python 3.3.0 with universal Unicode according to PEP 393
- Allow opening of non-latin filenames on Windows, by using the non-standard _wfopen(), meaning that the IfcSpfStream no longer relies on a std::istream but a FILE* descriptor
2012-12-31 11:47:46 +00:00
Thomas Krijnen 6064ab0fa4 Disable building the QT Viewer from CMake 2012-12-18 12:18:52 +00:00
Thomas Krijnen 48e61cdcea Address an incompatibility in IfcOpenHouse.cpp introduced within OCCT 6.5.2 2012-12-18 12:17:35 +00:00
Thomas Krijnen a33fc19ed6 Add the LGPL license text supplement to the repository 2012-11-22 18:13:26 +00:00
Thomas Krijnen 578dce4a47 Provide more contextual information in the IFC SPF file header 2012-11-17 15:19:38 +00:00
Thomas Krijnen f1322996f0 Fixed a bug writing IFC files using ICU 2012-11-17 15:18:52 +00:00
Thomas Krijnen 2353c25fb8 - Handle explicit attributes re-declared as derived in a subtype
- Update IfcOpenHouse to import correctly in Autodesk Autocad Architecture 2013
2012-11-10 09:36:34 +00:00
Thomas Krijnen e56281a72e - Correctly format REALs according to ISO 10303-21 instead of C++ std::stream double formatting
- Add the IfcHierarchyHelper to assist in the creation of IFC files
- Add the IfcOpenHouse example for writing topological geometry and tessellated Open Cascade shapes to IFC
2012-11-04 16:26:33 +00:00
Thomas Krijnen db98906643 Add Boost as a required dependency in the CMake build file 2012-11-04 11:04:55 +00:00
Thomas Krijnen e729795da2 Add an option to disable the subtraction of IfcOpeningElements from relating building elements to the IfcGeomObject settings 2012-10-19 08:20:43 +00:00
Thomas Krijnen 8b11a1baf7 Correctly escape apostrophes in strings on write using the IfcCharacterEncoder 2012-10-09 19:54:35 +00:00
Thomas Krijnen 2f500aa098 IfcGeom: Use the 'wire creation tolerance' on point projection for trimmed curves
Fall back to trimming by parameter if possible and point projection fails
2012-09-16 12:49:55 +00:00
Thomas Krijnen 0814c16f06 Fix compilation errors of IfcCharacterEncoder in case ICU is not available 2012-09-16 12:45:44 +00:00
Thomas Krijnen cb6884b48e Encode characters outside the valid range for IFC SPF files and escape backslashes when writing IFC files 2012-09-09 11:55:53 +00:00
208 changed files with 108688 additions and 47676 deletions
+10
View File
@@ -0,0 +1,10 @@
# Dependency and build folders created by the build scripts
/deps*/
/build*/
/install*/
/win/BuildDepsCache*.txt
# IfcExpressParser residue
/src/ifcexpressparser/__pycache__
/src/ifcexpressparser/express_parser.py
# Python test residue
/test/__pycache__
+165
View File
@@ -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.
+118 -80
View File
@@ -1,26 +1,126 @@
IfcOpenShell
============
open source (LGPL) software library for working with the IFC file format
Open source (LGPL) software library for working with the IFC ([IFC2x3 TC1] and [IFC4]) file format.
[http://ifcopenshell.org](http://ifcopenshell.org)
[http://academy.ifcopenshell.org](http://academy.ifcopenshell.org)
http://IfcOpenShell.org
Prerequisites
=============
* Git, CMake (2.6 or newer), Visual Studio 2008 or newer with C++ toolset (Windows), or GCC (*nix, Clang untested).
About this repository
=====================
This is an initiative to expose the functionality of IfcOpenShell for parsing and writing IFC files to a Python interface. The creation of a topological representation for building elements using Open Cascade is also wrapped by returning a string serialization of the Open Cascade TopoDS_Shape. Using SWIG, a wrapper is obtained for a C++ Class which evaluates its Express attribute names at runtime. The functions created by the SWIG wrapper closely resemble the C++ structure. An additional Python wrapper around these functions is created that is more idiomatic to Python.
Dependencies
============
* [Boost](http://www.boost.org/)
* Open Cascade - *optional*, but required for building IfcGeom
([official](http://www.opencascade.org/getocc/download/loadocc/) or [community edition](https://github.com/tpaviot/oce))
For converting IFC representation items into BRep solids and tesselated meshes
* [ICU](http://site.icu-project.org/) - *optional*
For handling code pages and Unicode in the parser
* [OpenCOLLADA](https://github.com/khronosGroup/OpenCOLLADA/) - *optional*
For IfcConvert to be able to write tessellated Collada (.dae) files
* [SWIG](http://www.swig.org/), [Python](https://www.python.org/) libraries - *optional*
For building the IfcOpenShell Python interface and the Blender add-on
* 3ds Max SDK - *optional*
For building the 3ds Max plug-in
The following interactive session illustrates its use:
Compiling on Windows
====================
Users are advised to build IfcOpenShell using the CMake file provided in
the cmake/ folder.
The preferred way to fetch and build this project's dependencies is to use the build scripts
in win/ folder. **See [win/readme.md] for more information**. Instructions in a nutshell
(**assuming Visual Studio 2015 x64 environment variables set**):
> git clone https://github.com/IfcOpenShell/IfcOpenShell.git
> cd IfcOpenShell\win
> build-deps.cmd
> run-cmake.bat
You can now open and build the solution file in Visual Studio:
> ..\build-vs2015-x64\IfcOpenShell.sln
As the scripts default to using the `RelWithDebInfo` configuration, and a freshly created solution by CMake defaults
to `Debug`, make sure to switch the used build configuration. Build the `INSTALL` project (right-click -> Project
Only) to deploy the headers and binaries into a single location if wanted/needed.
Alternatively, one can use the utility batch files to build and install the project easily from the command-line:
> build-ifcopenshell.cmd
> install-ifcopenshell.cmd
Alternatively, the old Visual Studio solution and project files requiring manual work can
be found from the win/sln folder.
Compiling on *nix
=================
Users are advised to build IfcOpenShell using the CMake file provided in
the cmake/ folder. There might be an Open CASCADE package in your operating
system's software repository. If not, you will need to compile Open
CASCADE yourself. See http://opencascade.org.
For building the IfcPython wrapper, SWIG and Python development are
required.
Additionally, on Ubuntu (and possibly other linux flavors) the following steps
install some of the prerequisites:
$ sudo apt-get install git swig cmake gcc g++ libftgl-dev libtbb2 libtbb-dev libboost-all-dev libgl1-mesa-dev libfreetype6-dev
$ git clone https://github.com/tpaviot/oce.git
$ cd oce
$ mkdir build && cd build
$ cmake ..
$ make
$ sudo make install
To build IfcOpenShell please take the following steps:
$ cd /path/to/IfcOpenShell/cmake
$ mkdir build
$ cd build
Optionally:
$ OCC_INCLUDE_PATH="/path/to/OpenCASCADE/include"
$ OCC_LIBRARY_PATH="/path/to/OpenCASCADE/lib"
$ export OCC_INCLUDE_PATH
$ export OCC_LIBRARY_PATH
$ cmake ../
$ make
If all worked out correctly you can now use IfcOpenShell. See the examples below.
Usage examples
==============
**Invoking IfcConvert from the command line**
$ wget ftp://ftp.dds.no/pub/ifc/Munkerud/Munkerud_hus6_BE.zip
$ unzip Munkerud_hus6_BE.zip
$ ./IfcConvert Munkerud_hus6_BE.ifc
$ less Munkerud_hus6_BE.obj
**Using the IfcOpenShell Python interface**
$ wget -O duplex.zip http://projects.buildingsmartalliance.org/files/?artifact_id=4278
$ unzip duplex.zip
$ python
>>> import ifcopenshell
>>> f = ifcopenshell.open("Duplex_A_20110907_optimized.ifc")
>>>
>>> # Accessing entity instances by type:
>>> f.by_type("ifcwall")[:2]
[#91=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FL9r',#1,'Basic Wall:Interior - Partition (92mm Stud):144586',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5198,#18806,'144586'), #92=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FLIE',#1,'Basic Wall:Interior - Partition (92mm Stud):143921',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5206,#18805,'143921')]
>>> wall = _[0]
>>> brep_data = ifcopenshell.create_shape(wall, ifcopenshell.SEW_SHELLS)
>>> len(wall) # number of EXPRESS attributes
8
>>> wall.GlobalId
>>>
>>> # Accessing EXPRESS attributes by name:
>>> wall.GlobalId
'2O2Fr$t4X7Zf8NOew3FL9r'
>>> wall.Name = "My wall"
>>> wall.NonExistingAttr
@@ -42,8 +142,11 @@ The following interactive session illustrates its use:
File ".\ifc_wrapper.py", line 114, in _set_argument
def _set_argument(self, *args): return _ifc_wrapper.entity_instance__set_argument(self, *args)
RuntimeError: INT is not a valid type for 'GlobalId'
>>> # Creating new entity instances
>>> f.createIfcCartesianPoint(Coordinates=(1.0,1.5,2.0))
#27530=IfcCartesianPoint((1.,1.5,2.))
>>>
>>> # Working with GlobalId attributes:
>>> import uuid
>>> ifcopenshell.guid.compress(uuid.uuid1().hex)
'3x4C8Q_6qHuv$P$FYkANRX'
@@ -52,81 +155,16 @@ The following interactive session illustrates its use:
>>> new_wall = f.createIfcWallStandardCase(new_guid, owner_hist, None, None, Tag='my_tag')
>>> new_wall.ObjectType = ''
>>> new_wall.ObjectPlacement = new_wall.Representation = None
>>>
>>> # Accessing entity instances by instance id or GlobalId:
>>> f[92]
#92=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FLIE',#1,'Basic Wall:Interior - Partition (92mm Stud):143921',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5206,#18805,'143921')
>>> f['2O2Fr$t4X7Zf8NOew3FLIE']
#92=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FLIE',#1,'Basic Wall:Interior - Partition (92mm Stud):143921',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5206,#18805,'143921')
>>>
>>> # Writing IFC-SPF files to disk:
>>> f.write("out.ifc")
Compiling on Windows
====================
Users are advised to use the Visual Studio .sln file in the win/ folder.
For Windows users a prebuilt Open CASCADE version is available from the
http://opencascade.org website. Download and install this version and
provide the paths to the Open CASCADE header and library files to MS
Visual Studio C++.
For building the Autodesk 3ds Max plugin, the 3ds Max SDK needs to be
installed as well as 3ds Max itself. Please provide the include and
library paths to Visual Studio.
For building the IfcPython wrapper, SWIG needs to be installed. Please
download the latest swigwin version from http://www.swig.org/download.html.
After extracting the .zip file, please add the extracted folder to the PATH
environment variable. Python needs to be installed, please provide the
include and library paths to Visual Studio.
Compiling on *nix
====================
Users are advised to build IfcOpenShell using the cmake file provided in
the cmake/ folder. There might be an Open CASCADE package in your operating
system's software repository. If not, you will need to compile Open
CASCADE yourself. See http://opencascade.org.
For building the IfcPython wrapper, SWIG and Python development are
required.
To build IfcOpenShell please take the following steps:
$ cd /path/to/IfcOpenShell/cmake
$ mkdir build
$ cd build
Optionally:
$ OCC_INCLUDE_PATH="/path/to/OpenCASCADE/include"
$ OCC_LIBRARY_PATH="/path/to/OpenCASCADE/lib"
$ export OCC_INCLUDE_PATH
$ export OCC_LIBRARY_PATH
$ cmake ../
$ make
Ubuntu Notes
============
The following sequence of commands has been tested successfully on Ubuntu 14.04.
OCE installation. This step worked OK with cmake 2.8.12.2, gcc 4.8.2, g++ 4.8.2. Also, it might take up to an hour to complete.
apt-get install git cmake gcc g++ libftgl-dev libtbb2 libtbb-dev libboost-all-dev
cd /
mkdir git && cd git
git clone https://github.com/tpaviot/oce.git
mkdir oceBuild && cd oceBuild
cmake ../oce
make -j4
sudo make install
IfcOpenShell installation. This step worked OK with cmake 2.8.12.2, gcc 4.8.2, g++ 4.8.2.
apt-get install swig
cd /git/
git clone https://github.com/aothms/IfcOpenShell.git
cd IfcOpenShell/cmake
mkdir build && cd build
cmake ../
make -j4
Once done, IfcConvert is to be found in the build folder.
[win/readme.md]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/win/readme.md "win/readme.md"
[IFC2x3 TC1]: http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc2x3-tc1-release "IFC2x3 TC1"
[IFC4]: http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc4-release "IFC4"
+406 -173
View File
@@ -1,17 +1,90 @@
cmake_minimum_required (VERSION 2.6)
################################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
################################################################################
cmake_minimum_required (VERSION 2.8.5)
project (IfcOpenShell)
OPTION(UNICODE_SUPPORT "Build IfcOpenShell with Unicode support (requires ICU)." ON)
OPTION(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON)
OPTION(HDF5_SUPPORT "Enable HDF5 support (requires HDF5, zlib)" ON)
OPTION(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF)
#TODO OPTION(IFCCONVERT_DOUBLE_PRECISION "IfcConvert: Use double precision floating-point numbers." OFF)
OPTION(USE_IFC4 "Use IFC 4 instead of IFC 2x3 (full rebuild recommended when switching this)" OFF)
OPTION(BUILD_IFCPYTHON "Build IfcPython." ON)
OPTION(BUILD_EXAMPLES "Build example applications." ON)
OPTION(USE_VLD "Use Visual Leak Detector for debugging memory leaks, MSVC-only." OFF)
# TODO QtViewer is deprecated ATM as it uses the 0.4 API
# OPTION(BUILD_QTVIEWER "Build IfcOpenShell Qt GUI Viewer (requires Qt 4 framework)." OFF)
# Create cache entries if absent for environment variables
MACRO(UNIFY_ENVVARS_AND_CACHE VAR)
IF ((NOT DEFINED ${VAR}) AND (NOT "$ENV{${VAR}}" STREQUAL ""))
SET(${VAR} "$ENV{${VAR}}" CACHE STRING "${VAR}" FORCE)
ENDIF()
ENDMACRO()
UNIFY_ENVVARS_AND_CACHE(OCC_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(OCC_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(ICU_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(ICU_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(HDF5_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(HDF5_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(PCRE_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE)
# Find Boost
IF(MSVC)
SET(Boost_USE_STATIC_LIBS ON)
SET(Boost_USE_STATIC_RUNTIME ON)
SET(Boost_USE_MULTITHREADED ON)
ENDIF()
FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options)
MESSAGE(STATUS "Boost include files found in ${Boost_INCLUDE_DIRS}")
MESSAGE(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}")
# Find Open CASCADE header files
IF("$ENV{OCC_INCLUDE_DIR}" STREQUAL "")
# Usage:
# SET(SOME_LIRARIES foo bar)
# ADD_DEBUG_VARIANTS(SOME_LIRARIES "${SOME_LIRARIES}" "d")
# "foo bar" -> "optimized foo debug food optimized bar debug bard"
FUNCTION(ADD_DEBUG_VARIANTS NAME LIBRARIES POSTFIX)
SET(LIBRARIES_STR "${LIBRARIES}")
SET(LIBRARIES "")
FOREACH(lib ${LIBRARIES_STR})
SET(LIBRARIES "${LIBRARIES} optimized ${lib}")
SET(LIBRARIES "${LIBRARIES} debug ${lib}${POSTFIX}")
ENDFOREACH()
STRING(STRIP ${LIBRARIES} LIBRARIES) # leading and trailing whitespace cause confusion
SEPARATE_ARGUMENTS(LIBRARIES) # "optimized <lib> debug <lib>" needs to be a list instead of a string
SET(${NAME} ${LIBRARIES} PARENT_SCOPE)
ENDFUNCTION()
# Find Open CASCADE
IF("${OCC_INCLUDE_DIR}" STREQUAL "")
SET(OCC_INCLUDE_DIR "/usr/include/opencascade/" CACHE FILEPATH "Open CASCADE header files")
MESSAGE(STATUS "Looking for opencascade include files in: ${OCC_INCLUDE_DIR}")
MESSAGE(STATUS "Use OCC_INCLUDE_DIR to specify another directory")
ELSE()
SET(OCC_INCLUDE_DIR $ENV{OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files")
SET(OCC_INCLUDE_DIR ${OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files")
MESSAGE(STATUS "Looking for opencascade include files in: ${OCC_INCLUDE_DIR}")
ENDIF()
@@ -22,209 +95,369 @@ ELSE()
MESSAGE(FATAL_ERROR "Unable to find header files, aborting")
ENDIF()
# Find Open CASCADE library files
IF("$ENV{OCC_LIBRARY_DIR}" STREQUAL "")
SET(OPENCASCADE_LIBRARIES
TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO
TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset
)
IF(MSVC)
ADD_DEBUG_VARIANTS(OPENCASCADE_LIBRARIES "${OPENCASCADE_LIBRARIES}" "d")
ENDIF()
IF("${OCC_LIBRARY_DIR}" STREQUAL "")
SET(OCC_LIBRARY_DIR "/usr/lib/" CACHE FILEPATH "Open CASCADE library files")
MESSAGE(STATUS "Looking for opencascade library files in: ${OCC_LIBRARY_DIR}")
MESSAGE(STATUS "Use OCC_LIBRARY_DIR to specify another directory")
ELSE()
SET(OCC_LIBRARY_DIR $ENV{OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files")
SET(OCC_LIBRARY_DIR ${OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files")
MESSAGE(STATUS "Looking for opencascade library files in: ${OCC_LIBRARY_DIR}")
ENDIF()
FIND_LIBRARY(libTKernel "TKernel" ${OCC_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64)
FIND_LIBRARY(libTKernel NAMES TKernel TKerneld PATHS ${OCC_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64)
IF(libTKernel)
MESSAGE(STATUS "Library files found")
ELSE()
MESSAGE(FATAL_ERROR "Unable to find library files, aborting")
ENDIF()
IF("$ENV{ICU_INCLUDE_DIR}" STREQUAL "")
MESSAGE(STATUS "No ICU include directory specified")
ElSE()
SET(ICU_INCLUDE_DIR CACHE FILEPATH "ICU header files")
IF(UNICODE_SUPPORT)
# Find ICU
IF("${ICU_INCLUDE_DIR}" STREQUAL "")
MESSAGE(STATUS "No ICU include directory specified")
ElSE()
SET(ICU_INCLUDE_DIR "${ICU_INCLUDE_DIR}" CACHE FILEPATH "ICU header files")
ENDIF()
IF("${ICU_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No ICU library directory specified")
ElSE()
SET(ICU_LIBRARY_DIR "${ICU_LIBRARY_DIR}" CACHE FILEPATH "ICU library files")
ENDIF()
FIND_LIBRARY(icu NAMES icuuc icuucd PATHS /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR})
IF(icu)
ADD_DEFINITIONS(-DHAVE_ICU)
MESSAGE(STATUS "ICU libraries found")
# NOTE icudata appears to be icudt on Windows/MSVC and icudata on others
# dl is included to resolve dlopen and friends symbols
IF(MSVC)
SET(ICU_LIBRARIES icuuc icudt)
ADD_DEBUG_VARIANTS(ICU_LIBRARIES "${ICU_LIBRARIES}" "d")
ADD_DEFINITIONS(-DU_STATIC_IMPLEMENTATION) # required for static ICU
ELSE()
SET(ICU_LIBRARIES icuuc icudata dl)
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR "UNICODE_SUPPORT enabled, but unable to find ICU. Disable UNICODE_SUPPORT or fix ICU paths to proceed.")
ENDIF()
ENDIF()
IF("$ENV{ICU_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No ICU library directory specified")
ElSE()
SET(ICU_LIBRARY_DIR CACHE FILEPATH "ICU library files")
IF(COLLADA_SUPPORT)
# Find OpenCOLLADA
IF("${OPENCOLLADA_INCLUDE_DIR}" STREQUAL "")
MESSAGE(STATUS "No OpenCOLLADA include directory specified")
SET(OPENCOLLADA_INCLUDE_DIR "/usr/local/include/opencollada" CACHE FILEPATH "OpenCOLLADA header files")
ElSE()
SET(OPENCOLLADA_INCLUDE_DIR "${OPENCOLLADA_INCLUDE_DIR}" CACHE FILEPATH "OpenCOLLADA header files")
ENDIF()
IF("${OPENCOLLADA_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No OpenCOLLADA library directory specified")
SET(OPENCOLLADA_LIBRARY_DIR "/usr/local/lib/opencollada" CACHE FILEPATH "OpenCOLLADA library files")
ElSE()
SET(OPENCOLLADA_LIBRARY_DIR "${OPENCOLLADA_LIBRARY_DIR}" CACHE FILEPATH "OpenCOLLADA library files")
ENDIF()
SET(OPENCOLLADA_INCLUDE_DIRS "${OPENCOLLADA_INCLUDE_DIR}/COLLADABaseUtils" "${OPENCOLLADA_INCLUDE_DIR}/COLLADAStreamWriter")
FIND_FILE(COLLADASWStreamWriter_h "COLLADASWStreamWriter.h" ${OPENCOLLADA_INCLUDE_DIRS})
IF(COLLADASWStreamWriter_h)
MESSAGE(STATUS "OpenCOLLADA header files found")
ADD_DEFINITIONS(-DWITH_OPENCOLLADA)
SET(OPENCOLLADA_LIBRARIES
GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader
OpenCOLLADAStreamWriter UTF buffer ftoa pcre
)
IF(NOT "${PCRE_LIBRARY_DIR}" STREQUAL "")
SET(OPENCOLLADA_LIBRARY_DIR ${OPENCOLLADA_LIBRARY_DIR} ${PCRE_LIBRARY_DIR})
ENDIF()
IF(MSVC)
ADD_DEBUG_VARIANTS(OPENCOLLADA_LIBRARIES "${OPENCOLLADA_LIBRARIES}" "d")
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find OpenCOLLADA. Disable COLLADA_SUPPORT or fix OpenCOLLADA paths to proceed.")
ENDIF()
ENDIF()
FIND_LIBRARY(icu "icuuc" /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR})
if(HDF5_SUPPORT)
IF("${HDF5_INCLUDE_DIR}" STREQUAL "")
MESSAGE(STATUS "No HDF5 include directory specified")
ElSE()
SET(HDF5_INCLUDE_DIR "${HDF5_INCLUDE_DIR}" CACHE FILEPATH "HDF5 header files")
ENDIF()
IF("${HDF5_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No HDF5 library directory specified")
ElSE()
SET(HDF5_LIBRARY_DIR "${HDF5_LIBRARY_DIR}" CACHE FILEPATH "HDF5 library files")
ENDIF()
IF(WIN32)
# An additional lib- prefix is added by HDF5 to denote static libraries
SET(HDF5_LIBRARIES libhdf5_cpp libhdf5 libzlib)
ELSE()
SET(HDF5_LIBRARIES hdf5_cpp hdf5 z szip)
ENDIF()
endif()
IF(icu)
MESSAGE(STATUS "ICU libraries found")
ADD_DEFINITIONS(-DHAVE_ICU)
ELSE()
MESSAGE(STATUS "Unable to find ICU library files, continuing")
# TODO Are these needed on other platforms still or can these be removed for good?
IF (NOT WIN32)
INCLUDE(CheckIncludeFileCXX)
MACRO(CHECK_ADD_OCE_OCC_DEF INCLUDE)
STRING(REPLACE . _ STR ${INCLUDE})
STRING(TOUPPER ${STR} STR)
CHECK_INCLUDE_FILE_CXX("${INCLUDE}" FOUND_${STR})
IF(FOUND_${STR})
ADD_DEFINITIONS(-DOCE_HAVE_${STR})
ADD_DEFINITIONS(-DHAVE_${STR})
ENDIF(FOUND_${STR})
ENDMACRO()
CHECK_ADD_OCE_OCC_DEF(limits)
CHECK_ADD_OCE_OCC_DEF(climits)
CHECK_ADD_OCE_OCC_DEF(limits.h)
CHECK_ADD_OCE_OCC_DEF(fstream)
CHECK_ADD_OCE_OCC_DEF(fstream.h)
CHECK_ADD_OCE_OCC_DEF(iomanip)
CHECK_ADD_OCE_OCC_DEF(iomanip.h)
CHECK_ADD_OCE_OCC_DEF(iostream)
CHECK_ADD_OCE_OCC_DEF(iostream.h)
ENDIF()
IF("$ENV{OPENCOLLADA_INCLUDE_DIR}" STREQUAL "")
MESSAGE(STATUS "No OpenCOLLADA include directory specified")
SET(OPENCOLLADA_INCLUDE_DIR "/usr/local/include/opencollada" CACHE FILEPATH "OpenCOLLADA header files")
ElSE()
SET(OPENCOLLADA_INCLUDE_DIR "$ENV{OPENCOLLADA_INCLUDE_DIR}" CACHE FILEPATH "OpenCOLLADA header files")
ENDIF()
IF("$ENV{OPENCOLLADA_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No OpenCOLLADA library directory specified")
SET(OPENCOLLADA_LIBRARY_DIR "/usr/local/lib/opencollada" CACHE FILEPATH "OpenCOLLADA library files")
ElSE()
SET(OPENCOLLADA_LIBRARY_DIR "$ENV{OPENCOLLADA_LIBRARY_DIR}" CACHE FILEPATH "OpenCOLLADA library files")
ENDIF()
SET(OPENCOLLADA_INCLUDE_DIRS "${OPENCOLLADA_INCLUDE_DIR}/COLLADABaseUtils" "${OPENCOLLADA_INCLUDE_DIR}/COLLADAStreamWriter")
FIND_FILE(COLLADASWStreamWriter_h "COLLADASWStreamWriter.h" ${OPENCOLLADA_INCLUDE_DIRS})
IF(COLLADASWStreamWriter_h)
MESSAGE(STATUS "OpenCOLLADA header files found")
ADD_DEFINITIONS(-DWITH_OPENCOLLADA)
SET(OPENCOLLADA_LIBRARIES
GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils
OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader
OpenCOLLADAStreamWriter UTF buffer ftoa pcre
)
ELSE()
MESSAGE(STATUS "OpenCOLLADA header files not found, continuing without COLLADA support")
ENDIF()
INCLUDE(CheckIncludeFileCXX)
MACRO(CHECK_ADD_OCE_OCC_DEF INCLUDE)
STRING(REPLACE . _ STR ${INCLUDE})
STRING(TOUPPER ${STR} STR)
CHECK_INCLUDE_FILE_CXX("${INCLUDE}" FOUND_${STR})
IF(FOUND_${STR})
ADD_DEFINITIONS(-DOCE_HAVE_${STR})
ADD_DEFINITIONS(-DHAVE_${STR})
ENDIF(FOUND_${STR})
ENDMACRO(CHECK_ADD_OCE_OCC_DEF)
CHECK_ADD_OCE_OCC_DEF(limits)
CHECK_ADD_OCE_OCC_DEF(climits)
CHECK_ADD_OCE_OCC_DEF(limits.h)
CHECK_ADD_OCE_OCC_DEF(fstream)
CHECK_ADD_OCE_OCC_DEF(fstream.h)
CHECK_ADD_OCE_OCC_DEF(iomanip)
CHECK_ADD_OCE_OCC_DEF(iomanip.h)
CHECK_ADD_OCE_OCC_DEF(iostream)
CHECK_ADD_OCE_OCC_DEF(iostream.h)
IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE "Release")
ENDIF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE "Release")
ENDIF()
# NOTE: RelWithDebInfo and Release use O2 (= /Ox /Gl /Gy/ = Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy) by default,
# with the exception with RelWithDebInfo has /Ob1 instead. /Ob2 has been observed to improve the performance
# of IfcConvert significantly.
# TODO Setting of /GL and /LTCG don't seem to apply for static libraries (IfcGeom, IfcParse)
if(ENABLE_BUILD_OPTIMIZATIONS)
if(MSVC)
# C++
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /GL")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
# Linker
# /OPT:REF enables also /OPT:ICF and disables INCREMENTAL
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
# /OPT:NOICF is recommended when /DEBUG is used (http://msdn.microsoft.com/en-us/library/xe4t6fc1.aspx)
set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
else()
#TODO GCC (& Clang?) optimizations
message(STATUS "ENABLE_BUILD_OPTIMIZATIONS not implemented for GCC/non-MSVC compilers.)")
endif()
endif()
IF(MSVC)
ADD_DEFINITIONS(-D_UNICODE)
ElSE(MSVC)
ADD_DEFINITIONS(-fPIC -Wno-non-virtual-dtor)
ENDIF(MSVC)
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} /usr/inc /usr/local/inc /usr/local/include/oce ${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS})
ADD_LIBRARY(IfcParse STATIC
../src/ifcparse/Ifc2x3.cpp
../src/ifcparse/Ifc4.cpp
../src/ifcparse/IfcUtil.cpp
../src/ifcparse/IfcParse.cpp
../src/ifcparse/IfcCharacterDecoder.cpp
../src/ifcparse/IfcWrite.cpp
../src/ifcparse/IfcGuidHelper.cpp
../src/ifcparse/IfcHierarchyHelper.cpp
../src/ifcparse/Ifc2x3-rt.cpp
../src/ifcparse/Ifc4-rt.cpp
../src/ifcparse/IfcUntypedEntity.cpp
)
ADD_LIBRARY(IfcGeom STATIC
../src/ifcgeom/IfcGeomCurves.cpp
../src/ifcgeom/IfcGeomFaces.cpp
../src/ifcgeom/IfcGeomFunctions.cpp
../src/ifcgeom/IfcGeomHelpers.cpp
../src/ifcgeom/IfcGeomObjects.cpp
../src/ifcgeom/IfcGeomRenderStyles.cpp
../src/ifcgeom/IfcGeomShapes.cpp
../src/ifcgeom/IfcGeomWires.cpp
../src/ifcgeom/IfcRegister.cpp
)
IF(icu)
TARGET_LINK_LIBRARIES(IfcParse icuuc)
IF(USE_VLD)
ADD_DEFINITIONS(-DUSE_VLD)
ENDIF()
# Enforce Unicode for CRT and Win32 API calls
ADD_DEFINITIONS(-D_UNICODE -DUNICODE)
# Disable warnings about unsafe C functions; we could use the safe C99 & C11 versions if we have no need for supporting old compilers.
ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS)
ADD_DEFINITIONS(-bigobj) # required for building the big ifcXXX.objs, https://msdn.microsoft.com/en-us/library/ms173499.aspx
# Bump up the warning level from the default 3 to 4.
ADD_DEFINITIONS(-W4)
IF(MSVC_VERSION GREATER 1800) # > 2013
# Disable overeager and false positives causing C4458 ("declaration of 'indentifier' hides class member"), at least for now.
ADD_DEFINITIONS(-wd4458)
ENDIF()
# Link against the static VC runtime
FOREACH(flag CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL
CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
IF(${flag} MATCHES "/MD")
STRING(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}")
ENDIF()
IF(${flag} MATCHES "/MDd")
STRING(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}")
ENDIF()
ENDFOREACH()
ElSE()
ADD_DEFINITIONS(-fPIC -Wno-non-virtual-dtor)
ENDIF()
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS}
${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${HDF5_INCLUDE_DIR}
)
if(NOT WIN32)
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} /usr/inc /usr/local/inc /usr/local/include/oce)
endif()
function(files_for_ifc_version IFC_VERSION RESULT_NAME)
set(IFC_PARSE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcparse)
set(${RESULT_NAME}
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.h
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}enum.h
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}-latebound.h
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.cpp
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}-latebound.cpp
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}-schema.cpp
PARENT_SCOPE
)
endfunction()
if(COMPILE_SCHEMA)
find_package(PythonInterp)
IF(NOT PYTHONINTERP_FOUND)
MESSAGE(FATAL_ERROR "A Python interpreter is necessary when COMPILE_SCHEMA is enabled. Disable COMPILE_SCHEMA or fix Python paths to proceed.")
ENDIF()
set(IFC_RELEASE_NOT_USED "2x3" "4")
# Install pyparsing if necessary
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST)
if ("${PYTHON_PACKAGE_LIST}" STREQUAL "")
execute_process(COMMAND pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST)
if ("${PYTHON_PACKAGE_LIST}" STREQUAL "")
message(WARNING "Failed to find pip. Pip is required to automatically install pyparsing")
endif()
endif()
string(FIND "${PYTHON_PACKAGE_LIST}" pyparsing PYPARSING_FOUND)
if ("${PYPARSING_FOUND}" STREQUAL "-1")
message(STATUS "Installing pyparsing")
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip "install" --user pyparsing RESULT_VARIABLE SUCCESS)
if (NOT "${SUCCESS}" STREQUAL "0")
execute_process(COMMAND pip "install" --user pyparsing RESULT_VARIABLE SUCCESS)
if (NOT "${SUCCESS}" STREQUAL "0")
message(WARNING "Failed to automatically install pyparsing. Please install manually")
endif()
endif()
else()
message(STATUS "Python interpreter with pyparsing found")
endif()
# Bootstrap the parser
message(STATUS "Compiling schema, this will take a while...")
execute_process(COMMAND ${PYTHON_EXECUTABLE} bootstrap.py express.bnf
WORKING_DIRECTORY ../src/ifcexpressparser
OUTPUT_FILE express_parser.py
RESULT_VARIABLE SUCCESS)
if (NOT "${SUCCESS}" STREQUAL "0")
MESSAGE(FATAL_ERROR "Failed to bootstrap parser. Make sure pyparsing is installed")
endif()
# Generate code
execute_process(COMMAND ${PYTHON_EXECUTABLE} ../ifcexpressparser/express_parser.py ../../${COMPILE_SCHEMA}
WORKING_DIRECTORY ../src/ifcparse
OUTPUT_VARIABLE COMPILED_SCHEMA_NAME)
# Prevent the schema that had just been compiled from being excluded
if("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC2X3")
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "2x3")
add_definitions(-DUSE_IFC2x3)
elseif("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC4")
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "4")
add_definitions(-DUSE_IFC4)
endif()
else()
if(USE_IFC4)
add_definitions(-DUSE_IFC4)
set(IFC_RELEASE_NOT_USED "2x3")
else()
add_definitions(-DUSE_IFC2x3) # TODO Make all caps? i.e. USE_IFC2X3
set(IFC_RELEASE_NOT_USED "4")
endif()
endif()
# IfcParse
file(GLOB IFCPARSE_H_FILES ../src/ifcparse/*.h)
file(GLOB IFCPARSE_CPP_FILES ../src/ifcparse/*.cpp)
foreach(IFC_RELEASE ${IFC_RELEASE_NOT_USED})
files_for_ifc_version(${IFC_RELEASE} SOURCE_FILES_NOT_USED)
foreach(SOURCE_FILE ${SOURCE_FILES_NOT_USED})
list(REMOVE_ITEM IFCPARSE_CPP_FILES ${SOURCE_FILE})
list(REMOVE_ITEM IFCPARSE_H_FILES ${SOURCE_FILE})
endforeach()
endforeach()
set(IFCPARSE_FILES ${IFCPARSE_CPP_FILES} ${IFCPARSE_H_FILES})
ADD_LIBRARY(IfcParse STATIC ${IFCPARSE_FILES})
IF(UNICODE_SUPPORT)
TARGET_LINK_LIBRARIES(IfcParse ${ICU_LIBRARIES})
ENDIF()
if(HDF5_SUPPORT)
TARGET_LINK_LIBRARIES(IfcParse ${HDF5_LIBRARIES})
endif()
# IfcGeom
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/*.h)
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp)
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES})
ADD_LIBRARY(IfcGeom STATIC ${IFCGEOM_FILES})
TARGET_LINK_LIBRARIES(IfcGeom IfcParse)
LINK_DIRECTORIES (${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} ${OPENCOLLADA_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS})
ADD_EXECUTABLE(IfcConvert
../src/ifcconvert/ColladaSerializer.cpp
../src/ifcconvert/IfcConvert.cpp
../src/ifcconvert/OpenCascadeBasedSerializer.cpp
../src/ifcconvert/WavefrontObjSerializer.cpp
LINK_DIRECTORIES(${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} ${OPENCOLLADA_LIBRARY_DIR}
${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS} ${HDF5_LIBRARY_DIR}
)
if(NOT WIN32)
LINK_DIRECTORIES(${LINK_DIRECTORIES} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64)
endif()
TARGET_LINK_LIBRARIES (IfcConvert IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES})
file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp)
file(GLOB IFCCONVERT_H_FILES ../src/ifcconvert/*.h)
set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES})
ADD_EXECUTABLE(IfcConvert ${IFCCONVERT_FILES})
ADD_EXECUTABLE(IfcGeomServer
../src/ifcgeomserver/IfcGeomServer.cpp
)
# Make sure cross-referenced symbols between static OCC libraries get
# resolved. Also add thread and rt libraries.
get_filename_component(libTKernelExt ${libTKernel} EXT)
if("${libTKernelExt}" STREQUAL ".a")
find_package(Threads)
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} rt dl)
endif()
TARGET_LINK_LIBRARIES (IfcGeomServer IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset)
TARGET_LINK_LIBRARIES(IfcConvert IfcParse IfcGeom ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${ICU_LIBRARIES})
# Build python wrapper using separate CMakeLists.txt
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
# IfcGeomServer
file(GLOB CPP_FILES ../src/ifcgeomserver/*.cpp)
file(GLOB H_FILES ../src/ifcgeomserver/*.h)
set(SOURCE_FILES ${CPP_FILES} ${H_FILES})
ADD_EXECUTABLE(IfcGeomServer ${SOURCE_FILES})
# Build IfcParseExamples using separate CMakeLists.txt
ADD_SUBDIRECTORY(../src/examples examples)
TARGET_LINK_LIBRARIES(IfcGeomServer IfcParse IfcGeom ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBRARIES})
# ADD_SUBDIRECTORY(../src/qtviewer qtviewer)
IF(BUILD_IFCPYTHON)
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
ENDIF()
# CMake installation targets
SET(include_files_geom
../src/ifcgeom/IfcGeom.h
../src/ifcgeom/IfcGeomObjects.h
../src/ifcgeom/IfcGeomRenderStyles.h
../src/ifcgeom/IfcRegister.h
../src/ifcgeom/IfcRegisterConvertCurve.h
../src/ifcgeom/IfcRegisterConvertFace.h
../src/ifcgeom/IfcRegisterConvertShape.h
../src/ifcgeom/IfcRegisterConvertShapes.h
../src/ifcgeom/IfcRegisterConvertWire.h
../src/ifcgeom/IfcRegisterCreateCache.h
../src/ifcgeom/IfcRegisterDef.h
../src/ifcgeom/IfcRegisterGeomHeader.h
../src/ifcgeom/IfcRegisterIsShapeCollection.h
../src/ifcgeom/IfcRegisterPurgeCache.h
../src/ifcgeom/IfcRegisterUndef.h
../src/ifcgeom/IfcGeomRenderStyles.h
../src/ifcgeom/IfcRepresentationShapeItem.h
)
SET(include_files_parse
../src/ifcparse/Ifc2x3.h
../src/ifcparse/Ifc2x3enum.h
../src/ifcparse/Ifc4.h
../src/ifcparse/Ifc4enum.h
../src/ifcparse/IfcCharacterDecoder.h
../src/ifcparse/IfcException.h
../src/ifcparse/IfcFile.h
../src/ifcparse/IfcHierarchyHelper.h
../src/ifcparse/IfcParse.h
../src/ifcparse/IfcUtil.h
../src/ifcparse/SharedPointer.h
IF(BUILD_EXAMPLES)
ADD_SUBDIRECTORY(../src/examples examples)
ENDIF()
IF(HDF5_SUPPORT)
ADD_SUBDIRECTORY(../src/hdf5_usecases hdf5_usecases)
ENDIF()
if(NOT MSVC)
add_definitions(-std=c++14)
endif()
../src/ifcparse/IfcWrite.h
../src/ifcparse/IfcWritableEntity.h
../src/ifcparse/Ifc2x3-rt.h
../src/ifcparse/Ifc4-rt.h
../src/ifcparse/IfcUntypedEntity.h
../src/ifcparse/IfcEntityDescriptor.h
)
INSTALL(FILES ${include_files_geom} DESTINATION include/ifcgeom)
INSTALL(FILES ${include_files_parse} DESTINATION include/ifcparse)
INSTALL(TARGETS IfcConvert DESTINATION bin)
# CMake installation targets
INSTALL(FILES ${IFCPARSE_H_FILES} DESTINATION include/ifcparse)
INSTALL(FILES ${IFCGEOM_H_FILES} DESTINATION include/ifcgeom)
INSTALL(TARGETS IfcConvert IfcGeomServer DESTINATION bin)
INSTALL(TARGETS IfcParse IfcGeom DESTINATION lib)
+372
View File
@@ -0,0 +1,372 @@
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
###############################################################################
# #
# This script builds IfcOpenShell and its dependencies #
# #
# Prerequisites for this script to function correctly: #
# * git * bzip2 * tar * c(++) compilers * yacc * autoconf #
# on debian 7.8 these can be obtained with: #
# $ apt-get install git bzip2 bizon autoconf gcc g++ #
# #
###############################################################################
set -e
PROJECT_NAME=IfcOpenShell
OCE_VERSION=0.16
PYTHON_VERSIONS=(2.7.9 3.3.6 3.4.2)
BOOST_VERSION=1.55.0
PCRE_VERSION=8.38
LIBXML_VERSION=2.9.3
CMAKE_VERSION=3.4.1
ICU_VERSION=56.1
# Helper function for coloured printing
BLACK_ON_WHITE="\033[0;30;107m"
RED="\033[31m"
GREEN="\033[32m"
YELLOW="\033[33m"
MAGENTA="\033[35m"
function cecho {
printf "$1$2\033[0m\n"
}
# Set defaults for missing empty environment variables
if [ -z "$IFCOS_NUM_BUILD_PROCS" ]; then
IFCOS_NUM_BUILD_PROCS=$(expr $(sysctl -n hw.ncpu 2> /dev/null || cat /proc/cpuinfo | grep processor | wc -l) + 1)
fi
if [ -z "$TARGET_ARCH" ]; then
TARGET_ARCH="$(uname -m)"
fi
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
CMAKE_DIR="$SCRIPT_DIR/../../cmake/"
if [ -z "$DEPS_DIR" ]; then
DEPS_DIR="$SCRIPT_DIR/../../build/$(uname)/"
[ -d $DEPS_DIR ] || mkdir -p $DEPS_DIR
DEPS_DIR=`readlink -f $DEPS_DIR`
fi
if [ -z "$BUILD_CFG" ]; then
BUILD_CFG="RelWithDebInfo"
fi
if [ -z "$BUILD_TYPE" ]; then
BUILD_TYPE=Build
fi
# Print build configuration information
cecho $BLACK_ON_WHITE "This script fetches and builds $PROJECT_NAME and its dependencies"
echo ""
cecho $GREEN "Script configuration:"
cecho $MAGENTA "* Target Architecture = $TARGET_ARCH"
echo " - Whether 32-bit (i686) or 64-bit (x86_64) will be built."
cecho $MAGENTA "* Dependency Directory = $DEPS_DIR"
echo " - The directory where $PROJECT_NAME dependencies are installed."
cecho $MAGENTA "* Build Config Type = $BUILD_CFG"
echo " - The used build configuration type for the dependencies."
echo " Defaults to RelWithDebInfo if not specified."
if [ "$BUILD_CFG" = "MinSizeRel" ]; then
cecho $RED " WARNING: MinSizeRel build can suffer from a significant performance loss."
fi
cecho $MAGENTA "* IFCOS_NUM_BUILD_PROCS = $IFCOS_NUM_BUILD_PROCS"
echo " - How many compiler processes may be run in parallel."
echo ""
# Check that required tools are in PATH
for cmd in git bunzip2 tar cc c++ autoconf yacc
do
which $cmd > /dev/null || { cecho $RED "Required tool '$cmd' not installed or not added to PATH" ; exit 1 ; }
done
which curl > /dev/null && DOWNLOAD="curl -sLO"
which wget > /dev/null && DOWNLOAD="wget -q --no-check-certificate"
if [ -z "$DOWNLOAD" ]; then
cecho $RED "No download application found, tried: curl, wget"
exit 1
fi
# Create log directory and file
mkdir -p $DEPS_DIR/logs
LOG_FILE=$DEPS_DIR/logs/`date +"%Y%m%d"`.log
BOOST_VERSION_UNDERSCORE=${BOOST_VERSION//./_}
ICU_VERSION_UNDERSCORE=${ICU_VERSION//./_}
CMAKE_VERSION_2=${CMAKE_VERSION:0:3}
OCE_LOCATION=https://github.com/tpaviot/oce/archive/OCE-$OCE_VERSION.tar.gz
BOOST_LOCATION=http://downloads.sourceforge.net/project/boost/boost/$BOOST_VERSION/boost_$BOOST_VERSION_UNDERSCORE.tar.bz2
OPENCOLLADA_LOCATION=https://github.com/KhronosGroup/OpenCOLLADA.git
OPENCOLLADA_COMMIT=f99d59e73e565a41715eaebc00c7664e1ee5e628
# Helper functions
function download {
[ -f $2 ] || $DOWNLOAD $1$2
}
function run_autoconf {
if [ ! -f configure ]; then
pushd . >>$LOG_FILE 2>&1
cd ..
./autogen.sh >>$LOG_FILE 2>&1
popd >>$LOG_FILE 2>&1
fi
../configure $2 --prefix=$DEPS_DIR/install/$1 >>$LOG_FILE 2>&1
}
function run_cmake {
if [ -z "$3" ]; then
P=..
else
P=$3
fi
$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake $P $2 -DCMAKE_BUILD_TYPE=$BUILD_TYPE >>$LOG_FILE 2>&1
}
function run_icu {
PLATFORM=`uname -s`
if [ $PLATFORM == "Darwin" ]; then
PLATFORM=MacOSX
fi
../source/runConfigureICU $PLATFORM $2 --prefix=$DEPS_DIR/install/$1 >>$LOG_FILE 2>&1
}
function git_clone {
[ -d $2 ] || git clone $1 >>$LOG_FILE 2>&1
if [ ! -z "$3" ]; then
cd $2
git checkout $3
cd ..
fi
}
function build_dependency {
if [ -e $DEPS_DIR/install/$1 ]; then
echo "Found existing $1"
return
fi
mkdir -p $DEPS_DIR/build/
cd $DEPS_DIR/build/
printf "\rFetching $1... "
$6 $4 $5 $7
if [ -d $5 ]; then
DEP_NAME=$5
else
DEP_NAME=`tar --exclude="*/*" -tf $5`
[ -z $DEP_NAME ] && DEP_NAME=`tar -tf $5 2> /dev/null | head -n 1 | cut -f1 -d /`
[ -d $DEP_NAME ] || tar -xf $5
fi
cd $DEP_NAME
if [ "$2" != "bjam" ]; then
[ -d build ] && rm -rf build
mkdir build
cd build
printf "\rConfiguring $1..."
run_$2 $1 "$3"
printf "\rBuilding $1... "
make -j$IFCOS_NUM_BUILD_PROCS >>$LOG_FILE 2>&1
printf "\rInstalling $1... "
make install >>$LOG_FILE 2>&1
printf "\rInstalled $1 \n"
else
printf "\rConfiguring $1..."
./bootstrap.sh >>$LOG_FILE 2>&1
printf "\rBuilding $1... "
./b2 $3 >>$LOG_FILE 2>&1
printf "\rInstalling $1... "
cp -R boost $DEPS_DIR/install/boost-$BOOST_VERSION/ >>$LOG_FILE 2>&1
printf "\rInstalled $1 \n"
fi
}
cecho $GREEN "Collecting dependencies:"
# Set compiler flags for 32bit builds on 64bit system
if [ "$TARGET_ARCH" == "i686" ] && [ "$(uname -m)" == "x86_64" ]; then
ADDITIONAL_ARGS="-m32 -arch i386"
fi
if [ "$(uname)" == "Darwin" ]; then
ADDITIONAL_ARGS="-macosx_version_min 10.6 $ADDITIONAL_ARGS"
fi
# If the linker supports GC sections, set it up to reduce binary file size
# -fPIC is required for the shared libraries to work
if man ld 2> /dev/null | grep gc-sections &> /dev/null; then
export CXXFLAGS="$CXXFLAGS -fPIC -fdata-sections -ffunction-sections -fvisibility=hidden -fvisibility-inlines-hidden $ADDITIONAL_ARGS"
export CFLAGS="$CFLAGS -fPIC -fdata-sections -ffunction-sections -fvisibility=hidden $ADDITIONAL_ARGS"
export LDFLAGS="$LDFLAGS -Wl,--gc-sections $ADDITIONAL_ARGS"
export CXXFLAGS_MINIMAL="$CXXFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
export CFLAGS_MINIMAL="$CFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
else
export CXXFLAGS="$CXXFLAGS -fPIC -fvisibility=hidden -fvisibility-inlines-hidden $ADDITIONAL_ARGS"
export CFLAGS="$CFLAGS -fPIC -fvisibility=hidden -fvisibility-inlines-hidden $ADDITIONAL_ARGS"
export LDFLAGS="$LDFLAGS -s -death_code $ADDITIONAL_ARGS"
export CXXFLAGS_MINIMAL="$CXXFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
export CFLAGS_MINIMAL="$CFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
fi
# Some dependencies need a more recent CMake version than most distros provide
build_dependency cmake-$CMAKE_VERSION autoconf "" https://cmake.org/files/v$CMAKE_VERSION_2/ cmake-$CMAKE_VERSION.tar.gz download
# Extract compiler flags from CMake to harmonize settings with other autoconf dependencies
CMAKE_FLAG_EXTRACT_DIR=ifcopenshell_cmake_test_`cat /dev/urandom | env LC_CTYPE=C tr -dc 'a-zA-Z0-9' | head -c 32`
[ -e $CMAKE_FLAG_EXTRACT_DIR ] && rm -rf $CMAKE_FLAG_EXTRACT_DIR
mkdir $CMAKE_FLAG_EXTRACT_DIR
cd $CMAKE_FLAG_EXTRACT_DIR
BUILD_CFG_UPPER=${BUILD_CFG^^}
for FL in C CXX LD; do
echo "
message(\"\${CMAKE_${FL}_FLAGS_${BUILD_CFG_UPPER}}\")
" > CMakeLists.txt
declare ${FL}FLAGS="`$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake . 2>&1 >/dev/null`"
declare ${FL}FLAGS_MINIMAL="`$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake . 2>&1 >/dev/null`"
done
cd ..
rm -rf $CMAKE_FLAG_EXTRACT_DIR
build_dependency pcre-$PCRE_VERSION autoconf "--disable-shared" ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ pcre-$PCRE_VERSION.tar.bz2 download
# An issue exists with swig-1.3 and python >= 3.2
# Therefore, build a recent copy from source
build_dependency swig autoconf "--with-pcre-prefix=$DEPS_DIR/install/pcre-$PCRE_VERSION" https://github.com/swig/swig.git swig git_clone rel-3.0.8
build_dependency oce-$OCE_VERSION cmake "-DOCE_DISABLE_TKSERVICE_FONT=ON -DOCE_TESTING=OFF -DOCE_BUILD_SHARED_LIB=OFF -DOCE_DISABLE_X11=ON -DOCE_VISUALISATION=OFF -DOCE_OCAF=OFF -DOCE_INSTALL_PREFIX=$DEPS_DIR/install/oce-$OCE_VERSION/" https://github.com/tpaviot/oce/archive/ OCE-$OCE_VERSION.tar.gz download
build_dependency libxml2-$LIBXML_VERSION autoconf "--without-python --disable-shared" ftp://xmlsoft.org/libxml2/ libxml2-$LIBXML_VERSION.tar.gz download
build_dependency OpenCOLLADA cmake "
-DLIBXML2_INCLUDE_DIR=$DEPS_DIR/install/libxml2-$LIBXML_VERSION/include/libxml2
-DLIBXML2_LIBRARIES=$DEPS_DIR/install/libxml2-$LIBXML_VERSION/lib/libxml2.a
-DPCRE_INCLUDE_DIR=$DEPS_DIR/install/pcre-$PCRE_VERSION/include
-DPCRE_PCREPOSIX_LIBRARY=$DEPS_DIR/install/pcre-$PCRE_VERSION/lib/libpcreposix.a
-DPCRE_PCRE_LIBRARY=$DEPS_DIR/install/pcre-$PCRE_VERSION/lib/libpcre.a
-DCMAKE_INSTALL_PREFIX=$DEPS_DIR/install/OpenCOLLADA/" https://github.com/KhronosGroup/OpenCOLLADA.git OpenCOLLADA git_clone
# Python should not be built with -fvisibility=hidden, from experience that introduces segfaults
OLD_CXX_FLAGS=$CXXFLAGS
OLD_C_FLAGS=$CFLAGS
OLD_LD_FLAGS=$LDFLAGS
export CXXFLAGS=$CXXFLAGS_MINIMAL
export CFLAGS=$CFLAGS_MINIMAL
export LDFLAGS=$LDFLAGS_MINIMAL
for PYTHON_VERSION in "${PYTHON_VERSIONS[@]}"; do
build_dependency python-$PYTHON_VERSION autoconf "" http://www.python.org/ftp/python/$PYTHON_VERSION/ Python-$PYTHON_VERSION.tgz download
done
export CXXFLAGS=$OLD_CXX_FLAGS
export CFLAGS=$OLD_C_FLAGS
export LDFLAGS=$OLD_LD_FLAGS
if [ "$(uname)" == "Darwin" ] && [ "$1" == "32" ]; then
BOOST_ADDRESS_MODEL="toolset=darwin architecture=x86 target-os=darwin address-model=32"
fi
build_dependency boost-$BOOST_VERSION bjam "--stagedir=$DEPS_DIR/install/boost-$BOOST_VERSION --with-program_options link=static $BOOST_ADDRESS_MODEL stage" http://downloads.sourceforge.net/project/boost/boost/$BOOST_VERSION/ boost_$BOOST_VERSION_UNDERSCORE.tar.bz2 download
build_dependency icu-$ICU_VERSION icu "--enable-static --disable-shared" http://download.icu-project.org/files/icu4c/$ICU_VERSION/ icu4c-${ICU_VERSION_UNDERSCORE}-src.tgz download
cecho $GREEN "Building IfcOpenShell:"
IFCOS_DIR=$DEPS_DIR/build/ifcopenshell
[ -d $IFCOS_DIR ] && rm -rf $IFCOS_DIR
mkdir -p $IFCOS_DIR
cd $IFCOS_DIR
mkdir -p executables
cd executables
printf "\rConfiguring executables..."
run_cmake "" "
-DBOOST_ROOT=$DEPS_DIR/install/boost-$BOOST_VERSION
-DOCC_INCLUDE_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/include/oce
-DOCC_LIBRARY_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/lib
-DOPENCOLLADA_INCLUDE_DIR=$DEPS_DIR/install/OpenCOLLADA/include/opencollada
-DOPENCOLLADA_LIBRARY_DIR=$DEPS_DIR/install/OpenCOLLADA/lib/opencollada
-DICU_INCLUDE_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/include
-DICU_LIBRARY_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/lib
-DPCRE_LIBRARY_DIR=$DEPS_DIR/install/pcre-$PCRE_VERSION/lib
-DBUILD_IFCPYTHON=OFF
" $CMAKE_DIR
printf "\rBuilding executables... "
make -j$IFCOS_NUM_BUILD_PROCS >>$LOG_FILE 2>&1
strip -s IfcConvert IfcGeomServer
cd ..
for PYTHON_VERSION in "${PYTHON_VERSIONS[@]}"; do
printf "\rConfiguring python $PYTHON_VERSION wrapper..."
mkdir -p python-$PYTHON_VERSION
cd python-$PYTHON_VERSION
PYTHON_LIBRARY=`ls $DEPS_DIR/install/python-$PYTHON_VERSION/lib/libpython*.a`
PYTHON_INCLUDE=`ls -d $DEPS_DIR/install/python-$PYTHON_VERSION/include/python*`
PYTHON_EXECUTABLE=$DEPS_DIR/install/python-$PYTHON_VERSION/bin/python
export PYTHON_LIBRARY_BASENAME=`basename $PYTHON_LIBRARY`
run_cmake "" "
-DBOOST_ROOT=$DEPS_DIR/install/boost-$BOOST_VERSION
-DOCC_INCLUDE_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/include/oce
-DOCC_LIBRARY_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/lib
-DOPENCOLLADA_INCLUDE_DIR=$DEPS_DIR/install/OpenCOLLADA/include/opencollada
-DOPENCOLLADA_LIBRARY_DIR=$DEPS_DIR/install/OpenCOLLADA/lib/opencollada
-DICU_INCLUDE_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/include
-DICU_LIBRARY_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/lib
-DPYTHON_LIBRARY=$PYTHON_LIBRARY
-DPYTHON_EXECUTABLE=$PYTHON_EXECUTABLE
-DPYTHON_INCLUDE_DIR=$PYTHON_INCLUDE
-DSWIG_EXECUTABLE=$DEPS_DIR/install/swig/bin/swig
" $CMAKE_DIR
# This still needs to be tested
# test "$(uname)" == "Darwin" && sed -i~ "s/-o/-flat_namespace -undefined suppress -o/" ifcwrap/CMakeFiles/_ifcopenshell_wrapper.dir/link.txt
printf "\rBuilding python $PYTHON_VERSION wrapper... "
make -j$IFCOS_NUM_BUILD_PROCS _ifcopenshell_wrapper >>$LOG_FILE 2>&1
strip -s \
-K PyInit__ifcopenshell_wrapper \
ifcwrap/_ifcopenshell_wrapper.so
done
printf "\rBuilt IfcOpenShell... \n\n"
+21 -2
View File
@@ -1,5 +1,24 @@
################################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
################################################################################
ADD_EXECUTABLE(IfcParseExamples IfcParseExamples.cpp)
TARGET_LINK_LIBRARIES (IfcParseExamples IfcParse)
TARGET_LINK_LIBRARIES(IfcParseExamples IfcParse)
ADD_EXECUTABLE(IfcOpenHouse IfcOpenHouse.cpp)
TARGET_LINK_LIBRARIES (IfcOpenHouse IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKOffset)
TARGET_LINK_LIBRARIES(IfcOpenHouse IfcParse IfcGeom ${OPENCASCADE_LIBRARIES})
+160 -100
View File
@@ -41,21 +41,25 @@
#include "../ifcparse/IfcHierarchyHelper.h"
#include "../ifcgeom/IfcGeom.h"
#if USE_VLD
#include <vld.h>
#endif
// Some convenience typedefs and definitions.
typedef std::string S;
typedef IfcWrite::IfcGuidHelper guid;
typedef IfcParse::IfcGlobalId guid;
typedef std::pair<double, double> XY;
boost::none_t const null = (static_cast<boost::none_t>(0));
boost::none_t const null = boost::none;
// The creation of Nurbs-surface for the IfcSite mesh, to be implemented lateron
void createGroundShape(TopoDS_Shape& shape);
int main(int argc, char** argv) {
int main() {
// The IfcHierarchyHelper is a subclass of the regular IfcFile that provides several
// convenience functions for working with geometry in IFC files.
IfcHierarchyHelper file;
file.filename("IfcOpenHouse.ifc");
file.header().file_name().name("IfcOpenHouse.ifc");
// Start by adding a wall to the file, initially leaving most attributes blank.
IfcSchema::IfcWallStandardCase* south_wall = new IfcSchema::IfcWallStandardCase(
@@ -83,17 +87,23 @@ int main(int argc, char** argv) {
// An IfcOwnerHistory has been initialized as well, which should be assigned to the wall.
south_wall->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
// The wall will be shaped as a box, with the dimensions specified in millimeters.
IfcSchema::IfcProductDefinitionShape* south_wall_shape = file.addBox(10000, 360, 3000);
// The wall will be shaped as a box, with the dimensions specified in millimeters. The resulting
// product definition will consist of both a body representation as well as an axis representation
// that runs over the centerline of the box in the X-axis.
IfcSchema::IfcProductDefinitionShape* south_wall_shape = file.addAxisBox(10000, 360, 3000);
// Obtain a reference to the placement of the IfcBuildingStorey in order to create a hierarchy
// of placements for the products
IfcSchema::IfcObjectPlacement* storey_placement = file.getSingle<IfcSchema::IfcBuildingStorey>()->ObjectPlacement();
// The shape has to be assigned to the representation of the wall and is placed at the origin
// of the coordinate system.
south_wall->setRepresentation(south_wall_shape);
south_wall->setObjectPlacement(file.addLocalPlacement());
south_wall->setObjectPlacement(file.addLocalPlacement(storey_placement));
// A pale white colour is assigned to the wall.
IfcSchema::IfcPresentationStyleAssignment* wall_colour = file.setSurfaceColour(
south_wall->Representation(), 0.75, 0.73, 0.68);
south_wall_shape, 0.75, 0.73, 0.68);
// Now create a footing for the wall to rest on.
IfcSchema::IfcFooting* footing = new IfcSchema::IfcFooting(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
@@ -104,90 +114,125 @@ int main(int argc, char** argv) {
// The footing will span the entire floor plan of our building. The IfcRepresentationContext is
// something that has been created automatically as well, but representations could have been
// assigned to a specific context, for example to add a two dimensional plan representation as well.
footing->setRepresentation(file.addBox(10100, 5460, 2000, 0, 0, 0, file.getSingle<IfcSchema::IfcRepresentationContext>()));
footing->setObjectPlacement(file.addLocalPlacement(0, 2500, -2000));
footing->setRepresentation(file.addBox(10100, 5460, 2000));
footing->setObjectPlacement(file.addLocalPlacement(storey_placement, 0, 2500, -2000));
// The footing will have a dark gray colour
IfcSchema::IfcPresentationStyleAssignment* footing_colour = file.setSurfaceColour(footing->Representation(), 0.26, 0.22, 0.18);
// IFC has two ways to apply boolean operations to geometry. IfcBooleanResults are commonly used
// to clip geometry to a surface, for example to a slanted roof. For openings that are filled
// with another element, for example a door or a window, an IfcOpeningElement is used instead.
// An opening element is created with rectangular geometry
// An opening element is created with rectangular geometry:
IfcSchema::IfcOpeningElement* west_opening = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
null, null, null, file.addLocalPlacement(-2500, 0, 400),
file.addBox(6000, 3630, 1600, 0, 0, 0, file.getSingle<IfcSchema::IfcRepresentationContext>()), null
null, null, null, file.addLocalPlacement(south_wall->ObjectPlacement(), -2500, 0, 400),
file.addBox(6000, 3630, 1600), null
#ifdef USE_IFC4
, IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING
#endif
);
file.AddEntity(west_opening);
file.addEntity(west_opening);
// Relate the opening element to the wall.
IfcSchema::IfcRelVoidsElement* void_element = new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
null, null, south_wall, west_opening);
file.AddEntity(void_element);
file.addEntity(void_element);
// Now create an additional opening
IfcSchema::IfcOpeningElement* south_opening = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
null, null, null, file.addLocalPlacement(3000, 0, 400),
file.addBox(1860, 3000, 1600, 0, 0, 0, file.getSingle<IfcSchema::IfcRepresentationContext>()), null
null, null, null, file.addLocalPlacement(storey_placement, 3000, 0, 400),
file.addBox(1860, 3000, 1600), null
#ifdef USE_IFC4
, IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING
#endif
);
file.AddEntity(south_opening);
file.AddEntity(new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, south_wall, south_opening));
file.addEntity(south_opening);
file.addEntity(new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, south_wall, south_opening));
// Create a roof element
IfcSchema::IfcRoof* south_roof = new IfcSchema::IfcRoof(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("South roof"), null, null,
0, 0, null, IfcSchema::IfcRoofTypeEnum::IfcRoofType_GABLE_ROOF);
// The roof geometry is slanted 45 degrees by specifying a direction for the box extrusion
south_roof->setRepresentation(file.addBox(10200, 360, sqrt(2.0*2900*2900), 0, file.addPlacement3d(0, 0, 0, 0, 1, 0),
file.addTriplet<IfcSchema::IfcDirection>(0, -sqrt(0.5), sqrt(0.5)), file.getSingle<IfcSchema::IfcRepresentationContext>()));
south_roof->setObjectPlacement(file.addLocalPlacement(0, -400, 2700));
file.addBuildingProduct(south_roof);
// Create a roof element that will consist of two slabs:
IfcSchema::IfcRoof* roof = new IfcSchema::IfcRoof(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("Roof"), null, null,
file.addLocalPlacement(storey_placement), 0, null, IfcSchema::IfcRoofTypeEnum::IfcRoofType_GABLE_ROOF);
// The roof geometry is slanted 45 degrees by specifying a direction for the box extrusion
IfcSchema::IfcShapeRepresentation* roof_rep = file.addEmptyRepresentation();
file.addBox(roof_rep, 10200, 360, sqrt(2.0*2900*2900), 0, file.addPlacement3d(0, 0, 0, 0, 1, 0),
file.addTriplet<IfcSchema::IfcDirection>(0, -sqrt(0.5), sqrt(0.5)));
// CV-2x3-144: Roofs are aggregates and shall have at least one contained element and no own geometry
IfcSchema::IfcSlab* south_roof_part = new IfcSchema::IfcSlab(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("South roof"),
null, null, 0, 0, null, IfcSchema::IfcSlabTypeEnum::IfcSlabType_ROOF);
// The geometry is instantiated by using IfcMappedItems. This way geometry definitions can
// be reused while maintaining the cardinality constraint that the ShapeOfProduct relation
// imposes on the IfcProductDefinitionShape. Note that this constrained is lifted in IFC4.
south_roof_part->setRepresentation(file.addMappedItem(roof_rep));
south_roof_part->setObjectPlacement(file.addLocalPlacement(roof->ObjectPlacement(), 0, -400, 2700));
// The same roof geometry is re-used on the north side of the roof, by inverting the X-axis of
// the local placement the roof is rotated 180 degrees around the Z-axis
IfcSchema::IfcRoof* north_roof = new IfcSchema::IfcRoof(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("North roof"),
null, null, 0, 0, null, IfcSchema::IfcRoofTypeEnum::IfcRoofType_GABLE_ROOF);
north_roof->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
north_roof->setRepresentation(south_roof->Representation());
north_roof->setObjectPlacement(file.addLocalPlacement(0, 5400, 2700, 0, 0, 1, -1, 0, 0));
file.addBuildingProduct(north_roof);
IfcSchema::IfcSlab* north_roof_part = new IfcSchema::IfcSlab(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("North roof"),
null, null, 0, 0, null, IfcSchema::IfcSlabTypeEnum::IfcSlabType_ROOF);
north_roof_part->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
north_roof_part->setRepresentation(file.addMappedItem(roof_rep));
north_roof_part->setObjectPlacement(file.addLocalPlacement(roof->ObjectPlacement(), 0, 5400, 2700, 0, 0, 1, -1, 0, 0));
IfcSchema::IfcObjectDefinition::list::ptr roof_parts(new IfcSchema::IfcObjectDefinition::list);
roof_parts->push(south_roof_part);
roof_parts->push(north_roof_part);
IfcSchema::IfcRelDecomposes* roof_decomposition = new IfcSchema::IfcRelAggregates(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
null, null, roof, roof_parts);
file.addEntity(roof_decomposition);
// By specifying a surface style for the south part of the roof, it gets assigned to the other
// roof part as well, because they share the same representation.
file.setSurfaceColour(south_roof->Representation(), 0.24, 0.08, 0.04);
file.addBuildingProduct(south_roof_part);
file.addBuildingProduct(north_roof_part);
file.addBuildingProduct(roof);
file.setSurfaceColour(roof_rep, 0.24, 0.08, 0.04);
// Copy the south wall to the north
file.addBuildingProduct(new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("North wall"),
null, null, file.addLocalPlacement(0, 5000, 0), south_wall->Representation(), null
IfcSchema::IfcWallStandardCase* north_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("North wall"),
null, null, file.addLocalPlacement(storey_placement, 0, 5000, 0), file.addAxisBox(10000, 360, 3000), null
#ifdef USE_IFC4
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
#endif
));
);
file.addBuildingProduct(north_wall);
file.setSurfaceColour(north_wall->Representation(), wall_colour);
// Two identical representations are created for the two remaining walls. Mapped items
// are not used, because it is not allowed by the standard for wall body representations.
// MappedItems are not allowed for Axis representations as per CV-2x3-161
IfcSchema::IfcProductDefinitionShape* clipped_wall_body_reps[2];
for (int i = 0; i < 2; ++i) {
IfcSchema::IfcShapeRepresentation* body = file.addEmptyRepresentation();
file.addBox(body, 5000, 360, 6000);
// The wall geometry is clipped using two IfcHalfSpaceSolids, created from an
// 'axis 3d placement' that specifies the plane against which the geometry is clipped.
file.clipRepresentation(body, file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false);
file.clipRepresentation(body, file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false);
file.setSurfaceColour(body, wall_colour);
IfcSchema::IfcShapeRepresentation* axis = file.addEmptyRepresentation("Axis", "Curve2D");
file.addAxis(axis, 5000);
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
reps->push(body);
reps->push(axis);
clipped_wall_body_reps[i] = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
}
// Now create a wall on the east of the building, again starting with just a box shape
IfcSchema::IfcWallStandardCase* east_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
S("East wall"), null, null, file.addLocalPlacement(4820, 2500, 0, 0, 0, 1, 0, 1, 0), file.addBox(5000, 360, 6000), null
S("East wall"), null, null, file.addLocalPlacement(storey_placement, 4820, 2500, 0, 0, 0, 1, 0, 1, 0), clipped_wall_body_reps[0], null
#ifdef USE_IFC4
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
#endif
);
file.addBuildingProduct(east_wall);
// The east wall geometry is clipped using two IfcHalfSpaceSolids, created from an
// 'axis 3d placement' that specifies the plane against which the geometry is clipped.
file.clipRepresentation(east_wall->Representation(), file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false);
file.clipRepresentation(east_wall->Representation(), file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false);
file.setSurfaceColour(east_wall->Representation(), wall_colour);
// The east wall is copied to the west location of the house
IfcSchema::IfcWallStandardCase* west_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
S("West wall"), null, null, file.addLocalPlacement(-4820, 2500, 0, 0, 0, 1, 0, -1, 0), east_wall->Representation(), null
S("West wall"), null, null, file.addLocalPlacement(storey_placement, -4820, 2500, 0, 0, 0, 1, 0, -1, 0), clipped_wall_body_reps[1], null
#ifdef USE_IFC4
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
#endif
@@ -199,27 +244,31 @@ int main(int argc, char** argv) {
// wall will not feature this opening.
// NB: an Opening Element can only be used to create a single void within a single Element, as per:
// http://www.buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcproductextension/lexical/ifcfeatureelementsubtraction.htm
// Not all viewers support opening elements with mapped representations, hence an exact copy of the
// same subtraction box is instantiated for the otherwise identical opening element.
IfcSchema::IfcOpeningElement* west_opening_copy = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
null, null, null, west_opening->ObjectPlacement(), west_opening->Representation(), null
null, null, null, file.addLocalPlacement(west_wall->ObjectPlacement(), 2500, -2500+4820, 400, 0, 0, 1, 0, 1, 0),
file.addBox(6000, 3630, 1600), null
#ifdef USE_IFC4
, IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING
#endif
);
file.AddEntity(west_opening_copy);
file.AddEntity(new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, west_wall, west_opening_copy));
file.addEntity(west_opening_copy);
file.addEntity(new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, west_wall, west_opening_copy));
// Up until now we have only used simple extrusions for the creation of the geometry. For the
// ground mesh of the IfcSite we will use a Nurbs surface created in Open Cascade. The surface
// will be tesselated using the deflection specified.
TopoDS_Shape shape;
createGroundShape(shape);
IfcEntities geometrical_entities(new IfcEntityList());
IfcEntityList::ptr geometrical_entities(new IfcEntityList);
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::tesselate(shape, 100., geometrical_entities);
file.getSingle<IfcSchema::IfcSite>()->setRepresentation(ground_representation);
file.AddEntities(geometrical_entities);
IfcSchema::IfcShapeRepresentation::list ground_reps = geometrical_entities->as<IfcSchema::IfcShapeRepresentation>();
for (IfcSchema::IfcShapeRepresentation::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
(*it)->setContextOfItems(file.getSingle<IfcSchema::IfcRepresentationContext>());
file.addEntities(geometrical_entities);
IfcSchema::IfcShapeRepresentation::list::ptr ground_reps = geometrical_entities->as<IfcSchema::IfcShapeRepresentation>();
for (IfcSchema::IfcShapeRepresentation::list::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
(*it)->setContextOfItems(file.getRepresentationContext("Model"));
}
file.setSurfaceColour(ground_representation, 0.15, 0.25, 0.05);
@@ -246,7 +295,7 @@ int main(int argc, char** argv) {
, null
#endif
);
IfcSchema::IfcMaterialLayer::list layers (new IfcTemplatedEntityList<IfcSchema::IfcMaterialLayer>());
IfcSchema::IfcMaterialLayer::list::ptr layers (new IfcTemplatedEntityList<IfcSchema::IfcMaterialLayer>());
layers->push(layer);
IfcSchema::IfcMaterialLayerSet* layer_set = new IfcSchema::IfcMaterialLayerSet(
layers,
@@ -271,17 +320,17 @@ int main(int argc, char** argv) {
null,
null,
#ifdef USE_IFC4
file.EntitiesByType<IfcSchema::IfcWallStandardCase>()->generalize(),
file.entitiesByType<IfcSchema::IfcWallStandardCase>()->generalize(),
#else
file.EntitiesByType<IfcSchema::IfcWallStandardCase>()->as<IfcSchema::IfcRoot>(),
file.entitiesByType<IfcSchema::IfcWallStandardCase>()->as<IfcSchema::IfcRoot>(),
#endif
layer_usage);
file.AddEntity(material);
file.AddEntity(layer);
file.AddEntity(layer_set);
file.AddEntity(layer_usage);
file.AddEntity(associates_material);
file.addEntity(material);
file.addEntity(layer);
file.addEntity(layer_set);
file.addEntity(layer_usage);
file.addEntity(associates_material);
// In addition, another common way to represent geometry in IFC files is to use extrusions of
// planar areas bounded by a polygon.
@@ -293,7 +342,7 @@ int main(int argc, char** argv) {
stair_points.push_back(XY(500, 400));
stair_points.push_back(XY( 0, 400));
IfcSchema::IfcStairFlight* stair = new IfcSchema::IfcStairFlight(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
null, null, null, file.addLocalPlacement(5050, 1000, 0, 0, 1, 0, 1, 0, 0),
null, null, null, file.addLocalPlacement(storey_placement, 5050, 1000, 0, 0, 1, 0, 1, 0, 0),
file.addExtrudedPolyline(stair_points, 1200), null, 2, 2, 0.2, 0.25
#ifdef USE_IFC4
, IfcSchema::IfcStairFlightTypeEnum::IfcStairFlightType_STRAIGHT
@@ -304,19 +353,19 @@ int main(int argc, char** argv) {
file.setSurfaceColour(stair->Representation(), footing_colour);
IfcSchema::IfcOpeningElement* door_opening = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
null, null, null, file.addLocalPlacement(5000-180, 2500-900, 0), file.addBox(1000, 1000, 2200), null
null, null, null, file.addLocalPlacement(storey_placement, 5000-180, 2500-900, 0), file.addBox(1000, 1000, 2200), null
#ifdef USE_IFC4
, IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING
#endif
);
file.AddEntity(door_opening);
file.AddEntity(new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, east_wall, door_opening));
file.addEntity(door_opening);
file.addEntity(new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, east_wall, door_opening));
// A single shape representation can contain multiple representiation items. This way a product
// can be a composition of multiple solids. The following door will be composed of four boxes
// which constitute the door and its frame.
IfcSchema::IfcDoor* door = new IfcSchema::IfcDoor(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, null,
file.addLocalPlacement(4800, 1600, 0, 0, 0, 1, 0, 1, 0), 0, null, 2200, 1000
file.addLocalPlacement(storey_placement, 4800, 1600, 0, 0, 0, 1, 0, 1, 0), 0, null, 2200, 1000
#ifdef USE_IFC4
, IfcSchema::IfcDoorTypeEnum::IfcDoorType_DOOR
, IfcSchema::IfcDoorTypeOperationEnum::IfcDoorTypeOperation_SINGLE_SWING_LEFT
@@ -324,9 +373,9 @@ int main(int argc, char** argv) {
#endif
);
door->setRepresentation(file.addBox(80, 80, 2120, 0, file.addPlacement3d(460, 0, 0)));
IfcSchema::IfcRepresentation::list door_representations = door->Representation()->Representations();
IfcSchema::IfcRepresentation::list::ptr door_representations = door->Representation()->Representations();
IfcSchema::IfcShapeRepresentation* door_body = 0;
for (IfcSchema::IfcRepresentation::it i = door_representations->begin(); i != door_representations->end(); ++i) {
for (IfcSchema::IfcRepresentation::list::it i = door_representations->begin(); i != door_representations->end(); ++i) {
IfcSchema::IfcRepresentation* rep = *i;
if (rep->is(IfcSchema::Type::IfcShapeRepresentation) && rep->RepresentationIdentifier() == "Body") {
door_body = (IfcSchema::IfcShapeRepresentation*) rep;
@@ -337,7 +386,11 @@ int main(int argc, char** argv) {
file.addBox(door_body, 860, 30, 2120);
file.addBuildingProduct(door);
file.setSurfaceColour(door->Representation(), 0.9, 0.9, 0.9);
file.AddEntity(new IfcSchema::IfcRelFillsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, door_opening, door));
file.addEntity(new IfcSchema::IfcRelFillsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, door_opening, door));
IfcSchema::IfcDoorStyle* door_style = new IfcSchema::IfcDoorStyle(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("Door type"), null, null, null, null, null,
IfcSchema::IfcDoorStyleOperationEnum::IfcDoorStyleOperation_SINGLE_SWING_LEFT, IfcSchema::IfcDoorStyleConstructionEnum::IfcDoorStyleConstruction_WOOD, false, false);
file.addRelatedObject<IfcSchema::IfcRelDefinesByType>(door_style, door);
// Surface styles are assigned to representation items, hence there is no real limitation to
// assign different colours within the same representation. However, some viewers have
@@ -350,32 +403,39 @@ int main(int argc, char** argv) {
// Therefore the OverallWidth and OverallHeight of the window attributes will need to
// match the bounding box of the representation. Furthermore, the window placement needs
// to align with the lowerleft corner of the constituent parts.
IfcSchema::IfcProductDefinitionShape::list frame_representations (new IfcTemplatedEntityList<IfcSchema::IfcProductDefinitionShape>());
frame_representations->push(file.addBox(1860, 90, 90));
frame_representations->push(*frame_representations->begin()); // Add a reference to the shape created above
frame_representations->push(file.addBox(90, 90, 1420));
frame_representations->push(*(frame_representations->end()-1)); // Add a reference to the shape created above
IfcSchema::IfcShapeRepresentation::list::ptr frame_representations(new IfcSchema::IfcShapeRepresentation::list);
IfcSchema::IfcShapeRepresentation* horizontal_bar = file.addEmptyRepresentation();
IfcSchema::IfcShapeRepresentation* vertical_bar = file.addEmptyRepresentation();
file.addBox(horizontal_bar, 1860, 90, 90);
file.addBox(vertical_bar, 90, 90, 1420);
frame_representations->push(horizontal_bar);
frame_representations->push(horizontal_bar); // Add another reference to the horizontal bar created above
frame_representations->push(vertical_bar);
frame_representations->push(vertical_bar); // Add another reference to the vertical bar created above
// The beams all have the same surface style assigned
IfcSchema::IfcPresentationStyleAssignment* frame_style = 0;
for (IfcSchema::IfcProductDefinitionShape::it i = frame_representations->begin(); i != frame_representations->end(); ++i) {
for (IfcSchema::IfcShapeRepresentation::list::it i = frame_representations->begin(); i != frame_representations->end(); i += 2) {
if (frame_style) {
file.setSurfaceColour(*i, frame_style);
} else {
frame_style = file.setSurfaceColour(*i, 0.5, 0.4, 0.3);
}
// Because of the duplication the iterator is incremented twice
}
// This window will be placed at five locations within the building. A list of placements is
// created and is iterated over to create all window instances.
IfcSchema::IfcLocalPlacement::list window_placements (new IfcTemplatedEntityList<IfcSchema::IfcLocalPlacement>());
window_placements->push(file.addLocalPlacement(2*-1770-430-930, -45, 400));
window_placements->push(file.addLocalPlacement( -1770-430-930, -45, 400));
window_placements->push(file.addLocalPlacement( -430-930, -45, 400));
window_placements->push(file.addLocalPlacement( 3000-930, -45, 400));
window_placements->push(file.addLocalPlacement( -4855+45, 885-930, 400, 0, 0, 1, 0, 1, 0));
IfcSchema::IfcLocalPlacement::list::ptr window_placements (new IfcSchema::IfcLocalPlacement::list);
window_placements->push(file.addLocalPlacement(storey_placement, 2*-1770-430-930, -45, 400));
window_placements->push(file.addLocalPlacement(storey_placement, -1770-430-930, -45, 400));
window_placements->push(file.addLocalPlacement(storey_placement, -430-930, -45, 400));
window_placements->push(file.addLocalPlacement(storey_placement, 3000-930, -45, 400));
window_placements->push(file.addLocalPlacement(storey_placement, -4855+45, 885-930, 400, 0, 0, 1, 0, 1, 0));
for (IfcSchema::IfcLocalPlacement::it it = window_placements->begin(); it != window_placements->end(); ++it) {
for (IfcSchema::IfcLocalPlacement::list::it it = window_placements->begin(); it != window_placements->end(); ++it) {
// Create the window at the current location
IfcSchema::IfcLocalPlacement* place = *it;
@@ -390,42 +450,42 @@ int main(int argc, char** argv) {
file.addBuildingProduct(window);
// Initalize a list of parts for the window to be composed of
IfcSchema::IfcObjectDefinition::list window_parts(new IfcTemplatedEntityList<IfcSchema::IfcObjectDefinition>());
IfcSchema::IfcObjectDefinition::list::ptr window_parts(new IfcTemplatedEntityList<IfcSchema::IfcObjectDefinition>());
// The placements for the beams are not shared accross the different windows because every
// beam is placed relative to its parent window entity.
IfcSchema::IfcLocalPlacement::list frame_placements (new IfcTemplatedEntityList<IfcSchema::IfcLocalPlacement>());
frame_placements->push(file.addLocalPlacement( 930,45));
frame_placements->push(file.addLocalPlacement( 930, 45, 1510));
frame_placements->push(file.addLocalPlacement(-885+930, 45, 90));
frame_placements->push(file.addLocalPlacement( 885+930, 45, 90));
IfcSchema::IfcLocalPlacement::list::ptr frame_placements (new IfcTemplatedEntityList<IfcSchema::IfcLocalPlacement>());
frame_placements->push(file.addLocalPlacement(storey_placement, 930,45));
frame_placements->push(file.addLocalPlacement(storey_placement, 930, 45, 1510));
frame_placements->push(file.addLocalPlacement(storey_placement, -885+930, 45, 90));
frame_placements->push(file.addLocalPlacement(storey_placement, 885+930, 45, 90));
// Now iterate over the placements and representations of the beam and add them to list of parts
IfcSchema::IfcLocalPlacement::it frame_placement;
IfcSchema::IfcProductDefinitionShape::it frame_representation;
IfcSchema::IfcLocalPlacement::list::it frame_placement;
IfcSchema::IfcShapeRepresentation::list::it frame_representation;
for (frame_placement = frame_placements->begin(), frame_representation = frame_representations->begin();
frame_placement != frame_placements->end() && frame_representation != frame_representations->end();
++frame_placement, ++frame_representation)
{
IfcSchema::IfcMember* frame_part = new IfcSchema::IfcMember(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
null, null, null, *frame_placement, *frame_representation, null
null, null, null, *frame_placement, file.addMappedItem(*frame_representation), null
#ifdef USE_IFC4
, IfcSchema::IfcMemberTypeEnum::IfcMemberType_MULLION
#endif
);
file.AddEntity(frame_part);
file.addEntity(frame_part);
window_parts->push(frame_part);
file.relatePlacements(window, frame_part);
}
// Add the glass plate to the list of parts
IfcSchema::IfcPlate* glass_part = new IfcSchema::IfcPlate(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null,
null, null, file.addLocalPlacement(930, 45, 90), file.addBox(1680, 10, 1420), null
null, null, file.addLocalPlacement(storey_placement, 930, 45, 90), file.addBox(1680, 10, 1420), null
#ifdef USE_IFC4
, IfcSchema::IfcPlateTypeEnum::IfcPlateType_SHEET
#endif
);
file.AddEntity(glass_part);
file.addEntity(glass_part);
window_parts->push(glass_part);
file.relatePlacements(window, glass_part);
file.setSurfaceColour(glass_part->Representation(), 0.6, 0.7, 0.75, 0.1);
@@ -434,7 +494,7 @@ int main(int argc, char** argv) {
// tools will consider the window a single entity that can be selected as a whole.
IfcSchema::IfcRelDecomposes* decomposition = new IfcSchema::IfcRelAggregates(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
null, null, window, window_parts);
file.AddEntity(decomposition);
file.addEntity(decomposition);
}
// Finally create a file stream for our output and write the IFC file to it.
@@ -479,6 +539,6 @@ void createGroundShape(TopoDS_Shape& shape) {
#if OCC_VERSION_HEX < 0x60502
shape = BRepBuilderAPI_MakeFace(surf);
#else
shape = BRepBuilderAPI_MakeFace(surf, 1);
shape = BRepBuilderAPI_MakeFace(surf, Precision::Confusion());
#endif
}
+10 -7
View File
@@ -17,9 +17,12 @@
* *
********************************************************************************/
#include "../ifcparse/IfcParse.h"
#include "../ifcparse/IfcFile.h"
#if USE_VLD
#include <vld.h>
#endif
using namespace IfcSchema;
int main(int argc, char** argv) {
@@ -41,7 +44,7 @@ int main(int argc, char** argv) {
// Lets get a list of IfcBuildingElements, this is the parent
// type of things like walls, windows and doors.
// EntitiesByType is a templated function and returns a
// entitiesByType is a templated function and returns a
// templated class that behaves like a std::vector.
// Note that the return types are all typedef'ed as members of
// the generated classes, ::list for the templated vector class,
@@ -55,17 +58,17 @@ int main(int argc, char** argv) {
// we need to cast them to IfcWindows. Since these properties
// are optional we need to make sure the properties are
// defined for the window in question before accessing them.
IfcBuildingElement::list elements = file.EntitiesByType<IfcBuildingElement>();
IfcBuildingElement::list::ptr elements = file.entitiesByType<IfcBuildingElement>();
std::cout << "Found " << elements->Size() << " elements in " << argv[1] << ":" << std::endl;
std::cout << "Found " << elements->size() << " elements in " << argv[1] << ":" << std::endl;
for ( IfcBuildingElement::it it = elements->begin(); it != elements->end(); ++ it ) {
for ( IfcBuildingElement::list::it it = elements->begin(); it != elements->end(); ++ it ) {
const IfcBuildingElement::ptr element = *it;
const IfcBuildingElement* element = *it;
std::cout << element->entity->toString() << std::endl;
if ( element->is(IfcWindow::Class()) ) {
const IfcWindow::ptr window = reinterpret_pointer_cast<IfcBuildingElement,IfcWindow>(element);
const IfcWindow* window = (IfcWindow*)element;
if ( window->hasOverallWidth() && window->hasOverallHeight() ) {
const double area = window->OverallWidth()*window->OverallHeight();
+29 -29
View File
@@ -33,8 +33,8 @@
#include "../ifcparse/IfcHierarchyHelper.h"
typedef std::string S;
typedef IfcWrite::IfcGuidHelper guid;
boost::none_t const null = (static_cast<boost::none_t>(0));
typedef IfcParse::IfcGlobalId guid;
boost::none_t const null = boost::none;
static int i = 0;
void create_product_from_item(IfcHierarchyHelper& file, IfcSchema::IfcRepresentationItem* item, const std::string& s) {
@@ -43,16 +43,16 @@ void create_product_from_item(IfcHierarchyHelper& file, IfcSchema::IfcRepresenta
file.addBuildingProduct(product);
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
product->setObjectPlacement(file.addLocalPlacement(120 * i++));
product->setObjectPlacement(file.addLocalPlacement(0, 120 * i++));
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
items->push(item);
if (s == "GeometricSet") {
IfcSchema::IfcGeometricSet* set = new IfcSchema::IfcGeometricSet(items->generalize());
file.AddEntity(set);
items = IfcSchema::IfcRepresentationItem::list(new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
file.addEntity(set);
items = IfcSchema::IfcRepresentationItem::list::ptr(new IfcSchema::IfcRepresentationItem::list());
items->push(set);
}
@@ -60,21 +60,21 @@ void create_product_from_item(IfcHierarchyHelper& file, IfcSchema::IfcRepresenta
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), s, items);
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
file.AddEntity(rep);
file.AddEntity(shape);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
file.addEntity(rep);
file.addEntity(shape);
product->setRepresentation(shape);
}
void create_surfaces_from_profile(IfcHierarchyHelper& file, IfcSchema::IfcProfileDef* profile) {
IfcSchema::IfcSurfaceOfLinearExtrusion* extrusion = new IfcSchema::IfcSurfaceOfLinearExtrusion(profile, file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 100.);
file.AddEntity(extrusion);
file.addEntity(extrusion);
IfcSchema::IfcAxis1Placement* ax1 = new IfcSchema::IfcAxis1Placement(file.addTriplet<IfcSchema::IfcCartesianPoint>(0,100,0), file.addTriplet<IfcSchema::IfcDirection>(1,0,0));
IfcSchema::IfcSurfaceOfRevolution* revolution = new IfcSchema::IfcSurfaceOfRevolution(profile, file.addPlacement3d(), ax1);
file.AddEntity(ax1);
file.AddEntity(revolution);
file.addEntity(ax1);
file.addEntity(revolution);
create_product_from_item(file, extrusion, "GeometricSet");
create_product_from_item(file, revolution, "GeometricSet");
@@ -82,14 +82,14 @@ void create_surfaces_from_profile(IfcHierarchyHelper& file, IfcSchema::IfcProfil
void create_solids_from_profile(IfcHierarchyHelper& file, IfcSchema::IfcProfileDef* profile) {
IfcSchema::IfcExtrudedAreaSolid* extrusion = new IfcSchema::IfcExtrudedAreaSolid(profile, file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 100.);
file.AddEntity(extrusion);
file.addEntity(extrusion);
IfcSchema::IfcAxis1Placement* ax1 = new IfcSchema::IfcAxis1Placement(file.addTriplet<IfcSchema::IfcCartesianPoint>(0,100,0), file.addTriplet<IfcSchema::IfcDirection>(1,0,0));
IfcSchema::IfcRevolvedAreaSolid* revolution1 = new IfcSchema::IfcRevolvedAreaSolid(profile, file.addPlacement3d(), ax1, 360.);
IfcSchema::IfcRevolvedAreaSolid* revolution2 = new IfcSchema::IfcRevolvedAreaSolid(profile, file.addPlacement3d(), ax1, 90.);
file.AddEntity(ax1);
file.AddEntity(revolution1);
file.AddEntity(revolution2);
file.addEntity(ax1);
file.addEntity(revolution1);
file.addEntity(revolution2);
create_product_from_item(file, extrusion, "SweptSolid");
create_product_from_item(file, revolution1, "SweptSolid");
@@ -99,8 +99,8 @@ void create_solids_from_profile(IfcHierarchyHelper& file, IfcSchema::IfcProfileD
void create_products_from_curve(IfcHierarchyHelper& file, IfcSchema::IfcBoundedCurve* curve) {
IfcSchema::IfcArbitraryOpenProfileDef* open = new IfcSchema::IfcArbitraryOpenProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_CURVE, null, curve);
IfcSchema::IfcCenterLineProfileDef* center_line = new IfcSchema::IfcCenterLineProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, null, curve, 10.);
file.AddEntity(open);
file.AddEntity(center_line);
file.addEntity(open);
file.addEntity(center_line);
create_surfaces_from_profile(file, open);
create_solids_from_profile(file, center_line);
@@ -109,27 +109,27 @@ void create_products_from_curve(IfcHierarchyHelper& file, IfcSchema::IfcBoundedC
int main(int argc, char** argv) {
const char filename[] = "IfcArbitraryOpenProfileDef.ifc";
IfcHierarchyHelper file;
file.filename(filename);
file.header().file_name().name(filename);
double coords1[] = {-50.0, 0.0};
double coords2[] = { 50.0, 0.0};
IfcSchema::IfcCartesianPoint::list points (new IfcTemplatedEntityList<IfcSchema::IfcCartesianPoint>());
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list());
points->push(new IfcSchema::IfcCartesianPoint(std::vector<double>(coords1, coords1+2)));
points->push(new IfcSchema::IfcCartesianPoint(std::vector<double>(coords2, coords2+2)));
file.AddEntities(points->generalize());
file.addEntities(points->generalize());
IfcSchema::IfcPolyline* poly = new IfcSchema::IfcPolyline(points);
file.AddEntity(poly);
file.addEntity(poly);
create_products_from_curve(file, poly);
IfcSchema::IfcEllipse* ellipse = new IfcSchema::IfcEllipse(file.addPlacement2d(), 50., 25.);
file.AddEntity(ellipse);
IfcEntities trim1(new IfcEntityList());
IfcEntities trim2(new IfcEntityList());
trim1->push(new IfcWrite::IfcSelectHelper( 0., Ifc2x3::Type::IfcParameterValue));
trim2->push(new IfcWrite::IfcSelectHelper(180., Ifc2x3::Type::IfcParameterValue));
file.addEntity(ellipse);
IfcEntityList::ptr trim1(new IfcEntityList);
IfcEntityList::ptr trim2(new IfcEntityList);
trim1->push(new IfcSchema::IfcParameterValue( 0.));
trim2->push(new IfcSchema::IfcParameterValue(180.));
IfcSchema::IfcTrimmedCurve* trim = new IfcSchema::IfcTrimmedCurve(ellipse, trim1, trim2, true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
file.AddEntity(trim);
file.addEntity(trim);
create_products_from_curve(file, trim);
+16 -16
View File
@@ -32,19 +32,19 @@
#include "../ifcparse/IfcHierarchyHelper.h"
typedef std::string S;
typedef IfcWrite::IfcGuidHelper guid;
boost::none_t const null = (static_cast<boost::none_t>(0));
typedef IfcParse::IfcGlobalId guid;
boost::none_t const null = boost::none;
int main(int argc, char** argv) {
const char filename[] = "IfcCompositeProfileDef.ifc";
IfcHierarchyHelper file;
file.filename(filename);
file.header().file_name().name(filename);
double coords1[] = {100.0, 0.0};
double coords2[] = {200.0, 0.0};
double coords3[] = {300.0, 0.0};
IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list());
IfcSchema::IfcCartesianTransformationOperator2D* transform1 = new IfcSchema::IfcCartesianTransformationOperator2D(file.addDoublet<IfcSchema::IfcDirection>(1, 0), file.addDoublet<IfcSchema::IfcDirection>(0, -1), file.addDoublet<IfcSchema::IfcCartesianPoint>(40, 0), null);
IfcSchema::IfcCartesianTransformationOperator2D* transform2 = new IfcSchema::IfcCartesianTransformationOperator2D(file.addDoublet<IfcSchema::IfcDirection>(0, -1), file.addDoublet<IfcSchema::IfcDirection>(1, 0), file.addDoublet<IfcSchema::IfcCartesianPoint>(40, 0), 0.3);
@@ -65,11 +65,11 @@ int main(int argc, char** argv) {
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
null, file.addPlacement2d(80.), 50.0, 25.0, 5.0, 10.0, 2.0, null);
file.AddEntity(p2);
file.AddEntity(p3);
file.addEntity(p2);
file.addEntity(p3);
file.AddEntity(transform1);
file.AddEntity(transform2);
file.addEntity(transform1);
file.addEntity(transform2);
IfcSchema::IfcDerivedProfileDef* p5 = new IfcSchema::IfcDerivedProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, null, p2, transform1, null);
IfcSchema::IfcDerivedProfileDef* p6 = new IfcSchema::IfcDerivedProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, null, p3, transform2, null);
@@ -79,7 +79,7 @@ int main(int argc, char** argv) {
profiles->push(p6);
profiles->push(p4);
file.AddEntities(profiles->generalize());
file.addEntities(profiles->generalize());
IfcSchema::IfcCompositeProfileDef* composite = new IfcSchema::IfcCompositeProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, S("IFC"), profiles, null);
@@ -95,20 +95,20 @@ int main(int argc, char** argv) {
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(composite,
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
file.AddEntity(composite);
file.AddEntity(solid);
file.addEntity(composite);
file.addEntity(solid);
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
items->push(solid);
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("SweptSolid"), items);
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
file.AddEntity(rep);
file.AddEntity(shape);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
file.addEntity(rep);
file.addEntity(shape);
product->setRepresentation(shape);
+9 -9
View File
@@ -32,8 +32,8 @@
#include "../ifcparse/IfcHierarchyHelper.h"
typedef std::string S;
typedef IfcWrite::IfcGuidHelper guid;
boost::none_t const null = (static_cast<boost::none_t>(0));
typedef IfcParse::IfcGlobalId guid;
boost::none_t const null = boost::none;
class Node {
private:
@@ -127,7 +127,7 @@ public:
}
my = new IfcSchema::IfcBooleanResult(o, left->serialize(file), right->serialize(file));
}
file.AddEntity(my);
file.addEntity(my);
return my;
}
};
@@ -135,7 +135,7 @@ public:
int main(int argc, char** argv) {
const char filename[] = "IfcCsgPrimitive.ifc";
IfcHierarchyHelper file;
file.filename(filename);
file.header().file_name().name(filename);
IfcSchema::IfcRepresentationItem* csg1 = Node::Box(8000.,6000.,3000.).subtract(
Node::Box(7600.,5600.,2800.).move(200.,200.,200.)
@@ -171,8 +171,8 @@ int main(int argc, char** argv) {
product->setObjectPlacement(file.addLocalPlacement());
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
items->push(csg1);
items->push(csg2);
@@ -180,9 +180,9 @@ int main(int argc, char** argv) {
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("CSG"), items);
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
file.AddEntity(rep);
file.AddEntity(shape);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
file.addEntity(rep);
file.addEntity(shape);
product->setRepresentation(shape);
+22 -22
View File
@@ -32,8 +32,8 @@
#include "../ifcparse/IfcHierarchyHelper.h"
typedef std::string S;
typedef IfcWrite::IfcGuidHelper guid;
boost::none_t const null = (static_cast<boost::none_t>(0));
typedef IfcParse::IfcGlobalId guid;
boost::none_t const null = boost::none;
typedef struct {
double r1;
@@ -58,66 +58,66 @@ void create_testcase_for(IfcHierarchyHelper& file, const EllipsePie& pie, Ifc2x3
Ifc2x3::IfcCartesianPoint* p2 = new Ifc2x3::IfcCartesianPoint(coords2);
Ifc2x3::IfcCartesianPoint* p3 = new Ifc2x3::IfcCartesianPoint(coords3);
Ifc2x3::IfcCartesianPoint::list points(new IfcTemplatedEntityList<Ifc2x3::IfcCartesianPoint>());
Ifc2x3::IfcCartesianPoint::list::ptr points(new Ifc2x3::IfcCartesianPoint::list());
points->push(p3);
points->push(p1);
points->push(p2);
file.AddEntities(points->generalize());
file.addEntities(points->generalize());
Ifc2x3::IfcEllipse* ellipse = new Ifc2x3::IfcEllipse(file.addPlacement2d(), pie.r1, pie.r2);
file.AddEntity(ellipse);
IfcEntities trim1(new IfcEntityList());
IfcEntities trim2(new IfcEntityList());
file.addEntity(ellipse);
IfcEntityList::ptr trim1(new IfcEntityList);
IfcEntityList::ptr trim2(new IfcEntityList);
if (pref == Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER) {
trim1->push(new IfcWrite::IfcSelectHelper(pie.t1, Ifc2x3::Type::IfcParameterValue));
trim2->push(new IfcWrite::IfcSelectHelper(pie.t2, Ifc2x3::Type::IfcParameterValue));
trim1->push(new Ifc2x3::IfcParameterValue(pie.t1));
trim2->push(new Ifc2x3::IfcParameterValue(pie.t2));
} else {
trim1->push(p2);
trim2->push(p3);
}
Ifc2x3::IfcTrimmedCurve* trim = new Ifc2x3::IfcTrimmedCurve(ellipse, trim1, trim2, true, pref);
file.AddEntity(trim);
file.addEntity(trim);
Ifc2x3::IfcCompositeCurveSegment::list segments(new IfcTemplatedEntityList<Ifc2x3::IfcCompositeCurveSegment>());
Ifc2x3::IfcCompositeCurveSegment::list::ptr segments(new Ifc2x3::IfcCompositeCurveSegment::list());
Ifc2x3::IfcCompositeCurveSegment* s2 = new Ifc2x3::IfcCompositeCurveSegment(Ifc2x3::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, trim);
Ifc2x3::IfcPolyline* poly = new Ifc2x3::IfcPolyline(points);
file.AddEntity(poly);
file.addEntity(poly);
Ifc2x3::IfcCompositeCurveSegment* s1 = new Ifc2x3::IfcCompositeCurveSegment(Ifc2x3::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, poly);
segments->push(s1);
segments->push(s2);
file.AddEntities(segments->generalize());
file.addEntities(segments->generalize());
Ifc2x3::IfcCompositeCurve* ccurve = new Ifc2x3::IfcCompositeCurve(segments, false);
Ifc2x3::IfcArbitraryClosedProfileDef* profile = new Ifc2x3::IfcArbitraryClosedProfileDef(Ifc2x3::IfcProfileTypeEnum::IfcProfileType_AREA, null, ccurve);
file.AddEntity(ccurve);
file.AddEntity(profile);
file.addEntity(ccurve);
file.addEntity(profile);
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
guid(), 0, S("profile"), null, null, 0, 0, null, null);
file.addBuildingProduct(product);
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
product->setObjectPlacement(file.addLocalPlacement(200 * i++));
product->setObjectPlacement(file.addLocalPlacement(0, 200 * i++));
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(profile,
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
file.AddEntity(solid);
file.addEntity(solid);
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
items->push(solid);
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("SweptSolid"), items);
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
file.AddEntity(rep);
file.AddEntity(shape);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
file.addEntity(rep);
file.addEntity(shape);
product->setRepresentation(shape);
}
+207
View File
@@ -0,0 +1,207 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* Example that generates various forms of IfcFace *
* *
********************************************************************************/
#include "../ifcparse/Ifc2x3.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcHierarchyHelper.h"
typedef std::string S;
typedef IfcParse::IfcGlobalId guid;
boost::none_t const null = (static_cast<boost::none_t>(0));
static int x = 0;
void create_testcase(IfcHierarchyHelper& file, IfcSchema::IfcFace* face, const std::string& name) {
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
faces->push(face);
IfcSchema::IfcOpenShell* shell = new IfcSchema::IfcOpenShell(faces);
IfcSchema::IfcConnectedFaceSet::list::ptr shells(new IfcSchema::IfcConnectedFaceSet::list);
shells->push(shell);
IfcSchema::IfcFaceBasedSurfaceModel* model = new IfcSchema::IfcFaceBasedSurfaceModel(shells);
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
guid(), 0, name, null, null, 0, 0, null, null);
file.addBuildingProduct(product);
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
product->setObjectPlacement(file.addLocalPlacement(0, 1000 * x++, 0));
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
items->push(model);
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
file.getRepresentationContext("Model"), S("Body"), S("SurfaceModel"), items);
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
file.addEntity(shape);
product->setRepresentation(shape);
}
int main(int argc, char** argv) {
IfcHierarchyHelper file;
{
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
bounds->push(bound);
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
create_testcase(file, face, "polyloop");
}
{
IfcSchema::IfcCartesianPoint* point1 = file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, 0., 0.);
IfcSchema::IfcCartesianPoint* point2 = file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, 0., 0.);
IfcSchema::IfcVertexPoint* vertex1 = new IfcSchema::IfcVertexPoint(point1);
IfcSchema::IfcVertexPoint* vertex2 = new IfcSchema::IfcVertexPoint(point2);
IfcSchema::IfcCircle* circle = new IfcSchema::IfcCircle(file.addPlacement2d(), 400.);
IfcSchema::IfcEdgeCurve* edge1 = new IfcSchema::IfcEdgeCurve(vertex1, vertex2, circle, true);
IfcSchema::IfcEdgeCurve* edge2 = new IfcSchema::IfcEdgeCurve(vertex2, vertex1, circle, true);
IfcSchema::IfcOrientedEdge* oriented_edge1 = new IfcSchema::IfcOrientedEdge(edge1, true);
IfcSchema::IfcOrientedEdge* oriented_edge2 = new IfcSchema::IfcOrientedEdge(edge2, true);
IfcSchema::IfcOrientedEdge::list::ptr edges(new IfcSchema::IfcOrientedEdge::list);
edges->push(oriented_edge1);
edges->push(oriented_edge2);
IfcSchema::IfcEdgeLoop* loop = new IfcSchema::IfcEdgeLoop(edges);
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
bounds->push(bound);
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
create_testcase(file, face, "circle");
}
{
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
IfcSchema::IfcFaceOuterBound* outer_bound = new IfcSchema::IfcFaceOuterBound(loop, true);
IfcSchema::IfcCartesianPoint::list::ptr points2 (new IfcSchema::IfcCartesianPoint::list);
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-300, -300, 0));
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, -300, 0));
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, +300, 0));
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-300, +300, 0));
IfcSchema::IfcPolyLoop* loop2 = new IfcSchema::IfcPolyLoop(points2);
IfcSchema::IfcFaceBound* inner_bound1 = new IfcSchema::IfcFaceBound(loop2, false);
IfcSchema::IfcCartesianPoint::list::ptr points3 (new IfcSchema::IfcCartesianPoint::list);
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, +300, 0));
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+300, +300, 0));
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+300, -300, 0));
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, -300, 0));
IfcSchema::IfcPolyLoop* loop3 = new IfcSchema::IfcPolyLoop(points3);
IfcSchema::IfcFaceBound* inner_bound2 = new IfcSchema::IfcFaceBound(loop3, true);
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
bounds->push(inner_bound1);
bounds->push(outer_bound);
bounds->push(inner_bound2);
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
create_testcase(file, face, "polyloop with holes");
}
{
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, -400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, +400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
IfcSchema::IfcFaceOuterBound* bound1 = new IfcSchema::IfcFaceOuterBound(loop, true);
IfcSchema::IfcCartesianPoint::list::ptr points2 (new IfcSchema::IfcCartesianPoint::list);
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, +400, 0));
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, -400, 0));
IfcSchema::IfcPolyLoop* loop2 = new IfcSchema::IfcPolyLoop(points2);
IfcSchema::IfcFaceOuterBound* bound2 = new IfcSchema::IfcFaceOuterBound(loop2, false);
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
bounds->push(bound1);
bounds->push(bound2);
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
create_testcase(file, face, "multiple outer boundaries (invalid)");
}
{
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 1e-6));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
bounds->push(bound);
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
create_testcase(file, face, "imprecise polyloop");
}
{
IfcSchema::IfcCartesianPoint* point1 = file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, 0., 0.);
IfcSchema::IfcCartesianPoint* point2 = file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, 0., 0.);
IfcSchema::IfcVertexPoint* vertex1 = new IfcSchema::IfcVertexPoint(point1);
IfcSchema::IfcVertexPoint* vertex2 = new IfcSchema::IfcVertexPoint(point2);
IfcSchema::IfcCircle* circle = new IfcSchema::IfcCircle(file.addPlacement2d(), 400.);
IfcSchema::IfcEdgeCurve* edge1 = new IfcSchema::IfcEdgeCurve(vertex1, vertex2, circle, true);
IfcSchema::IfcEdgeCurve* edge2 = new IfcSchema::IfcEdgeCurve(vertex2, vertex1, circle, true);
IfcSchema::IfcOrientedEdge* oriented_edge1 = new IfcSchema::IfcOrientedEdge(edge1, true);
IfcSchema::IfcOrientedEdge* oriented_edge2 = new IfcSchema::IfcOrientedEdge(edge2, true);
IfcSchema::IfcOrientedEdge::list::ptr edges(new IfcSchema::IfcOrientedEdge::list);
edges->push(oriented_edge1);
edges->push(oriented_edge2);
IfcSchema::IfcEdgeLoop* loop = new IfcSchema::IfcEdgeLoop(edges);
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
bounds->push(bound);
IfcSchema::IfcCartesianPoint::list::ptr trim1(new IfcSchema::IfcCartesianPoint::list);
IfcSchema::IfcCartesianPoint::list::ptr trim2(new IfcSchema::IfcCartesianPoint::list);
trim1->push(point1);
trim2->push(point2);
IfcSchema::IfcTrimmedCurve* trimmed_curve = new IfcSchema::IfcTrimmedCurve(circle, trim1->generalize(), trim2->generalize(), true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);
IfcSchema::IfcArbitraryOpenProfileDef* profile = new IfcSchema::IfcArbitraryOpenProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_CURVE, boost::none, trimmed_curve);
IfcSchema::IfcAxis1Placement* place = new IfcSchema::IfcAxis1Placement(file.addTriplet<IfcSchema::IfcCartesianPoint>(0., 0., 0.), file.addTriplet<IfcSchema::IfcDirection>(1., 0., 0.));
IfcSchema::IfcSurfaceOfRevolution* surface = new IfcSchema::IfcSurfaceOfRevolution(profile, file.addPlacement3d(), place);
IfcSchema::IfcFace* face = new IfcSchema::IfcFaceSurface(bounds, surface, true);
create_testcase(file, face, "face surface");
}
const std::string filename = "faces.ifc";
file.header().file_name().name(filename);
std::ofstream f(filename.c_str());
f << file;
}
+22 -19
View File
@@ -35,7 +35,7 @@ typedef std::string S;
typedef IfcWrite::IfcGuidHelper guid;
boost::none_t const null = (static_cast<boost::none_t>(0));
void create_testcase_for(IfcSchema::IfcProfileDef::list profiles) {
void create_testcase_for(IfcSchema::IfcProfileDef::list::ptr profiles) {
IfcSchema::IfcProfileDef* profile = *profiles->begin();
const std::string profile_type = IfcSchema::Type::ToString(profile->type());
const std::string filename = profile_type + ".ifc";
@@ -44,7 +44,7 @@ void create_testcase_for(IfcSchema::IfcProfileDef::list profiles) {
file.filename(filename);
int i = 0;
for (IfcSchema::IfcProfileDef::it it = profiles->begin(); it != profiles->end(); ++it, ++i) {
for (IfcSchema::IfcProfileDef::list::it it = profiles->begin(); it != profiles->end(); ++it, ++i) {
IfcSchema::IfcProfileDef* profile = *it;
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
guid(), 0, S("profile"), null, null, 0, 0, null, null);
@@ -52,7 +52,7 @@ void create_testcase_for(IfcSchema::IfcProfileDef::list profiles) {
file.getSingle<IfcSchema::IfcProject>()->setName(profile_type);
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
product->setObjectPlacement(file.addLocalPlacement(100 * i));
product->setObjectPlacement(file.addLocalPlacement(0, 100. * i));
if (profile->is(IfcSchema::Type::IfcParameterizedProfileDef)) {
((IfcSchema::IfcParameterizedProfileDef*) profile)->setPosition(file.addPlacement2d());
@@ -61,11 +61,11 @@ void create_testcase_for(IfcSchema::IfcProfileDef::list profiles) {
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(profile,
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
file.AddEntity(profile);
file.AddEntity(solid);
file.addEntity(profile);
file.addEntity(solid);
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
items->push(solid);
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
@@ -73,8 +73,8 @@ void create_testcase_for(IfcSchema::IfcProfileDef::list profiles) {
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
file.AddEntity(rep);
file.AddEntity(shape);
file.addEntity(rep);
file.addEntity(shape);
product->setRepresentation(shape);
}
@@ -84,7 +84,7 @@ void create_testcase_for(IfcSchema::IfcProfileDef::list profiles) {
}
int main(int argc, char** argv) {
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
profiles->push(new Ifc2x3::IfcUShapeProfileDef(
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
null, 0, 50.0, 25.0, 5.0, 5.0, null, null, null, null));
@@ -99,7 +99,7 @@ int main(int argc, char** argv) {
null, 0, 50.0, 25.0, 5.0, 5.0, 1.0, 3.0, 6.0, null));
create_testcase_for(profiles); }
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
profiles->push(new Ifc2x3::IfcTShapeProfileDef(
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
null, 0, 50.0, 25.0, 5.0, 5.0, null, null, null, null, null, null));
@@ -114,7 +114,7 @@ int main(int argc, char** argv) {
null, 0, 50.0, 25.0, 5.0, 5.0, 3.0, 2.0, 1.0, 2.0, 2.0, null));
create_testcase_for(profiles); }
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
profiles->push(new Ifc2x3::IfcZShapeProfileDef(
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
null, 0, 50.0, 25.0, 5.0, 5.0, null, null));
@@ -123,7 +123,7 @@ int main(int argc, char** argv) {
null, 0, 50.0, 25.0, 5.0, 5.0, 2.0, 2.0));
create_testcase_for(profiles); }
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
profiles->push(new Ifc2x3::IfcEllipseProfileDef(
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
null, 0, 25.0, 15.0));
@@ -132,16 +132,19 @@ int main(int argc, char** argv) {
null, 0, 15.0, 25.0));
create_testcase_for(profiles); }
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
profiles->push(new Ifc2x3::IfcIShapeProfileDef(
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
null, 0, 25.0, 50.0, 5.0, 5.0, null));
profiles->push(new Ifc2x3::IfcIShapeProfileDef(
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
null, 0, 25.0, 50.0, 5.0, 5.0, 2.0));
profiles->push(new Ifc2x3::IfcAsymmetricIShapeProfileDef(
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
null, 0, 25.0, 50.0, 5.0, 5.0, 2.0, 20.0, 10.0, 5.0, null));
create_testcase_for(profiles); }
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
profiles->push(new Ifc2x3::IfcLShapeProfileDef(
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
null, 0, 50.0, 25.0, 5.0, null, null, null, null, null));
@@ -156,7 +159,7 @@ int main(int argc, char** argv) {
null, 0, 50.0, 25.0, 5.0, 1.0, 2.0, 2.0, null, null));
create_testcase_for(profiles); }
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
profiles->push(new Ifc2x3::IfcCShapeProfileDef(
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
null, 0, 50.0, 25.0, 5.0, 10.0, null, null));
@@ -165,7 +168,7 @@ int main(int argc, char** argv) {
null, 0, 50.0, 25.0, 5.0, 10.0, 2.0, null));
create_testcase_for(profiles); }
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
profiles->push(new Ifc2x3::IfcCircleProfileDef(
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
null, 0, 25.0));
@@ -174,7 +177,7 @@ int main(int argc, char** argv) {
null, 0, 25.0, 5.0));
create_testcase_for(profiles); }
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
profiles->push(new Ifc2x3::IfcRectangleProfileDef(
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
null, 0, 50.0, 25.0));
@@ -189,7 +192,7 @@ int main(int argc, char** argv) {
null, 0, 50.0, 25.0, 5.0, 2.0, 4.0));
create_testcase_for(profiles); }
{ IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
profiles->push(new Ifc2x3::IfcTrapeziumProfileDef(
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
null, 0, 50.0, 30.0, 25.0, 0.0));
File diff suppressed because it is too large Load Diff
+85
View File
@@ -0,0 +1,85 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* Example that generates an IfcTriangulatedFaceSet *
* *
********************************************************************************/
#include "../ifcparse/Ifc4.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcHierarchyHelper.h"
#include "suzanne_geometry.h"
typedef std::string S;
typedef IfcParse::IfcGlobalId guid;
boost::none_t const null = (static_cast<boost::none_t>(0));
template <typename T>
std::vector< std::vector<T> > create_vector_from_array(const T* arr, unsigned size) {
std::vector< std::vector<T> > result;
result.reserve(size);
for (unsigned i = 0; i < size; ) {
std::vector<T> ts; ts.reserve(3);
for (unsigned j = 0; j < 3; ++i, ++j) {
ts.push_back(arr[i]);
}
result.push_back(ts);
}
return result;
}
int main(int argc, char** argv) {
IfcHierarchyHelper file;
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
guid(), 0, S("Blender's Suzanne"), null, null, 0, 0, null, null);
file.addBuildingProduct(product);
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
product->setObjectPlacement(file.addLocalPlacement());
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
std::vector< std::vector< double > > vertices_vector = create_vector_from_array(vertices, sizeof(vertices) / sizeof(vertices[0]));
std::vector< std::vector< int > > indices_vector = create_vector_from_array(indices, sizeof(indices) / sizeof(indices[0]));
IfcSchema::IfcCartesianPointList3D* coordinates = new IfcSchema::IfcCartesianPointList3D(vertices_vector);
IfcSchema::IfcTriangulatedFaceSet* faceset = new IfcSchema::IfcTriangulatedFaceSet(coordinates, null, null, indices_vector, null);
items->push(faceset);
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
file.getRepresentationContext("Model"), S("Body"), S("SurfaceModel"), items);
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
file.addEntity(shape);
product->setRepresentation(shape);
const std::string filename = "tesselated_faceset.ifc";
file.header().file_name().name(filename);
std::ofstream f(filename.c_str());
f << file;
}
+24
View File
@@ -0,0 +1,24 @@
################################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
################################################################################
ADD_EXECUTABLE(hdf5_federate federate.cpp)
TARGET_LINK_LIBRARIES(hdf5_federate IfcParse ${ICU_LIBRARIES} ${Boost_LIBRARIES})
ADD_EXECUTABLE(hdf5_lod lod.cpp)
TARGET_LINK_LIBRARIES(hdf5_lod IfcParse IfcGeom ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBRARIES})
+361
View File
@@ -0,0 +1,361 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include "../../../src/ifcparse/IfcHdf5File.h"
#include "../../../src/ifcparse/IfcWritableEntity.h"
#include <boost/lexical_cast.hpp>
#include <set>
#include <algorithm>
#include "multifile_instance_locator.h"
#pragma warning(disable:4100)
// A comparison operator that is used to isolate the shared hierarchy
class ifc_inst_cmp {
public:
// For these we simply assume that only a single instance exists
bool operator()(IfcSchema::IfcSite* a, IfcSchema::IfcSite* b) const { return false; }
bool operator()(IfcSchema::IfcProject* a, IfcSchema::IfcProject* b) const { return false; }
bool operator()(IfcSchema::IfcBuilding* a, IfcSchema::IfcBuilding* b) const { return false; }
bool operator()(IfcSchema::IfcPostalAddress* a, IfcSchema::IfcPostalAddress* b) const { return false; }
bool operator()(IfcSchema::IfcUnitAssignment* a, IfcSchema::IfcUnitAssignment* b) const { return false; }
bool operator()(IfcSchema::IfcConversionBasedUnit* a, IfcSchema::IfcConversionBasedUnit* b) const {
return a->Name() < b->Name();
}
bool operator()(IfcSchema::IfcDimensionalExponents* a, IfcSchema::IfcDimensionalExponents* b) const {
// For every attribute (which are all integers) check equality
unsigned num_attrs = a->data().getArgumentCount();
for (unsigned i = 0; i < num_attrs; ++i) {
const int v1 = *a->data().getArgument(i);
const int v2 = *b->data().getArgument(i);
if (v1 != v2) {
return v1 < v2;
}
}
return false;
}
bool operator()(IfcSchema::IfcMeasureWithUnit* a, IfcSchema::IfcMeasureWithUnit* b) const {
// Assume the value component is enough to differentiate
double v1 = *a->ValueComponent()->data().getArgument(0);
double v2 = *b->ValueComponent()->data().getArgument(0);
return v1 < v2;
}
bool operator()(IfcSchema::IfcGeometricRepresentationSubContext* a, IfcSchema::IfcGeometricRepresentationSubContext* b) const {
return a->ContextType() < b->ContextType();
}
bool operator()(IfcSchema::IfcGeometricRepresentationContext* a, IfcSchema::IfcGeometricRepresentationContext* b) const {
return a->ContextType() < b->ContextType();
}
bool operator()(IfcSchema::IfcSIUnit* a, IfcSchema::IfcSIUnit* b) const {
// Assume same units accross files
return a->UnitType() < b->UnitType();
}
bool operator()(IfcSchema::IfcBuildingStorey* a, IfcSchema::IfcBuildingStorey* b) const {
return a->Name() < b->Name();
}
bool operator()(IfcSchema::IfcCartesianPoint* a, IfcSchema::IfcCartesianPoint* b) const {
return a->Coordinates() < b->Coordinates();
}
bool operator()(IfcSchema::IfcDirection* a, IfcSchema::IfcDirection* b) const {
return a->DirectionRatios() < b->DirectionRatios();
}
bool operator()(IfcSchema::IfcAxis2Placement3D* a, IfcSchema::IfcAxis2Placement3D* b) const {
if (a->Location()->Coordinates() != b->Location()->Coordinates()) {
return (*this)(a->Location(), b->Location());
}
if (b->hasAxis()) {
if (!a->hasAxis()) {
return true;
} else {
return (*this)(a->Axis(), b->Axis());
}
}
if (b->hasRefDirection()) {
if (!a->hasRefDirection()) {
return true;
} else {
return (*this)(a->RefDirection(), b->RefDirection());
}
}
return false;
}
bool operator()(IfcSchema::IfcLocalPlacement* a, IfcSchema::IfcLocalPlacement* b) const {
if (b->hasPlacementRelTo()) {
if (!a->hasPlacementRelTo()) {
return true;
} else {
return (*this)(a->PlacementRelTo(), b->PlacementRelTo());
}
}
return (*this)(a->RelativePlacement(), b->RelativePlacement());
}
bool operator()(IfcUtil::IfcBaseClass* a, IfcUtil::IfcBaseClass* b) const {
if (a->declaration().type() != b->declaration().type()) {
return a->declaration().type() < b->declaration().type();
// throw std::runtime_error("Types not matching");
}
if (a->declaration().type() == IfcSchema::Type::IfcSite) { return (*this)((IfcSchema::IfcSite*) a, (IfcSchema::IfcSite*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcConversionBasedUnit) { return (*this)((IfcSchema::IfcConversionBasedUnit*) a, (IfcSchema::IfcConversionBasedUnit*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcDimensionalExponents) { return (*this)((IfcSchema::IfcDimensionalExponents*) a, (IfcSchema::IfcDimensionalExponents*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcMeasureWithUnit) { return (*this)((IfcSchema::IfcMeasureWithUnit*) a, (IfcSchema::IfcMeasureWithUnit*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcProject) { return (*this)((IfcSchema::IfcProject*) a, (IfcSchema::IfcProject*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcBuilding) { return (*this)((IfcSchema::IfcBuilding*) a, (IfcSchema::IfcBuilding*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcPostalAddress) { return (*this)((IfcSchema::IfcPostalAddress*) a, (IfcSchema::IfcPostalAddress*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcUnitAssignment) { return (*this)((IfcSchema::IfcUnitAssignment*) a, (IfcSchema::IfcUnitAssignment*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcGeometricRepresentationSubContext) { return (*this)((IfcSchema::IfcGeometricRepresentationSubContext*) a, (IfcSchema::IfcGeometricRepresentationSubContext*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcGeometricRepresentationContext) { return (*this)((IfcSchema::IfcGeometricRepresentationContext*) a, (IfcSchema::IfcGeometricRepresentationContext*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcSIUnit) { return (*this)((IfcSchema::IfcSIUnit*) a, (IfcSchema::IfcSIUnit*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcBuildingStorey) { return (*this)((IfcSchema::IfcBuildingStorey*) a, (IfcSchema::IfcBuildingStorey*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcCartesianPoint) { return (*this)((IfcSchema::IfcCartesianPoint*) a, (IfcSchema::IfcCartesianPoint*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcDirection) { return (*this)((IfcSchema::IfcDirection*) a, (IfcSchema::IfcDirection*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcAxis2Placement3D) { return (*this)((IfcSchema::IfcAxis2Placement3D*) a, (IfcSchema::IfcAxis2Placement3D*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcLocalPlacement) { return (*this)((IfcSchema::IfcLocalPlacement*) a, (IfcSchema::IfcLocalPlacement*) b); }
// Should these be removed if an owner history is created manually?
if (a->declaration().type() == IfcSchema::Type::IfcPerson) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
if (a->declaration().type() == IfcSchema::Type::IfcOrganization) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
if (a->declaration().type() == IfcSchema::Type::IfcPersonAndOrganization) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
if (a->declaration().type() == IfcSchema::Type::IfcOwnerHistory) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
if (a->declaration().type() == IfcSchema::Type::IfcApplication) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
std::cerr << "Unexpected type: " + IfcSchema::Type::ToString(a->declaration().type()) << std::endl;
throw std::runtime_error("Unexpected type: " + IfcSchema::Type::ToString(a->declaration().type()));
}
};
// Usage: hdf5_federate Office_A_20110811_optimized.ifc Office_S_20110811_optimized.ifc Office_MEP_20110811_optimized.ifc
int main(int argc, char** argv) {
// A set of datatypes for the shared hierarchy
std::set<IfcSchema::Type::Enum> shared {
IfcSchema::Type::IfcSite,
IfcSchema::Type::IfcConversionBasedUnit,
IfcSchema::Type::IfcDimensionalExponents,
IfcSchema::Type::IfcMeasureWithUnit,
IfcSchema::Type::IfcProject,
IfcSchema::Type::IfcBuilding,
IfcSchema::Type::IfcPostalAddress,
IfcSchema::Type::IfcUnitAssignment,
IfcSchema::Type::IfcGeometricRepresentationSubContext,
IfcSchema::Type::IfcGeometricRepresentationContext,
IfcSchema::Type::IfcSIUnit,
IfcSchema::Type::IfcBuildingStorey
};
// Open the set of input files
std::vector<IfcParse::IfcFile*> files;
for (int i = 1; i < argc; ++i) {
files.push_back(new IfcParse::IfcFile());
files.back()->Init(argv[i]);
}
// Detect shared instances
std::set<IfcUtil::IfcBaseClass*> shared_instances;
for (auto& ty : shared) {
std::cout << IfcSchema::Type::ToString(ty) << std::endl;
for (auto& file : files) {
IfcEntityList::ptr insts = file->entitiesByType(ty);
std::vector<IfcUtil::IfcBaseClass*> no_subtypes;
std::copy_if(insts->begin(), insts->end(), std::back_inserter(no_subtypes), [ty](IfcUtil::IfcBaseClass* inst) {
return inst->declaration().type() == ty;
});
std::set<IfcUtil::IfcBaseClass*, ifc_inst_cmp> insts_unique(no_subtypes.begin(), no_subtypes.end());
if (insts_unique.size() != no_subtypes.size()) {
throw std::runtime_error("Non-unique instances encountered within file");
}
shared_instances.insert(insts_unique.begin(), insts_unique.end());
}
}
// Follow forward references for shared instances
std::set<IfcUtil::IfcBaseClass*> shared_instances_and_refs;
for (auto& inst : shared_instances) {
IfcEntityList::ptr insts = inst->data().file->traverse(inst);
// Filter out simple types
std::vector<IfcUtil::IfcBaseClass*> insts_without_types;
std::copy_if(insts->begin(), insts->end(), std::back_inserter(insts_without_types), [](IfcUtil::IfcBaseClass* inst) {
return inst->declaration().as_entity() != nullptr;
});
shared_instances_and_refs.insert(insts_without_types.begin(), insts_without_types.end());
}
time_t now_;
time(&now_);
int now = (int)now_;
// Create a novel ownerhistory for the shared hierarchy
IfcSchema::IfcPerson* person = new IfcSchema::IfcPerson(std::string("tfk"), std::string("Krijnen"), std::string("Thomas"), boost::none, boost::none, boost::none, boost::none, boost::none);
IfcSchema::IfcOrganization* org = new IfcSchema::IfcOrganization(std::string("TU/e"), "Eindhoven University of Technology", boost::none, boost::none, boost::none);
IfcSchema::IfcPersonAndOrganization* pando = new IfcSchema::IfcPersonAndOrganization(person, org, boost::none);
IfcSchema::IfcApplication* appl = new IfcSchema::IfcApplication(org, "v1", "IfcOpenShell-HDF5", "IfcOpenShell-HDF5");
IfcSchema::IfcOwnerHistory* owner_history = new IfcSchema::IfcOwnerHistory(pando, appl, IfcSchema::IfcStateEnum::IfcState_READONLY, IfcSchema::IfcChangeActionEnum::IfcChangeAction_ADDED, now, pando, appl, now);
std::vector<IfcUtil::IfcBaseClass*> replacements{ person, org, pando, appl, owner_history};
std::vector<IfcUtil::IfcBaseClass*> shared_instances_and_refs_vector(shared_instances_and_refs.begin(), shared_instances_and_refs.end());
IfcParse::IfcFile temp;
for (int i = 0; i < 0x1000001; ++i) temp.FreshId();
std::for_each(replacements.begin(), replacements.end(), [&shared_instances_and_refs_vector, &temp](IfcUtil::IfcBaseClass* new_inst) {
temp.addEntity(new_inst);
shared_instances_and_refs_vector.erase(
std::remove_if(shared_instances_and_refs_vector.begin(), shared_instances_and_refs_vector.end(), [new_inst](IfcUtil::IfcBaseClass* orig_inst) {
return orig_inst->declaration().type() == new_inst->declaration().type();
}),
shared_instances_and_refs_vector.end()
);
shared_instances_and_refs_vector.push_back(new_inst);
});
shared_instances_and_refs.clear();
shared_instances_and_refs.insert(shared_instances_and_refs_vector.begin(), shared_instances_and_refs_vector.end());
// Assign the new ownerhistory to rooted elements in the shared hierarchy
std::for_each(shared_instances_and_refs.begin(), shared_instances_and_refs.end(), [owner_history](IfcUtil::IfcBaseClass* inst) {
const IfcParse::entity* e = inst->declaration().as_entity();
if (e) {
auto attributes = e->all_attributes();
int index = 0;
std::for_each(attributes.begin(), attributes.end(), [&index, inst, owner_history](const IfcParse::entity::attribute* attr) {
const IfcParse::named_type* nt = attr->type_of_attribute()->as_named_type();
if (nt) {
const IfcParse::entity* e2 = nt->declared_type()->as_entity();
if (e2 && e2->type() == IfcSchema::Type::IfcOwnerHistory) {
IfcWrite::IfcWritableEntity* writable = new IfcWrite::IfcWritableEntity(&inst->data());
writable->setArgument(index, owner_history);
inst->data(writable);
}
}
index++;
});
}
});
std::set<IfcUtil::IfcBaseClass*, ifc_inst_cmp> shared_instances_and_refs_unique(shared_instances_and_refs.begin(), shared_instances_and_refs.end());
// Serialize models into different groups
IfcParse::Hdf5Settings settings;
settings.profile() = IfcParse::Hdf5Settings::standard_referenced;
settings.compress() = true;
settings.chunk_size() = 1024;
std::vector<std::string> names;
std::vector<std::pair<std::string::const_iterator, std::string::const_iterator>> fixes;
std::string common_prefix, common_postfix;
for (int i = 1; i < argc; ++i) {
names.push_back(argv[i]);
fixes.push_back({ names.back().begin(), names.back().end() - 1 });
}
while (true) {
std::vector<char> chars;
std::transform(fixes.begin(), fixes.end(), std::back_inserter(chars), [](auto& pair) {
if (pair.first == pair.second) return '\0';
return (*pair.first++);
});
auto pred = std::bind(std::equal_to<char>(), std::placeholders::_1, chars.front());
if (chars.front() != 0 && std::all_of(chars.begin()+1, chars.end(), pred)) {
common_prefix.push_back(chars.front());
} else {
break;
}
}
while (true) {
std::vector<char> chars;
std::transform(fixes.begin(), fixes.end(), std::back_inserter(chars), [](auto& pair) {
if (pair.first == pair.second) return '\0';
return (*pair.second--);
});
auto pred = std::bind(std::equal_to<char>(), std::placeholders::_1, chars.front());
if (chars.front() != 0 && std::all_of(chars.begin() + 1, chars.end(), pred)) {
common_postfix.insert(common_postfix.begin(), chars.front());
} else {
break;
}
}
H5::H5File file(common_prefix + common_postfix + ".hdf", H5F_ACC_TRUNC);
H5::Group group1 = file.createGroup("population");
IfcParse::IfcHdf5File ifc_hdf5(file, get_schema(), settings);
IfcParse::IfcSpfHeader header;
header.set_default();
IfcParse::instance_enumerator shared_insts_enum(&header, shared_instances_and_refs_unique.begin(), shared_instances_and_refs_unique.end());
multifile_instance_locator* locator = new multifile_instance_locator(file, group1, [&shared_instances_and_refs_unique](IfcUtil::IfcBaseClass* inst) {
auto it = shared_instances_and_refs_unique.find(inst);
if (it == shared_instances_and_refs_unique.end()) {
return inst;
} else {
return *it;
}
}, shared_instances_and_refs_unique.begin(), shared_instances_and_refs_unique.end());
ifc_hdf5.write_schema();
ifc_hdf5.write_population(group1, shared_insts_enum, locator);
int n = 0;
for (auto f : files) {
auto filename = argv[n++ + 1];
H5::Group discipline_group = file.createGroup(filename);
H5::Group child_group = discipline_group.createGroup("population");
locator->next(filename, child_group, f);
IfcParse::instance_enumerator inst_enum(&f->header(), locator->full_begin(), locator->full_end());
ifc_hdf5.write_population(child_group, inst_enum, locator);
}
return 0;
}
+472
View File
@@ -0,0 +1,472 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include "../../../src/ifcparse/IfcHdf5File.h"
#include "../../../src/ifcgeom/IfcGeom.h"
#include "../../../src/ifcparse/IfcWritableEntity.h"
#include <Bnd_Box.hxx>
#include <BRepBndLib.hxx>
#include <BRep_Builder.hxx>
#include <TopoDS_Compound.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepBuilderAPI_GTransform.hxx>
#include <algorithm>
#include "multifile_instance_locator.h"
void generate_bounding_boxes(IfcParse::IfcFile& f, const std::string& fn) {
IfcGeom::Kernel kernel;
auto unit_factor = kernel.initializeUnits(*f.entitiesByType<IfcSchema::IfcUnitAssignment>()->begin());
IfcGeom::IteratorSettings settings;
settings.convert_back_units() = true;
settings.disable_triangulation() = true;
settings.disable_opening_subtractions() = true;
IfcSchema::IfcProductDefinitionShape::list::ptr defs_ = f.entitiesByType<IfcSchema::IfcProductDefinitionShape>();
std::vector<IfcSchema::IfcProductDefinitionShape*> defs(defs_->begin(), defs_->end());
// Make sure to sort by id to have new definitions lining up in the same order
std::sort(defs.begin(), defs.end(), [](IfcSchema::IfcProductDefinitionShape* a, IfcSchema::IfcProductDefinitionShape* b) {
return a->data().id() < b->data().id();
});
std::ofstream str(fn.c_str(), std::ios_base::binary);
int N = defs.size(), n = 0;
std::cerr << "boxes:" << std::endl;
// In newer versions of IfcOpenShell this is a method Kernel::apply_transformation()
auto apply_transformation = [](const TopoDS_Shape& s, const gp_GTrsf& gt) {
if (gt.Form() == gp_Other) {
return BRepBuilderAPI_GTransform(s, gt, true).Shape();
}
gp_Trsf t = gt.Trsf();
if (t.Form() == gp_Identity) {
return s;
} else {
/// @todo set to 1. and exactly 1. or use epsilon?
if (t.ScaleFactor() != 1.) {
return BRepBuilderAPI_Transform(s, t, true).Shape();
} else {
return s.Moved(t);
}
}
};
// In newer versions of IfcOpenShell this is a method BRep::as_compound()
auto brep_as_compound = [&apply_transformation](const IfcGeom::Representation::BRep& brep) {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++it) {
const TopoDS_Shape& s = it->Shape();
gp_GTrsf trsf = it->Placement();
if (brep.settings().convert_back_units()) {
gp_Trsf scale;
scale.SetScaleFactor(1.0 / brep.settings().unit_magnitude());
trsf.PreMultiply(scale);
}
const TopoDS_Shape moved_shape = apply_transformation(s, trsf);
builder.Add(compound, moved_shape);
}
return compound;
};
// Generate non-aa bounding boxes in local coordinates as a tuple of six doubles from existing IfcProductDefinitionShape instances
std::for_each(defs.begin(), defs.end(), [&kernel, &brep_as_compound, &str, N, &n, &settings](IfcSchema::IfcProductDefinitionShape* def) {
Bnd_Box box;
auto prods = def->data().getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>();
if (prods->size() != 1) return;
IfcSchema::IfcProduct* prod = *prods->begin();
auto reps = def->Representations();
std::for_each(reps->begin(), reps->end(), [&kernel, &brep_as_compound, &settings, &box, prod](auto rep) {
if (rep->RepresentationIdentifier() == "Body") {
IfcGeom::BRepElement<double>* elem = kernel.create_brep_for_representation_and_product<double>(settings, rep, prod);
BRepBndLib::AddClose(brep_as_compound(elem->geometry()), box);
delete elem;
}
});
const size_t name = def->data().id();
double xyz[6];
box.Get(xyz[0], xyz[1], xyz[2], xyz[3], xyz[4], xyz[5]);
str.write((char*)&name, sizeof(size_t));
str.write((char*)xyz, sizeof(double) * 6);
if (n++ % 1000 == 0) {
std::cerr << "\r" << n * 100 / N << std::flush;
}
});
std::cerr << std::endl;
}
void find_geometric_types(IfcParse::IfcFile& f, const std::string& tfn) {
std::ofstream str(tfn.c_str(), std::ios_base::binary);
IfcSchema::IfcProductDefinitionShape::list::ptr defs_ = f.entitiesByType<IfcSchema::IfcProductDefinitionShape>();
std::vector<IfcSchema::IfcProductDefinitionShape*> defs(defs_->begin(), defs_->end());
// Make sure to sort by id to have new definitions lining up in the same order
std::sort(defs.begin(), defs.end(), [](IfcSchema::IfcProductDefinitionShape* a, IfcSchema::IfcProductDefinitionShape* b) {
return a->data().id() < b->data().id();
});
// Initial choice of geometric types
std::set<IfcSchema::Type::Enum> geometric_types{
IfcSchema::Type::IfcStyledItem, IfcSchema::Type::IfcMaterialDefinitionRepresentation, IfcSchema::Type::IfcStyledRepresentation,
IfcSchema::Type::IfcSurfaceStyleRendering, IfcSchema::Type::IfcSurfaceStyle, IfcSchema::Type::IfcPresentationLayerAssignment,
IfcSchema::Type::IfcPresentationStyleAssignment, IfcSchema::Type::IfcColourRgb
};
std::set<IfcSchema::Type::Enum> other_types;
// Find all instances
std::set<IfcUtil::IfcBaseClass*> geometric_instances;
for (auto ty : geometric_types) {
auto insts = f.entitiesByType(ty);
std::for_each(insts->begin(), insts->end(), [&geometric_instances](IfcUtil::IfcBaseClass* inst) {
geometric_instances.insert(inst);
});
}
int N, n;
// Not referenced. Revit generates unused IfcExtrudedAreaSolids some times.
auto repitems = f.entitiesByType(IfcSchema::Type::IfcRepresentationItem);
std::for_each(repitems->begin(), repitems->end(), [&f, &geometric_instances](IfcUtil::IfcBaseClass* inst) {
auto invs = f.getInverse(inst->data().id(), IfcSchema::Type::UNDEFINED, -1);
if (invs->size() == 0) {
auto refs = f.traverse(inst);
std::for_each(refs->begin(), refs->end(), [&geometric_instances](IfcUtil::IfcBaseClass* inst2) {
if (inst2->declaration().as_entity()) {
geometric_instances.insert(inst2);
}
});
}
});
// Recurse over forward attributes
auto vist_geometric = [&f, &geometric_types, &geometric_instances, &N, &n](IfcUtil::IfcBaseEntity* def) {
auto refs = f.traverse(def);
geometric_instances.insert(refs->begin(), refs->end());
std::for_each(refs->begin(), refs->end(), [&geometric_types](IfcUtil::IfcBaseClass* inst) {
if (inst->declaration().as_entity()) {
geometric_types.insert(inst->declaration().type());
}
});
if (n++ % 1000 == 0) {
std::cerr << "\r" << (n * 100 / N) << std::flush;
}
};
n = 0;
N = defs.size();
std::for_each(defs.begin(), defs.end(), vist_geometric);
// Include connection geometry (e.g space boundaries) as well
auto connection_geom = f.entitiesByType<IfcSchema::IfcConnectionGeometry>();
n = 0;
N = connection_geom->size();
std::for_each(connection_geom->begin(), connection_geom->end(), vist_geometric);
// Traverse again all instances, but now to detect which geometric types are fully and only shared by geometric instances
std::function<void(IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*)> fn;
fn = [&f, &geometric_instances, &other_types, &fn](IfcUtil::IfcBaseClass* root, IfcUtil::IfcBaseClass* inst) {
if (geometric_instances.find(inst) == geometric_instances.end()) {
auto ty = inst->declaration().type();
other_types.insert(ty);
auto refs = f.traverse(inst, 1);
std::for_each(refs->begin() + 1, refs->end(), [&fn, root](IfcUtil::IfcBaseClass* inst) {
if (inst->declaration().as_entity()) {
fn(root, inst);
}
});
}
};
N = std::distance(f.begin(), f.end());
n = 0;
std::for_each(f.begin(), f.end(), [&fn, N, &n](const auto& pair) {
fn(pair.second, pair.second);
if (n++ % 1000 == 0) {
std::cerr << "\r" << n * 100 / N << std::flush;
}
});
std::set<IfcSchema::Type::Enum> only_geometric;
std::set_difference(geometric_types.begin(), geometric_types.end(),
other_types.begin(), other_types.end(),
std::inserter(only_geometric, only_geometric.begin()));
only_geometric.erase(IfcSchema::Type::IfcGeometricRepresentationContext);
only_geometric.erase(IfcSchema::Type::IfcGeometricRepresentationSubContext);
std::cerr << "\nOnly geometric:" << std::endl;
for (auto ty : only_geometric) {
std::cerr << IfcSchema::Type::ToString(ty) << std::endl;
const size_t name = ty;
str.write((char*)&name, sizeof(size_t));
}
}
int main(int argc, char** argv) {
const std::string cache_fn = argv[1] + std::string(".boxes.bin");
const std::string types_fn = argv[1] + std::string(".types.bin");
if (argc == 2 && !ifstream(cache_fn).good()) {
std::string command = std::string("\"\"") + argv[0] + "\" \"" + argv[1] + "\" -b\"";
if (system(command.c_str()) != 0) {
return 1;
}
}
if (argc == 2 && !ifstream(types_fn).good()) {
std::string command = std::string("\"\"") + argv[0] + "\" \"" + argv[1] + "\" -t\"";
if (system(command.c_str()) != 0) {
return 1;
}
}
IfcParse::IfcFile f;
f.Init(argv[1]);
if (argc == 3 && std::string(argv[2]) == "-b") {
generate_bounding_boxes(f, cache_fn);
return 0;
}
if (argc == 3 && std::string(argv[2]) == "-t") {
find_geometric_types(f, types_fn);
return 0;
}
std::set<IfcSchema::Type::Enum> only_geometric;
{
std::ifstream str(types_fn.c_str(), std::ios_base::binary);
while (!str.eof()) {
size_t name;
str.read((char*)&name, sizeof(size_t));
only_geometric.insert((IfcSchema::Type::Enum) name);
}
}
std::set<IfcSchema::Type::Enum> property_types {
IfcSchema::Type::IfcRelDefines,
IfcSchema::Type::IfcPropertySetDefinition,
IfcSchema::Type::IfcTypeObject,
IfcSchema::Type::IfcProperty,
IfcSchema::Type::IfcPhysicalQuantity,
IfcSchema::Type::IfcRelAssociatesClassification,
IfcSchema::Type::IfcClassification,
IfcSchema::Type::IfcClassificationReference,
IfcSchema::Type::IfcRelAssociatesMaterial,
IfcSchema::Type::IfcMaterialList,
IfcSchema::Type::IfcMaterialLayerSetUsage,
IfcSchema::Type::IfcMaterialLayerSet,
IfcSchema::Type::IfcMaterialLayer,
IfcSchema::Type::IfcMaterial
};
std::vector<IfcUtil::IfcBaseClass*> new_defs, old_defs, old_prop_defs, old_geom_defs, old_box_defs, all_old_defs, all_defs;
std::for_each(only_geometric.begin(), only_geometric.end(), [&f, &old_geom_defs](IfcSchema::Type::Enum t) {
auto insts = f.entitiesByType(t);
std::for_each(insts->begin(), insts->end(), [t, &old_geom_defs](IfcUtil::IfcBaseClass* inst) {
if (inst->declaration().type() == t) {
old_geom_defs.push_back(inst);
}
});
});
std::for_each(f.begin(), f.end(), [&only_geometric, &old_defs, &old_prop_defs, &property_types](const auto& pair) {
IfcUtil::IfcBaseClass* inst = pair.second;
// This is checked the other way around to include subtypes
bool is_property = false;
for (auto pty : property_types) {
if (inst->declaration().is(pty)) {
is_property = true;
break;
}
}
auto ty = inst->declaration().type();
if (is_property) {
old_prop_defs.push_back(inst);
} else if (only_geometric.find(ty) == only_geometric.end()) {
old_defs.push_back(inst);
}
});
IfcSchema::IfcRepresentationContext* context = 0;
auto reps = (*f.entitiesByType<IfcSchema::IfcProductDefinitionShape>()->begin())->Representations();
std::for_each(reps->begin(), reps->end(), [&context](auto rep) {
IfcGeom::IfcRepresentationShapeItems items;
if (rep->RepresentationIdentifier() == "Body") {
context = rep->ContextOfItems();
}
});
auto id = f.FreshId();
int num_points_added = 0;
// Create bounding box representation from the 6-tuple definitions
{
std::ifstream str(cache_fn.c_str(), std::ios_base::binary);
while (!str.eof()) {
size_t name;
double xyz[6];
str.read((char*)&name, sizeof(size_t));
str.read((char*)xyz, sizeof(double) * 6);
IfcSchema::IfcCartesianPoint* corner = new IfcSchema::IfcCartesianPoint(std::vector<double>{xyz[0], xyz[1], xyz[2]});;
IfcSchema::IfcBoundingBox* bbox = new IfcSchema::IfcBoundingBox(corner, xyz[3] - xyz[0], xyz[4] - xyz[1], xyz[5] - xyz[2]);
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
items->push(bbox);
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(context, std::string("Body"), std::string("BoundingBox"), items);
IfcSchema::IfcRepresentation::list::ptr new_reps(new IfcSchema::IfcRepresentation::list);
new_reps->push(rep);
IfcSchema::IfcProductDefinitionShape* new_def = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, new_reps);
corner->data().isWritable()->setId(id++);
// NB: Corner is added to existing definitions
old_defs.push_back(corner); ++num_points_added;
new_defs.push_back(bbox);
new_defs.push_back(rep);
new_defs.push_back(new_def);
}
}
std::for_each(new_defs.begin(), new_defs.end(), [&id](auto new_def) {
new_def->data().isWritable()->setId(id++);
});
auto iden = [](IfcUtil::IfcBaseClass* inst) { return inst; };
std::set<IfcSchema::Type::Enum> old_new_geom_types;
std::vector<std::vector<IfcUtil::IfcBaseClass*>*> all_vectors = std::vector<std::vector<IfcUtil::IfcBaseClass*>*>{ &new_defs, &old_prop_defs, &old_defs, &old_geom_defs };
for (auto vec_ : all_vectors) {
auto& vec = *vec_;
for (auto& inst : vec) {
old_new_geom_types.insert(inst->declaration().type());
}
}
// Generate proper buckets of data and serialize
all_old_defs.insert(all_old_defs.end(), old_defs.begin(), old_defs.end());
all_old_defs.insert(all_old_defs.end(), old_prop_defs.begin(), old_prop_defs.end());
all_old_defs.insert(all_old_defs.end(), old_geom_defs.begin(), old_geom_defs.end());
all_defs.insert(all_defs.end(), all_old_defs.begin(), all_old_defs.end());
all_defs.insert(all_defs.end(), new_defs.begin(), new_defs.end());
old_box_defs.insert(old_box_defs.end(), old_defs.begin(), old_defs.end());
old_box_defs.insert(old_box_defs.end(), new_defs.begin(), new_defs.end());
auto contexts = f.entitiesByType<IfcSchema::IfcRepresentationContext>();
old_box_defs.insert(old_box_defs.end(), contexts->begin(), contexts->end());
{
int num_insts1 = std::distance(all_old_defs.begin(), all_old_defs.end());
int num_insts2 = std::distance(f.begin(), f.end());
if ((num_insts1 - num_points_added) != num_insts2) {
std::cerr << "Missign instances " << num_insts1 << " - " << num_points_added << " != " << num_insts2 << std::endl;
abort();
}
}
multifile_instance_locator* locator = new multifile_instance_locator(
old_new_geom_types.begin(), old_new_geom_types.end(),
all_old_defs.begin(), all_old_defs.end());
IfcParse::Hdf5Settings settings;
settings.profile() = IfcParse::Hdf5Settings::padded;
settings.compress() = true;
settings.chunk_size() = 1024;
H5::H5File hdf(argv[1] + std::string(".hdf"), H5F_ACC_TRUNC);
H5::H5File geom_hdf(argv[1] + std::string("-geometry.hdf"), H5F_ACC_TRUNC);
H5::H5File box_hdf(argv[1] + std::string("-bounding-boxes.hdf"), H5F_ACC_TRUNC);
H5::H5File prop_hdf(argv[1] + std::string("-properties.hdf"), H5F_ACC_TRUNC);
hdf.createGroup("geometry").close();
hdf.createGroup("bounding-boxes").close();
hdf.createGroup("properties").close();
hdf.mount("geometry", geom_hdf, H5::PropList::DEFAULT);
hdf.mount("bounding-boxes", box_hdf, H5::PropList::DEFAULT);
hdf.mount("properties", prop_hdf, H5::PropList::DEFAULT);
H5::Group main_population = hdf.createGroup("population");
H5::Group geom_population = hdf.createGroup("geometry/population");
H5::Group box_population = hdf.createGroup("bounding-boxes/population");
H5::Group prop_population = hdf.createGroup("properties/population");
{
IfcParse::IfcHdf5File ifc_hdf5(hdf, get_schema(), settings);
IfcParse::instance_categorizer categorizer(all_defs.begin(), all_defs.end());
ifc_hdf5.write_schema(&categorizer);
{
IfcParse::instance_enumerator enumerator(&f.header(), old_defs.begin(), old_defs.end());
ifc_hdf5.write_population(main_population, enumerator, locator);
}
{
IfcParse::instance_enumerator enumerator(&f.header(), old_geom_defs.begin(), old_geom_defs.end());
ifc_hdf5.write_population(geom_population, enumerator, locator);
}
{
IfcParse::instance_enumerator enumerator(&f.header(), old_prop_defs.begin(), old_prop_defs.end());
ifc_hdf5.write_population(prop_population, enumerator, locator);
}
{
// locator is setup with all_old_defs, need to switch to new_defs + old_defs for the cartesian points
// NB: also geom rep context
locator->next(box_population, old_box_defs.begin(), old_box_defs.end());
IfcParse::instance_enumerator enumerator(&f.header(), new_defs.begin(), new_defs.end());
ifc_hdf5.write_population(box_population, enumerator, locator);
}
}
}
@@ -0,0 +1,275 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
class multifile_instance_locator : public IfcParse::abstract_instance_locator {
public:
typedef std::function<IfcUtil::IfcBaseClass*(IfcUtil::IfcBaseClass*)> mapping_t;
typedef std::pair<
std::vector<IfcSchema::Type::Enum>,
std::vector< std::vector<IfcUtil::IfcBaseEntity*> >
> population_t;
typedef std::vector<IfcUtil::IfcBaseClass*>::const_iterator full_const_iterator;
private:
H5::H5File* root_file_;
mapping_t mapping_;
std::set<IfcUtil::IfcBaseClass*> initial_population_set_;
std::set<IfcSchema::Type::Enum> initial_types_included_set_;
population_t initial_population_;
population_t subsequent_population_;
std::vector<IfcUtil::IfcBaseClass*> subsequent_minus_initial_;
H5::Group* initial_group_;
H5::Group* subsequent_group_;
H5::H5File* subsequent_file_;
std::string root_;
public:
template <typename ForwardIterator>
multifile_instance_locator(H5::H5File& root_file, H5::Group& group, mapping_t mapping, ForwardIterator b, ForwardIterator e)
: root_file_(&root_file)
, mapping_(mapping)
, initial_group_(&group)
, subsequent_group_(nullptr)
{
initial_population_set_.insert(b, e);
std::set<IfcSchema::Type::Enum> names_set;
std::for_each(b, e, [this, &names_set](IfcUtil::IfcBaseClass* inst) {
IfcSchema::Type::Enum ty = inst->declaration().type();
if (names_set.find(ty) == names_set.end()) {
initial_population_.first.push_back(ty);
names_set.insert(ty);
}
});
std::sort(initial_population_.first.begin(), initial_population_.first.end());
std::for_each(this->begin(), this->end(), [this, &b, &e](IfcSchema::Type::Enum t) {
std::vector<IfcUtil::IfcBaseEntity*> by_type;
std::for_each(b, e, [t,&by_type](IfcUtil::IfcBaseClass* inst) {
if (inst->declaration().type() == t && inst->declaration().as_entity()) {
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
}
});
std::sort(by_type.begin(), by_type.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
return i1->data().id() < i2->data().id();
});
initial_population_.second.emplace_back(by_type);
});
}
template <typename ForwardIteratorTypes, typename ForwardIteratorInsts>
multifile_instance_locator(ForwardIteratorTypes types_all_begin, ForwardIteratorTypes types_all_end, ForwardIteratorInsts insts_begin, ForwardIteratorInsts insts_end)
: subsequent_group_(nullptr)
{
initial_population_.first.assign(types_all_begin, types_all_end);
std::sort(initial_population_.first.begin(), initial_population_.first.end());
std::for_each(this->begin(), this->end(), [this, &insts_begin, &insts_end](IfcSchema::Type::Enum t) {
std::vector<IfcUtil::IfcBaseEntity*> by_type;
std::for_each(insts_begin, insts_end, [t, &by_type](IfcUtil::IfcBaseClass* inst) {
if (inst->declaration().type() == t && inst->declaration().as_entity()) {
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
}
});
std::sort(by_type.begin(), by_type.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
return i1->data().id() < i2->data().id();
});
initial_population_.second.emplace_back(by_type);
});
}
const_iterator begin() const {
if (subsequent_group_) {
return subsequent_population_.first.begin();
} else {
return initial_population_.first.begin();
}
}
const_iterator end() const {
if (subsequent_group_) {
return subsequent_population_.first.end();
} else {
return initial_population_.first.end();
}
}
full_const_iterator full_begin() const {
return subsequent_minus_initial_.begin();
}
full_const_iterator full_end() const {
return subsequent_minus_initial_.end();
}
const std::vector<IfcUtil::IfcBaseEntity*>& instances(IfcSchema::Type::Enum t) {
if (subsequent_group_) {
return subsequent_population_.second[std::lower_bound(begin(), end(), t) - begin()];
} else {
return initial_population_.second[std::lower_bound(begin(), end(), t) - begin()];
}
}
std::pair<int, int> operator()(IfcUtil::IfcBaseClass* v) {
if (IfcSchema::Type::IsSimple(v->declaration().type())) {
throw std::exception("Simple type not expected here");
}
IfcSchema::Type::Enum t = v->declaration().type();
// This remains constant for subsequent model serializations?
auto& dataset_names = initial_population_.first;
auto tt = std::lower_bound(dataset_names.begin(), dataset_names.end(), t);
int a = std::distance(dataset_names.begin(), tt);
int b;
const std::vector<IfcUtil::IfcBaseEntity*>& insts = instances(t);
auto it = std::lower_bound(insts.begin(), insts.end(), v, [](IfcUtil::IfcBaseClass* other, IfcUtil::IfcBaseClass* val) {
// An ordering based on ID is not equivalent to an ordering based on pointer address!
return other->data().id() < val->data().id();
});
if (it == insts.end()) {
throw std::runtime_error("Unable to find instance");
}
b = std::distance(insts.begin(), it);
return std::make_pair(a, b);
}
void make_reference(IfcUtil::IfcBaseClass* v, void*& ptr) {
v = mapping_(v);
IfcSchema::Type::Enum t = v->declaration().type();
population_t* pop;
H5::Group* group;
boost::optional<std::string> current_root;
if (initial_population_set_.find(v) != initial_population_set_.end()) {
pop = &initial_population_;
group = initial_group_;
current_root = boost::none;
} else {
pop = &subsequent_population_;
group = subsequent_group_;
current_root = root_;
}
int a = std::lower_bound(pop->first.begin(), pop->first.end(), t) - pop->first.begin();
auto& vec = pop->second[a];
hsize_t coord = std::lower_bound(vec.begin(), vec.end(), v, [](IfcUtil::IfcBaseClass* other, IfcUtil::IfcBaseClass* val) {
return other->data().id() < val->data().id();
}) - vec.begin();
hsize_t dims = instances(v->declaration().type()).size();
H5::DataSpace space(1, &dims);
space.selectElements(H5S_SELECT_SET, 1, &coord);
const std::string path = IfcSchema::Type::ToString(pop->first[a]);
std::string full_path = group->getObjName() + "/" + path + "_objects" + "/" + path + "_instances";
root_file_->reference(ptr, full_path, space);
ptr = static_cast<uint8_t*>(ptr) + sizeof(hdset_reg_ref_t);
}
template <typename ForwardIt>
void next(H5::Group& group, ForwardIt insts_begin, ForwardIt insts_end) {
subsequent_group_ = &group;
subsequent_population_.first = initial_population_.first;
subsequent_population_.second.clear();
std::for_each(this->begin(), this->end(), [this, &insts_begin, &insts_end](IfcSchema::Type::Enum t) {
std::vector<IfcUtil::IfcBaseEntity*> by_type;
std::for_each(insts_begin, insts_end, [t, &by_type](IfcUtil::IfcBaseClass* inst) {
if (inst->declaration().type() == t && inst->declaration().as_entity()) {
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
}
});
std::sort(by_type.begin(), by_type.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
return i1->data().id() < i2->data().id();
});
subsequent_population_.second.emplace_back(by_type);
});
}
void next(const std::string& name, H5::Group& group, IfcParse::IfcFile* f) {
subsequent_group_ = &group;
root_ = name;
subsequent_population_.first.clear();
subsequent_population_.second.clear();
subsequent_minus_initial_.clear();
auto f_begin = f->begin();
auto f_end = f->end();
std::set<IfcSchema::Type::Enum> names_set;
std::for_each(f_begin, f_end, [this, &names_set](auto& pair) {
IfcUtil::IfcBaseClass* inst = mapping_(pair.second);
if (initial_population_set_.find(inst) == initial_population_set_.end()) {
IfcSchema::Type::Enum ty = inst->declaration().type();
if (names_set.find(ty) == names_set.end()) {
subsequent_population_.first.push_back(ty);
names_set.insert(ty);
}
subsequent_minus_initial_.push_back(inst);
}
});
auto& names = subsequent_population_.first;
std::sort(names.begin(), names.end());
auto& vecs = subsequent_population_.second;
vecs.resize(names.size());
std::for_each(f_begin, f_end, [this, &names, &vecs](auto& pair) {
IfcUtil::IfcBaseClass* inst = mapping_(pair.second);
if (initial_population_set_.find(inst) == initial_population_set_.end() && inst->declaration().as_entity()) {
IfcSchema::Type::Enum ty = inst->declaration().type();
auto a = std::lower_bound(names.begin(), names.end(), ty) - names.begin();
auto& by_type = vecs[a];
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
}
});
std::for_each(vecs.begin(), vecs.end(), [](auto& vec) {
std::sort(vec.begin(), vec.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
return i1->data().id() < i2->data().id();
});
});
}
};
+83 -81
View File
@@ -30,27 +30,16 @@ bl_info = {
"description": "Import files in the "\
"Industry Foundation Classes (.ifc) file format",
"author": "Thomas Krijnen, IfcOpenShell",
"blender": (2, 5, 8),
"api": 37702,
"blender": (2, 73, 0),
"location": "File > Import",
"warning": "",
"wiki_url": "http://sourceforge.net/apps/"\
"mediawiki/ifcopenshell/index.php",
"tracker_url": "http://sourceforge.net/tracker/?group_id=543113",
"tracker_url": "https://sourceforge.net/p/ifcopenshell/"\
"_list/tickets?source=navbar",
"category": "Import-Export"}
import sys
max_unicode = 0x110000-1 if sys.platform[0:5] == 'linux' else 0x10000-1
wrong_unicode = max_unicode != sys.maxunicode
if wrong_unicode:
print("\nWarning: wrong unicode representation detected, switching to "\
"compatibility layer for text transferral, may result in undefined "\
"behaviour, please use offical release from http://blender.org\n")
if "bpy" in locals():
import imp
if "IfcImport" in locals():
imp.reload(IfcImport)
if "ifcopenshell" in locals():
imp.reload(ifcopenshell)
import bpy
import mathutils
@@ -70,54 +59,64 @@ bpy.types.Object.ifc_type = StringProperty(name="IFC Entity Type",
description="The STEP Datatype keyword")
def import_ifc(filename, use_names, process_relations):
global wrong_unicode
from . import IfcImport
def import_ifc(filename, use_names, process_relations, blender_booleans):
from . import ifcopenshell
from .ifcopenshell import geom as ifcopenshell_geom
print("Reading %s..."%bpy.path.basename(filename))
if wrong_unicode:
valid_file = IfcImport.InitUCS2(
''.join(['\0']+['\0%s'%s for s in filename]+['\0\0'])
)
else:
valid_file = IfcImport.Init(filename)
settings = ifcopenshell_geom.settings()
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, blender_booleans)
iterator = ifcopenshell_geom.iterator(settings, filename)
valid_file = iterator.initialize()
if not valid_file:
IfcImport.CleanUp()
return False
print("Done reading file")
id_to_object = {}
id_to_parent = {}
id_to_matrix = {}
openings = []
old_progress = -1
print("Creating geometry...")
while True:
ob = IfcImport.Get()
if wrong_unicode:
ob_name = ''.join([chr(c) for c in ob.name_as_intvector()])
ob_type = ''.join([chr(c) for c in ob.type_as_intvector()])
ob_guid = ''.join([chr(c) for c in ob.guid_as_intvector()])
else:
ob_name, ob_type, ob_guid = ob.name, ob.type, ob.guid
f = ob.mesh.faces
v = ob.mesh.verts
m = ob.matrix
t = ob_type[0:21]
nm = ob_name if len(ob_name) and use_names else ob_guid
ob = iterator.get()
f = ob.geometry.faces
v = ob.geometry.verts
mats = ob.geometry.materials
matids = ob.geometry.material_ids
m = ob.transformation.matrix.data
t = ob.type[0:21]
nm = ob.name if len(ob.name) and use_names else ob.guid
verts = [[v[i], v[i + 1], v[i + 2]] \
for i in range(0, len(v), 3)]
faces = [[f[i], f[i + 1], f[i + 2]] \
for i in range(0, len(f), 3)]
me = bpy.data.meshes.new('mesh%d' % ob.mesh.id)
me = bpy.data.meshes.new('mesh%d' % ob.geometry.id)
me.from_pydata(verts, [], faces)
if t in bpy.data.materials:
mat = bpy.data.materials[t]
mat.use_fake_user = True
else:
mat = bpy.data.materials.new(t)
me.materials.append(mat)
def add_material(mname, props):
if mname in bpy.data.materials:
mat = bpy.data.materials[mname]
mat.use_fake_user = True
else:
mat = bpy.data.materials.new(mname)
for k,v in props.items():
setattr(mat, k, v)
me.materials.append(mat)
needs_default = -1 in matids
if needs_default: add_material(t, {})
for mat in mats:
props = {}
if mat.has_diffuse: props['diffuse_color'] = mat.diffuse
if mat.has_specular: props['specular_color'] = mat.specular
if mat.has_transparency and mat.transparency > 0:
props['alpha'] = 1.0 - mat.transparency
props['use_transparency'] = True
if mat.has_specularity: props['specular_hardness'] = mat.specularity
add_material(mat.name, props)
bob = bpy.data.objects.new(nm, me)
mat = mathutils.Matrix(([m[0], m[1], m[2], 0],
@@ -138,10 +137,12 @@ def import_ifc(filename, use_names, process_relations):
bpy.ops.object.mode_set(mode='OBJECT')
bob.ifc_id, bob.ifc_guid, bob.ifc_name, bob.ifc_type = \
ob.id, ob_guid, ob_name, ob_type
ob.id, ob.guid, ob.name, ob.type
bob.hide = ob_type == 'IfcSpace' or ob_type == 'IfcOpeningElement'
bob.hide_render = bob.hide
if ob.type == 'IfcSpace' or ob.type == 'IfcOpeningElement':
if not (ob.type == 'IfcOpeningElement' and blender_booleans):
bob.hide = bob.hide_render = True
bob.draw_type = 'WIRE'
if ob.id not in id_to_object: id_to_object[ob.id] = []
id_to_object[ob.id].append(bob)
@@ -149,11 +150,19 @@ def import_ifc(filename, use_names, process_relations):
if ob.parent_id > 0:
id_to_parent[ob.id] = ob.parent_id
progress = IfcImport.Progress() // 2
if blender_booleans and ob.type == 'IfcOpeningElement':
openings.append(ob.id)
faces = me.polygons if hasattr(me, 'polygons') else me.faces
if len(faces) == len(matids):
for face, matid in zip(faces, matids):
face.material_index = matid + (1 if needs_default else 0)
progress = iterator.progress() // 2
if progress > old_progress:
print("\r[" + "#" * progress + " " * (50 - progress) + "]", end="")
old_progress = progress
if not IfcImport.Next():
if not iterator.next():
break
print("\rDone creating geometry" + " " * 30)
@@ -169,24 +178,13 @@ def import_ifc(filename, use_names, process_relations):
if parent_id in id_to_object:
bob = id_to_object[parent_id][0]
else:
parent_ob = IfcImport.GetObject(parent_id)
parent_ob = iterator.getObject(parent_id)
if parent_ob.id == -1:
bob = None
else:
if wrong_unicode:
parent_ob_name = ''.join(
[chr(c) for c in parent_ob.name_as_intvector()])
parent_ob_type = ''.join(
[chr(c) for c in parent_ob.type_as_intvector()])
parent_ob_guid = ''.join(
[chr(c) for c in parent_ob.guid_as_intvector()])
else:
parent_ob_name, parent_ob_type, parent_ob_guid = \
parent_ob.name, parent_ob.type, parent_ob.guid
m = parent_ob.matrix
nm = parent_ob_name if len(parent_ob_name) and use_names \
else parent_ob_guid
m = parent_ob.transformation.matrix.data
nm = parent_ob.name if len(parent_ob.name) and use_names \
else parent_ob.guid
bob = bpy.data.objects.new(nm, None)
mat = mathutils.Matrix((
@@ -201,7 +199,7 @@ def import_ifc(filename, use_names, process_relations):
bob.ifc_id = parent_ob.id
bob.ifc_name, bob.ifc_type, bob.ifc_guid = \
parent_ob_name, parent_ob_type, parent_ob_guid
parent_ob.name, parent_ob.type, parent_ob.guid
if parent_ob.parent_id > 0:
id_to_parent[parent_id] = parent_ob.parent_id
@@ -226,13 +224,19 @@ def import_ifc(filename, use_names, process_relations):
if process_relations:
print("Done processing relations")
if not wrong_unicode:
txt = bpy.data.texts.new("%s.log"%bpy.path.basename(filename))
txt.from_string(IfcImport.GetLog())
for opening_id in openings:
parent_id = id_to_parent[opening_id]
if parent_id in id_to_object:
parent_ob = id_to_object[parent_id][0]
for opening_ob in id_to_object[opening_id]:
mod = parent_ob.modifiers.new("opening", "BOOLEAN")
mod.operation = "DIFFERENCE"
mod.object = opening_ob
txt = bpy.data.texts.new("%s.log"%bpy.path.basename(filename))
txt.from_string(iterator.getLog())
IfcImport.CleanUp()
return True
@@ -251,15 +255,13 @@ class ImportIFC(bpy.types.Operator, ImportHelper):
" relations to parenting" \
" (warning: may be slow on large files)",
default=False)
blender_booleans = BoolProperty(name="Use Blender booleans",
description="Use Blender boolean modifiers for opening" \
" elements",
default=False)
def execute(self, context):
global wrong_unicode
if wrong_unicode and sys.platform[0:5] != 'linux':
self.report({'ERROR'},
'Your version of Blender is incompatible with IfcBlender\n' \
'Please use the offical release from http://blender.org instead'
)
elif not import_ifc(self.filepath, self.use_names, self.process_relations):
if not import_ifc(self.filepath, self.use_names, self.process_relations, self.blender_booleans):
self.report({'ERROR'},
'Unable to parse .ifc file or no geometrical entities found'
)
+63 -52
View File
@@ -28,30 +28,30 @@ std::string collada_id(const std::string& s) {
id.reserve(s.size());
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
const std::string::value_type c = *it;
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_')) {
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_') || ( c == '-')) {
id.push_back(c);
}
}
return id;
}
void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<float>& floats, const char* coords /* = "XYZ" */) {
void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<double>& floats, const char* coords /* = "XYZ" */) {
COLLADASW::FloatSource source(mSW);
source.setId(mesh_id + suffix);
source.setArrayId(mesh_id + suffix + COLLADASW::LibraryGeometries::ARRAY_ID_SUFFIX);
source.setAccessorStride(strlen(coords));
source.setAccessorCount(floats.size() / 3);
source.setAccessorStride((unsigned long)strlen(coords));
source.setAccessorCount((unsigned long)floats.size() / 3);
for (unsigned int i = 0; i < source.getAccessorStride(); ++i) {
source.getParameterNameList().push_back(std::string(1, coords[i]));
}
source.prepareToAppendValues();
for (std::vector<float>::const_iterator it = floats.begin(); it != floats.end(); ++it) {
for (std::vector<double>::const_iterator it = floats.begin(); it != floats.end(); ++it) {
source.appendValues(*it);
}
source.finish();
}
void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::string& default_material_name, const std::vector<float>& positions, const std::vector<float>& normals, const std::vector<int>& indices, const std::vector<int> material_ids, const std::vector<IfcGeomObjects::Material>& materials) {
void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials) {
openMesh(mesh_id);
// The normals vector can be empty for example when the WELD_VERTICES setting is used.
@@ -68,19 +68,15 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str
vertices.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::POSITION, "#" + mesh_id + COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX));
vertices.add();
std::vector<int>::const_iterator index_range_start = indices.begin();
std::vector<int>::const_iterator index_range_start = faces.begin();
std::vector<int>::const_iterator material_it = material_ids.begin();
int previous_material_id = -2;
for (std::vector<int>::const_iterator it = indices.begin(); ; it += 3) {
const int current_material_id = material_it == material_ids.end()
? -3
: *(material_it++);
const int num_triangles = std::distance(index_range_start, it) / 3;
if ((previous_material_id != current_material_id && num_triangles > 0) || (it == indices.end())) {
int previous_material_id = -1;
for (std::vector<int>::const_iterator it = faces.begin(); !faces.empty(); it += 3) {
const int current_material_id = *(material_it++);
const unsigned long num_triangles = (unsigned long)std::distance(index_range_start, it) / 3;
if ((previous_material_id != current_material_id && num_triangles > 0) || (it == faces.end())) {
COLLADASW::Triangles triangles(mSW);
triangles.setMaterial(collada_id(previous_material_id < 0
? default_material_name
: materials[previous_material_id].name()));
triangles.setMaterial(materials[previous_material_id].name());
triangles.setCount(num_triangles);
int offset = 0;
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX,"#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++ ) );
@@ -100,11 +96,44 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str
index_range_start = it;
}
previous_material_id = current_material_id;
if (it == indices.end()) {
if (it == faces.end()) {
break;
}
}
std::set<int> faces_set (faces.begin(), faces.end());
typedef std::vector< std::pair<int, std::vector<unsigned long> > > linelist_t;
linelist_t linelist;
int num_lines = 0;
for ( std::vector<int>::const_iterator it = edges.begin(); it != edges.end(); ++num_lines) {
const int i1 = *(it++);
const int i2 = *(it++);
if (faces_set.find(i1) != faces_set.end() || faces_set.find(i2) != faces_set.end()) {
continue;
}
const int current_material_id = *(material_it++);
if ((previous_material_id != current_material_id) || (num_lines == 0)) {
linelist.resize(linelist.size() + 1);
}
linelist.rbegin()->second.push_back(i1);
linelist.rbegin()->second.push_back(i2);
}
for (linelist_t::const_iterator it = linelist.begin(); it != linelist.end(); ++it) {
COLLADASW::Lines lines(mSW);
lines.setMaterial(materials[it->first].name());
lines.setCount((unsigned long)it->second.size());
int offset = 0;
lines.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX, "#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++));
lines.prepareToAppendValues();
lines.appendValues(it->second);
lines.finish();
}
closeMesh();
closeGeometry();
}
@@ -113,7 +142,7 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::close() {
closeLibrary();
}
void ColladaSerializer::ColladaExporter::ColladaScene::add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<float>& matrix) {
void ColladaSerializer::ColladaExporter::ColladaScene::add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<double>& matrix) {
if (!scene_opened) {
openVisualScene(scene_id);
scene_opened = true;
@@ -155,7 +184,7 @@ void ColladaSerializer::ColladaExporter::ColladaScene::write() {
}
}
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeomObjects::Material& material) {
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeom::Material& material) {
openEffect(collada_id(material.name()) + "-fx");
COLLADASW::EffectProfile effect(mSW);
effect.setShaderType(COLLADASW::EffectProfile::LAMBERT);
@@ -186,20 +215,20 @@ void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::close
closeLibrary();
}
void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const IfcGeomObjects::Material& material) {
void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const IfcGeom::Material& material) {
if (!contains(material)) {
effects.write(material);
materials.push_back(material);
}
}
bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeomObjects::Material& material) {
bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeom::Material& material) {
return std::find(materials.begin(), materials.end(), material) != materials.end();
}
void ColladaSerializer::ColladaExporter::ColladaMaterials::write() {
effects.close();
for (std::vector<IfcGeomObjects::Material>::const_iterator it = materials.begin(); it != materials.end(); ++it) {
for (std::vector<IfcGeom::Material>::const_iterator it = materials.begin(); it != materials.end(); ++it) {
const std::string& material_name = collada_id((*it).name());
openMaterial(material_name);
addInstanceEffect("#" + material_name + "-fx");
@@ -218,34 +247,16 @@ void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_n
asset.add();
}
void ColladaSerializer::ColladaExporter::writeTesselated(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<float>& matrix, const std::vector<float>& vertices, const std::vector<float>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids, const std::vector<IfcGeomObjects::Material>& _materials) {
const IfcGeomObjects::Material default_for_type = IfcGeomObjects::Material(IfcGeom::get_default_style(type));
void ColladaSerializer::ColladaExporter::write(const std::string& unique_id, const std::string& type, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& _materials) {
std::vector<std::string> material_references;
const bool needs_default = std::find(material_ids.begin(), material_ids.end(), -1) != material_ids.end();
if (needs_default) {
if (!materials.contains(default_for_type)) {
materials.add(default_for_type);
}
material_references.push_back(collada_id(default_for_type.name()));
}
for (std::vector<IfcGeomObjects::Material>::const_iterator it = _materials.begin(); it != _materials.end(); ++it) {
const IfcGeomObjects::Material& material = *it;
for (std::vector<IfcGeom::Material>::const_iterator it = _materials.begin(); it != _materials.end(); ++it) {
const IfcGeom::Material& material = *it;
if (!materials.contains(material)) {
materials.add(material);
}
material_references.push_back(collada_id(material.name()));
}
deferreds.push_back(DeferredObject(guid, name, type, obj_id, matrix, vertices, normals, indices, material_ids, _materials, material_references));
}
const std::string ColladaSerializer::ColladaExporter::DeferredObject::Name() const {
std::stringstream ss;
if (!this->name.empty()) {
ss << this->obj_id << "_" << this->name;
} else {
ss << this->guid;
}
return collada_id(ss.str());
deferreds.push_back(DeferredObject(unique_id, type, matrix, vertices, normals, faces, edges, material_ids, _materials, material_references));
}
void ColladaSerializer::ColladaExporter::endDocument() {
@@ -253,13 +264,13 @@ void ColladaSerializer::ColladaExporter::endDocument() {
// only at this point all objects are written to the stream.
materials.write();
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
const std::string object_name = it->Name();
geometries.write(object_name, it->type, it->vertices, it->normals, it->indices, it->material_ids, it->materials);
const std::string object_name = it->unique_id + "-representation";
geometries.write(object_name, it->type, it->vertices, it->normals, it->faces, it->edges, it->material_ids, it->materials);
}
geometries.close();
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
const std::string object_name = it->Name();
scene.add(object_name + "-instance", object_name, object_name, it->material_references, it->matrix);
const std::string object_name = it->unique_id;
scene.add(object_name, object_name, object_name + "-representation", it->material_references, it->matrix);
}
scene.write();
stream.endDocument();
@@ -273,9 +284,9 @@ void ColladaSerializer::writeHeader() {
exporter.startDocument(unit_name, unit_magnitude);
}
void ColladaSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject* o) {
const IfcGeomObjects::IfcRepresentationTriangulation& mesh = o->mesh();
exporter.writeTesselated(o->guid(), o->name(), o->type(), o->id(), o->matrix(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.material_ids(), mesh.materials());
void ColladaSerializer::write(const IfcGeom::TriangulationElement<double>* o) {
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
exporter.write(o->unique_id(), o->type(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.edges(), mesh.material_ids(), mesh.materials());
}
void ColladaSerializer::finalize() {
+42 -26
View File
@@ -22,6 +22,10 @@
#ifndef COLLADASERIALIZER_H
#define COLLADASERIALIZER_H
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4201 4512)
#endif
#include <COLLADASWStreamWriter.h>
#include <COLLADASWPrimitves.h>
#include <COLLADASWLibraryGeometries.h>
@@ -34,30 +38,39 @@
#include <COLLADASWLibraryMaterials.h>
#include <COLLADASWBaseInputElement.h>
#include <COLLADASWAsset.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include "../ifcgeom/IfcGeomObjects.h"
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcconvert/GeometrySerializer.h"
class ColladaSerializer : public GeometrySerializer
{
// TODO The vast amount of implement details of ColladaSerializer could be hidden to the cpp file.
private:
class ColladaExporter
{
private:
class ColladaGeometries : public COLLADASW::LibraryGeometries
{
ColladaGeometries(const ColladaGeometries&); //N/A
ColladaGeometries& operator =(const ColladaGeometries&); //N/A
public:
explicit ColladaGeometries(COLLADASW::StreamWriter& stream)
: COLLADASW::LibraryGeometries(&stream)
{}
void addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<float>& floats, const char* coords = "XYZ");
void write(const std::string mesh_id, const std::string& default_material_name, const std::vector<float>& positions, const std::vector<float>& normals, const std::vector<int>& indices, const std::vector<int> material_ids, const std::vector<IfcGeomObjects::Material>& materials);
void addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<double>& floats, const char* coords = "XYZ");
void write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials);
void close();
};
class ColladaScene : public COLLADASW::LibraryVisualScenes
{
private:
ColladaScene(const ColladaScene&); //N/A
ColladaScene& operator =(const ColladaScene&); //N/A
const std::string scene_id;
bool scene_opened;
public:
@@ -66,59 +79,61 @@ private:
, scene_id(scene_id)
, scene_opened(false)
{}
void add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<float>& matrix);
void add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<double>& matrix);
void write();
};
class ColladaMaterials : public COLLADASW::LibraryMaterials
{
ColladaMaterials(const ColladaMaterials&); //N/A
ColladaMaterials& operator =(const ColladaMaterials&); //N/A
private:
class ColladaEffects : public COLLADASW::LibraryEffects
{
ColladaEffects(const ColladaEffects&); //N/A
ColladaEffects& operator =(const ColladaEffects&); //N/A
public:
explicit ColladaEffects(COLLADASW::StreamWriter& stream)
: COLLADASW::LibraryEffects(&stream)
{}
void write(const IfcGeomObjects::Material& material);
void write(const IfcGeom::Material& material);
void close();
};
std::vector<IfcGeomObjects::Material> materials;
std::vector<IfcGeom::Material> materials;
ColladaEffects effects;
public:
explicit ColladaMaterials(COLLADASW::StreamWriter& stream)
: COLLADASW::LibraryMaterials(&stream)
, effects(stream)
{}
void add(const IfcGeomObjects::Material& material);
bool contains(const IfcGeomObjects::Material& material);
void add(const IfcGeom::Material& material);
bool contains(const IfcGeom::Material& material);
void write();
};
class DeferredObject {
public:
std::string guid, name, type;
int obj_id;
std::vector<float> matrix;
std::vector<float> vertices;
std::vector<float> normals;
std::vector<int> indices;
std::string unique_id, type;
std::vector<double> matrix;
std::vector<double> vertices;
std::vector<double> normals;
std::vector<int> faces;
std::vector<int> edges;
std::vector<int> material_ids;
std::vector<IfcGeomObjects::Material> materials;
std::vector<IfcGeom::Material> materials;
std::vector<std::string> material_references;
DeferredObject(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<float>& matrix, const std::vector<float>& vertices,
const std::vector<float>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids,
const std::vector<IfcGeomObjects::Material>& materials, const std::vector<std::string>& material_references)
: guid(guid)
, name(name)
DeferredObject(const std::string& unique_id, const std::string& type, const std::vector<double>& matrix, const std::vector<double>& vertices,
const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int>& material_ids,
const std::vector<IfcGeom::Material>& materials, const std::vector<std::string>& material_references)
: unique_id(unique_id)
, type(type)
, obj_id(obj_id)
, matrix(matrix)
, vertices(vertices)
, normals(normals)
, indices(indices)
, faces(faces)
, edges(edges)
, material_ids(material_ids)
, materials(materials)
, material_references(material_references)
{}
const std::string Name() const;
};
COLLADABU::NativeString filename;
COLLADASW::StreamWriter stream;
@@ -136,7 +151,7 @@ private:
std::vector<DeferredObject> deferreds;
virtual ~ColladaExporter() {}
void startDocument(const std::string& unit_name, float unit_magnitude);
void writeTesselated(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<float>& matrix, const std::vector<float>& vertices, const std::vector<float>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids, const std::vector<IfcGeomObjects::Material>& materials);
void write(const std::string& unique_id, const std::string& type, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& materials);
void endDocument();
};
ColladaExporter exporter;
@@ -149,14 +164,15 @@ public:
{}
bool ready();
void writeHeader();
void writeTesselated(const IfcGeomObjects::IfcGeomObject* o);
void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) {}
void write(const IfcGeom::TriangulationElement<double>* o);
void write(const IfcGeom::BRepElement<double>* /*o*/) {}
void finalize();
bool isTesselated() const { return true; }
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
unit_name = name;
unit_magnitude = magnitude;
}
void setFile(IfcParse::IfcFile*) {}
};
#endif
+7 -8
View File
@@ -20,17 +20,16 @@
#ifndef GEOMETRYSERIALIZER_H
#define GEOMETRYSERIALIZER_H
#include "../ifcgeom/IfcGeomObjects.h"
#include "../ifcconvert/Serializer.h"
#include "../ifcgeom/IfcGeomIterator.h"
class GeometrySerializer {
class GeometrySerializer : public Serializer {
public:
virtual bool ready() = 0;
virtual void writeHeader() = 0;
virtual void finalize() = 0;
virtual bool isTesselated() const = 0;
virtual ~GeometrySerializer() {}
virtual void writeTesselated(const IfcGeomObjects::IfcGeomObject* o) = 0;
virtual void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) = 0;
virtual bool isTesselated() const = 0;
virtual void write(const IfcGeom::TriangulationElement<double>* o) = 0;
virtual void write(const IfcGeom::BRepElement<double>* o) = 0;
virtual void setUnitNameAndMagnitude(const std::string& name, float magnitude) = 0;
};
+268 -87
View File
@@ -26,19 +26,37 @@
* *
********************************************************************************/
#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
#define BOOST_MPL_LIMIT_LIST_SIZE 30
#include <fstream>
#include <sstream>
#include <set>
#include <time.h>
#include <boost/program_options.hpp>
#include <boost/algorithm/string.hpp>
#include "../ifcgeom/IfcGeomObjects.h"
#include "../ifcparse/Hdf5Settings.h"
#include "../ifcparse/IfcHdf5File.h"
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcconvert/ColladaSerializer.h"
#include "../ifcconvert/IgesSerializer.h"
#include "../ifcconvert/StepSerializer.h"
#include "../ifcconvert/WavefrontObjSerializer.h"
#include "../ifcconvert/XmlSerializer.h"
#include "../ifcconvert/SvgSerializer.h"
#include <IGESControl_Controller.hxx>
#include <Standard_Version.hxx>
#if USE_VLD
#include <vld.h>
#endif
static std::string DEFAULT_EXTENSION = "obj";
void printVersion() {
std::cerr << "IfcOpenShell IfcConvert " << IFCOPENSHELL_VERSION << std::endl;
@@ -51,10 +69,14 @@ void printUsage(const boost::program_options::options_description& generic_optio
<< "Converts the geometry in an IFC file into one of the following formats:" << std::endl
<< " .obj WaveFront OBJ (a .mtl file is also created)" << std::endl;
#ifdef WITH_OPENCOLLADA
std::cerr << " .dae Collada Digital Assets Exchange" << std::endl;
std::cerr << " .dae Collada Digital Asset Exchange" << std::endl;
#endif
std::cerr << " .stp STEP Standard for the Exchange of Product Data" << std::endl
<< " .igs IGES Initial Graphics Exchange Specification" << std::endl
<< " .xml XML Property definitions and decomposition tree" << std::endl
<< " .svg SVG Scalable Vector Graphics (2d floor plan)" << std::endl
<< " .hdf HDF5 Efficient binary IFC serialization" << std::endl
<< " .ifc IFC-SPF Standard p21 IFC serialization" << std::endl
<< std::endl
<< "Command line options" << std::endl << generic_options << std::endl
<< "Advanced options" << std::endl << geom_options << std::endl;
@@ -84,35 +106,77 @@ int main(int argc, char** argv) {
("input-file", boost::program_options::value<std::string>(), "input IFC file")
("output-file", boost::program_options::value<std::string>(), "output geometry file");
std::vector<std::string> ignore_types_vector;
std::string bounds, hdf5_profile;
uint32_t hdf5_chunk_size;
std::vector<std::string> entity_vector;
std::vector<std::string> hdf5_ref_attributes;
std::vector<std::string> hdf5_mount_points;
boost::program_options::options_description geom_options;
geom_options.add_options()
("weld-vertices", "Specifies whether vertices are welded, meaning that the coordinates "
"vector will only contain unique xyz-triplets. This results in a "
"manifold mesh which is useful for modelling applications, but might "
"result in unwanted shading artifacts in rendering applications.")
("use-world-coords", "Specifies whether to apply the local placements of building elements "
"directly to the coordinates of the representation mesh rather than "
"to represent the local placement in the 4x3 matrix, which will in that "
"case be the identity matrix.")
("convert-back-units", "Specifies whether to convert back geometrical output back to the "
"unit of measure in which it is defined in the IFC file. Default is "
"to use meters.")
("sew-shells", "Specifies whether to sew the faces of IfcConnectedFaceSets together. This is a "
"potentially time consuming operation, but guarantees a consistent orientation "
"of surface normals, even if the faces are not properly oriented in the IFC file.")
("merge-boolean-operands", "Specifies whether to merge all IfcOpeningElement operands into a single "
"operand before applying the subtraction operation. This may "
"introduce a performance improvement at the risk of failing, in "
"which case the subtraction is applied one-by-one.")
("force-ccw-face-orientation", "Recompute topological face normals using Newell's Method to "
"guarantee that face vertices are defined in a Counter Clock "
"Wise order, even if the faces are not part of a closed shell.")
("disable-opening-subtractions", "Specifies whether to disable the boolean subtraction of "
"IfcOpeningElement Representations from their RelatingElements.")
("ignore-types", boost::program_options::value< std::vector<std::string> >(&ignore_types_vector)->multitoken(),
"A list of IFC datatype keywords that should not be included in the geometrical output. "
"Defaults to IfcOpeningElement and IfcSpace");
("plan",
"Specifies whether to include curves in the output result. Typically "
"these are representations of type Plan or Axis. Excluded by default.")
("model",
"Specifies whether to include surfaces and solids in the output result. "
"Typically these are representations of type Body or Facetation. "
"Included by default.")
("weld-vertices",
"Specifies whether vertices are welded, meaning that the coordinates "
"vector will only contain unique xyz-triplets. This results in a "
"manifold mesh which is useful for modelling applications, but might "
"result in unwanted shading artefacts in rendering applications.")
("use-world-coords",
"Specifies whether to apply the local placements of building elements "
"directly to the coordinates of the representation mesh rather than "
"to represent the local placement in the 4x3 matrix, which will in that "
"case be the identity matrix.")
("convert-back-units",
"Specifies whether to convert back geometrical output back to the "
"unit of measure in which it is defined in the IFC file. Default is "
"to use meters.")
("sew-shells",
"Specifies whether to sew the faces of IfcConnectedFaceSets together. "
"This is a potentially time consuming operation, but guarantees a "
"consistent orientation of surface normals, even if the faces are not "
"properly oriented in the IFC file.")
#if OCC_VERSION_HEX < 0x60900
// In Open CASCADE version prior to 6.9.0 boolean operations with multiple
// arguments where not introduced yet and a work-around was implemented to
// subtract multiple openings as a single compound. This hack is obsolete
// for newer versions of Open CASCADE.
("merge-boolean-operands",
"Specifies whether to merge all IfcOpeningElement operands into a single "
"operand before applying the subtraction operation. This may "
"introduce a performance improvement at the risk of failing, in "
"which case the subtraction is applied one-by-one.")
#endif
("disable-opening-subtractions",
"Specifies whether to disable the boolean subtraction of "
"IfcOpeningElement Representations from their RelatingElements.")
("bounds", boost::program_options::value<std::string>(&bounds),
"Specifies the bounding rectangle, for example 512x512, to which the "
"output will be scaled. Only used when converting to SVG.")
("hdf5-profile", boost::program_options::value<std::string>(&hdf5_profile), "")
("hdf5-compress", "")
("hdf5-fix-cartesian-point", "")
("hdf5-fix-global-id", "")
("hdf5-instantiate-inverse", "")
("hdf5-instantiate-select", "")
("hdf5-mount", boost::program_options::value< std::vector<std::string> >(&hdf5_mount_points)->multitoken(),
"")
("hdf5-chunk-size", boost::program_options::value(&hdf5_chunk_size), "")
("hdf5-ref-attributes", boost::program_options::value< std::vector<std::string> >(&hdf5_ref_attributes)->multitoken(),
"")
("include",
"Specifies that the entities listed after --entities are to be included")
("exclude",
"Specifies that the entities listed after --entities are to be excluded")
("entities", boost::program_options::value< std::vector<std::string> >(&entity_vector)->multitoken(),
"A list of entities that should be included in or excluded from the "
"geometrical output, depending on whether --ignore or --include is "
"specified. Defaults to IfcOpeningElement and IfcSpace to be excluded.");
boost::program_options::options_description cmdline_options;
cmdline_options.add(generic_options).add(fileio_options).add(geom_options);
@@ -128,13 +192,19 @@ int main(int argc, char** argv) {
} catch (const boost::program_options::unknown_option& e) {
std::cerr << "[Error] Unknown option '" << e.get_option_name() << "'" << std::endl << std::endl;
// Usage information will be emitted below
} catch (...) {
// Catch other errors such as invalid command line syntax
}
boost::program_options::notify(vmap);
if (vmap.count("version")) {
printVersion();
return 1;
return 0;
} else if (vmap.count("help") || !vmap.count("input-file")) {
printUsage(generic_options, geom_options);
return vmap.count("help") ? 0 : 1;
} else if (vmap.count("include") && vmap.count("exclude")) {
std::cerr << "[Error] --include and --ignore can not be specified together" << std::endl;
printUsage(generic_options, geom_options);
return 1;
}
@@ -144,23 +214,31 @@ int main(int argc, char** argv) {
const bool use_world_coords = vmap.count("use-world-coords") != 0;
const bool convert_back_units = vmap.count("convert-back-units") != 0;
const bool sew_shells = vmap.count("sew-shells") != 0;
#if OCC_VERSION_HEX < 0x60900
const bool merge_boolean_operands = vmap.count("merge-boolean-operands") != 0;
const bool force_ccw_face_orientation = vmap.count("force-ccw-face-orientation") != 0;
#endif
const bool disable_opening_subtractions = vmap.count("disable-opening-subtractions") != 0;
bool include_entities = vmap.count("include") != 0;
const bool include_plan = vmap.count("plan") != 0;
const bool include_model = vmap.count("model") != 0 || (!include_plan);
boost::optional<int> bounding_width, bounding_height;
if (vmap.count("bounds") == 1) {
int w, h;
if (sscanf(bounds.c_str(), "%ux%u", &w, &h) == 2) {
bounding_width = w;
bounding_height = h;
} else {
std::cerr << "[Error] Invalid use of --bounds" << std::endl;
printUsage(generic_options, geom_options);
return 1;
}
}
// Gets the set ifc types to be ignored from the command line.
std::set<std::string> ignore_types;
for (std::vector<std::string>::const_iterator it = ignore_types_vector.begin(); it != ignore_types_vector.end(); ++it) {
std::string lowercase_type = *it;
for (std::string::iterator c = lowercase_type.begin(); c != lowercase_type.end(); ++c) {
*c = tolower(*c);
}
ignore_types.insert(lowercase_type);
}
// If none are specified these are the defaults to skip from output
if (ignore_types_vector.empty()) {
ignore_types.insert("ifcopeningelement");
ignore_types.insert("ifcspace");
std::set<std::string> entities;
for (std::vector<std::string>::const_iterator it = entity_vector.begin(); it != entity_vector.end(); ++it) {
const std::string& mixed_case_type = *it;
entities.insert(boost::to_lower_copy(mixed_case_type));
}
const std::string input_filename = vmap["input-file"].as<std::string>();
@@ -168,35 +246,117 @@ int main(int argc, char** argv) {
// to maintain backwards compatibility with the obsolete IfcObj executable.
const std::string output_filename = vmap.count("output-file") == 1
? vmap["output-file"].as<std::string>()
: change_extension(input_filename, "obj");
: change_extension(input_filename, DEFAULT_EXTENSION);
if (output_filename.size() < 5) {
printUsage(generic_options, geom_options);
return 1;
}
IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS, use_world_coords);
IfcGeomObjects::Settings(IfcGeomObjects::WELD_VERTICES, weld_vertices);
IfcGeomObjects::Settings(IfcGeomObjects::SEW_SHELLS, sew_shells);
IfcGeomObjects::Settings(IfcGeomObjects::CONVERT_BACK_UNITS, convert_back_units);
IfcGeomObjects::Settings(IfcGeomObjects::FASTER_BOOLEANS, merge_boolean_operands);
IfcGeomObjects::Settings(IfcGeomObjects::FORCE_CCW_FACE_ORIENTATION, force_ccw_face_orientation);
IfcGeomObjects::Settings(IfcGeomObjects::DISABLE_OPENING_SUBTRACTIONS, disable_opening_subtractions);
std::string output_extension = output_filename.substr(output_filename.size()-4);
for (std::string::iterator c = output_extension.begin(); c != output_extension.end(); ++c) {
*c = tolower(*c);
boost::to_lower(output_extension);
// If no entities are specified these are the defaults to skip from output
if (entity_vector.empty()) {
if (output_extension == ".svg") {
entities.insert("ifcspace");
include_entities = true;
} else {
entities.insert("ifcopeningelement");
entities.insert("ifcspace");
}
}
Logger::SetOutput(&std::cout, &log_stream);
Logger::Verbosity(verbose ? Logger::LOG_NOTICE : Logger::LOG_ERROR);
if (output_extension == ".xml") {
int exit_code = 1;
try {
XmlSerializer s(output_filename);
IfcParse::IfcFile f;
if (!f.Init(input_filename)) {
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file");
} else {
s.setFile(&f);
s.finalize();
exit_code = 0;
}
} catch (...) {}
write_log();
return exit_code;
} else if (output_extension == ".hdf") {
int exit_code = 1;
// try {
IfcParse::IfcFile f;
if (!f.Init(input_filename)) {
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file");
} else {
IfcParse::Hdf5Settings settings;
settings.compress() = vmap.count("hdf5-compress") != 0;
settings.fix_cartesian_point() = vmap.count("hdf5-fix-cartesian-point") != 0;
settings.fix_global_id() = vmap.count("hdf5-fix-global-id") != 0;
settings.instantiate_inverse() = vmap.count("hdf5-instantiate-inverse") != 0;
settings.instantiate_select() = vmap.count("hdf5-instantiate-select") != 0;
std::sort(hdf5_ref_attributes.begin(), hdf5_ref_attributes.end());
settings.ref_attributes() = hdf5_ref_attributes;
if (vmap.count("hdf5-chunk-size") == 1) {
settings.chunk_size() = hdf5_chunk_size;
}
if (vmap.count("hdf5-profile") == 1) {
settings.profile() = IfcParse::Hdf5Settings::ProfileFromString(hdf5_profile);
}
f.write_hdf5(output_filename, settings);
exit_code = 0;
}
// } catch (...) {}
write_log();
// std::cin.get();
return exit_code;
} else if (output_extension == ".ifc") {
bool success = false;
const std::string input_extension = input_filename.substr(input_filename.size() - 4);
if (input_extension == ".ifc") {
IfcParse::IfcFile f;
if (f.Init(input_filename)) {
std::ofstream of(output_filename.c_str());
of << f;
success = true;
} else {
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file");
}
} else if (input_extension == ".hdf") {
std::ofstream fs(output_filename.c_str());
IfcParse::IfcHdf5File::convert_to_spf(input_filename, fs, hdf5_mount_points);
success = true;
} else {
Logger::Message(Logger::LOG_ERROR, "Unknown input extension");
}
write_log();
return success ? 0 : 1;
}
IfcGeom::IteratorSettings settings;
settings.set(IfcGeom::IteratorSettings::APPLY_DEFAULT_MATERIALS, true);
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, use_world_coords);
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, weld_vertices);
settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, sew_shells);
settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, convert_back_units);
#if OCC_VERSION_HEX < 0x60900
settings.set(IfcGeom::IteratorSettings::FASTER_BOOLEANS, merge_boolean_operands);
#endif
settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, disable_opening_subtractions);
settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, include_plan);
settings.set(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES, !include_model);
GeometrySerializer* serializer;
if (output_extension == ".obj") {
const std::string mtl_filename = output_filename.substr(0,output_filename.size()-3) + "mtl";
if (!use_world_coords) {
Logger::Message(Logger::LOG_NOTICE, "Using world coords when writing WaveFront OBJ files");
IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS, true);
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true);
}
serializer = new WaveFrontOBJSerializer(output_filename, mtl_filename);
#ifdef WITH_OPENCOLLADA
@@ -210,6 +370,15 @@ int main(int argc, char** argv) {
// See: http://tracker.dev.opencascade.org/view.php?id=23679
IGESControl_Controller::Init();
serializer = new IgesSerializer(output_filename);
} else if (output_extension == ".svg") {
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
serializer = new SvgSerializer(output_filename);
if (bounding_width && bounding_height) {
((SvgSerializer*) serializer)->setBoundingRectangle(
static_cast<double>(*bounding_width),
static_cast<double>(*bounding_height)
);
}
} else {
Logger::Message(Logger::LOG_ERROR, "Unknown output filename extension");
write_log();
@@ -217,30 +386,45 @@ int main(int argc, char** argv) {
return 1;
}
if (!serializer->isTesselated()) {
if (weld_vertices) {
Logger::Message(Logger::LOG_NOTICE, "Weld vertices setting ignored when writing STEP or IGES files");
}
settings.disable_triangulation() = true;
}
IfcGeom::Iterator<double> context_iterator(settings, input_filename);
try {
if (include_entities) {
context_iterator.includeEntities(entities);
} else {
context_iterator.excludeEntities(entities);
}
} catch (const IfcParse::IfcException& e) {
std::cout << "[Error] " << e.what() << std::endl;
return 1;
}
if (!serializer->ready()) {
Logger::Message(Logger::LOG_ERROR, "Unable to open output file for writing");
write_log();
return 1;
}
if (!serializer->isTesselated()) {
IfcGeomObjects::Settings(IfcGeomObjects::DISABLE_TRIANGULATION, true);
if (weld_vertices) {
Logger::Message(Logger::LOG_NOTICE, "Weld vertices setting ignored when writing STEP or IGES files");
}
}
time_t start,end;
time(&start);
// Parse the file supplied in argv[1]. Returns true on succes.
if ( ! IfcGeomObjects::Init(input_filename, &std::cout, &log_stream) ) {
if (!context_iterator.initialize()) {
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file or no geometrical entities found");
write_log();
return 1;
}
serializer->setFile(context_iterator.getFile());
if (convert_back_units) {
serializer->setUnitNameAndMagnitude(IfcGeomObjects::GetUnitName(), IfcGeomObjects::GetUnitMagnitude());
serializer->setUnitNameAndMagnitude(context_iterator.getUnitName(), static_cast<const float>(context_iterator.getUnitMagnitude()));
} else {
serializer->setUnitNameAndMagnitude("METER", 1.0f);
}
@@ -252,35 +436,30 @@ int main(int argc, char** argv) {
int old_progress = -1;
Logger::Status("Creating geometry...");
// The functions IfcGeomObjects::Get() and IfcGeomObjects::Next() wrap an iterator of all geometrical entities in the Ifc file.
// IfcGeomObjects::Get() returns an IfcGeomObjects::IfcGeomObject (see IfcGeomObjects.h for definition)
// IfcGeomObjects::Next() is used to poll whether more geometrical entities are available
// The functions IfcGeom::Iterator::get() and IfcGeom::Iterator::next()
// wrap an iterator of all geometrical products in the Ifc file.
// IfcGeom::Iterator::get() returns an IfcGeom::TriangulationElement or
// -BRepElement pointer, based on current settings. (see IfcGeomIterator.h
// for definition) IfcGeom::Iterator::next() is used to poll whether more
// geometrical entities are available. None of these functions throw
// exceptions, neither for parsing errors or geometrical errors. Upon
// calling next() the entity to be returned has already been processed, a
// true return value guarantees that a successfully processed product is
// available.
do {
const IfcGeomObjects::IfcObject* geom_object;
const IfcGeom::Element<double>* geom_object = context_iterator.get();
if (serializer->isTesselated()) {
geom_object = IfcGeomObjects::Get();
serializer->write(static_cast<const IfcGeom::TriangulationElement<double>*>(geom_object));
} else {
geom_object = IfcGeomObjects::GetShapeModel();
serializer->write(static_cast<const IfcGeom::BRepElement<double>*>(geom_object));
}
std::string lowercase_type = geom_object->type();
for (std::string::iterator c = lowercase_type.begin(); c != lowercase_type.end(); ++c) {
*c = tolower(*c);
}
if (ignore_types.find(lowercase_type) != ignore_types.end()) continue;
if (serializer->isTesselated()) {
serializer->writeTesselated(static_cast<const IfcGeomObjects::IfcGeomObject*>(geom_object));
} else {
serializer->writeShapeModel(static_cast<const IfcGeomObjects::IfcGeomShapeModelObject*>(geom_object));
}
const int progress = IfcGeomObjects::Progress() / 2;
if ( old_progress!= progress ) Logger::ProgressBar(progress);
const int progress = context_iterator.progress() / 2;
if (old_progress!= progress) Logger::ProgressBar(progress);
old_progress = progress;
} while ( IfcGeomObjects::Next() );
} while (context_iterator.next());
serializer->finalize();
delete serializer;
@@ -292,6 +471,8 @@ int main(int argc, char** argv) {
time(&end);
int dif = (int) difftime (end,start);
printf ("\nConversion took %d seconds\n", dif );
return 0;
}
void write_log() {
+3 -3
View File
@@ -20,11 +20,10 @@
#ifndef IGESSERIALIZER_H
#define IGESSERIALIZER_H
#include <IGESControl_Controller.hxx>
#include <IGESControl_Writer.hxx>
#include <Interface_Static.hxx>
#include "../ifcgeom/IfcGeomObjects.h"
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcconvert/OpenCascadeBasedSerializer.h"
@@ -43,9 +42,10 @@ public:
void finalize() {
writer.Write(out_filename.c_str());
}
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
void setUnitNameAndMagnitude(const std::string& /*name*/, float magnitude) {
const char* symbol = getSymbolForUnitMagnitude(magnitude);
if (symbol) {
Interface_Static::SetCVal("xstep.cascade.unit", symbol);
Interface_Static::SetCVal("write.iges.unit", symbol);
}
}
+19 -16
View File
@@ -24,6 +24,8 @@
#include <BRepBuilderAPI_GTransform.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <Standard_Version.hxx>
#include "OpenCascadeBasedSerializer.h"
bool OpenCascadeBasedSerializer::ready() {
@@ -34,18 +36,19 @@ bool OpenCascadeBasedSerializer::ready() {
return succeeded;
}
void OpenCascadeBasedSerializer::writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) {
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->mesh().begin(); it != o->mesh().end(); ++ it) {
void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement<double>* o) {
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) {
gp_GTrsf gtrsf = it->Placement();
// TODO:
gp_GTrsf o_trsf;
int k = 0;
for( int i = 1; i < 5; ++ i )
for ( int j = 1; j < 4; ++ j )
o_trsf.SetValue(j, i, o->matrix()[k++]);
const gp_Trsf& o_trsf = o->transformation().data();
gtrsf.PreMultiply(o_trsf);
if (o->geometry().settings().convert_back_units()) {
gp_Trsf scale;
scale.SetScaleFactor(1.0 / o->geometry().settings().unit_magnitude());
gtrsf.PreMultiply(scale);
}
const TopoDS_Shape& s = it->Shape();
bool trsf_valid = false;
@@ -64,18 +67,18 @@ void OpenCascadeBasedSerializer::writeShapeModel(const IfcGeomObjects::IfcGeomSh
}
#define RATHER_SMALL (1e-3)
#define ALMOST_THE_SAME(a,b) (fabs(a-b) < RATHER_SMALL)
#define APPROXIMATELY_THE_SAME(a,b) (fabs(a-b) < RATHER_SMALL)
const char* OpenCascadeBasedSerializer::getSymbolForUnitMagnitude(float mag) {
if (ALMOST_THE_SAME(mag, 0.001f)) {
if (APPROXIMATELY_THE_SAME(mag, 0.001f)) {
return "MM";
} else if (ALMOST_THE_SAME(mag, 0.01f)) {
} else if (APPROXIMATELY_THE_SAME(mag, 0.01f)) {
return "CM";
} else if (ALMOST_THE_SAME(mag, 1.0f)) {
} else if (APPROXIMATELY_THE_SAME(mag, 1.0f)) {
return "M";
} else if (ALMOST_THE_SAME(mag, 0.3048f)) {
} else if (APPROXIMATELY_THE_SAME(mag, 0.3048f)) {
return "FT";
} else if (ALMOST_THE_SAME(mag, 0.0254f)) {
} else if (APPROXIMATELY_THE_SAME(mag, 0.0254f)) {
return "INCH";
} else {
return 0;
+7 -5
View File
@@ -20,13 +20,15 @@
#ifndef OPENCASCADEBASEDSERIALIZER_H
#define OPENCASCADEBASEDSERIALIZER_H
#include "../ifcgeom/IfcGeomObjects.h"
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcconvert/GeometrySerializer.h"
class OpenCascadeBasedSerializer : public GeometrySerializer {
OpenCascadeBasedSerializer(const OpenCascadeBasedSerializer&); //N/A
OpenCascadeBasedSerializer& operator =(const OpenCascadeBasedSerializer&); //N/A
protected:
const std::string& out_filename;
const std::string out_filename;
const char* getSymbolForUnitMagnitude(float mag);
public:
explicit OpenCascadeBasedSerializer(const std::string& out_filename)
@@ -35,12 +37,12 @@ public:
{}
virtual ~OpenCascadeBasedSerializer() {}
void writeHeader() {}
void writeMaterial(const IfcGeom::SurfaceStyle& style) {}
bool ready();
virtual void writeShape(const TopoDS_Shape& shape) = 0;
void writeTesselated(const IfcGeomObjects::IfcGeomObject* o) {}
void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o);
void write(const IfcGeom::TriangulationElement<double>* /*o*/) {}
void write(const IfcGeom::BRepElement<double>* o);
bool isTesselated() const { return false; }
void setFile(IfcParse::IfcFile*) {}
};
#endif
@@ -1,4 +1,4 @@
/********************************************************************************
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
@@ -17,22 +17,19 @@
* *
********************************************************************************/
/********************************************************************************
* *
* This file defines the shared pointer implementation to use, shared pointers *
* are used extensively in IfcOpenShell *
* *
********************************************************************************/
#ifndef SERIALIZER_H
#define SERIALIZER_H
#include "../ifcparse/IfcFile.h"
class Serializer {
public:
virtual ~Serializer() {}
virtual bool ready() = 0;
virtual void writeHeader() = 0;
virtual void finalize() = 0;
virtual void setFile(IfcParse::IfcFile*) = 0;
};
#ifdef __GNUC__
#include <tr1/memory>
#define SHARED_PTR std::tr1::shared_ptr
#else
#ifdef _MSC_VER
#include <memory>
#define SHARED_PTR std::tr1::shared_ptr
#else
#include <boost/shared_ptr.hpp>
#define SHARED_PTR boost::shared_ptr
#endif
#endif
+3 -3
View File
@@ -20,11 +20,10 @@
#ifndef STEPSERIALIZER_H
#define STEPSERIALIZER_H
#include <STEPControl_Controller.hxx>
#include <STEPControl_Writer.hxx>
#include <Interface_Static.hxx>
#include "../ifcgeom/IfcGeomObjects.h"
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcconvert/OpenCascadeBasedSerializer.h"
@@ -49,9 +48,10 @@ public:
writer.Write(out_filename.c_str());
std::cout.rdbuf(sb);
}
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
void setUnitNameAndMagnitude(const std::string& /*name*/, float magnitude) {
const char* symbol = getSymbolForUnitMagnitude(magnitude);
if (symbol) {
Interface_Static::SetCVal("xstep.cascade.unit", symbol);
Interface_Static::SetCVal("write.step.unit", symbol);
}
}
-78
View File
@@ -1,78 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* This file defines default materials for several IFC datatypes *
* *
********************************************************************************/
#ifndef SURFACESTYLE_H
#define SURFACESTYLE_H
#include <string>
#include <sstream>
#include <array>
class SurfaceStyle {
public:
class ColorComponent {
private:
std::array<double, 3> data;
public:
ColorComponent(double r, double g, double b) {
data[0] = r; data[1] = g; data[2] = b;
}
const double& R() const { return data[0]; }
const double& G() const { return data[1]; }
const double& B() const { return data[2]; }
double& R() { return data[0]; }
double& G() { return data[1]; }
double& B() { return data[2]; }
};
private:
std::string name;
ColorComponent diffuse, specular, ambient;
double transparency;
double specularity;
public:
SurfaceStyle(const std::string& name,
double dr = 0.7, double dg = 0.7, double db = 0.7,
double sr = 0.2, double sg = 0.2, double sb = 0.2,
double ar = 0.1, double ag = 0.1, double ab = 0.1,
double Ns = 10.0, double Tr = 1.0)
: name(name)
, diffuse(dr, dg, db)
, specular(sr, sg, sb)
, ambient(ar, ag, ab)
, transparency(Tr)
, specularity(Ns)
{}
const std::string& Name() const { return name; }
const ColorComponent& Diffuse() const { return diffuse; }
const ColorComponent& Specular() const { return specular; }
const ColorComponent& Ambient() const { return ambient; }
double Transparency() const { return transparency; }
double Specularity() const { return specularity; }
};
SurfaceStyle GetDefaultMaterial(const std::string& s);
#endif
+355
View File
@@ -0,0 +1,355 @@
/********************************************************************************
* *
* Copyright 2015 IfcOpenShell and ROOT B.V. *
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include <string>
#include <fstream>
#include <cstdio>
#include <limits>
#include <algorithm>
#include <gp_Pln.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <BRepBuilderAPI_GTransform.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <TopExp_Explorer.hxx>
#include <BRep_Tool.hxx>
#include <BRepAlgo_Section.hxx>
#include <BRepTools.hxx>
#include <BRepAlgoAPI_Section.hxx>
#include <ShapeAnalysis_FreeBounds.hxx>
#include <TopTools_HSequenceOfShape.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Line.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Ellipse.hxx>
#include <gp_Ax22d.hxx>
#include <Standard_Version.hxx>
#include "../ifcparse/IfcGlobalId.h"
#include "SvgSerializer.h"
const double PI2 = M_PI * 2.;
bool SvgSerializer::ready() {
return true;
}
void SvgSerializer::write(path_object& p, const TopoDS_Wire& wire) {
/* ShapeFix_Wire fix;
Handle(ShapeExtend_WireData) data = new ShapeExtend_WireData;
for (TopExp_Explorer edges(result, TopAbs_EDGE); edges.More(); edges.Next()) {
data->Add(edges.Current());
}
fix.Load(data);
fix.FixReorder();
fix.FixConnected();
const TopoDS_Wire fixed_wire = fix.Wire(); */
bool first = true;
util::string_buffer path;
path.add(" <path style=\"stroke:black; fill:none;\" d=\"");
for (TopExp_Explorer edges(wire, TopAbs_EDGE); edges.More(); edges.Next()) {
const TopoDS_Edge& edge = TopoDS::Edge(edges.Current());
double u1, u2;
Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, u1, u2);
const bool reversed = edge.Orientation() == TopAbs_REVERSED;
gp_Pnt p1, p2;
curve->D0(u1, p1);
curve->D0(u2, p2);
if (reversed) {
std::swap(p1, p2);
}
if (first) {
path.add("M");
addXCoordinate(path.add(p1.X()));
path.add(",");
addYCoordinate(path.add(p1.Y()));
growBoundingBox(p1.X(), p1.Y());
}
growBoundingBox(p2.X(), p2.Y());
Handle(Standard_Type) ty = curve->DynamicType();
if (ty == STANDARD_TYPE(Geom_Circle) || ty == STANDARD_TYPE(Geom_Ellipse)) {
Handle(Geom_Conic) conic = Handle(Geom_Conic)::DownCast(curve);
const bool mirrored = conic->Position().Axis().Direction().Z() < 0;
double r1, r2;
bool larger_arc_segment = (fmod(u2 - u1 + PI2, PI2) > M_PI);
bool positive_direction = (u2 > u1);
if (mirrored != reversed) {
// In case the local coordinate system is mirrored
// the direction is reversed.
positive_direction = !positive_direction;
}
if (ty == STANDARD_TYPE(Geom_Circle)) {
Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(curve);
r1 = r2 = circle->Radius();
} else {
Handle(Geom_Ellipse) ellipse = Handle(Geom_Ellipse)::DownCast(curve);
r1 = ellipse->MajorRadius();
r2 = ellipse->MinorRadius();
}
// Calculate the angle between 2d vecs to have signed result
const gp_Dir& d = conic->Position().XDirection();
const gp_Dir2d d2(d.X(), d.Y());
const double ang = d2.Angle(gp::DX2d());
// Write radii
path.add(" A");
addSizeComponent(path.add(r1));
path.add(",");
addSizeComponent(path.add(r2));
// Write X-axis rotation
{ std::stringstream ss; ss << " " << ang << " ";
path.add(ss.str()); }
// Write large-arc-flag and sweep-flag
path.add(std::string(1, '0'+static_cast<int>(larger_arc_segment)));
path.add(",");
path.add(std::string(1, '0'+static_cast<int>(positive_direction)));
path.add(" ");
// Write arc end point
xcoords.push_back(path.add(p2.X()));
path.add(",");
ycoords.push_back(path.add(p2.Y()));
} else {
// Either a Geom_Line or something unimplemented,
// drawn as a straight line segment.
path.add(" L");
xcoords.push_back(path.add(p2.X()));
path.add(",");
ycoords.push_back(path.add(p2.Y()));
}
first = false;
}
path.add("\"/>\n");
p.second.push_back(path);
}
SvgSerializer::path_object& SvgSerializer::start_path(IfcSchema::IfcBuildingStorey* storey, const std::string& id) {
SvgSerializer::path_object& p = paths.insert(std::make_pair(storey, path_object()))->second;
p.first = id;
return p;
}
void SvgSerializer::write(const IfcGeom::BRepElement<double>* o) {
IfcSchema::IfcBuildingStorey* storey = 0;
IfcSchema::IfcObjectDefinition* obdef = static_cast<IfcSchema::IfcObjectDefinition*>(file->entityById(o->id()));
#ifndef USE_IFC4
typedef IfcSchema::IfcRelDecomposes decomposition_element;
#else
typedef IfcSchema::IfcRelAggregates decomposition_element;
#endif
for (;;) {
// Iterate over the decomposing element to find the parent IfcBuildingStorey
decomposition_element::list::ptr decomposes = obdef->Decomposes();
if (!decomposes->size()) {
if (obdef->declaration().is(IfcSchema::Type::IfcElement)) {
IfcSchema::IfcRelContainedInSpatialStructure::list::ptr containment = ((IfcSchema::IfcElement*)obdef)->ContainedInStructure();
if (!containment->size()) {
break;
}
for (IfcSchema::IfcRelContainedInSpatialStructure::list::it it = containment->begin(); it != containment->end(); ++it) {
IfcSchema::IfcRelContainedInSpatialStructure* container = *it;
if (container->RelatingStructure() != obdef) {
obdef = container->RelatingStructure();
}
}
} else {
break;
}
} else {
for (decomposition_element::list::it it = decomposes->begin(); it != decomposes->end(); ++it) {
decomposition_element* decompose = *it;
if (decompose->RelatingObject() != obdef) {
obdef = decompose->RelatingObject();
}
}
}
if (obdef->declaration().is(IfcSchema::Type::IfcBuildingStorey)) {
storey = static_cast<IfcSchema::IfcBuildingStorey*>(obdef);
break;
}
}
if (!storey) return;
path_object& p = start_path(storey, nameElement(o));
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) {
gp_GTrsf gtrsf = it->Placement();
const gp_Trsf& o_trsf = o->transformation().data();
gtrsf.PreMultiply(o_trsf);
const TopoDS_Shape& s = it->Shape();
bool trsf_valid = false;
gp_Trsf trsf;
try {
trsf = gtrsf.Trsf();
trsf_valid = true;
} catch (...) {}
const TopoDS_Shape moved_shape = trsf_valid
? BRepBuilderAPI_Transform(s, trsf, true).Shape()
: BRepBuilderAPI_GTransform(s, gtrsf, true).Shape();
const double inf = std::numeric_limits<double>::infinity();
double zmin = inf;
double zmax = -inf;
{TopExp_Explorer exp(moved_shape, TopAbs_VERTEX);
for (; exp.More(); exp.Next()) {
const TopoDS_Vertex& vertex = TopoDS::Vertex(exp.Current());
gp_Pnt pnt = BRep_Tool::Pnt(vertex);
if (pnt.Z() < zmin) { zmin = pnt.Z(); }
if (pnt.Z() > zmax) { zmax = pnt.Z(); }
}}
if (section_height) {
if (zmin > section_height || zmax < section_height) continue;
} else {
if (zmin == inf || (zmax - zmin) < 1.) continue;
}
const double cut_z = section_height.get_value_or(zmin + 1.);
// Create a horizontal cross section 1 meter above the bottom point of the shape
TopoDS_Shape result = BRepAlgoAPI_Section(moved_shape, gp_Pln(gp_Pnt(0, 0, cut_z), gp::DZ()));
Handle(TopTools_HSequenceOfShape) edges = new TopTools_HSequenceOfShape();
Handle(TopTools_HSequenceOfShape) wires = new TopTools_HSequenceOfShape();
{TopExp_Explorer exp(result, TopAbs_EDGE);
for (; exp.More(); exp.Next()) {
edges->Append(exp.Current());
}}
ShapeAnalysis_FreeBounds::ConnectEdgesToWires(edges, 1e-5, false, wires);
gp_Pnt prev;
for (int i = 1; i <= wires->Length(); ++i) {
const TopoDS_Wire& wire = TopoDS::Wire(wires->Value(i));
write(p, wire);
}
}
}
void SvgSerializer::setBoundingRectangle(double width, double height) {
this->width = width;
this->height = height;
this->rescale = true;
}
void SvgSerializer::finalize() {
if (rescale) {
// Scale the resulting image to a bounding rectangle specified by command line arguments
const double dx = xmax - xmin;
const double dy = ymax - ymin;
double sc = 1.;
if (dx / width > dy / height) {
sc = width / dx;
} else {
sc = height / dy;
}
const double cx = xmin * sc;
const double cy = ymin * sc;
{std::vector< boost::shared_ptr<util::string_buffer::float_item> >::const_iterator it;
for (it = xcoords.begin(); it != xcoords.end(); ++it) {
double& v = (*it)->value();
v = v * sc - cx;
}
for (it = ycoords.begin(); it != ycoords.end(); ++it) {
double& v = (*it)->value();
v = v * sc - cy;
}
for (it = radii.begin(); it != radii.end(); ++it) {
(*it)->value() *= sc;
}}
}
std::multimap<IfcSchema::IfcBuildingStorey*, path_object>::const_iterator it;
IfcSchema::IfcBuildingStorey* previous = 0;
bool first = true;
for (it = paths.begin(); it != paths.end(); ++it) {
if (it->first != previous || first) {
if (!first) {
svg_file << " </g>\n";
}
std::ostringstream oss;
svg_file << " <g " << nameElement(it->first) << ">\n";
}
svg_file << " <g " << it->second.first << ">\n";
std::vector<util::string_buffer>::const_iterator jt;
for (jt = it->second.second.begin(); jt != it->second.second.end(); ++jt) {
svg_file << jt->str();
}
svg_file << " </g>\n";
previous = it->first;
first = false;
}
svg_file << " </g>\n";
svg_file << "</svg>" << std::endl;
}
void SvgSerializer::writeHeader() {
svg_file << "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n";
}
std::string SvgSerializer::nameElement(const IfcGeom::Element<double>* elem) {
std::ostringstream oss;
const std::string type = "product";
oss << "id=\"" << type << "-" << elem->unique_id() << "\"";
return oss.str();
}
std::string SvgSerializer::nameElement(const IfcSchema::IfcProduct* elem) {
std::ostringstream oss;
const std::string type = elem->declaration().is(IfcSchema::Type::IfcBuildingStorey) ? "storey" : "product";
oss << "id=\"product-" << IfcParse::IfcGlobalId(elem->GlobalId()).formatted() << "\"";
return oss.str();
}
+79
View File
@@ -0,0 +1,79 @@
/********************************************************************************
* *
* Copyright 2015 IfcOpenShell and ROOT B.V. *
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef SVGSERIALIZER_H
#define SVGSERIALIZER_H
#include <sstream>
#include <string>
#include <limits>
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcconvert/GeometrySerializer.h"
#include "../ifcconvert/util.h"
class SvgSerializer : public GeometrySerializer {
public:
typedef std::pair<std::string, std::vector<util::string_buffer> > path_object;
protected:
std::ofstream svg_file;
double xmin, ymin, xmax, ymax, width, height;
boost::optional<double> section_height;
bool rescale;
std::multimap<IfcSchema::IfcBuildingStorey*, path_object> paths;
std::vector< boost::shared_ptr<util::string_buffer::float_item> > xcoords;
std::vector< boost::shared_ptr<util::string_buffer::float_item> > ycoords;
std::vector< boost::shared_ptr<util::string_buffer::float_item> > radii;
IfcParse::IfcFile* file;
public:
explicit SvgSerializer(const std::string& out_filename)
: GeometrySerializer()
, svg_file(out_filename.c_str())
, xmin(+std::numeric_limits<double>::infinity())
, xmax(-std::numeric_limits<double>::infinity())
, ymin(+std::numeric_limits<double>::infinity())
, ymax(-std::numeric_limits<double>::infinity())
, rescale(false)
, file(0)
{}
virtual void addXCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { xcoords.push_back(fi); }
virtual void addYCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { ycoords.push_back(fi); }
virtual void addSizeComponent(const boost::shared_ptr<util::string_buffer::float_item>& fi) { radii.push_back(fi); }
virtual void growBoundingBox(double x, double y) { if (x < xmin) xmin = x; if (x > xmax) xmax = x; if (y < ymin) ymin = y; if (y > ymax) ymax = y; }
virtual ~SvgSerializer() {}
virtual void writeHeader();
virtual bool ready();
virtual void write(const IfcGeom::TriangulationElement<double>* /*o*/) {}
virtual void write(const IfcGeom::BRepElement<double>* o);
virtual void write(path_object& p, const TopoDS_Wire& wire);
virtual path_object& start_path(IfcSchema::IfcBuildingStorey* storey, const std::string& id);
virtual bool isTesselated() const { return false; }
virtual void finalize();
virtual void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
virtual void setFile(IfcParse::IfcFile* f) { file = f; }
virtual void setBoundingRectangle(double width, double height);
virtual void setSectionHeight(double h) { section_height = h; }
virtual std::string nameElement(const IfcGeom::Element<double>* elem);
virtual std::string nameElement(const IfcSchema::IfcProduct* elem);
};
#endif
+47 -20
View File
@@ -17,12 +17,13 @@
* *
********************************************************************************/
#include <limits>
#include <iomanip>
#include "../ifcgeom/IfcGeomRenderStyles.h"
#include "WavefrontObjSerializer.h"
#include <iomanip>
bool WaveFrontOBJSerializer::ready() {
return obj_stream.is_open() && mtl_stream.is_open();
}
@@ -43,7 +44,7 @@ void WaveFrontOBJSerializer::writeHeader() {
mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n";
}
void WaveFrontOBJSerializer::writeMaterial(const IfcGeomObjects::Material& style) {
void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style) {
mtl_stream << "newmtl " << style.name() << "\n";
if (style.hasDiffuse()) {
const double* diffuse = style.diffuse();
@@ -65,25 +66,24 @@ void WaveFrontOBJSerializer::writeMaterial(const IfcGeomObjects::Material& style
}
}
}
void WaveFrontOBJSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject* o) {
void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<double>* o) {
std::string tmp = o->name().empty() ? o->guid() : o->name();
std::replace( tmp.begin(), tmp.end(), ' ', '_');
const std::string name = tmp;
obj_stream << "g " << name << "\n";
obj_stream << "g " << o->unique_id() << "\n";
obj_stream << "s 1" << "\n";
const IfcGeomObjects::IfcRepresentationTriangulation& mesh = o->mesh();
obj_stream << std::setprecision(std::numeric_limits<double>::digits10);
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
const int vcount = mesh.verts().size() / 3;
for ( std::vector<float>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) {
const int vcount = (int)mesh.verts().size() / 3;
for ( std::vector<double>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) {
const double x = *(it++);
const double y = *(it++);
const double z = *(it++);
obj_stream << "v " << x << " " << y << " " << z << "\n";
}
for ( std::vector<float>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) {
for ( std::vector<double>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) {
const double x = *(it++);
const double y = *(it++);
const double z = *(it++);
@@ -97,12 +97,7 @@ void WaveFrontOBJSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject
const int material_id = *(material_it++);
if (material_id != previous_material_id) {
IfcGeomObjects::Material material(0);
if (material_id >= 0) {
material = mesh.materials()[material_id];
} else {
material = IfcGeomObjects::Material(IfcGeom::get_default_style(o->type()));
}
const IfcGeom::Material& material = mesh.materials()[material_id];
const std::string material_name = material.name();
obj_stream << "usemtl " << material_name << "\n";
if (materials.find(material_name) == materials.end()) {
@@ -116,6 +111,38 @@ void WaveFrontOBJSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject
const int v2 = *(it++)+vcount_total;
const int v3 = *(it++)+vcount_total;
obj_stream << "f " << v1 << "//" << v1 << " " << v2 << "//" << v2 << " " << v3 << "//" << v3 << "\n";
}
vcount_total += vcount;
std::set<int> faces_set (mesh.faces().begin(), mesh.faces().end());
const std::vector<int>& edges = mesh.edges();
for ( std::vector<int>::const_iterator it = edges.begin(); it != edges.end(); ) {
const int i1 = *(it++);
const int i2 = *(it++);
if (faces_set.find(i1) != faces_set.end() || faces_set.find(i2) != faces_set.end()) {
continue;
}
const int material_id = *(material_it++);
if (material_id != previous_material_id) {
const IfcGeom::Material& material = mesh.materials()[material_id];
const std::string material_name = material.name();
obj_stream << "usemtl " << material_name << "\n";
if (materials.find(material_name) == materials.end()) {
writeMaterial(material);
materials.insert(material_name);
}
previous_material_id = material_id;
}
const int v1 = i1 + vcount_total;
const int v2 = i2 + vcount_total;
obj_stream << "l " << v1 << " " << v2 << "\n";
}
vcount_total += vcount;
}
+5 -4
View File
@@ -44,12 +44,13 @@ public:
virtual ~WaveFrontOBJSerializer() {}
bool ready();
void writeHeader();
void writeMaterial(const IfcGeomObjects::Material& style);
void writeTesselated(const IfcGeomObjects::IfcGeomObject* o);
void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) {}
void writeMaterial(const IfcGeom::Material& style);
void write(const IfcGeom::TriangulationElement<double>* o);
void write(const IfcGeom::BRepElement<double>* /*o*/) {}
void finalize() {}
bool isTesselated() const { return true; }
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {}
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
void setFile(IfcParse::IfcFile*) {}
};
#endif
+293
View File
@@ -0,0 +1,293 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include <map>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/foreach.hpp>
#include <boost/version.hpp>
#include "XmlSerializer.h"
#include <algorithm>
using boost::property_tree::ptree;
using namespace IfcSchema;
static std::map<std::string, std::string> argument_name_map;
// Format an IFC attribute and maybe returns as string. Only literal scalar
// values are converted. Things like entity instances and lists are omitted.
boost::optional<std::string> format_attribute(const Argument* argument, IfcUtil::ArgumentType argument_type) {
boost::optional<std::string> value;
switch(argument_type) {
case IfcUtil::Argument_BOOL: {
const bool b = *argument;
value = b ? "true" : "false";
break; }
case IfcUtil::Argument_DOUBLE: {
const double d = *argument;
std::stringstream stream;
stream << d;
value = stream.str();
break; }
case IfcUtil::Argument_STRING:
case IfcUtil::Argument_ENUMERATION: {
value = static_cast<std::string>(*argument);
break; }
case IfcUtil::Argument_INT: {
const int v = *argument;
std::stringstream stream;
stream << v;
value = stream.str();
break; }
case IfcUtil::Argument_ENTITY_INSTANCE: {
IfcUtil::IfcBaseClass* e = *argument;
if (Type::IsSimple(e->declaration().type())) {
IfcUtil::IfcBaseType* f = (IfcUtil::IfcBaseType*) e;
value = format_attribute(f->data().getArgument(0), f->data().getArgument(0)->type());
} else if (e->declaration().is(IfcSchema::Type::IfcSIUnit) || e->declaration().is(IfcSchema::Type::IfcConversionBasedUnit)) {
// Some string concatenation to have a unit name as a XML attribute.
std::string unit_name;
if (e->declaration().is(IfcSchema::Type::IfcSIUnit)) {
IfcSchema::IfcSIUnit* unit = (IfcSchema::IfcSIUnit*) e;
unit_name = IfcSchema::IfcSIUnitName::ToString(unit->Name());
if (unit->hasPrefix()) {
unit_name = IfcSchema::IfcSIPrefix::ToString(unit->Prefix()) + unit_name;
}
} else {
IfcSchema::IfcConversionBasedUnit* unit = (IfcSchema::IfcConversionBasedUnit*) e;
unit_name = unit->Name();
}
// TODO add toLower() and toUpper() string helper functions for the project
std::transform(unit_name.begin(), unit_name.end(), unit_name.begin(), ::tolower);
value = unit_name;
}
break; }
}
return value;
}
// Formats an entity instances as a ptree node, and insert into the DOM. Recurses
// over the entity attributes and writes them as xml attributes of the node.
ptree& format_entity_instance(IfcUtil::IfcBaseEntity* instance, ptree& tree, bool as_link = false) {
ptree child;
const unsigned n = instance->data().getArgumentCount();
std::vector<const IfcParse::entity::attribute*> attributes = instance->declaration().all_attributes();
for (unsigned i = 0; i < n; ++i) {
const Argument* argument = instance->data().getArgument(i);
if (argument->isNull()) continue;
std::string argument_name = attributes[i]->name();
std::map<std::string, std::string>::const_iterator argument_name_it;
argument_name_it = argument_name_map.find(argument_name);
if (argument_name_it != argument_name_map.end()) {
argument_name = argument_name_it->second;
}
const IfcUtil::ArgumentType argument_type = instance->data().getArgument(i)->type();
boost::optional<std::string> value;
try {
value = format_attribute(argument, argument_type);
} catch (...) {}
if (value) {
if (as_link) {
if (argument_name == "id") {
child.put("<xmlattr>.xlink:href", std::string("#") + *value);
}
} else {
std::stringstream stream;
stream << "<xmlattr>." << argument_name;
child.put(stream.str(), *value);
}
}
}
return tree.add_child(Type::ToString(instance->declaration().type()), child);
}
// A function to be called recursively. Template specialization is used
// to descend into decomposition, containment and property relationships.
template <typename A>
void descend(A* instance, ptree& tree) {
format_entity_instance(instance, tree);
}
// Returns related entity instances using IFC's objectified relationship
// model. The second and third argument require a member function pointer.
template <typename T, typename U, typename V, typename F, typename G>
typename V::list::ptr get_related(T* t, F f, G g) {
typename U::list::ptr li = (*t.*f)()->template as<U>();
typename V::list::ptr acc(new typename V::list);
for (typename U::list::it it = li->begin(); it != li->end(); ++it) {
U* u = *it;
acc->push((*u.*g)()->template as<V>());
}
return acc;
}
// Descends into the tree by recursing into IfcRelContainedInSpatialStructure,
// IfcRelDecomposes and IfcRelDefinesByProperties relations.
template <>
void descend(IfcProduct* product, ptree& tree) {
ptree& child = format_entity_instance(product, tree);
if (product->declaration().is(Type::IfcSpatialStructureElement)) {
IfcSpatialStructureElement* structure = (IfcSpatialStructureElement*) product;
IfcProduct::list::ptr elements = get_related
<IfcSpatialStructureElement, IfcRelContainedInSpatialStructure, IfcProduct>
(structure, &IfcSpatialStructureElement::ContainsElements, &IfcRelContainedInSpatialStructure::RelatedElements);
for (IfcProduct::list::it it = elements->begin(); it != elements->end(); ++it) {
descend(*it, child);
}
}
#ifdef USE_IFC2x3
IfcObjectDefinition::list::ptr structures = get_related
<IfcProduct, IfcRelDecomposes, IfcObjectDefinition>
(product, &IfcProduct::IsDecomposedBy, &IfcRelDecomposes::RelatedObjects);
#else
IfcObjectDefinition::list::ptr structures = get_related
<IfcProduct, IfcRelAggregates, IfcObjectDefinition>
(product, &IfcProduct::IsDecomposedBy, &IfcRelAggregates::RelatedObjects);
#endif
for (IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
IfcObjectDefinition* ob = *it;
if (ob->declaration().is(Type::IfcSpatialStructureElement)) {
descend((IfcProduct*)ob, child);
} else {
descend(ob, child);
}
}
IfcPropertySetDefinition::list::ptr property_sets = get_related
<IfcProduct, IfcRelDefinesByProperties, IfcPropertySetDefinition>
(product, &IfcProduct::IsDefinedBy, &IfcRelDefinesByProperties::RelatingPropertyDefinition);
for (IfcPropertySetDefinition::list::it it = property_sets->begin(); it != property_sets->end(); ++it) {
IfcPropertySetDefinition* pset = *it;
if (pset->declaration().is(Type::IfcPropertySet)) {
format_entity_instance(pset, child, true);
}
}
}
// Descends into the tree by recursing into IfcRelDecomposes relations.
template <>
void descend(IfcProject* project, ptree& tree) {
ptree& child = format_entity_instance(project, tree);
#ifdef USE_IFC2x3
IfcObjectDefinition::list::ptr structures = get_related
<IfcProject, IfcRelDecomposes, IfcObjectDefinition>
(project, &IfcProject::IsDecomposedBy, &IfcRelDecomposes::RelatedObjects);
#else
IfcObjectDefinition::list::ptr structures = get_related
<IfcProject, IfcRelAggregates, IfcObjectDefinition>
(project, &IfcProduct::IsDecomposedBy, &IfcRelAggregates::RelatedObjects);
#endif
for (IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
IfcObjectDefinition* ob = *it;
if (ob->declaration().is(Type::IfcSpatialStructureElement)) {
descend((IfcProduct*)ob, child);
} else {
descend(ob, child);
}
}
}
// Format IfcProperty instances and insert into the DOM. IfcComplexProperties are flattened out.
void format_properties(IfcProperty::list::ptr properties, ptree& node) {
for (IfcProperty::list::it it = properties->begin(); it != properties->end(); ++it) {
IfcProperty* p = *it;
if (p->declaration().is(Type::IfcComplexProperty)) {
IfcComplexProperty* complex = (IfcComplexProperty*) p;
format_properties(complex->HasProperties(), node);
} else {
format_entity_instance(p, node);
}
}
}
void XmlSerializer::finalize() {
argument_name_map.insert(std::make_pair("GlobalId", "id"));
IfcProject::list::ptr projects = file->entitiesByType<IfcProject>();
if (projects->size() != 1) {
Logger::Message(Logger::LOG_ERROR, "Expected a single IfcProject");
return;
}
IfcProject* project = *projects->begin();
ptree root, header, decomposition, properties;
// Write the SPF header as XML nodes.
BOOST_FOREACH(const std::string& s, file->header().file_description().description()) {
header.add_child("file_description.description", ptree(s));
}
BOOST_FOREACH(const std::string& s, file->header().file_name().author()) {
header.add_child("file_name.author", ptree(s));
}
BOOST_FOREACH(const std::string& s, file->header().file_name().organization()) {
header.add_child("file_name.organization", ptree(s));
}
BOOST_FOREACH(const std::string& s, file->header().file_schema().schema_identifiers()) {
header.add_child("file_schema.schema_identifiers", ptree(s));
}
header.put("file_description.implementation_level", file->header().file_description().implementation_level());
header.put("file_name.name", file->header().file_name().name());
header.put("file_name.time_stamp", file->header().file_name().time_stamp());
header.put("file_name.preprocessor_version", file->header().file_name().preprocessor_version());
header.put("file_name.originating_system", file->header().file_name().originating_system());
header.put("file_name.authorization", file->header().file_name().authorization());
// Descend into the decomposition structure of the IFC file.
descend(project, decomposition);
// Write all property sets and values as XML nodes.
IfcPropertySet::list::ptr psets = file->entitiesByType<IfcPropertySet>();
for (IfcPropertySet::list::it it = psets->begin(); it != psets->end(); ++it) {
IfcPropertySet* pset = *it;
ptree& node = format_entity_instance(pset, properties);
format_properties(pset->HasProperties(), node);
}
root.add_child("ifc.header", header);
root.add_child("ifc.properties", properties);
root.add_child("ifc.decomposition", decomposition);
root.put("ifc.<xmlattr>.xmlns:xlink", "http://www.w3.org/1999/xlink");
#if BOOST_VERSION >= 105600
boost::property_tree::xml_writer_settings<ptree::key_type> settings = boost::property_tree::xml_writer_make_settings<ptree::key_type>('\t', 1);
#else
boost::property_tree::xml_writer_settings<char> settings('\t', 1);
#endif
boost::property_tree::write_xml(xml_filename, root, std::locale(), settings);
}
+41
View File
@@ -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
+43
View File
@@ -0,0 +1,43 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include <set>
#include <iostream>
#include "../ifcconvert/util.h"
using namespace util;
boost::shared_ptr<string_buffer::string_item> string_buffer::add(const std::string& s) {
boost::shared_ptr<string_item> i = boost::shared_ptr<string_item>(new string_item(s));
items.push_back(i);
return i;
}
boost::shared_ptr<string_buffer::float_item> string_buffer::add(const double& d) {
boost::shared_ptr<float_item> i = boost::shared_ptr<float_item>(new float_item(d));
items.push_back(i);
return i;
}
std::string string_buffer::str() const {
std::stringstream ss;
for (std::vector< boost::shared_ptr<item> >::const_iterator it = items.begin(); it != items.end(); ++it) {
ss << (**it).str();
}
return ss.str();
}
+64
View File
@@ -0,0 +1,64 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef IFCCONVERT_UTIL_H
#define IFCCONVERT_UTIL_H
#include <sstream>
#include <vector>
#include <boost/shared_ptr.hpp>
namespace util {
class string_buffer {
public:
class item {
public:
virtual std::string str() const = 0;
};
class string_item : public item {
std::string s;
public:
string_item(const std::string& s) : s(s) {}
void assign(const std::string& s) { this->s = s; }
const std::string& value() const { return s; }
std::string& value() { return s; }
std::string str() const { return s; }
};
class float_item : public item {
double d;
public:
float_item(const double& d) : d(d) {}
void assign(const double& d) { this->d = d; }
const double& value() const { return d; }
double& value() { return d; }
std::string str() const { std::stringstream ss; ss << d; return ss.str(); }
};
private:
std::vector< boost::shared_ptr<item> > items;
void clear();
void assign(const std::vector< boost::shared_ptr<item> >& other);
public:
boost::shared_ptr<string_item> add(const std::string& s);
boost::shared_ptr<float_item> add(const double& d);
std::string str() const;
};
}
#endif
-71
View File
@@ -1,71 +0,0 @@
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
###############################################################################
# #
# This files uses the documentation files from buildingSMART to generate #
# descriptions from EXPRESS names that are suitable for comments in the C++ #
# code. The .csv files used by this file are generated from the MS Office #
# Access database, which in turn has been generated from the IFC baseline #
# documentation by the IFCDOC utility provided by buildingSMART. #
# #
###############################################################################
import re,csv
import csv
try: from html.entities import entitydefs
except: from htmlentitydefs import entitydefs
name_to_oid = {}
oid_to_desc = {}
oid_to_name = {}
oid_to_pid = {}
regices = list(zip([re.compile(s,re.M) for s in [r'<[\w\n=" \-/\.;_\t:%#,\?\(\)]+>',r'(\n[\t ]*){2,}',r'^[\t ]+','^']],['','\n\n',' ','/// ']))
definition_files = ['DocEntity.csv', 'DocEnumeration.csv', 'DocDefined.csv', 'DocSelect.csv']
for fn in definition_files:
with open(fn) as f:
for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'):
name_to_oid[name] = oid
oid_to_name[oid] = name
oid_to_desc[oid] = desc
with open('DocEntityAttributes.csv') as f:
for pid, x, oid in csv.reader(f, delimiter=';', quotechar='"'):
oid_to_pid[oid] = pid
with open('DocAttribute.csv') as f:
for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'):
pid = oid_to_pid[oid]
pname = oid_to_name[pid]
name_to_oid[(pname, name)] = oid
oid_to_desc[oid] = desc
def description(item):
global name_to_oid, oid_to_desc, oid_to_name, oid_to_pid
oid = name_to_oid.get(item,0)
desc = oid_to_desc.get(oid,None)
if desc:
for a,b in entitydefs.items(): desc = desc.replace("&%s;"%a,b)
desc = desc.replace("\r","")
for r,s in regices[:-1]: desc = r.sub(s,desc)
desc = desc.strip()
r,s = regices[-1]
desc = r.sub(s,desc)
return desc
-779
View File
@@ -1,779 +0,0 @@
header = """
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
""".strip()
###############################################################################
# #
# This file can be used to generate C++ code from Express schema files. The #
# generated code works alongside the IfcOpenShell IfcParse library. This #
# script has only been tested on IFC2X3_TC1.exp and will most probably not #
# work on any other schemas. #
# #
# Note this script uses funcparserlib, which is available at: #
# http://code.google.com/p/funcparserlib/ #
# The script only works with revision 30f7ee896bc9 because it uses the some() #
# parser and is incompatible with other changes as well. #
# #
###############################################################################
import os, sys
import IfcDocumentation
filename = sys.argv[1]
#
# A class to split the Express schema files into seperate tokens
#
class Tokenizer(object):
comment = ['(*','*)']
termchars = ',;()=[]:'
def __init__(self, fn):
if hasattr(fn,'read'): object.__setattr__(self,'f',fn)
else: object.__setattr__(self,'f',open(fn,'rb'))
def __getattr__(self, name):
return getattr(self.f, name)
def __setattr__(self, name, value):
setattr(self.f, name, value)
def __iter__(self): return self
def next(self):
def get():
buffer = ''
in_comment = False
in_string = False
offset = self.tell()
while True:
c = self.read(2)
if len(c) < 2: raise StopIteration
if c in Tokenizer.comment:
in_comment = c == Tokenizer.comment[0]
continue
if in_string and c == "''":
buffer += "'"
continue
self.seek(-1,1)
if not in_string and c[0].isspace():
if ( len(buffer) ): return buffer
else:
offset = self.tell()
continue
if not in_comment:
if len(buffer) and (c[0] in Tokenizer.termchars or buffer[-1] in Tokenizer.termchars):
self.seek(-1,1)
return buffer
buffer += c[0]
return get()
#
# Some global variables to keep track of variable names
#
express_to_cpp = {
'BOOLEAN':'bool',
'LOGICAL':'bool',
'INTEGER':'int',
'REAL':'double',
'NUMBER':'double',
'STRING':'std::string'
}
schema_version = ''
enumerations = set()
selections = set()
entity_names = set()
simple_types = {}
selectable_simple_types = set()
argument_count = {}
parent_relations = {}
argument_names_and_types = {}
entity_map = {}
#
# Since inherited arguments of Express entities are placed in sequence before the
# non-inherited ones, we need to keep track of how many inherited arguments exist
#
def argument_start(c):
if c not in parent_relations: return 0
i = 0
while True:
c = parent_relations[c]
i += argument_count[c] if c in argument_count else 0
if not (c in parent_relations): break
return i
def parent_arguments(c):
if c not in parent_relations: return []
l = []
while True:
c = parent_relations[c]
i += argument_count[c] if c in argument_count else 0
if not (c in parent_relations): break
return []
#
# Every constructor also initializes their parent class members, hence they
# need be stored as well.
#
def parent_arguments(c):
if c not in parent_relations: return []
l = []
while True:
c = parent_relations[c]
i += argument_count[c] if c in argument_count else 0
if not (c in parent_relations): break
return []
#
# Several classes to generate code from Express types and entities
#
class ArrayType:
def __init__(self,l):
self.type = express_to_cpp.get(l[3],l[3])
self.upper = l[2]
self.lower = l[1]
def is_select_list(self): return self.type in selections
def __str__(self):
if self.type in entity_names:
return "SHARED_PTR< IfcTemplatedEntityList< %s > >"%self.type
elif self.type in selections:
return "SHARED_PTR< IfcTemplatedEntityList< IfcAbstractSelect > >"
else:
return "std::vector< %(type)s > /*[%(lower)s:%(upper)s]*/"%self.__dict__
def is_shared_ptr(self): return self.type in entity_names or self.type in selections
def type_enum(self):
if self.type in simple_types:
t = simple_types[self.type].type_enum()
else:
t = self.type
if t in entity_names or t == "Argument_ENTITY":
return "Argument_ENTITY_LIST"
elif t in selections:
return "Argument_ENTITY_LIST"
elif t == "int":
return "Argument_VECTOR_INT"
elif t == "double" or t == "Argument_DOUBLE":
return "Argument_VECTOR_DOUBLE"
elif t == "std::string" or t == "Argument_STRING":
return "Argument_VECTOR_STRING"
elif isinstance(t, BinaryType):
return "Argument_UNKNOWN"
else:
assert False, t
class ScalarType:
def __init__(self,l): self.type = express_to_cpp.get(l,l)
def __str__(self): return self.type
def is_select_list(self): return False
def type_enum(self):
if self.type in simple_types:
return simple_types[self.type].type_enum()
elif self.type in entity_names:
return "Argument_ENTITY"
else:
return { "bool":"Argument_BOOL","int":"Argument_INT","double":"Argument_DOUBLE","std::string":"Argument_STRING"}[self.type]
class EnumType:
def __init__(self,l):
self.v = [(x,'%s_%s'%('%(fancy_name)s',x)) for x in l]
self.maxlen = max([len(v) for v in self.v])
def __str__(self):
if generator_mode == 'HEADER':
return "enum {%s}"%", ".join([v2 for v1,v2 in self.v])
elif generator_mode == 'SOURCE_TO':
return '{ "%s" }'%'","'.join([v1 for v1,v2 in self.v])
elif generator_mode == 'SOURCE_FROM':
return "".join([' if(s=="%s"%s) return ::%s::%s::%s;\n'%(v1.upper()," "*(self.maxlen-len(v1)),schema_version,"%(name)s",v2) for v1,v2 in self.v])
def is_select_list(self): return False
def __len__(self): return len(self.v)
def type_enum(self):
return "Argument_ENUMERATION"
class SelectType:
def __init__(self,l):
for x in l:
if x in simple_types: selectable_simple_types.add(x)
def __str__(self): return "IfcSchemaEntity"
def is_select_list(self): return False
def type_enum(self): return "Argument_ENTITY"
class BinaryType:
def __init__(self,l): self.l = int(l)
def __str__(self): return "char[%s]"%self.l
def is_select_list(self): return False
def type_enum(self): raise NotImplementedError()
class InverseType:
def __init__(self,l):
self.name, self.type, self.reference = l
def type_enum(self): return "Argument_ENTITY"
def is_select_list(self): return False
class Typedef:
def __init__(self,l):
self.name,self.type=l[1:3]
self.fancy_name = self.name[:-4] if self.name.endswith("Enum") else self.name
if isinstance(self.type,EnumType):
enumerations.add(self.name)
self.len = len(self.type)
elif isinstance(self.type,SelectType): selections.add(self.name)
simple_types[self.name] = self
comment = IfcDocumentation.description(self.name)
self.comment = comment+"\n" if comment else ''
def __str__(self):
global generator_mode
if generator_mode == 'HEADER' and isinstance(self.type,EnumType):
return ("namespace %(name)s {\n%(comment)stypedef %(type)s %(name)s;\nconst char* ToString(%(name)s v);\n%(name)s FromString(const std::string& s);\n}"%self.__dict__)%self.__dict__
elif generator_mode == 'HEADER':
return "%stypedef %s %s;"%(self.comment,self.type,self.name)
elif generator_mode == 'SOURCE' and isinstance(self.type,EnumType):
generator_mode = 'SOURCE_TO'
s = "const char* %(name)s::ToString(%(name)s v) {\n if ( v < 0 || v >= %(len)d ) throw IfcException(\"Unable to find find keyword in schema\");\n const char* names[] = %(type)s;\n return names[v];\n}\n"%self.__dict__
generator_mode = 'SOURCE_FROM'
s += ("%(name)s::%(name)s %(name)s::FromString(const std::string& s) {\n%(type)s throw IfcException(\"Unable to find find keyword in schema\");\n}"%self.__dict__)%self.__dict__
generator_mode = 'SOURCE'
return s
def type_enum(self):
return self.type.type_enum()
class Argument(object):
def __init__(self,l):
self.name, self.optional, self.type = l
def is_enum(self): return str(self.type) in enumerations
def type_str(self):
if self.type.is_select_list():
# This is extremely hackish indeed
return "optional< IfcEntities >" if self.optional else "IfcEntities"
elif str(self.type) in entity_names:
return "%(type)s*"%self.__dict__
else:
t = "%(type)s::%(type)s"%self.__dict__ if self.is_enum() else self.type
return "optional< %s >"%t if self.optional else t
class ArgumentList:
def __init__(self,l):
self.l = [Argument(a) for a in l]
self.argstart = 0
def __len__(self): return len(self.l)
def __str__(self):
s = ""
argv = self.argstart
for a in self.l:
class_name = indent = comment = optional_comment = ""
is_array = isinstance(a.type,ArrayType) and a.type.is_shared_ptr()
return_type = str(a.type)
if generator_mode == 'SOURCE':
class_name = "%(class_name)s::"
if isinstance(a.type,BinaryType) or (isinstance(a.type,ArrayType) and isinstance(a.type.type,BinaryType)):
function_body = " { throw; /* Not implemented argument*/ }"
elif isinstance(a.type,ArrayType) and str(a.type.type) in entity_names:
function_body = " { RETURN_AS_LIST(%s,%d) }"%(a.type.type,argv)
elif isinstance(a.type,ArrayType) and str(a.type.type) in selections:
function_body = " { RETURN_AS_LIST(IfcAbstractSelect,%d) }"%(argv)
elif return_type in entity_names:
function_body = " { return reinterpret_pointer_cast<IfcBaseClass,%s>(*entity->getArgument(%d)); }"%(return_type,argv)
elif return_type in enumerations:
function_body = " { return %s::FromString(*entity->getArgument(%d)); }"%(return_type,argv)
else:
function_body = " { return *entity->getArgument(%d); }"%argv
function_body2 = " { return !entity->getArgument(%d)->isNull(); }"%argv
if isinstance(a.type,BinaryType) or (isinstance(a.type,ArrayType) and isinstance(a.type.type,BinaryType)):
function_body3 = " { if ( ! entity->isWritable() ) { throw; } }"
elif return_type in enumerations:
function_body3 = " { if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%d,v%s,%s::ToString(v)); }"%(argv,"->generalize()" if is_array else "",return_type)
else:
function_body3 = " { if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%d,v%s); }"%(argv,"->generalize()" if is_array else "")
else:
indent = " "
function_body = function_body2 = function_body3 = ";"
comment = IfcDocumentation.description((self.class_name,a.name))
comment = comment+"\n" if comment else ''
comment = comment.replace("///","%s///"%indent)
optional_comment = "%s/// Whether the optional attribute %s is defined for this %s\n"%(indent,a.name,self.class_name)
if a.optional: s += "\n%s%sbool %shas%s()%s"%(optional_comment,indent,class_name,a.name,function_body2)
if ( str(a.type) in enumerations ):
return_type = "%(type)s::%(type)s"%a.__dict__
elif ( str(a.type) in entity_names ):
return_type = "%(type)s*"%a.__dict__
s += "\n%s%s%s %s%s()%s"%(comment,indent,return_type,class_name,a.name,function_body)
s += "\n%svoid %sset%s(%s v)%s"%(indent,class_name,a.name,return_type,function_body3)
argv += 1
if generator_mode == 'HEADER':
s += "\n virtual unsigned int getArgumentCount() const { return %(n_arguments)d; }" % dict(class_name=self.class_name, n_arguments=len(self.l) + argument_start(self.class_name))
s += "\n virtual ArgumentType getArgumentType(unsigned int i) const {"
if len(self.l):
s += " switch (i) {"
for i, a in enumerate(self.l):
s += "case %d: " % (i + argument_start(self.class_name))
s += "return %s; " % a.type.type_enum()
s += "}"
if self.parent_class is not None:
s += " return %s::getArgumentType(i); }" % self.parent_class
else:
s += " throw IfcException(\"argument out of range\"); }"
s += "\n virtual const char* getArgumentName(unsigned int i) const {"
if len(self.l):
s += " switch (i) {"
for i, a in enumerate(self.l):
s += "case %d: " % (i + argument_start(self.class_name))
s += "return \"%s\"; " % a.name
s += "}"
if self.parent_class is not None:
s += " return %s::getArgumentName(i); }" % self.parent_class
else:
s += " throw IfcException(\"argument out of range\"); }"
s += "\n virtual ArgumentPtr getArgument(unsigned int i) const { return entity->getArgument(i); }"
return s
class InverseList:
def __init__(self,l):
self.l = l
def __str__(self):
if self.l is None: return ""
s = ""
for i in self.l:
if generator_mode == 'HEADER':
s += "\n SHARED_PTR< IfcTemplatedEntityList< %s > > %s(); // INVERSE %s::%s"%(i.type.type,i.name,i.type.type,i.reference)
elif generator_mode == 'SOURCE':
s += "\n%s::list %s::%s() { RETURN_INVERSE(%s) }"%(i.type.type,"%(class_name)s",i.name,i.type.type)
return s
class Classdef:
def __init__(self,l):
self.class_name, self.parent_class, self.arguments, self.inverse = l
self.arguments.class_name = self.class_name
self.arguments.parent_class = self.parent_class
entity_names.add(self.class_name)
parent_relations[self.class_name] = self.parent_class
argument_count[self.class_name] = len(self.arguments)
entity_map[self.class_name] = self
def get_attributes(self, get_parent=True):
s = entity_map[self.parent_class].get_attributes() if get_parent and self.parent_class else []
s += [(a.name,not not a.optional,a.type.type_enum(),a.type.type if a.is_enum() else None) for a in self.arguments.l]
return s
def get_constructor_args(self):
s = entity_map[self.parent_class].get_constructor_args() if self.parent_class else []
i = len(s) + 1
s += ["%s v%d_%s"%(a.type_str(),b+i,a.name) for a,b in zip(self.arguments.l,range(len(self.arguments)))]
return s
def get_constructor_implementation(self):
s = entity_map[self.parent_class].get_constructor_implementation() if self.parent_class else []
i = len(s) + 1
b = 0
for a in self.arguments.l:
is_enumeration = str(a.type) in enumerations
# boost::optional is not used for pointer types, because they are set to NULL using 0
use_boost_optional = a.optional and str(a.type) not in entity_names
# boost::optional types need to be dereferenced before passing to the writable entity
dereference = "*" if use_boost_optional else ""
generalize = "->generalize()" if (isinstance(a.type,ArrayType) and a.type.is_shared_ptr() and not a.type.is_select_list()) else ""
if isinstance(a.type,BinaryType) or (isinstance(a.type,ArrayType) and isinstance(a.type.type,BinaryType)):
continue
if is_enumeration:
impl = "e->setArgument(%d,%sv%d_%s,%s::ToString(%sv%d_%s))"%(b+i-1,dereference,b+i,a.name,str(a.type),dereference,b+i,a.name)
else:
impl = "e->setArgument(%d,(%sv%d_%s)%s)"%(b+i-1,dereference,b+i,a.name,generalize)
if use_boost_optional:
s.append("if (v%d_%s) { %s; } else { e->setArgument(%d); } "%(b+i,a.name,impl,b+i-1))
else: s.append(impl)
b += 1
return s#"; ".join(s)
def __str__(self):
self.constructor_args_list = self.get_constructor_args()
self.constructor_args = ", ".join(self.constructor_args_list)
if generator_mode == 'HEADER':
comment = IfcDocumentation.description(self.class_name)
comment = comment+"\n" if comment else ''
return "%sclass %s : public %s {\npublic:%s%s%s\n};" % (comment,self.class_name,
"IfcBaseEntity" if self.parent_class is None else self.parent_class,
self.arguments,
self.inverse,
("\n bool is(Type::Enum v) const;"+
"\n Type::Enum type() const;"+
"\n static Type::Enum Class();"+
"\n %(class_name)s (IfcAbstractEntityPtr e = IfcAbstractEntityPtr());"+
("\n %(class_name)s (%(constructor_args)s);" if len(self.constructor_args_list) else "")+
"\n typedef %(class_name)s* ptr;"+
"\n typedef SHARED_PTR< IfcTemplatedEntityList< %(class_name)s > > list;"+
"\n typedef IfcTemplatedEntityList< %(class_name)s >::it it;")%self.__dict__
)
elif generator_mode == 'SOURCE':
self.arguments.argstart = argument_start(self.class_name)
self.constructor_implementation = "; ".join(self.get_constructor_implementation())
return (("\n// Function implementations for %(class_name)s"+str(self.arguments)+str(self.inverse)+
("\nbool %(class_name)s::is(Type::Enum v) const { return v == Type::%(class_name)s; }" if self.parent_class is None else
"\nbool %(class_name)s::is(Type::Enum v) const { return v == Type::%(class_name)s || %(parent_class)s::is(v); }")+
"\nType::Enum %(class_name)s::type() const { return Type::%(class_name)s; }"+
"\nType::Enum %(class_name)s::Class() { return Type::%(class_name)s; }"+
"\n%(class_name)s::%(class_name)s(IfcAbstractEntityPtr e) { if (!is(Type::%(class_name)s)) throw IfcException(\"Unable to find find keyword in schema\"); entity = e; }"+
("\n%(class_name)s::%(class_name)s(%(constructor_args)s) { IfcWritableEntity* e = new IfcWritableEntity(Class()); %(constructor_implementation)s; entity = e; EntityBuffer::Add(this); }" if len(self.constructor_args_list) else "")
)%self.__dict__)%self.__dict__
from funcparserlib.parser import a, skip, many, maybe, some
#
# Lambda functions to map combinator output to classes
#
array_type = lambda t: ArrayType(t)
scalar_type = lambda t: ScalarType(t)
enum_type = lambda t: EnumType(t)
select_type = lambda t: SelectType(t)
binary_type = lambda t: BinaryType(t)
inverse_type = lambda t: InverseType(t)
format_type = lambda t: Typedef(t)
argument_list = lambda t: ArgumentList(t)
inverse_list = lambda t: InverseList(t)
format_options = lambda t: [t[0]]+t[1]
#
# The actual grammar definition
#
s = some(lambda t: not t in ['UNIQUE','WHERE','END_ENTITY','END_TYPE','INVERSE','DERIVE'])
x = lambda s:skip(a(s))
list_or_array = a('ARRAY') | a('LIST') | a('SET')
binary = x('BINARY')+x('(') + s + x(')') >> binary_type
array = list_or_array + x('[') + s + x(':') + s + x(']') + x('OF') + skip(maybe(a('UNIQUE'))) + (binary|s) >> array_type
options = x('(') + s + many(x(',')+s) + x(')') >> format_options
enum = x('ENUMERATION') + x('OF') + options >> enum_type
select = x('SELECT') + options >> select_type
single = s + skip(maybe(x('(')+s+x(')')) + maybe(a('FIXED'))) >> scalar_type
type_type = array | enum | select | single
type_start = a('TYPE') + s + x('=') + type_type + x(';')
type_end = a('END_TYPE') + x(';')
to_end = many(some(lambda t: t != ';'))
clause = s + x(':') + to_end + x(';')
where = a('WHERE') + many(clause)
type = type_start + maybe(where) + type_end >> format_type
subtype = x('SUBTYPE') + x('OF') + x('(') + s + x(')')
supertype = maybe(x('ABSTRACT')) + x('SUPERTYPE') + x('OF') + x('(') + x('ONEOF') + options + x(')')
entity_start = x('ENTITY') + s + skip(maybe(supertype)) + maybe(subtype) + x(';')
entity_end = x('END_ENTITY') + x(';')
key_value = s + x(':') + maybe(a('OPTIONAL')) + (array|binary|single) + x(';')
arguments = many(key_value) >> argument_list
unique_value = s + x(':') + s + many(a(',')+s) + a(';')
unique = skip(a('UNIQUE') + many(unique_value))
inverse_def = s + x(':') + (array|single) + x('FOR') + s + x(';') >> inverse_type
inverse = maybe(x('INVERSE') + many( inverse_def )) >> inverse_list
derive = skip(a('DERIVE') + many(clause))
entity = entity_start + arguments + skip(maybe(unique)) + skip(maybe(derive)) + inverse + skip(maybe(where)) + entity_end >> Classdef
schema = skip(a('SCHEMA')) + s + x(';')
express = schema + many(type) + many(entity)
schema_version,types,entities = express.parse(list(Tokenizer(filename)))
schema_version = schema_version.capitalize()
#
# Writing of the three generated files starts here
#
h_file = open("%s.h"%schema_version,'w')
h2_file = open("%s-rt.h"%schema_version,'w')
enumh_file = open("%senum.h"%schema_version,'w')
cpp_file = open("%s.cpp"%schema_version,'w')
cpp2_file = open("%s-rt.cpp"%schema_version,'w')
header += """
/********************************************************************************
* *
* This file has been generated from %s. Do not make modifications *
* but instead modify the python script that has been used to generate this. *
* *
********************************************************************************/
"""%filename
generator_mode = 'HEADER'
print >>h_file, header
print >>h2_file, header
print >>enumh_file, header
print >>cpp_file, header
print >>cpp2_file, header
print >>h_file, """#ifndef %(schema_upper)s_H
#define %(schema_upper)s_H
#include <string>
#include <vector>
#include <map>
#include <set>
#include <boost/optional.hpp>
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/ArgumentType.h"
#include "../ifcparse/%(schema)senum.h"
using namespace IfcUtil;
using IfcParse::IfcException;
using boost::optional;
#define RETURN_INVERSE(T) \\
IfcEntities e = entity->getInverse(T::Class()); \\
SHARED_PTR< IfcTemplatedEntityList<T> > l ( new IfcTemplatedEntityList<T>() ); \\
for ( IfcEntityList::it it = e->begin(); it != e->end(); ++ it ) { \\
l->push(reinterpret_pointer_cast<IfcBaseClass,T>(*it)); \\
} \\
return l;
#define RETURN_AS_SINGLE(T,a) \\
return reinterpret_pointer_cast<IfcBaseClass,T>(*entity->getArgument(a));
#define RETURN_AS_LIST(T,a) \\
IfcEntities e = *entity->getArgument(a); \\
SHARED_PTR< IfcTemplatedEntityList<T> > l ( new IfcTemplatedEntityList<T>() ); \\
for ( IfcEntityList::it it = e->begin(); it != e->end(); ++ it ) { \\
l->push(reinterpret_pointer_cast<IfcBaseClass,T>(*it)); \\
} \\
return l;
namespace %(schema)s {
"""%{'schema_upper':schema_version.upper(),'schema':schema_version}
simple_enumerations = sorted(simple_types)
entity_enumerations = sorted(entity_names)
all_enumerations = simple_enumerations + entity_enumerations
print >>enumh_file, """#ifndef IFC2X3ENUM_H
#define IFC2X3ENUM_H
#include "../ifcparse/ArgumentType.h"
namespace Ifc2x3 {
namespace Type {
typedef enum {
%(enum)s
} Enum;
Enum Parent(Enum v);
Enum FromString(const std::string& s);
std::string ToString(Enum v);
bool IsSimple(Enum v);
}
}
#endif
"""%{'schema_upper':schema_version.upper(),'schema':schema_version,'enum':", ".join(all_enumerations + ["ALL"])}
print >>h2_file, """#ifndef IFC2X3RT_H
#define IFC2X3RT_H
#include "../ifcparse/ArgumentType.h"
namespace Ifc2x3 {
namespace Type {
int GetAttributeCount(Enum t);
int GetAttributeIndex(Enum t, const std::string& a);
IfcUtil::ArgumentType GetAttributeType(Enum t, unsigned char a);
const std::string& GetAttributeName(Enum t, unsigned char a);
bool GetAttributeOptional(Enum t, unsigned char a);
std::pair<const char*, int> GetEnumerationIndex(Enum t, const std::string& a);
Enum GetAttributeEnumerationClass(Enum t, unsigned char a);
}}
#endif
"""
defined_types = set(express_to_cpp.values())
deferred_types = []
for t in [T for T in types if not (isinstance(T.type,EnumType) or isinstance(T.type,SelectType))]:
if isinstance(t.type,ScalarType) and str(t.type) not in defined_types:
deferred_types.append(t)
else:
print >>h_file, t
for t in [T for T in types if isinstance(T.type,SelectType)]:
print >>h_file, t
for t in deferred_types:
print >>h_file, t
for t in [T for T in types if isinstance(T.type,EnumType)]:
print >>h_file, t
print >>h_file, "// Forward definitions"
print >>h_file, "class %s;\n"%"; class ".join([e.class_name for e in entities])
defined_classes = set()
while True:
classes = [c for c in entities if c.class_name not in defined_classes]
if not len(classes): break
for c in classes:
if c.parent_class is None or c.parent_class in defined_classes:
defined_classes.add(c.class_name)
print >>h_file, c
print >>h_file, "void InitStringMap();"
print >>h_file, "IfcSchemaEntity SchemaEntity(IfcAbstractEntityPtr e = 0);"
print >>h_file, "}\n\n#endif"
generator_mode = 'SOURCE'
print >>cpp2_file, """#include "../ifcparse/%(schema)s.h"
#include "../ifcparse/%(schema)s-rt.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcWrite.h"
#include "../ifcparse/IfcWritableEntity.h"
#include "../ifcparse/ArgumentType.h"
using namespace %(schema)s;
using namespace IfcParse;
using namespace IfcWrite;"""%{'schema':schema_version}
print >>cpp_file, """#include "../ifcparse/%(schema)s.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcWrite.h"
#include "../ifcparse/IfcWritableEntity.h"
#include "../ifcparse/ArgumentType.h"
using namespace %(schema)s;
using namespace IfcParse;
using namespace IfcWrite;
IfcSchemaEntity %(schema)s::SchemaEntity(IfcAbstractEntityPtr e) {
switch(e->type()){"""%{'schema':schema_version}
for e in simple_enumerations:
print >>cpp_file, " case Type::%s: return new IfcEntitySelect(e); break;"%e
for e in entity_enumerations:
print >>cpp_file, " case Type::%s: return new %s(e); break;"%(e,e)
print >>cpp_file, " default: throw IfcException(\"Unable to find find keyword in schema\"); break; "
print >>cpp_file, " }\n}"
print >>cpp_file
print >>cpp_file, "std::string Type::ToString(Enum v) {"
print >>cpp_file, " if (v < 0 || v >= %d) throw IfcException(\"Unable to find find keyword in schema\");"%len(all_enumerations)
print >>cpp_file, ' const char* names[] = { "%s" };'%'","'.join(all_enumerations)
print >>cpp_file, ' return names[v];'
print >>cpp_file, "}"
print >>cpp_file
print >>cpp_file, "std::map<std::string,Type::Enum> string_map;"
print >>cpp2_file, "std::map<Type::Enum,IfcEntityDescriptor*> entity_descriptor_map;"
print >>cpp2_file, "std::map<Type::Enum,IfcEnumerationDescriptor*> enumeration_descriptor_map;"
maxlen = max([len(e) for e in all_enumerations])
string_map,attribute_count_map,attribute_index_map,attribute_name_map,attribute_optional_map,attribute_type_map = [""]*6
print >>cpp2_file, "void InitDescriptorMap() {"
print >>cpp2_file, " IfcEntityDescriptor* current;"
for k,v in simple_types.items():
if k in enumerations or k in selections: continue
print >>cpp2_file, " current = entity_descriptor_map[Type::%s] = new IfcEntityDescriptor(Type::%s,0);"%(k,k)
print >>cpp2_file, " current->add(\"wrappedValue\",false,%s);"%(v.type_enum())
rt_entities = set()
while True:
todo = [e for e in entities if e.class_name not in rt_entities]
if len(todo) == 0: break
for e in todo:
if e.parent_class and e.parent_class not in rt_entities: continue
rt_entities.add(e.class_name)
args = e.get_attributes(False)
parent_descriptor = ("entity_descriptor_map.find(Type::%s)->second"%e.parent_class) if e.parent_class else "0"
print >>cpp2_file, " current = entity_descriptor_map[Type::%s] = new IfcEntityDescriptor(Type::%s,%s);"%(e.class_name,e.class_name,parent_descriptor)
for a,i in zip(args,range(len(args))):
name,optional,type,enum_class = a
if enum_class:
print >>cpp2_file, " current->add(\"%s\",%s,%s,Type::%s);"%(name,"true" if optional else "false",type,enum_class)
else:
print >>cpp2_file, " current->add(\"%s\",%s,%s);"%(name,"true" if optional else "false",type)
print >>cpp2_file, " // Enumerations"
print >>cpp2_file, " IfcEnumerationDescriptor* current_enum;"
print >>cpp2_file, " std::vector<std::string> values;"
for e, name in [(e, name) for name, e in simple_types.items() if name in enumerations]:
print >>cpp2_file, " values.clear(); values.reserve(128);"
for value in e.type.v:
print >>cpp2_file, " values.push_back(\"%s\");"%value[0]
print >>cpp2_file, " current_enum = enumeration_descriptor_map[Type::%s] = new IfcEnumerationDescriptor(Type::%s, values);"%(name,name)
print >>cpp2_file, "}"
for e in all_enumerations:
string_map += ' string_map["%s"%s] = Type::%s;\n'%(e.upper()," "*(maxlen-len(e)),e)
print >>cpp_file, """void Ifc2x3::InitStringMap() {
%(string_map)s
}"""%locals()
print >>cpp_file, """Type::Enum Type::FromString(const std::string& s) {
if (string_map.empty()) ::Ifc2x3::InitStringMap();
std::map<std::string,Type::Enum>::const_iterator it = string_map.find(s);
if ( it == string_map.end() ) throw IfcException("Unable to find find keyword in schema");
else return it->second;
}"""
print >>cpp_file, "Type::Enum Type::Parent(Enum v){"
print >>cpp_file, " if (v < 0 || v >= %d) return (Enum)-1;"%len(all_enumerations)
for e in entity_enumerations:
if e not in parent_relations or parent_relations[e] is None: continue
print >>cpp_file, ' if(v==%s%s) { return %s; }'%(e," "*(maxlen-len(e)),parent_relations[e])
print >>cpp_file, " return (Enum)-1;"
print >>cpp_file, "}"
print >>cpp_file, "bool Type::IsSimple(Enum v){"
print >>cpp_file, " return v == Type::%s;"%" || v == Type::".join(simple_enumerations)
print >>cpp_file, "}"
for t in [T for T in types if isinstance(T.type,EnumType)]:
print >>cpp_file, t
for e in entities: print >>cpp_file, e,
print >>cpp_file, ""
print >>cpp2_file, """int Type::GetAttributeIndex(Enum t, const std::string& a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentIndex(a);
}
int Type::GetAttributeCount(Enum t) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentCount();
}
ArgumentType Type::GetAttributeType(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentType(a);
}
const std::string& Type::GetAttributeName(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentName(a);
}
bool Type::GetAttributeOptional(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentOptional(a);
}
std::pair<const char*, int> Type::GetEnumerationIndex(Enum t, const std::string& a) {
if (enumeration_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEnumerationDescriptor*>::const_iterator i = enumeration_descriptor_map.find(t);
if ( i == enumeration_descriptor_map.end() ) throw IfcException("Value not found");
else return i->second->getIndex(a);
}
Type::Enum Type::GetAttributeEnumerationClass(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else {
Type::Enum t = i->second->getArgumentEnumerationClass(a);
if ( t == Type::ALL ) throw IfcException("Not an enumeration");
else return t;
}
}
"""
+3 -1
View File
@@ -4,6 +4,8 @@ the IFC schema and will most likely fail on any other Express schema.
The code can be invoked in the following way and results in two header files
and a single implementation file named according to the schema name in the
Express file. A python 3 interpreter with the pyparsing library is required.
Express file. A python 3 interpreter with the pyparsing [1] library is required.
$ python bootstrap.py express.bnf > express_parser.py && python express_parser.py IFC2X3_TC1.exp
[1] http://pyparsing.wikispaces.com/Download+and+Installation
+32 -23
View File
@@ -115,7 +115,7 @@ actions = {
'general_aggregation_types' : "lambda t: AggregationType(t)",
'select_type' : "lambda t: SelectType(t)",
'binary_type' : "lambda t: BinaryType(t)",
'subtype_declaration' : "lambda t: SubtypeExpression(t)",
'subtype_declaration' : "lambda t: SubTypeExpression(t)",
'derive_clause' : "lambda t: AttributeList('derive', t)",
'derived_attr' : "lambda t: DerivedAttribute(t)",
'inverse_clause' : "lambda t: AttributeList('inverse', t)",
@@ -158,36 +158,45 @@ for id in to_emit:
stmt = "Suppress%s" % stmt
statements.append("%s << %s" % (id, stmt))
print ("""import sys
from pyparsing import *
from nodes import *
print ("""import os
import sys
import pickle
%s
cache_file = sys.argv[1] + ".cache.dat"
if os.path.exists(cache_file):
with open(cache_file, "rb") as f:
mapping = pickle.load(f)
else:
from pyparsing import *
from nodes import *
import schema
import mapping
%s
syntax.ignore("--" + restOfLine)
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
ast = syntax.parseFile(sys.argv[1])
schema = schema.Schema(ast)
mapping = mapping.Mapping(schema)
import schema
import mapping
with open(cache_file, "wb") as f:
pickle.dump(mapping, f, protocol=0)
import header
import enum_header
import implementation
import rt_header
import rt_implementation
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
ast = syntax.parseFile(sys.argv[1])
schema = schema.Schema(ast)
mapping = mapping.Mapping(schema)
import latebound_header
import latebound_implementation
import schema_class
header.Header(mapping).emit()
enum_header.EnumHeader(mapping).emit()
implementation.Implementation(mapping).emit()
rt_header.RuntimeTypingHeader(mapping).emit()
rt_implementation.RuntimeTypingImplementation(mapping).emit()
latebound_header.LateBoundHeader(mapping).emit()
latebound_implementation.LateBoundImplementation(mapping).emit()
schema_class.SchemaClass(mapping).emit()
def retry():
import imp
imp.reload(rt_header)
imp.reload(rt_implementation)
rt_header.RuntimeTypingHeader(mapping).emit()
rt_implementation.RuntimeTypingImplementation(mapping).emit()
"""%('\n'.join(statements)))
sys.stdout.write(mapping.schema.name)
"""%('\n '.join(statements)))
+35
View File
@@ -0,0 +1,35 @@
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
class Base(object):
"""
A base class for all code generation classes. Currently only working around
some python 2/3 incompatibilities in terms of unicode file handling.
"""
def emit(self):
import platform
if tuple(map(int, platform.python_version_tuple())) < (2, 8):
from io import open as unicode_open
unicode_type = unicode
else:
unicode_open = open
unicode_type = lambda x, *args, **kwargs: x
f = unicode_open(self.file_name, 'w', encoding='utf-8')
f.write(unicode_type(repr(self), encoding='utf-8', errors='ignore'))
f.close()
+11 -4
View File
@@ -27,11 +27,17 @@
# #
###############################################################################
import re,csv
import re
import os
import csv
from builtins import open
try: from html.entities import entitydefs
except: from htmlentitydefs import entitydefs
make_absolute = lambda fn: os.path.join(os.path.dirname(os.path.realpath(__file__)), fn)
name_to_oid = {}
oid_to_desc = {}
oid_to_name = {}
@@ -39,18 +45,19 @@ oid_to_pid = {}
regices = list(zip([re.compile(s,re.M) for s in [r'<[\w\n=" \-/\.;_\t:%#,\?\(\)]+>',r'(\n[\t ]*){2,}',r'^[\t ]+']],['','\n\n',' ']))
definition_files = ['DocEntity.csv', 'DocEnumeration.csv', 'DocDefined.csv', 'DocSelect.csv']
definition_files = map(make_absolute, definition_files)
for fn in definition_files:
with open(fn) as f:
with open(fn, encoding='utf-8', errors='ignore') as f:
for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'):
name_to_oid[name] = oid
oid_to_name[oid] = name
oid_to_desc[oid] = desc
with open('DocEntityAttributes.csv') as f:
with open(make_absolute('DocEntityAttributes.csv'), encoding='utf-8', errors='ignore') as f:
for pid, x, oid in csv.reader(f, delimiter=';', quotechar='"'):
oid_to_pid[oid] = pid
with open('DocAttribute.csv') as f:
with open(make_absolute('DocAttribute.csv'), encoding='utf-8', errors='ignore') as f:
for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'):
pid = oid_to_pid[oid]
pname = oid_to_name[pid]
+7 -6
View File
@@ -18,10 +18,11 @@
###############################################################################
import templates
import codegen
class EnumHeader:
class EnumHeader(codegen.Base):
def __init__(self, mapping):
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]))
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]), key=lambda s: s.lower())
self.str = templates.enum_header % {
'schema_name_upper' : mapping.schema.name.upper(),
@@ -30,9 +31,9 @@ class EnumHeader:
}
self.schema_name = mapping.schema.name.capitalize()
self.file_name = '%senum.h'%self.schema_name
def __repr__(self):
return self.str
def emit(self):
f = open('%senum.h'%self.schema_name, 'w', encoding='utf-8')
f.write(str(self))
f.close()
+33 -28
View File
@@ -17,39 +17,40 @@
# #
###############################################################################
import codegen
import templates
import documentation
class Header:
class Header(codegen.Base):
def __init__(self, mapping):
emitted_types = set(mapping.express_to_cpp_typemapping.values())
declarations = []
write = lambda str, **kwargs: declarations.append(str%dict({
'documentation': templates.multi_line_comment(documentation.description(kwargs['name']))}, **kwargs))
for name, type in mapping.schema.simpletypes.items():
type_str = mapping.make_type_string(type)
type_dep = mapping.get_type_dep(type)
if type_dep in emitted_types:
write(templates.simpletype, name=name, type=type_str)
emitted_types.add(name)
forward_names = list(mapping.schema.entities.keys()) + list(mapping.schema.simpletypes.keys())
forward_definitions = "".join(["class %s; "%n for n in forward_names])
for name, type in mapping.schema.selects.items():
write(templates.select, name=name)
emitted_types.add(name)
for name, type in mapping.schema.simpletypes.items():
if name not in emitted_types:
type_str = mapping.make_type_string(type)
write(templates.simpletype, name=name, type=type_str)
emitted_types.add(name)
for name, type in mapping.schema.enumerations.items():
short_name = name[:-4] if name.endswith("Enum") else name
write(templates.enumeration, name=name, values=", ".join(["%s_%s"%(short_name, v) for v in type.values]))
forward_definitions = "".join(["class %s; "%n for n in mapping.schema.entities.keys()])
emitted_simpletypes = set()
while len(emitted_simpletypes) < len(mapping.schema.simpletypes):
for name, type in mapping.schema.simpletypes.items():
if name in emitted_simpletypes: continue
type_str = mapping.make_type_string(mapping.flatten_type_string(type))
attr_type = mapping.make_argument_type(type)
superclass = mapping.simple_type_parent(name)
if superclass is None:
superclass = "IfcUtil::IfcBaseType"
elif superclass not in emitted_simpletypes:
continue
emitted_simpletypes.add(name)
write(templates.simpletype, name=name, type=type_str, attr_type=attr_type, superclass=superclass)
class_definitions = []
@@ -65,11 +66,11 @@ class Header:
def write_method(attr):
if attr.optional:
attr_lines.append(templates.optional_attribute_description % (attr.name, name))
attr_lines.append("bool has%s();"%(attr.name))
attr_lines.append("bool has%s() const;"%(attr.name))
attr_lines.extend(["/// %s"%d for d in documentation.description((name, attr.name))])
type_str = mapping.get_parameter_type(attr, allow_optional=False, allow_entities=False)
if mapping.make_argument_type(attr) != "IfcUtil::Argument_UNKNOWN":
attr_lines.append("%s %s();"%(type_str, attr.name))
attr_lines.append("%s %s() const;"%(type_str, attr.name))
attr_lines.append("void set%s(%s v);"%(attr.name, type_str))
[write_method(attr) for attr in type.attributes]
@@ -95,14 +96,19 @@ class Header:
argument_start = argument_count - len(type.attributes)
argument_name_function_body_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return "%s"; '%(i+argument_start, attr.name) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
argument_name_function_body_tail = (" return %s::getArgumentName(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcException("argument out of range"); '
argument_name_function_body_tail = (" return %s::getArgumentName(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
argument_name_function_body = argument_name_function_body_switch_stmt + argument_name_function_body_tail
argument_type_function_body_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return %s; '%(i+argument_start, mapping.make_argument_type(attr)) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
argument_type_function_body_tail = (" return %s::getArgumentType(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcException("argument out of range"); '
argument_type_function_body_tail = (" return %s::getArgumentType(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
argument_type_function_body = argument_type_function_body_switch_stmt + argument_type_function_body_tail
argument_entity_function_body_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return %s; '%(i+argument_start, mapping.make_argument_entity(attr)) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
argument_entity_function_body_tail = (" return %s::getArgumentEntity(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
argument_entity_function_body = argument_entity_function_body_switch_stmt + argument_entity_function_body_tail
constructor_arguments = ", ".join("%(full_type)s v%(index)d_%(name)s"%a for a in mapping.get_assignable_arguments(type))
@@ -118,10 +124,9 @@ class Header:
}
self.schema_name = mapping.schema.name.capitalize()
self.file_name = '%s.h'%self.schema_name
def __repr__(self):
return self.str
def emit(self):
f = open('%s.h'%self.schema_name, 'w', encoding='utf-8')
f.write(str(self))
f.close()
+83 -17
View File
@@ -17,9 +17,10 @@
# #
###############################################################################
import codegen
import templates
class Implementation:
class Implementation(codegen.Base):
def __init__(self, mapping):
enumeration_functions = []
entity_implementations = []
@@ -61,17 +62,27 @@ class Implementation:
if not arg['is_inherited'] and not arg['is_derived']:
if arg['is_optional']:
write_attr(
templates.function,
templates.const_function,
class_name = name,
name = 'has%s'%arg['name'],
arguments = '',
return_type = 'bool',
body = templates.optional_attr_stmt % {'index':arg['index']-1}
)
def find_template(arg):
simple = mapping.schema.is_simpletype(arg['list_instance_type'])
select = arg['list_instance_type'] == "IfcUtil::IfcBaseClass"
express = mapping.flatten_type_string(arg['list_instance_type']) in mapping.express_to_cpp_typemapping
if arg['is_enum']: return templates.get_attr_stmt_enum
elif arg['is_nested'] and arg['is_templated_list']: return templates.get_attr_stmt_nested_array
elif arg['is_templated_list'] and not (select or simple or express): return templates.get_attr_stmt_array
elif arg['non_optional_type'].endswith('*'): return templates.get_attr_stmt_entity
else: return templates.get_attr_stmt
tmpl = templates.get_attr_stmt_enum if arg['is_enum'] else templates.get_attr_stmt_array if arg['is_array'] and not mapping.schema.is_simpletype(arg['list_instance_type']) and arg['list_instance_type'] not in mapping.express_to_cpp_typemapping else templates.get_attr_stmt_entity if arg['non_optional_type'].endswith('*') else templates.get_attr_stmt
tmpl = find_template(arg)
write_attr(
templates.function,
templates.const_function,
class_name = name,
name = arg['name'],
arguments = '',
@@ -80,8 +91,16 @@ class Implementation:
'type' : arg['non_optional_type'].split('::')[0],
'list_instance_type' : arg['list_instance_type']}
)
def find_template(arg):
simple = mapping.schema.is_simpletype(arg['list_instance_type'])
select = arg['list_instance_type'] == "IfcUtil::IfcBaseClass"
express = arg['list_instance_type'] in mapping.express_to_cpp_typemapping
if arg['is_enum']: return templates.set_attr_stmt_enum
elif arg['is_templated_list'] and not (select or simple or express): return templates.set_attr_stmt_array
else: return templates.set_attr_stmt
tmpl = templates.set_attr_stmt_enum if arg['is_enum'] else templates.set_attr_stmt_array if arg['is_array'] and not mapping.schema.is_simpletype(arg['list_instance_type']) and arg['list_instance_type'] not in mapping.express_to_cpp_typemapping else templates.set_attr_stmt
tmpl = find_template(arg)
write_attr(
templates.function,
class_name = name,
@@ -110,16 +129,20 @@ class Implementation:
'index' : arg['index']-1,
'stmt' : impl}
constructor_implementations.append(impl)
def get_attribute_index(entity, attr_name):
related_entity = mapping.schema.entities[entity]
return [a['name'] for a in mapping.get_assignable_arguments(related_entity, include_derived=True)].index(attr_name)
inverse = [templates.function % {
inverse = [templates.const_function % {
'class_name' : name,
'name' : i.name,
'arguments' : '',
'return_type' : '%s::list' % i.entity,
'body' : templates.get_inverse % {'type': i.entity}
'return_type' : '%s::list::ptr' % i.entity,
'body' : templates.get_inverse % {'type': i.entity, 'index':get_attribute_index(i.entity, i.attribute)}
} for i in (type.inverse.elements if type.inverse else [])]
superclass = "%s((IfcAbstractEntityPtr)0)" % type.supertypes[0] if len(type.supertypes) == 1 else 'IfcUtil::IfcBaseEntity()'
superclass = "%s((IfcAbstractEntity*)0)" % type.supertypes[0] if len(type.supertypes) == 1 else 'IfcUtil::IfcBaseEntity()'
write(
templates.entity_implementation,
@@ -133,10 +156,10 @@ class Implementation:
)
selectable_simple_types = sorted(set(sum([b.values for a,b in mapping.schema.selects.items()], [])) & set(mapping.schema.types.keys()))
schema_entity_statements += [templates.schema_simple_stmt%locals() for name in selectable_simple_types]
schema_entity_statements += [templates.schema_entity_stmt%locals() for name, type in mapping.schema.simpletypes.items()]
schema_entity_statements += [templates.schema_entity_stmt%locals() for name, type in mapping.schema.entities.items()]
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]))
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]), key=lambda s: s.lower())
max_len = max(map(len, enumerable_types))
type_name_strings = catc(map(stringify, enumerable_types))
string_map_statements = [templates.string_map_statement % {
@@ -154,6 +177,48 @@ class Implementation:
max_id = len(enumerable_types)
simple_type_statements = cator("v == Type::%s"%name for name in selectable_simple_types)
simple_type_impl = []
for class_name, type in mapping.schema.simpletypes.items():
type_str = mapping.make_type_string(mapping.flatten_type_string(type))
attr_type = mapping.make_argument_type(type)
superclass = mapping.simple_type_parent(class_name)
simpletype_impl_is = templates.simpletype_impl_is_with_supertype if superclass \
else templates.simpletype_impl_is_without_supertype
constructor = templates.constructor_single_initlist if superclass \
else templates.constructor
simpletype_impl_cast = templates.simpletype_impl_cast_templated if mapping.is_templated_list(type) \
else templates.simpletype_impl_cast
simpletype_impl_constructor = templates.simpletype_impl_constructor_templated if mapping.is_templated_list(type) \
else templates.simpletype_impl_constructor
def compose(params):
class_name, attr_type, superclass, superclass_init, name, tmpl, return_type, args, body = params
underlying_type = mapping.list_instance_type(type)
arguments = ",".join(args)
body = body % locals()
return tmpl % locals()
simple_type_impl.append(templates.simpletype_impl_comment % {'name': class_name})
simple_type_impl.extend(map(compose, map(lambda x: (class_name, attr_type, superclass, "(IfcAbstractEntity*)0")+x, (
#('getArgumentType', templates.const_function, 'IfcUtil::ArgumentType', ('unsigned int i',), templates.simpletype_impl_argument_type ),
#('getArgument', templates.const_function, 'Argument*', ('unsigned int i',), templates.simpletype_impl_argument ),
#('is', templates.const_function, 'bool', ('Type::Enum v',), simpletype_impl_is ),
#('type', templates.const_function, 'Type::Enum', (), templates.simpletype_impl_type ),
('Class', templates.function, 'Type::Enum', (), templates.simpletype_impl_class ),
('declaration', templates.const_function, 'const IfcParse::type_declaration&', (), templates.simpletype_impl_declaration ),
('', constructor, '', ('IfcAbstractEntity* e',), templates.simpletype_impl_explicit_constructor),
('', constructor, '', ("%s v" % type_str,), simpletype_impl_constructor ),
('', templates.cast_function, type_str, (), simpletype_impl_cast )
))))
simple_type_impl.append('')
external_definitions = ["extern entity* %s_type;" % n for n in mapping.schema.entities.keys() ] + \
["extern type_declaration* %s_type;" % n for n in mapping.schema.simpletypes.keys()]
self.str = templates.implementation % {
'schema_name_upper' : mapping.schema.name.upper(),
@@ -165,14 +230,15 @@ class Implementation:
'string_map_statements' : catnl(string_map_statements),
'simple_type_statement' : simple_type_statements,
'parent_type_statements' : catnl(parent_type_statements),
'entity_implementations' : catnl(entity_implementations)
'entity_implementations' : catnl(entity_implementations),
'simple_type_impl' : catnl(simple_type_impl),
'external_definitions' : catnl(external_definitions)
}
self.schema_name = mapping.schema.name.capitalize()
self.file_name = '%s.cpp'%self.schema_name
def __repr__(self):
return self.str
def emit(self):
f = open('%s.cpp'%self.schema_name, 'w', encoding='utf-8')
f.write(str(self))
f.close()
@@ -17,19 +17,20 @@
# #
###############################################################################
import codegen
import templates
class RuntimeTypingHeader:
class LateBoundHeader(codegen.Base):
def __init__(self, mapping):
self.str = templates.rt_header % {
self.str = templates.lb_header % {
'schema_name_upper' : mapping.schema.name.upper(),
'schema_name' : mapping.schema.name.capitalize()
}
self.schema_name = mapping.schema.name.capitalize()
self.file_name = '%s-latebound.h'%self.schema_name
def __repr__(self):
return self.str
def emit(self):
f = open('%s-rt.h'%self.schema_name, 'w', encoding='utf-8')
f.write(str(self))
f.close()
@@ -17,9 +17,10 @@
# #
###############################################################################
import codegen
import templates
class RuntimeTypingImplementation:
class LateBoundImplementation(codegen.Base):
def __init__(self, mapping):
schema_name = mapping.schema.name.capitalize()
@@ -32,7 +33,7 @@ class RuntimeTypingImplementation:
entity_descriptors.append(templates.entity_descriptor % {
'type' : name,
'parent_statement' : '0',
'entity_descriptor_attributes' : templates.entity_descriptor_attribute % {
'entity_descriptor_attributes' : templates.entity_descriptor_attribute_without_entity % {
'name' : 'wrappedValue',
'optional' : 'false',
'type' : mapping.make_argument_type(mapping.schema.types[name].type)
@@ -49,12 +50,14 @@ class RuntimeTypingImplementation:
entity_descriptor_attributes = []
for arg in constructor_arguments:
if not arg['is_inherited']:
tmpl = templates.entity_descriptor_attribute_enum if arg['argument_type_enum'] == 'IfcUtil::Argument_ENUMERATION' else templates.entity_descriptor_attribute
is_enumeration = arg['argument_type_enum'] == 'IfcUtil::Argument_ENUMERATION'
tmpl = templates.entity_descriptor_attribute_with_entity
entity_name = arg['argument_type'] if is_enumeration else arg['argument_entity'].split('::')[1]
entity_descriptor_attributes.append(tmpl % {
'name' : arg['name'],
'optional' : 'true' if arg['is_optional'] else 'false',
'type' : arg['argument_type_enum'],
'enum_type' : arg['argument_type']
'name' : arg['name'],
'optional' : 'true' if arg['is_optional'] else 'false',
'type' : arg['argument_type_enum'],
'entity_name': entity_name
})
emitted_entities.add(name)
@@ -98,7 +101,7 @@ class RuntimeTypingImplementation:
'index' : related_attrs.index(attr.attribute)
})
self.str = templates.rt_implementation % {
self.str = templates.lb_implementation % {
'schema_name_upper' : mapping.schema.name.upper(),
'schema_name' : mapping.schema.name.capitalize(),
'entity_descriptors' : '\n'.join(entity_descriptors),
@@ -108,10 +111,9 @@ class RuntimeTypingImplementation:
}
self.schema_name = mapping.schema.name.capitalize()
self.file_name = '%s-latebound.cpp'%self.schema_name
def __repr__(self):
return self.str
def emit(self):
f = open('%s-rt.cpp'%self.schema_name, 'w', encoding='utf-8')
f.write(str(self))
f.close()
+89 -42
View File
@@ -17,6 +17,9 @@
# #
###############################################################################
from __future__ import print_function
import sys
import nodes
import templates
@@ -24,24 +27,44 @@ class Mapping:
express_to_cpp_typemapping = {
'boolean' : 'bool',
'logical' : 'bool',
'logical' : 'boost::logic::tribool',
'integer' : 'int',
'real' : 'double',
'number' : 'double',
'string' : 'std::string'
'string' : 'std::string',
'binary' : 'boost::dynamic_bitset<>'
}
supported_argument_types = set([
'INT', 'BOOL', 'TRIBOOL', 'DOUBLE', 'STRING', 'BINARY', 'ENUMERATION', 'ENTITY_INSTANCE',
'AGGREGATE_OF_INT', 'AGGREGATE_OF_BOOL', 'AGGREGATE_OF_TRIBOOL', 'AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_STRING', 'AGGREGATE_OF_BINARY', 'AGGREGATE_OF_ENTITY_INSTANCE',
'AGGREGATE_OF_AGGREGATE_OF_INT', 'AGGREGATE_OF_AGGREGATE_OF_BOOL', 'AGGREGATE_OF_AGGREGATE_OF_TRIBOOL', 'AGGREGATE_OF_AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE',
])
def __init__(self, schema):
self.schema = schema
def flatten_type_string(self, type):
return self.flatten_type_string(self.schema.types[type].type.type) if self.schema.is_simpletype(type) else type
def flatten_type(self, type):
res = self.flatten_type(self.schema.types[type].type.type) if self.schema.is_simpletype(type) else type
return res
def simple_type_parent(self, type):
parent = self.schema.types[type].type.type
if isinstance(parent, nodes.AggregationType): parent = None
return None if str(parent) in self.express_to_cpp_typemapping else parent
def make_type_string(self, type):
if isinstance(type, str):
return self.express_to_cpp_typemapping.get(type, type)
if isinstance(type, (str, nodes.BinaryType)):
return self.express_to_cpp_typemapping.get(str(type), type)
else:
is_list = self.schema.is_entity(type.type)
tmpl = templates.list_type if is_list else templates.array_type
is_nested_list = isinstance(type.type, nodes.AggregationType)
tmpl = templates.list_list_type if is_nested_list else templates.list_type if is_list else templates.array_type
return tmpl % {
'instance_type' : self.make_type_string(type.type),
'instance_type' : self.make_type_string(self.flatten_type_string(type.type)),
'lower' : type.bounds.lower,
'upper' : type.bounds.upper,
}
@@ -53,61 +76,73 @@ class Mapping:
return self.is_array(self.schema.types[type].type.type)
else:
return False
def make_argument_entity(self, attr):
type = attr.type if hasattr(attr, 'type') else attr
while isinstance(type, nodes.AggregationType): type = type.type
if str(type) in self.express_to_cpp_typemapping: return "Type::UNDEFINED"
else: return "Type::%s" % type
def make_argument_type(self, attr):
def _make_argument_type(type):
if type in self.express_to_cpp_typemapping:
return self.express_to_cpp_typemapping.get(type, type).split('::')[-1].upper()
elif self.schema.is_entity(type):
return "ENTITY"
elif self.schema.is_type(type):
return _make_argument_type(self.schema.types[type].type.type)
if self.schema.is_entity(type) or isinstance(type, nodes.SelectType):
return "ENTITY_INSTANCE"
elif isinstance(type, nodes.BinaryType):
return "UNKNOWN"
return "BINARY"
elif isinstance(type, nodes.EnumerationType):
return "ENUMERATION"
elif isinstance(type, nodes.SelectType):
return "ENTITY"
elif isinstance(type, nodes.AggregationType):
ty = _make_argument_type(type.type)
if ty == "UNKNOWN": return "UNKNOWN"
return "ENTITY_LIST" if ty == "ENTITY" else ("VECTOR_%s"%ty)
else: raise ValueError
supported = {'INT', 'BOOL', 'DOUBLE', 'STRING', 'VECTOR_INT', 'VECTOR_DOUBLE', 'VECTOR_STRING', 'ENTITY', 'ENTITY_LIST', 'ENUMERATION'}
ty = _make_argument_type(attr.type)
if ty not in supported: ty = 'UNKNOWN'
return "AGGREGATE_OF_" + ty
elif str(type) in self.express_to_cpp_typemapping:
return self.express_to_cpp_typemapping.get(str(type), type).split('::')[-1].upper()
elif self.schema.is_type(type):
return _make_argument_type(self.schema.types[type].type.type)
else:
raise ValueError("Unable to map type %r for attribute %r" % (type, attr))
ty = _make_argument_type(attr.type if hasattr(attr, 'type') else attr)
if ty not in self.supported_argument_types:
print("Attribute %r (%s) mapped as 'unknown'" % (attr, ty), file=sys.stderr)
ty = 'UNKNOWN'
return "IfcUtil::Argument_%s" % ty
def get_type_dep(self, type):
if isinstance(type, str):
return self.express_to_cpp_typemapping.get(type, type)
return self.express_to_cpp_typemapping.get(str(type), type)
else:
return self.get_type_dep(type.type)
def get_parameter_type(self, attr, allow_optional, allow_entities, allow_pointer = True):
type_str = self.express_to_cpp_typemapping.get(str(attr.type), attr.type)
attr_type = self.flatten_type(attr.type)
type_str = self.express_to_cpp_typemapping.get(str(attr_type), attr_type)
is_ptr = False
if self.schema.is_enumeration(attr.type):
type_str = '%s::%s'%(attr.type, attr.type)
if self.schema.is_enumeration(attr_type):
type_str = '%s::%s'%(attr_type, attr_type)
elif isinstance(type_str, nodes.AggregationType):
ty = self.get_parameter_type(attr.type, False, allow_entities, allow_pointer=False)
if allow_entities and self.schema.is_select(attr.type.type):
is_nested_list = isinstance(attr_type.type, nodes.AggregationType)
ty = self.get_parameter_type(attr_type.type if is_nested_list else attr_type, False, allow_entities, False)
if self.schema.is_select(attr_type.type):
type_str = templates.untyped_list
elif self.schema.is_simpletype(ty) or ty in self.express_to_cpp_typemapping.values():
type_str = templates.array_type % {
elif self.schema.is_simpletype(ty) or str(ty) in self.express_to_cpp_typemapping.values():
tmpl = templates.nested_array_type if is_nested_list else templates.array_type
type_str = tmpl % {
'instance_type' : ty,
'lower' : attr.type.bounds.lower,
'upper' : attr.type.bounds.upper
'lower' : attr_type.bounds.lower,
'upper' : attr_type.bounds.upper
}
else:
type_str = templates.list_type % {
tmpl = templates.list_list_type if is_nested_list else templates.list_type
type_str = tmpl % {
'instance_type': ty
}
elif allow_pointer and self.schema.is_entity(type_str):
elif allow_pointer and (self.schema.is_entity(type_str) or self.schema.is_select(type_str)):
type_str += '*'
is_ptr = True
elif not allow_pointer and self.schema.is_select(type_str):
type_str = "IfcUtil::IfcAbstractSelect"
type_str = "IfcUtil::IfcBaseClass*"
is_ptr = True
if allow_optional and attr.optional and not is_ptr:
type_str = "boost::optional< %s >"%type_str
@@ -126,19 +161,29 @@ class Mapping:
return c + ([str(s) for s in t.derive.elements] if t.derive else [])
def list_instance_type(self, attr):
f = lambda v : 'IfcUtil::IfcAbstractSelect' if self.schema.is_select(v) else v
if self.is_array(attr.type) and not isinstance(attr.type, str):
return f(attr.type.type)
elif self.is_array(attr.type) and isinstance(attr.type, str):
return f(attr.type)
else: return None
attr_type = attr.type if isinstance(attr, nodes.ExplicitAttribute) else attr
if isinstance(attr_type, str): return None
f = lambda v : 'IfcUtil::IfcBaseClass' if self.schema.is_select(v) else str(v)
if self.is_array(attr_type):
if not isinstance(attr_type, str) and self.is_array(attr_type.type):
if isinstance(attr_type.type, str):
return f(attr_type.type)
else: return f(attr_type.type.type)
else:
if isinstance(attr_type, str):
return f(attr_type)
else: return f(attr_type.type)
return None
def is_templated_list(self, attr):
attr_type = attr.type if isinstance(attr, nodes.ExplicitAttribute) else attr
if isinstance(attr, str): return False
ty = self.list_instance_type(attr)
arr = self.is_array(attr.type)
if ty is None: return False
arr = self.is_array(attr_type)
simple = self.schema.is_simpletype(ty)
express = ty in self.express_to_cpp_typemapping
select = ty == 'IfcUtil::IfcAbstractSelect'
express = self.flatten_type_string(ty) in self.express_to_cpp_typemapping
select = ty == 'IfcUtil::IfcBaseClass'
return arr and not simple and not express and not select
def get_assignable_arguments(self, t, include_derived = False):
@@ -163,9 +208,11 @@ class Mapping:
'is_inherited' : i < num_inherited,
'is_enum' : attr.type in self.schema.enumerations,
'is_array' : self.is_array(attr.type),
'is_nested' : self.is_array(attr.type) and not isinstance(attr.type, str) and self.is_array(attr.type.type),
'is_derived' : attr.name in derived,
'is_templated_list' : self.is_templated_list(attr),
'argument_type_enum' : self.make_argument_type(attr),
'argument_entity' : self.make_argument_entity(attr),
'argument_type' : attr.type
} for i, attr in attrs if include(attr)]
+17 -7
View File
@@ -44,15 +44,17 @@ class TypeDeclaration(Node):
class EntityDeclaration(Node):
name = property(lambda self: self.tokens[1])
attributes = property(lambda self: self.tokens_of_type(ExplicitAttribute))
abstract = property(lambda self: self.single_token_of_type(SuperTypeExpression) is not None and \
self.single_token_of_type(SuperTypeExpression).abstract)
def init(self):
assert self.tokens[0] == 'entity'
s = self.single_token_of_type(SubtypeExpression)
s = self.single_token_of_type(SubTypeExpression)
self.inverse = self.single_token_of_type(AttributeList, 'type', 'inverse')
self.derive = self.single_token_of_type(AttributeList, 'type', 'derive')
self.supertypes = s.types if s else []
def __repr__(self):
builder = ""
builder += "Entity(%s)" % (self.name)
builder += "%sEntity(%s)" % ("Abstract " if self.abstract else "", self.name)
if len(self.supertypes):
builder += "\n Supertypes: %s"%(",".join(self.supertypes))
if len(self.attributes):
@@ -106,12 +108,20 @@ class SelectType(Node):
class SubSuperTypeExpression(Node):
type = property(lambda self: self.tokens[0])
types = property(lambda self: self.tokens[3::2])
abstract = False
def init(self):
assert self.type == self.class_type
if self.tokens[0] == 'abstract':
self.tokens = self.tokens[1:]
self.abstract = True
assert self.type == self.type_relationship
class SubtypeExpression(SubSuperTypeExpression):
class_type = 'subtype'
class SubTypeExpression(SubSuperTypeExpression):
type_relationship = 'subtype'
class SuperTypeExpression(SubSuperTypeExpression):
type_relationship = 'supertype'
class AttributeList(Node):
@@ -127,7 +137,7 @@ class AttributeList(Node):
class InverseAttribute(Node):
name = property(lambda self: self.tokens[0])
type = property(lambda self: self.tokens[2])
type = property(lambda self: None if len(self.tokens) == 6 else self.tokens[2])
bounds = property(lambda self: None if len(self.tokens) == 6 else self.tokens[3])
entity = property(lambda self: self.tokens[-4])
attribute = property(lambda self: self.tokens[-2])
@@ -149,7 +159,7 @@ class BinaryType(Node):
def init(self):
pass
def __repr__(self):
return "BINARY"
return "binary"
class BoundSpecification(Node):
+15 -10
View File
@@ -18,29 +18,34 @@
###############################################################################
import nodes
import platform
import collections
if tuple(map(int, platform.python_version_tuple())) < (2, 7):
import ordereddict
collections.OrderedDict = ordereddict.OrderedDict
class Schema:
def is_enumeration(self, v):
return v in self.enumerations
return str(v) in self.enumerations
def is_select(self, v):
return v in self.selects
return str(v) in self.selects
def is_simpletype(self, v):
return v in self.simpletypes
return str(v) in self.simpletypes
def is_type(self, v):
return v in self.types
return str(v) in self.types
def is_entity(self, v):
return v in self.entities
return str(v) in self.entities
def __init__(self, parsetree):
self.name = parsetree[1]
sort = lambda d: collections.OrderedDict(sorted(d.items()))
sort = lambda d: collections.OrderedDict(sorted(d))
self.types = sort({t.name:t for t in parsetree if isinstance(t, nodes.TypeDeclaration)})
self.entities = sort({t.name:t for t in parsetree if isinstance(t, nodes.EntityDeclaration)})
self.types = sort([(t.name,t) for t in parsetree if isinstance(t, nodes.TypeDeclaration)])
self.entities = sort([(t.name,t) for t in parsetree if isinstance(t, nodes.EntityDeclaration)])
of_type = lambda *types: sort({a: b.type.type for a,b in self.types.items() if any(isinstance(b.type.type, ty) for ty in types)})
of_type = lambda *types: sort([(a, b.type.type) for a,b in self.types.items() if any(isinstance(b.type.type, ty) for ty in types)])
self.enumerations = of_type(nodes.EnumerationType)
self.selects = of_type(nodes.SelectType)
self.simpletypes = of_type(str, nodes.AggregationType)
self.simpletypes = of_type(str, nodes.AggregationType, nodes.BinaryType)
+215
View File
@@ -0,0 +1,215 @@
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
import operator
import nodes
import codegen
import templates
class SchemaClass(codegen.Base):
def __init__(self, mapping):
class UnmetDependenciesException(Exception): pass
schema_name = mapping.schema.name
declared_types = []
def get_declared_type(type, emitted_names=None):
if isinstance(type, nodes.AggregationType):
aggr_type = type.aggregate_type
make_bound = lambda b: -1 if b == '?' else int(b)
bound1, bound2 = map(make_bound, (type.bounds.lower, type.bounds.upper))
decl_type = get_declared_type(type.type, emitted_names)
return "new aggregation_type(aggregation_type::%(aggr_type)s_type, %(bound1)d, %(bound2)d, %(decl_type)s)" % locals()
elif isinstance(type, nodes.BinaryType):
return "new simple_type(simple_type::binary_type)"
elif isinstance(type, str):
if mapping.schema.is_type(type) or mapping.schema.is_entity(type):
if emitted_names is None or type in emitted_types:
return "new named_type(%s_type)" % type
else:
raise UnmetDependenciesException(type)
else:
return "new simple_type(simple_type::%s_type)" % type
def find_inverse_name_and_index(entity_name, attribute_name):
attributes_per_subtype = []
while True:
entity = mapping.schema.entities[entity_name]
attr_names = list(map(operator.attrgetter('name'), entity.attributes))
if len(attr_names):
attributes_per_subtype.append((entity_name, attr_names))
if len(entity.supertypes) != 1: break
entity_name = entity.supertypes[0]
index = 0
for et, attrs in attributes_per_subtype[::-1]:
try: return et, attrs.index(attribute_name)
except: pass
self.schema_name = mapping.schema.name.capitalize()
statements = ['',
'#include "../ifcparse/IfcSchema.h"',
'',
'using namespace IfcParse;'
'']
collections_by_type = (('entity', mapping.schema.entities ),
('type_declaration', mapping.schema.simpletypes ),
('select_type', mapping.schema.selects ),
('enumeration_type', mapping.schema.enumerations))
for cpp_type, collection in collections_by_type:
for name in collection.keys():
statements.append('%(cpp_type)s* %(name)s_type = 0;' % locals())
statements.append("""
#if defined(__clang__)
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC push_options
#pragma GCC optimize ("O0")
#elif defined(_MSC_VER)
#pragma optimize("", off)
#endif
""")
statements.append('schema_definition* populate_schema() {')
emitted_types = set()
# while len(emitted_types) < len(set(mapping.schema.simpletypes.keys()) - {"IfcPropertySetDefinitionSet"}):
while len(emitted_types) < len(set(mapping.schema.simpletypes.keys()) - {"IfcPropertySetDefinitionSet"}):
for name, type in mapping.schema.simpletypes.items():
if name in emitted_types: continue
# No support for types refering to entities :(
if name == "IfcPropertySetDefinitionSet": continue
try:
declared_type = get_declared_type(type, emitted_types)
except UnmetDependenciesException:
continue
statements.append(' %(name)s_type = new type_declaration(IfcSchema::Type::%(name)s, %(declared_type)s);' % locals())
emitted_types.add(name)
declared_types.append('%(name)s_type' % locals())
for name, enum in mapping.schema.enumerations.items():
statements.append(' {')
statements.append(' std::vector<std::string> items; items.reserve(%d);' % len(enum.values))
statements.extend(map(lambda v: ' items.push_back("%s");' % v, sorted(enum.values)))
statements.append(' %(name)s_type = new enumeration_type(IfcSchema::Type::%(name)s, items);' % locals())
statements.append(' }')
declared_types.append('%(name)s_type' % locals())
emitted_entities = set()
while len(emitted_entities) < len(mapping.schema.entities):
for name, type in mapping.schema.entities.items():
if name in emitted_entities: continue
if len(type.supertypes) == 0 or set(type.supertypes) < emitted_entities:
supertype = '0' if len(type.supertypes) == 0 else '%s_type' % type.supertypes[0]
statements.append(' %(name)s_type = new entity(IfcSchema::Type::%(name)s, %(supertype)s);' % locals())
emitted_entities.add(name)
declared_types.append('%(name)s_type' % locals())
emmited = emitted_types | emitted_entities | set(mapping.schema.enumerations.keys())
emitted_selects = set()
while len(emitted_selects) < len(mapping.schema.selects):
for name, type in mapping.schema.selects.items():
if name in emitted_selects: continue
type_values = sorted(set(type.values) - {"IfcPropertySetDefinitionSet"})
if set(type_values) < emmited:
statements.append(' {')
statements.append(' std::vector<const declaration*> items; items.reserve(%d);' % len(type_values))
statements.extend(map(lambda v: ' items.push_back(%s_type);' % v, sorted(type_values)))
statements.append(' %(name)s_type = new select_type(IfcSchema::Type::%(name)s, items);' % locals())
statements.append(' }')
emitted_selects.add(name)
emmited.add(name)
declared_types.append('%(name)s_type' % locals())
num_declarations = len(declared_types)
for name, type in mapping.schema.entities.items():
derived = set(mapping.derived_in_supertype(type))
attribute_names = list(map(operator.attrgetter('name'), mapping.arguments(type)))
statements.append(' {')
statements.append(' std::vector<const entity::attribute*> attributes; attributes.reserve(%d);' % len(type.attributes))
for attr in type.attributes:
attr_name, optional = attr.name, str(attr.optional).lower()
decl_type = get_declared_type(attr.type)
statements.append(' attributes.push_back(new entity::attribute("%(attr_name)s", %(decl_type)s, %(optional)s));' % locals())
statements.append(' std::vector<bool> derived; derived.reserve(%d);' % len(attribute_names))
statements.append(' ' + " ".join(map(lambda b: 'derived.push_back(%s);' % str(b in derived).lower(), attribute_names)))
statements.append(' %(name)s_type->set_attributes(attributes, derived);' % locals())
statements.append(' }')
for name, type in mapping.schema.entities.items():
if type.inverse:
statements.append(' {')
statements.append(' std::vector<const entity::inverse_attribute*> attributes; attributes.reserve(%d);' % len(type.inverse.elements))
for attr in type.inverse.elements:
if attr.bounds:
make_bound = lambda b: -1 if b == '?' else int(b)
bound1, bound2 = map(make_bound, (attr.bounds.lower, attr.bounds.upper))
else:
bound1, bound2 = -1, -1
attr_name, aggr_type, entity_ref = attr.name, attr.type, attr.entity
if aggr_type is None: aggr_type = 'unspecified'
attribute_entity, attribute_entity_index = find_inverse_name_and_index(entity_ref, attr.attribute)
statements.append(' attributes.push_back(new entity::inverse_attribute("%(attr_name)s", entity::inverse_attribute::%(aggr_type)s_type, %(bound1)d, %(bound2)d, %(entity_ref)s_type, %(attribute_entity)s_type->attributes()[%(attribute_entity_index)d]));' % locals())
statements.append(' %(name)s_type->set_inverse_attributes(attributes);' % locals())
statements.append(' }')
statements.append('')
statements.append(' std::vector<const declaration*> declarations; declarations.reserve(%(num_declarations)d);' % locals())
for type_name in declared_types:
statements.append(' declarations.push_back(%(type_name)s);' % locals())
statements.append(' return new schema_definition("%(schema_name)s", declarations, true);' % locals())
statements.extend(('}',''))
statements.append("""
#if defined(__clang__)
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC pop_options
#elif defined(_MSC_VER)
#pragma optimize("", on)
#endif
""")
statements.extend(('const schema_definition& get_schema() {',
'',
' static const schema_definition* s = populate_schema();',
' return *s;',
'}','',''))
self.str = "\n".join(statements)
self.file_name = '%s-schema.cpp'%self.schema_name
def __repr__(self):
return self.str
+147 -82
View File
@@ -23,18 +23,27 @@ header = """
#include <string>
#include <vector>
#include <map>
#include <boost/optional.hpp>
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcSchema.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/%(schema_name)senum.h"
const IfcParse::schema_definition& get_schema();
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4100)
#endif
#define IfcSchema %(schema_name)s
namespace %(schema_name)s {
const char* const Identifier = "%(schema_name_upper)s";
// Forward definitions
%(forward_definitions)s
@@ -42,9 +51,13 @@ namespace %(schema_name)s {
%(class_definitions)s
void InitStringMap();
IfcUtil::IfcSchemaEntity SchemaEntity(IfcAbstractEntityPtr e = 0);
IfcUtil::IfcBaseClass* SchemaEntity(IfcAbstractEntity* e = 0);
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif
"""
@@ -58,7 +71,7 @@ namespace %(schema_name)s {
namespace Type {
typedef enum {
%(types)s, ALL
%(types)s, UNDEFINED
} Enum;
Enum Parent(Enum v);
Enum FromString(const std::string& s);
@@ -71,7 +84,7 @@ namespace Type {
#endif
"""
rt_header = """
lb_header = """
#ifndef %(schema_name_upper)sRT_H
#define %(schema_name_upper)sRT_H
@@ -86,12 +99,13 @@ namespace Type {
int GetAttributeCount(Enum t);
int GetAttributeIndex(Enum t, const std::string& a);
IfcUtil::ArgumentType GetAttributeType(Enum t, unsigned char a);
Enum GetAttributeEntity(Enum t, unsigned char a);
const std::string& GetAttributeName(Enum t, unsigned char a);
bool GetAttributeOptional(Enum t, unsigned char a);
bool GetAttributeDerived(Enum t, unsigned char a);
std::pair<const char*, int> GetEnumerationIndex(Enum t, const std::string& a);
std::pair<Enum, unsigned> GetInverseAttribute(Enum t, const std::string& a);
Enum GetAttributeEnumerationClass(Enum t, unsigned char a);
std::set<std::string> GetInverseAttributeNames(Enum t);
void PopulateDerivedFields(IfcWrite::IfcWritableEntity* e);
}}
@@ -100,15 +114,21 @@ namespace Type {
implementation= """
#include "../ifcparse/%(schema_name)s.h"
#include "../ifcparse/IfcSchema.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcWrite.h"
#include "../ifcparse/IfcWritableEntity.h"
#include <map>
using namespace %(schema_name)s;
using namespace IfcParse;
using namespace IfcWrite;
IfcUtil::IfcSchemaEntity %(schema_name)s::SchemaEntity(IfcAbstractEntityPtr e) {
// External definitions
%(external_definitions)s
IfcUtil::IfcBaseClass* %(schema_name)s::SchemaEntity(IfcAbstractEntity* e) {
switch(e->type()) {
%(schema_entity_statements)s
default: throw IfcException("Unable to find find keyword in schema"); break;
@@ -145,33 +165,16 @@ bool Type::IsSimple(Enum v) {
%(enumeration_functions)s
#define RETURN_INVERSE(T) \
IfcEntities e = entity->getInverse(T::Class()); \
SHARED_PTR< IfcTemplatedEntityList<T> > l ( new IfcTemplatedEntityList<T>() ); \
for ( IfcEntityList::it it = e->begin(); it != e->end(); ++ it ) { \
l->push(reinterpret_pointer_cast<IfcBaseClass,T>(*it)); \
} \
return l;
#define RETURN_AS_SINGLE(T,a) \
return reinterpret_pointer_cast<IfcBaseClass,T>(*entity->getArgument(a));
#define RETURN_AS_LIST(T,a) \
IfcEntities e = *entity->getArgument(a); \
SHARED_PTR< IfcTemplatedEntityList<T> > l ( new IfcTemplatedEntityList<T>() ); \
for ( IfcEntityList::it it = e->begin(); it != e->end(); ++ it ) { \
l->push(reinterpret_pointer_cast<IfcBaseClass,T>(*it)); \
} \
return l;
%(simple_type_impl)s
%(entity_implementations)s
"""
rt_implementation = """
lb_implementation = """
#include <set>
#include "../ifcparse/%(schema_name)s.h"
#include "../ifcparse/%(schema_name)s-rt.h"
#include "../ifcparse/%(schema_name)s-latebound.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcWrite.h"
#include "../ifcparse/IfcWritableEntity.h"
@@ -183,10 +186,23 @@ using namespace IfcParse;
using namespace IfcWrite;
using namespace IfcUtil;
std::map<Type::Enum,IfcEntityDescriptor*> entity_descriptor_map;
std::map<Type::Enum,IfcEnumerationDescriptor*> enumeration_descriptor_map;
std::map<std::pair<Type::Enum, std::string>, std::pair<Type::Enum, int> > inverse_map;
std::map<Type::Enum,std::set<int> > derived_map;
typedef std::map<Type::Enum,IfcEntityDescriptor*> entity_descriptor_map_t;
typedef std::map<Type::Enum,IfcEnumerationDescriptor*> enumeration_descriptor_map_t;
typedef std::map<Type::Enum, std::map<std::string, std::pair<Type::Enum, int> > > inverse_map_t;
typedef std::map<Type::Enum,std::set<int> > derived_map_t;
entity_descriptor_map_t entity_descriptor_map;
enumeration_descriptor_map_t enumeration_descriptor_map;
inverse_map_t inverse_map;
derived_map_t derived_map;
#if defined(__clang__)
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC push_options
#pragma GCC optimize ("O0")
#elif defined(_MSC_VER)
#pragma optimize("", off)
#endif
void InitDescriptorMap() {
IfcEntityDescriptor* current;
@@ -205,6 +221,13 @@ void InitDerivedMap() {
%(derived_field_statements)s
}
#if defined(__clang__)
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC pop_options
#elif defined(_MSC_VER)
#pragma optimize("", on)
#endif
int Type::GetAttributeIndex(Enum t, const std::string& a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
@@ -226,6 +249,13 @@ ArgumentType Type::GetAttributeType(Enum t, unsigned char a) {
else return i->second->getArgumentType(a);
}
Type::Enum Type::GetAttributeEntity(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentEntity(a);
}
const std::string& Type::GetAttributeName(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
@@ -254,35 +284,49 @@ std::pair<const char*, int> Type::GetEnumerationIndex(Enum t, const std::string&
}
std::pair<Type::Enum, unsigned> Type::GetInverseAttribute(Enum t, const std::string& a) {
if (inverse_map.empty()) ::InitInverseMap();
std::map<std::pair<Type::Enum, std::string>, std::pair<Type::Enum, int> >::const_iterator it;
std::pair<Type::Enum, std::string> key = std::make_pair(t, a);
while (true) {
it = inverse_map.find(key);
if (it != inverse_map.end()) return it->second;
if ((key.first = Parent(key.first)) == -1) break;
if (inverse_map.empty()) ::InitInverseMap();
inverse_map_t::const_iterator it;
inverse_map_t::mapped_type::const_iterator jt;
for(;;) {
it = inverse_map.find(t);
if (it != inverse_map.end()) {
jt = it->second.find(a);
if (jt != it->second.end()) {
return jt->second;
}
}
if ((t = Parent(t)) == -1) break;
}
throw IfcException("Attribute not found");
}
Type::Enum Type::GetAttributeEnumerationClass(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else {
Type::Enum t = i->second->getArgumentEnumerationClass(a);
if ( t == Type::ALL ) throw IfcException("Not an enumeration");
else return t;
std::set<std::string> Type::GetInverseAttributeNames(Enum t) {
if (inverse_map.empty()) ::InitInverseMap();
inverse_map_t::const_iterator it;
inverse_map_t::mapped_type::const_iterator jt;
std::set<std::string> return_value;
for (;;) {
it = inverse_map.find(t);
if (it != inverse_map.end()) {
for (jt = it->second.begin(); jt != it->second.end(); ++jt) {
return_value.insert(jt->first);
}
}
if ((t = Parent(t)) == -1) break;
}
return return_value;
}
void Type::PopulateDerivedFields(IfcWrite::IfcWritableEntity* e) {
std::map<Type::Enum, std::set<int> >::const_iterator i = derived_map.find(e->type());
if (i != derived_map.end()) {
for (std::set<int>::const_iterator it = i->second.begin(); it != i->second.end(); ++it) {
e->setArgumentDerived(*it);
}
}
if (i != derived_map.end()) {
for (std::set<int>::const_iterator it = i->second.begin(); it != i->second.end(); ++it) {
e->setArgumentDerived(*it);
}
}
}
"""
@@ -290,8 +334,8 @@ entity_descriptor = """ current = entity_descriptor_map[Type::%(type)s] = new
%(entity_descriptor_attributes)s"""
entity_descriptor_parent = "entity_descriptor_map.find(Type::%(type)s)->second"
entity_descriptor_attribute = ' current->add("%(name)s",%(optional)s,%(type)s);'
entity_descriptor_attribute_enum = ' current->add("%(name)s",%(optional)s,%(type)s,Type::%(enum_type)s);'
entity_descriptor_attribute_without_entity = ' current->add("%(name)s",%(optional)s,%(type)s);'
entity_descriptor_attribute_with_entity = ' current->add("%(name)s",%(optional)s,%(type)s,Type::%(entity_name)s);'
enumeration_descriptor = """ values.clear(); values.reserve(128);
%(enumeration_descriptor_values)s
@@ -303,11 +347,32 @@ derived_field_statement = ' {std::set<int> idxs; %(statements)sderived_map[Ty
derived_field_statement_attrs = 'idxs.insert(%d); '
simpletype = """%(documentation)s
typedef %(type)s %(name)s;
class %(name)s : public %(superclass)s {
public:
virtual const IfcParse::type_declaration& declaration() const;
static Type::Enum Class();
explicit %(name)s (IfcAbstractEntity* e);
%(name)s (%(type)s v);
operator %(type)s() const;
};
"""
simpletype_impl_comment = "// Function implementations for %(name)s"
simpletype_impl_argument_type = "if (i == 0) { return %(attr_type)s; } else { throw IfcParse::IfcAttributeOutOfRangeException(\"Argument index out of range\"); }"
simpletype_impl_argument = "return data_->getArgument(i);"
simpletype_impl_is_with_supertype = "return v == Type::%(class_name)s || %(superclass)s::is(v);"
simpletype_impl_is_without_supertype = "return v == %(class_name)s::Class();"
simpletype_impl_type = "return Type::%(class_name)s;"
simpletype_impl_class = "return Type::%(class_name)s;"
simpletype_impl_explicit_constructor = "data_ = e;"
simpletype_impl_constructor = "IfcWritableEntity* e = new IfcWritableEntity(Type::%(class_name)s); e->setArgument(0, v); data_ = e;"
simpletype_impl_constructor_templated = "IfcWritableEntity* e = new IfcWritableEntity(Type::%(class_name)s); e->setArgument(0, v->generalize()); data_ = e;"
simpletype_impl_cast = "return *data_->getArgument(0);"
simpletype_impl_cast_templated = "IfcEntityList::ptr es = *data_->getArgument(0); return es->as<%(underlying_type)s>();"
simpletype_impl_declaration = "return *%(class_name)s_type;"
select = """%(documentation)s
typedef IfcUtil::IfcSchemaEntity %(name)s;
typedef IfcUtil::IfcBaseClass %(name)s;
"""
enumeration = """namespace %(name)s {
@@ -321,18 +386,11 @@ const char* ToString(%(name)s v);
entity = """%(documentation)s
class %(name)s %(superclass)s{
public:
%(attributes)s virtual unsigned int getArgumentCount() const { return %(argument_count)d; }
virtual IfcUtil::ArgumentType getArgumentType(unsigned int i) const {%(argument_type_function_body)s}
virtual const char* getArgumentName(unsigned int i) const {%(argument_name_function_body)s}
virtual ArgumentPtr getArgument(unsigned int i) const { return entity->getArgument(i); }
%(inverse)s bool is(Type::Enum v) const;
Type::Enum type() const;
%(attributes)s %(inverse)s virtual const IfcParse::entity& declaration() const;
static Type::Enum Class();
%(name)s (IfcAbstractEntityPtr e);
%(name)s (IfcAbstractEntity* e);
%(name)s (%(constructor_arguments)s);
typedef %(name)s* ptr;
typedef SHARED_PTR< IfcTemplatedEntityList< %(name)s > > list;
typedef IfcTemplatedEntityList< %(name)s >::it it;
typedef IfcTemplatedEntityList< %(name)s > list;
};
"""
@@ -350,43 +408,50 @@ const char* %(name)s::ToString(%(name)s v) {
"""
entity_implementation = """// Function implementations for %(name)s
%(attributes)s%(inverse)sbool %(name)s::is(Type::Enum v) const { return v == Type::%(name)s%(parent_type_test)s; }
Type::Enum %(name)s::type() const { return Type::%(name)s; }
%(attributes)s
%(inverse)s
const IfcParse::entity& %(name)s::declaration() const { return *%(name)s_type; }
Type::Enum %(name)s::Class() { return Type::%(name)s; }
%(name)s::%(name)s(IfcAbstractEntityPtr e) : %(superclass)s { if (!e) return; if (!e->is(Type::%(name)s)) throw IfcException("Unable to find find keyword in schema"); entity = e; }
%(name)s::%(name)s(%(constructor_arguments)s) : %(superclass)s { IfcWritableEntity* e = new IfcWritableEntity(Class());%(constructor_implementation)s entity = e; EntityBuffer::Add(this); }
%(name)s::%(name)s(IfcAbstractEntity* e) : %(superclass)s { if (!e) return; if (!e->is(Type::%(name)s)) throw IfcException("Unable to find find keyword in schema"); data_ = e; }
%(name)s::%(name)s(%(constructor_arguments)s) : %(superclass)s { IfcWritableEntity* e = new IfcWritableEntity(Class());%(constructor_implementation)s data_ = e; EntityBuffer::Add(this); }
"""
optional_attribute_description = "/// Whether the optional attribute %s is defined for this %s"
function = "%(return_type)s %(class_name)s::%(name)s(%(arguments)s) { %(body)s }"
const_function = "%(return_type)s %(class_name)s::%(name)s(%(arguments)s) const { %(body)s }"
constructor = "%(class_name)s::%(class_name)s(%(arguments)s) { %(body)s }"
constructor_single_initlist = "%(class_name)s::%(class_name)s(%(arguments)s) : %(superclass)s(%(superclass_init)s) { %(body)s }"
cast_function = "%(class_name)s::operator %(return_type)s() const { %(body)s }"
array_type = "std::vector< %(instance_type)s > /*[%(lower)s:%(upper)s]*/"
list_type = "SHARED_PTR< IfcTemplatedEntityList< %(instance_type)s > >"
untyped_list = "IfcEntities"
inverse_attr = "SHARED_PTR< IfcTemplatedEntityList< %(entity)s > > %(name)s(); // INVERSE %(entity)s::%(attribute)s"
nested_array_type = "std::vector< std::vector< %(instance_type)s > >"
list_type = "IfcTemplatedEntityList< %(instance_type)s >::ptr"
list_list_type = "IfcTemplatedEntityListList< %(instance_type)s >::ptr"
untyped_list = "IfcEntityList::ptr"
inverse_attr = "IfcTemplatedEntityList< %(entity)s >::ptr %(name)s() const; // INVERSE %(entity)s::%(attribute)s"
enum_from_string_stmt = ' if (s == "%(value)s") return ::%(schema_name)s::%(name)s::%(short_name)s_%(value)s;'
schema_entity_stmt = ' case Type::%(name)s: return new %(name)s(e); break;'
schema_simple_stmt = ' case Type::%(name)s: return new IfcUtil::IfcEntitySelect(e); break;'
string_map_statement = ' string_map["%(uppercase_name)s"%(padding)s] = Type::%(name)s;'
parent_type_stmt = ' if(v==%(name)s%(padding)s) { return %(parent)s; }'
parent_type_test = " || %s::is(v)"
optional_attr_stmt = "return !entity->getArgument(%(index)d)->isNull();"
optional_attr_stmt = "return !data_->getArgument(%(index)d)->isNull();"
get_attr_stmt = "return *entity->getArgument(%(index)d);"
get_attr_stmt_enum = "return %(type)s::FromString(*entity->getArgument(%(index)d));"
get_attr_stmt_entity = "return (%(type)s)((IfcUtil::IfcSchemaEntity)(*entity->getArgument(%(index)d)));"
get_attr_stmt_array = "RETURN_AS_LIST(%(list_instance_type)s,%(index)d)"
get_attr_stmt = "return *data_->getArgument(%(index)d);"
get_attr_stmt_enum = "return %(type)s::FromString(*data_->getArgument(%(index)d));"
get_attr_stmt_entity = "return (%(type)s)((IfcUtil::IfcBaseClass*)(*data_->getArgument(%(index)d)));"
get_attr_stmt_array = "IfcEntityList::ptr es = *data_->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
get_attr_stmt_nested_array = "IfcEntityListList::ptr es = *data_->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
get_inverse = "RETURN_INVERSE(%(type)s)"
get_inverse = "return data_->getInverse(Type::%(type)s, %(index)d)->as<%(type)s>();"
set_attr_stmt = "if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%(index)d,v);"
set_attr_stmt_enum = "if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%(index)d,v,%(type)s::ToString(v));"
set_attr_stmt_array = "if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%(index)d,v->generalize());"
set_attr_stmt = "if ( ! data_->isWritable() ) { data_ = new IfcWritableEntity(data_); } ((IfcWritableEntity*)data_)->setArgument(%(index)d,v);"
set_attr_stmt_enum = "if ( ! data_->isWritable() ) { data_ = new IfcWritableEntity(data_); } ((IfcWritableEntity*)data_)->setArgument(%(index)d,v,%(type)s::ToString(v));"
set_attr_stmt_array = "if ( ! data_->isWritable() ) { data_ = new IfcWritableEntity(data_); } ((IfcWritableEntity*)data_)->setArgument(%(index)d,v->generalize());"
constructor_stmt = " e->setArgument(%(index)d,(%(name)s));"
constructor_stmt_enum = " e->setArgument(%(index)d,%(name)s,%(type)s::ToString(%(name)s));"
@@ -394,7 +459,7 @@ constructor_stmt_array = " e->setArgument(%(index)d,(%(name)s)->generalize());"
constructor_stmt_optional = " if (%(name)s) {%(stmt)s } else { e->setArgument(%(index)d); }"
constructor_stmt_derived = " e->setArgumentDerived(%(index)d);"
inverse_implementation = " inverse_map.insert(std::make_pair(std::make_pair(Type::%(type)s, \"%(name)s\"), std::make_pair(Type::%(related_type)s, %(index)d)));"
inverse_implementation = " inverse_map[Type::%(type)s].insert(std::make_pair(\"%(name)s\", std::make_pair(Type::%(related_type)s, %(index)d)));"
def multi_line_comment(li):
return ("/// %s"%("\n/// ".join(li))) if len(li) else ""
+90 -22
View File
@@ -36,14 +36,33 @@
#include <TopoDS_Face.hxx>
#include <Geom_Curve.hxx>
#include <gp_Pln.hxx>
#include <TColgp_SequenceOfPnt.hxx>
#include "../ifcparse/IfcParse.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcgeom/IfcGeomElement.h"
#include "../ifcgeom/IfcGeomRepresentation.h"
#include "../ifcgeom/IfcRepresentationShapeItem.h"
#include "../ifcgeom/IfcGeomShapeType.h"
#define IN_CACHE(T,E,t,e) std::map<int,t>::const_iterator it = cache.T.find(E->data().id());\
if ( it != cache.T.end() ) { e = it->second; return true; }
#define CACHE(T,E,e) cache.T[E->data().id()] = e;
namespace IfcGeom {
class Cache {
public:
#include "IfcRegisterCreateCache.h"
std::map<int, SurfaceStyle> Style;
std::map<int, TopoDS_Shape> Shape;
};
class Kernel {
private:
Cache cache;
public:
// Tolerances and settings for various geometrical operations:
enum GeomValue {
// Specifies the deflection of the mesher
@@ -62,9 +81,6 @@ namespace IfcGeom {
// that consist of many faces is really detrimental for the performance.
// Default: 1000
GV_MAX_FACES_TO_SEW,
// By default singular faces have no explicitly defined orientation, to
// force faces to be defined CounterClockWise, set this value greater than zero.
GV_FORCE_CCW_FACE_ORIENTATION,
// The length unit used the creation of TopoDS_Shapes, primarily affects the
// interpretation of IfcCartesianPoints and IfcVector magnitudes
// DefaultL 1.0
@@ -76,25 +92,24 @@ namespace IfcGeom {
// The precision used in boolean operations, setting this value too low results
// in artefacts and potentially modelling failures
// Default: 0.00001 (obtained from IfcGeometricRepresentationContext if available)
GV_PRECISION
GV_PRECISION,
// Whether to process shapes of type Face or higher (1) Wire or lower (-1) or all (0)
GV_DIMENSIONALITY
};
const int DISABLE_OPENING_SUBTRACTIONS = 1 << 0;
const int DISABLE_OBJECT_PLACEMENT = 1 << 1;
const int SEW_SHELLS = 1 << 2;
const int CONVERT_TO_METERS = 1 << 3;
bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face);
bool convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire);
bool convert_shapes(const IfcUtil::IfcBaseClass* L, IfcRepresentationShapeItems& result);
bool is_shape_collection(const IfcUtil::IfcBaseClass* L);
IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseClass* L);
bool convert_shape(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
bool flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse);
bool convert_wire(const IfcUtil::IfcBaseClass* L, TopoDS_Wire& result);
bool convert_curve(const IfcUtil::IfcBaseClass* L, Handle(Geom_Curve)& result);
bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
bool convert_openings(const IfcSchema::IfcProduct::ptr entity, const IfcSchema::IfcRelVoidsElement::list& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
bool convert_openings_fast(const IfcSchema::IfcProduct::ptr entity, const IfcSchema::IfcRelVoidsElement::list& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
bool convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
IfcSchema::IfcSurfaceStyleShading* get_surface_style(IfcSchema::IfcRepresentationItem* item);
const IfcSchema::IfcRepresentationItem* find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item);
bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid);
bool is_compound(const TopoDS_Shape& shape);
bool is_convex(const TopoDS_Wire& wire);
@@ -106,19 +121,72 @@ namespace IfcGeom {
double shape_volume(const TopoDS_Shape& s);
double face_area(const TopoDS_Face& f);
void apply_tolerance(TopoDS_Shape& s, double t);
void SetValue(GeomValue var, double value);
double GetValue(GeomValue var);
std::string create_brep_data(IfcSchema::IfcProduct* s, unsigned int settings);
void initialize_units_and_precision(IfcSchema::IfcProject* proj, double& unit_magnitude, std::string& unit_name);
bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape);
IfcSchema::IfcProductDefinitionShape* tesselate(TopoDS_Shape& shape, double deflection, IfcEntities es);
void setValue(GeomValue var, double value);
double getValue(GeomValue var) const;
bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape);
void remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
void remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
bool wire_to_sequence_of_point(const TopoDS_Wire&, TColgp_SequenceOfPnt&);
void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed);
std::pair<std::string, double> initializeUnits(IfcSchema::IfcUnitAssignment*);
IfcSchema::IfcObjectDefinition* get_decomposing_entity(IfcSchema::IfcProduct*);
template <typename P>
IfcGeom::BRepElement<P>* create_brep_for_representation_and_product(const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*);
const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem* representation_item);
namespace Cache {
void Purge();
void PurgeShapeCache();
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) {
// For certain representation items, most notably boolean operands,
// a style definition might reside on one of its operands.
representation_item = find_item_carrying_style(representation_item);
IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem();
for (IfcSchema::IfcStyledItem::list::it jt = styled_items->begin(); jt != styled_items->end(); ++jt) {
#ifdef USE_IFC4
IfcEntityList::ptr style_assignments = (*jt)->Styles();
for (IfcEntityList::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
if (!(*kt)->declaration().is(IfcSchema::Type::IfcPresentationStyleAssignment)) {
continue;
}
IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt;
#else
IfcSchema::IfcPresentationStyleAssignment::list::ptr style_assignments = (*jt)->Styles();
for (IfcSchema::IfcPresentationStyleAssignment::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
IfcSchema::IfcPresentationStyleAssignment* style_assignment = *kt;
#endif
IfcEntityList::ptr styles = style_assignment->Styles();
for (IfcEntityList::it lt = styles->begin(); lt != styles->end(); ++lt) {
IfcUtil::IfcBaseClass* style = *lt;
if (style->declaration().is(IfcSchema::Type::IfcSurfaceStyle)) {
IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style;
if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) {
IfcEntityList::ptr styles_elements = surface_style->Styles();
for (IfcEntityList::it mt = styles_elements->begin(); mt != styles_elements->end(); ++mt) {
if ((*mt)->declaration().is(T::Class())) {
return std::make_pair(surface_style, (T*) *mt);
}
}
}
}
}
}
// StyledByItem is a SET [0:1] OF IfcStyledItem, so we
// break after encountering the first IfcStyledItem
break;
}
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0,0);
}
#include "IfcRegisterGeomHeader.h"
};
IfcSchema::IfcProductDefinitionShape* tesselate(TopoDS_Shape& shape, double deflection, IfcEntityList::ptr es);
}
#endif
+58 -19
View File
@@ -77,32 +77,36 @@
#include <TopLoc_Location.hxx>
#ifdef USE_IFC4
#include <Geom_BSplineCurve.hxx>
#endif
#include "../ifcgeom/IfcGeom.h"
bool IfcGeom::convert(const IfcSchema::IfcCircle::ptr l, Handle(Geom_Curve)& curve) {
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircle* l, Handle(Geom_Curve)& curve) {
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
if ( r < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l);
return false;
}
gp_Trsf trsf;
IfcSchema::IfcAxis2Placement placement = l->Position();
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
IfcGeom::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
IfcSchema::IfcAxis2Placement* placement = l->Position();
if (placement->declaration().is(IfcSchema::Type::IfcAxis2Placement3D)) {
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
} else {
gp_Trsf2d trsf2d;
IfcGeom::convert((IfcAxis2Placement2D*)placement,trsf2d);
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d);
trsf = trsf2d;
}
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
curve = new Geom_Circle(ax, r);
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcEllipse::ptr l, Handle(Geom_Curve)& curve) {
double x = l->SemiAxis1() * IfcGeom::GetValue(GV_LENGTH_UNIT);
double y = l->SemiAxis2() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipse* l, Handle(Geom_Curve)& curve) {
double x = l->SemiAxis1() * getValue(GV_LENGTH_UNIT);
double y = l->SemiAxis2() * getValue(GV_LENGTH_UNIT);
if (x < ALMOST_ZERO || y < ALMOST_ZERO) {
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l);
return false;
}
// Open Cascade does not allow ellipses of which the minor radius
@@ -111,12 +115,12 @@ bool IfcGeom::convert(const IfcSchema::IfcEllipse::ptr l, Handle(Geom_Curve)& cu
// when creating a trimmed curve off of an ellipse like this.
const bool rotated = y > x;
gp_Trsf trsf;
IfcSchema::IfcAxis2Placement placement = l->Position();
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
IfcGeom::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
IfcSchema::IfcAxis2Placement* placement = l->Position();
if (placement->declaration().is(IfcSchema::Type::IfcAxis2Placement3D)) {
convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
} else {
gp_Trsf2d trsf2d;
IfcGeom::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d);
convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d);
trsf = trsf2d;
}
gp_Ax2 ax = gp_Ax2();
@@ -128,11 +132,46 @@ bool IfcGeom::convert(const IfcSchema::IfcEllipse::ptr l, Handle(Geom_Curve)& cu
curve = new Geom_Ellipse(ax, x, y);
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcLine::ptr l, Handle(Geom_Curve)& curve) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcLine* l, Handle(Geom_Curve)& curve) {
gp_Pnt pnt;gp_Vec vec;
IfcGeom::convert(l->Pnt(),pnt);
IfcGeom::convert(l->Dir(),vec);
convert(l->Pnt(),pnt);
convert(l->Dir(),vec);
// See note at IfcGeomWires.cpp:237
curve = new Geom_Line(pnt,vec);
return true;
}
}
#ifdef USE_IFC4
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineCurveWithKnots* l, Handle(Geom_Curve)& curve) {
const IfcSchema::IfcCartesianPoint::list::ptr cps = l->ControlPointsList();
const std::vector<int> mults = l->KnotMultiplicities();
const std::vector<double> knots = l->Knots();
TColgp_Array1OfPnt Poles(0, cps->size() - 1);
TColStd_Array1OfReal Knots(0, (int)knots.size() - 1);
TColStd_Array1OfInteger Mults(0, (int)mults.size() - 1);
Standard_Integer Degree = l->Degree();
Standard_Boolean Periodic = l->ClosedCurve();
int i = 0;
for (IfcSchema::IfcCartesianPoint::list::it it = cps->begin(); it != cps->end(); ++it, ++i) {
gp_Pnt pnt;
if (!convert(*it, pnt)) return false;
Poles(i) = pnt;
}
i = 0;
for (std::vector<int>::const_iterator it = mults.begin(); it != mults.end(); ++it, ++i) {
Mults(i) = *it;
}
i = 0;
for (std::vector<double>::const_iterator it = knots.begin(); it != knots.end(); ++it, ++i) {
Knots(i) = *it;
}
curve = new Geom_BSplineCurve(Poles, Knots, Mults, Degree, Periodic);
return true;
}
#endif
+162
View File
@@ -0,0 +1,162 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef IFCGEOMELEMENT_H
#define IFCGEOMELEMENT_H
#include <string>
#include <algorithm>
#include "../ifcparse/IfcGlobalId.h"
#include "../ifcgeom/IfcGeomRepresentation.h"
#include "../ifcgeom/IfcGeomIteratorSettings.h"
namespace IfcGeom {
template <typename P>
class Matrix {
private:
std::vector<P> _data;
public:
Matrix(const ElementSettings& settings, const gp_Trsf& trsf) {
// Convert the gp_Trsf into a 4x3 Matrix
// Note that in case the CONVERT_BACK_UNITS setting is enabled
// the translation component of the matrix needs to be divided
// by the magnitude of the IFC model length unit because
// internally in IfcOpenShell everything is measured in meters.
for(int i = 1; i < 5; ++i) {
for (int j = 1; j < 4; ++j) {
const double trsf_value = trsf.Value(j,i);
const double matrix_value = i == 4 && settings.convert_back_units()
? trsf_value / settings.unit_magnitude()
: trsf_value;
_data.push_back(static_cast<P>(matrix_value));
}
}
}
const std::vector<P>& data() const { return _data; }
};
template <typename P>
class Transformation {
private:
gp_Trsf trsf;
Matrix<P> _matrix;
public:
Transformation(const ElementSettings& settings, const gp_Trsf& trsf)
: trsf(trsf)
, _matrix(settings, trsf)
{}
const gp_Trsf& data() const { return trsf; }
const Matrix<P>& matrix() const { return _matrix; }
};
template <typename P>
class Element {
private:
int _id;
int _parent_id;
std::string _name;
std::string _type;
std::string _guid;
std::string _context;
std::string _unique_id;
Transformation<P> _transformation;
public:
int id() const { return _id; }
int parent_id() const { return _parent_id; }
const std::string& name() const { return _name; }
const std::string& type() const { return _type; }
const std::string& guid() const { return _guid; }
const std::string& context() const { return _context; }
const std::string& unique_id() const { return _unique_id; }
const Transformation<P>& transformation() const { return _transformation; }
Element(const ElementSettings& settings, int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const std::string& context, const gp_Trsf& trsf)
: _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _context(context), _transformation(settings, trsf)
{
std::ostringstream oss;
oss << "product-" << IfcParse::IfcGlobalId(guid).formatted();
if (!_context.empty()) {
std::string ctx = _context;
std::transform(ctx.begin(), ctx.end(), ctx.begin(), ::tolower);
std::replace(ctx.begin(), ctx.end(), ' ', '-');
oss << "-" << ctx;
}
_unique_id = oss.str();
}
virtual ~Element() {}
};
template <typename P>
class BRepElement : public Element<P> {
private:
Representation::BRep* _geometry;
public:
const Representation::BRep& geometry() const { return *_geometry; }
BRepElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const std::string& context, const gp_Trsf& trsf, Representation::BRep* geometry)
: Element<P>(geometry->settings(),id,parent_id,name,type,guid,context,trsf)
, _geometry(geometry)
{}
virtual ~BRepElement() {
delete _geometry;
}
private:
BRepElement(const BRepElement& other);
BRepElement& operator=(const BRepElement& other);
};
template <typename P>
class TriangulationElement : public Element<P> {
private:
Representation::Triangulation<P>* _geometry;
public:
const Representation::Triangulation<P>& geometry() const { return *_geometry; }
TriangulationElement(const BRepElement<P>& shape_model)
: Element<P>(shape_model)
, _geometry(new Representation::Triangulation<P>(shape_model.geometry()))
{}
virtual ~TriangulationElement() {
delete _geometry;
}
private:
TriangulationElement(const TriangulationElement& other);
TriangulationElement& operator=(const TriangulationElement& other);
};
template <typename P>
class SerializedElement : public Element<P> {
private:
Representation::Serialization* _geometry;
public:
const Representation::Serialization& geometry() const { return *_geometry; }
SerializedElement(const BRepElement<P>& shape_model)
: Element<P>(shape_model)
, _geometry(new Representation::Serialization(shape_model.geometry()))
{}
virtual ~SerializedElement() {
delete _geometry;
}
private:
SerializedElement(const SerializedElement& other);
SerializedElement& operator=(const SerializedElement& other);
};
}
#endif
+425 -235
View File
@@ -47,6 +47,7 @@
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <Geom_Line.hxx>
#include <Geom_Plane.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Ellipse.hxx>
#include <Geom_TrimmedCurve.hxx>
@@ -70,6 +71,7 @@
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS_Iterator.hxx>
#include <BRepAlgoAPI_Cut.hxx>
@@ -83,134 +85,238 @@
#include <Standard_Failure.hxx>
#include <BRep_Tool.hxx>
#include <BRepCheck_Face.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <Standard_Version.hxx>
#ifdef USE_IFC4
#include <Geom_BSplineSurface.hxx>
#include <TColgp_Array2OfPnt.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#endif
#include "../ifcgeom/IfcGeom.h"
bool IfcGeom::convert(const IfcSchema::IfcFace::ptr l, TopoDS_Shape& face) {
IfcSchema::IfcFaceBound::list bounds = l->Bounds();
IfcSchema::IfcFaceBound::it it = bounds->begin();
IfcSchema::IfcLoop::ptr loop = (*it)->Bound();
TopoDS_Wire outer_wire;
if ( ! IfcGeom::convert_wire(loop,outer_wire) ) return false;
BRepBuilderAPI_MakeFace mf (outer_wire);
BRepBuilderAPI_FaceError er = mf.Error();
if ( er == BRepBuilderAPI_NotPlanar ) {
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(outer_wire, 0.01, TopAbs_WIRE);
mf.~BRepBuilderAPI_MakeFace();
new (&mf) BRepBuilderAPI_MakeFace(outer_wire);
er = mf.Error();
}
if ( er != BRepBuilderAPI_FaceDone ) return false;
if ( bounds->Size() == 1 ) {
face = mf.Face();
} else {
for( ++it; it != bounds->end(); ++ it) {
IfcSchema::IfcLoop::ptr loop = (*it)->Bound();
TopoDS_Wire wire;
if ( ! IfcGeom::convert_wire(loop,wire) ) return false;
mf.Add(wire);
}
if ( mf.IsDone() ) {
ShapeFix_Shape sfs(mf.Face());
sfs.Perform();
TopoDS_Shape sfs_shape = sfs.Shape();
bool is_face = sfs_shape.ShapeType() == TopAbs_FACE;
if ( is_face ) {
face = TopoDS::Face(sfs_shape);
} else {
return false;
}
} else {
return false;
}
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
if ( IfcGeom::GetValue(GV_FORCE_CCW_FACE_ORIENTATION)>0 ) {
// Check the orientation of the face by comparing the
// normal of the topological surface to the Newell's Method's
// normal. Newell's Method is used for the normal calculation
// as a simple edge cross product can give opposite results
// for a concave face boundary.
// Reference: Graphics Gems III p. 231
BRepGProp_Face prop(TopoDS::Face(face));
gp_Vec normal_direction;
gp_Pnt center;
double u1,u2,v1,v2;
prop.Bounds(u1,u2,v1,v2);
prop.Normal((u1+u2)/2.0,(v1+v2)/2.0,center,normal_direction);
gp_Dir face_normal1 = gp_Dir(normal_direction.XYZ());
Handle(Geom_Surface) face_surface;
const bool is_face_surface = l->declaration().is(IfcSchema::Type::IfcFaceSurface);
double x = 0, y = 0, z = 0;
gp_Pnt current, previous, first;
int n = 0;
// Iterate over the vertices of the outer wire (discarding
// any potential holes)
for ( TopExp_Explorer exp(outer_wire,TopAbs_VERTEX);; exp.Next()) {
unsigned has_more = exp.More();
if ( has_more ) {
const TopoDS_Vertex& v = TopoDS::Vertex(exp.Current());
current = BRep_Tool::Pnt(v);
} else {
current = first;
}
if ( n ) {
const double& xn = previous.X();
const double& yn = previous.Y();
const double& zn = previous.Z();
const double& xn1 = current.X();
const double& yn1 = current.Y();
const double& zn1 = current.Z();
x += (yn-yn1)*(zn+zn1);
y += (xn+xn1)*(zn-zn1);
z += (xn-xn1)*(yn+yn1);
} else {
first = current;
}
if ( !has_more ) {
break;
}
previous = current;
++n;
}
if (is_face_surface) {
IfcSchema::IfcFaceSurface* fs = (IfcSchema::IfcFaceSurface*) l;
fs->FaceSurface();
// FIXME: Surfaces are interpreted as a TopoDS_Shape
TopoDS_Shape surface_shape;
if (!convert_shape(fs->FaceSurface(), surface_shape)) return false;
// If Newell's normal does not point in the same direction
// as the topological face normal the face orientation is
// reversed
gp_Vec face_normal2(x,y,z);
if ( face_normal1.Dot(face_normal2) < 0 ) {
TopAbs_Orientation o = face.Orientation();
face.Orientation(o == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD);
}
// FIXME: Assert this obtaines the only face
TopExp_Explorer exp(surface_shape, TopAbs_FACE);
if (!exp.More()) return false;
TopoDS_Face surface = TopoDS::Face(exp.Current());
face_surface = BRep_Tool::Surface(surface);
}
// It might be a good idea to globally discard faces
// smaller than a certain treshold value. But for now
// only when processing IfcConnectedFacesets the small
// faces are skipped.
// return face_area(face) > 0.0001;
return true;
const int num_bounds = bounds->size();
int num_outer_bounds = 0;
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
IfcSchema::IfcFaceBound* bound = *it;
if (bound->declaration().is(IfcSchema::Type::IfcFaceOuterBound)) num_outer_bounds ++;
}
// The number of outer bounds should be one according to the schema. Also Open Cascade
// expects this, but it is not strictly checked. Regardless, if the number is greater,
// the face will still be processed as long as there are no holes. A compound of faces
// is returned in that case.
if (num_bounds > 1 && num_outer_bounds > 1 && num_bounds != num_outer_bounds) {
Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l);
return false;
}
TopoDS_Compound compound;
BRep_Builder builder;
if (num_outer_bounds > 1) {
builder.MakeCompound(compound);
}
// The builder is initialized on the heap because of the various different moments
// of initialization depending on the configuration of surfaces and boundaries.
BRepBuilderAPI_MakeFace* mf = 0;
bool success = false;
int processed = 0;
for (int process_interior = 0; process_interior <= 1; ++process_interior) {
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
IfcSchema::IfcFaceBound* bound = *it;
IfcSchema::IfcLoop* loop = bound->Bound();
bool same_sense = bound->Orientation();
const bool is_interior =
!bound->declaration().is(IfcSchema::Type::IfcFaceOuterBound) &&
(num_bounds > 1) &&
(num_outer_bounds < num_bounds);
// The exterior face boundary is processed first
if (is_interior == !process_interior) continue;
TopoDS_Wire wire;
if (!convert_wire(loop, wire)) {
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop);
delete mf;
return false;
}
/*
The approach below does not result in a significant speed-up
if (loop->declaration().is(IfcSchema::Type::IfcPolyLoop) && processed == 0 && face_surface.IsNull()) {
IfcSchema::IfcPolyLoop* polyloop = (IfcSchema::IfcPolyLoop*) loop;
IfcSchema::IfcCartesianPoint::list::ptr points = polyloop->Polygon();
if (points->size() == 3) {
// Help Open Cascade by finding the plane more efficiently
IfcSchema::IfcCartesianPoint::list::it point_iterator = points->begin();
gp_Pnt a, b, c;
convert(*point_iterator++, a);
convert(*point_iterator++, b);
convert(*point_iterator++, c);
const gp_XYZ ab = (b.XYZ() - a.XYZ());
const gp_XYZ ac = (c.XYZ() - a.XYZ());
const gp_Vec cross = ab.Crossed(ac);
if (cross.SquareMagnitude() > ALMOST_ZERO) {
const gp_Dir n = cross;
face_surface = new Geom_Plane(a, n);
}
}
}
*/
if (!same_sense) {
wire.Reverse();
}
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(wire, getValue(GV_PRECISION), TopAbs_WIRE);
if (!mf) {
if (face_surface.IsNull()) {
mf = new BRepBuilderAPI_MakeFace(wire);
} else {
mf = new BRepBuilderAPI_MakeFace(face_surface, wire);
}
/* BRepBuilderAPI_FaceError er = mf->Error();
if (er == BRepBuilderAPI_NotPlanar) {
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(wire, getValue(GV_PRECISION), TopAbs_WIRE);
delete mf;
mf = new BRepBuilderAPI_MakeFace(wire);
} */
if (mf->IsDone()) {
TopoDS_Face outer_face_bound = mf->Face();
if (BRepCheck_Face(outer_face_bound).OrientationOfWires() == BRepCheck_BadOrientationOfSubshape) {
wire.Reverse();
same_sense = !same_sense;
delete mf;
if (face_surface.IsNull()) {
mf = new BRepBuilderAPI_MakeFace(wire);
} else {
mf = new BRepBuilderAPI_MakeFace(face_surface, wire);
}
ShapeFix_Face fix(mf->Face());
fix.FixOrientation();
fix.Perform();
outer_face_bound = fix.Face();
}
// If the wires are reversed the face needs to be reversed as well in order
// to maintain the counter-clock-wise ordering of the bounding wire's vertices.
bool all_reversed = true;
TopoDS_Iterator jt(outer_face_bound, false);
for (; jt.More(); jt.Next()) {
const TopoDS_Wire& w = TopoDS::Wire(jt.Value());
if ((w.Orientation() != TopAbs_REVERSED) == same_sense) {
all_reversed = false;
}
}
if (all_reversed) {
outer_face_bound.Reverse();
}
if (num_outer_bounds > 1) {
builder.Add(compound, outer_face_bound);
delete mf; mf = 0;
} else if (num_bounds > 1) {
// Reinitialize the builder to the outer face
// bound in order to add holes more robustly.
delete mf;
// TODO: What about the face_surface?
mf = new BRepBuilderAPI_MakeFace(outer_face_bound);
} else {
face = outer_face_bound;
success = true;
}
} else {
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary", bound);
delete mf;
return false;
}
} else {
mf->Add(wire);
}
processed ++;
}
}
if (!success) {
success = processed == num_bounds;
if (success) {
if (num_outer_bounds > 1) {
face = compound;
} else {
success = success && mf->IsDone();
if (success) {
face = mf->Face();
}
}
}
}
if (success) {
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(face, getValue(GV_PRECISION), TopAbs_FACE);
}
delete mf;
return success;
}
bool IfcGeom::convert(const IfcSchema::IfcArbitraryClosedProfileDef::ptr l, TopoDS_Shape& face) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, TopoDS_Shape& face) {
TopoDS_Wire wire;
if ( ! IfcGeom::convert_wire(l->OuterCurve(),wire) ) return false;
if ( ! convert_wire(l->OuterCurve(),wire) ) return false;
TopoDS_Face f;
bool success = IfcGeom::convert_wire_to_face(wire, f);
bool success = convert_wire_to_face(wire, f);
if (success) face = f;
return success;
}
bool IfcGeom::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids::ptr l, TopoDS_Shape& face) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids* l, TopoDS_Shape& face) {
TopoDS_Wire profile;
if ( ! IfcGeom::convert_wire(l->OuterCurve(),profile) ) return false;
if ( ! convert_wire(l->OuterCurve(),profile) ) return false;
BRepBuilderAPI_MakeFace mf(profile);
IfcSchema::IfcCurve::list voids = l->InnerCurves();
for( IfcSchema::IfcCurve::it it = voids->begin(); it != voids->end(); ++ it ) {
IfcSchema::IfcCurve::list::ptr voids = l->InnerCurves();
for( IfcSchema::IfcCurve::list::it it = voids->begin(); it != voids->end(); ++ it ) {
TopoDS_Wire hole;
if ( IfcGeom::convert_wire(*it,hole) ) {
if ( convert_wire(*it,hole) ) {
mf.Add(hole);
}
}
@@ -220,52 +326,52 @@ bool IfcGeom::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids::ptr l, T
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcRectangleProfileDef::ptr l, TopoDS_Shape& face) {
const double x = l->XDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleProfileDef* l, TopoDS_Shape& face) {
const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
return false;
}
gp_Trsf2d trsf2d;
IfcGeom::convert(l->Position(),trsf2d);
IfcGeom::Kernel::convert(l->Position(),trsf2d);
double coords[8] = {-x,-y,x,-y,x,y,-x,y};
return IfcGeom::profile_helper(4,coords,0,0,0,trsf2d,face);
return profile_helper(4,coords,0,0,0,trsf2d,face);
}
bool IfcGeom::convert(const IfcSchema::IfcRoundedRectangleProfileDef::ptr l, TopoDS_Shape& face) {
const double x = l->XDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double r = l->RoundingRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef* l, TopoDS_Shape& face) {
const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
const double r = l->RoundingRadius() * getValue(GV_LENGTH_UNIT);
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || r < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
return false;
}
gp_Trsf2d trsf2d;
IfcGeom::convert(l->Position(),trsf2d);
IfcGeom::Kernel::convert(l->Position(),trsf2d);
double coords[8] = {-x,-y, x,-y, x,y, -x,y};
int fillets[4] = {0,1,2,3};
double radii[4] = {r,r,r,r};
return IfcGeom::profile_helper(4,coords,4,fillets,radii,trsf2d,face);
return profile_helper(4,coords,4,fillets,radii,trsf2d,face);
}
bool IfcGeom::convert(const IfcSchema::IfcRectangleHollowProfileDef::ptr l, TopoDS_Shape& face) {
const double x = l->XDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d = l->WallThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l, TopoDS_Shape& face) {
const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d = l->WallThickness() * getValue(GV_LENGTH_UNIT);
const bool fr1 = l->hasInnerFilletRadius();
const bool fr1 = l->hasOuterFilletRadius();
const bool fr2 = l->hasInnerFilletRadius();
const double r1 = fr2 ? l->OuterFilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT) : 0.;
const double r2 = fr1 ? l->InnerFilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT) : 0.;
const double r1 = fr1 ? l->OuterFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.;
const double r2 = fr2 ? l->InnerFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.;
if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
return false;
}
@@ -273,15 +379,15 @@ bool IfcGeom::convert(const IfcSchema::IfcRectangleHollowProfileDef::ptr l, Topo
TopoDS_Face f2;
gp_Trsf2d trsf2d;
IfcGeom::convert(l->Position(),trsf2d);
IfcGeom::Kernel::convert(l->Position(),trsf2d);
double coords1[8] = {-x ,-y, x ,-y, x, y, -x, y };
double coords2[8] = {-x+d,-y+d, x-d,-y+d, x-d,y-d, -x+d,y-d};
double radii1[4] = {r1,r1,r1,r1};
double radii2[4] = {r2,r2,r2,r2};
int fillets[4] = {0,1,2,3};
bool s1 = IfcGeom::profile_helper(4,coords1,fr1 ? 4 : 0,fillets,radii1,trsf2d,f1);
bool s2 = IfcGeom::profile_helper(4,coords2,fr2 ? 4 : 0,fillets,radii2,trsf2d,f2);
bool s1 = profile_helper(4,coords1,fr1 ? 4 : 0,fillets,radii1,trsf2d,f1);
bool s2 = profile_helper(4,coords2,fr2 ? 4 : 0,fillets,radii2,trsf2d,f2);
if (!s1 || !s2) return false;
@@ -300,53 +406,69 @@ bool IfcGeom::convert(const IfcSchema::IfcRectangleHollowProfileDef::ptr l, Topo
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcTrapeziumProfileDef::ptr l, TopoDS_Shape& face) {
const double x1 = l->BottomXDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double w = l->TopXDim() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double dx = l->TopXOffset() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrapeziumProfileDef* l, TopoDS_Shape& face) {
const double x1 = l->BottomXDim() / 2.0f * getValue(GV_LENGTH_UNIT);
const double w = l->TopXDim() * getValue(GV_LENGTH_UNIT);
const double dx = l->TopXOffset() * getValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
if ( x1 < ALMOST_ZERO || w < ALMOST_ZERO || y < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
return false;
}
gp_Trsf2d trsf2d;
IfcGeom::convert(l->Position(),trsf2d);
IfcGeom::Kernel::convert(l->Position(),trsf2d);
double coords[8] = {-x1,-y, x1,-y, dx+w-x1,y, dx-x1,y};
return IfcGeom::profile_helper(4,coords,0,0,0,trsf2d,face);
return profile_helper(4,coords,0,0,0,trsf2d,face);
}
bool IfcGeom::convert(const IfcSchema::IfcIShapeProfileDef::ptr l, TopoDS_Shape& face) {
const double x = l->OverallWidth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->OverallDepth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d2 = l->FlangeThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool doFillet = l->hasFilletRadius();
double f = 0.;
if ( doFillet ) {
f = l->FilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcIShapeProfileDef* l, TopoDS_Shape& face) {
const double x1 = l->OverallWidth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double y = l->OverallDepth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() / 2.0f * getValue(GV_LENGTH_UNIT);
const double dy1 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
bool doFillet1 = l->hasFilletRadius();
double f1 = 0.;
if ( doFillet1 ) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
}
if ( x == 0.0f || y == 0.0f || d1 == 0.0f || d2 == 0.0f ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
bool doFillet2 = doFillet1;
double x2 = x1, dy2 = dy1, f2 = f1;
if (l->declaration().is(IfcSchema::Type::IfcAsymmetricIShapeProfileDef)) {
IfcSchema::IfcAsymmetricIShapeProfileDef* assym = (IfcSchema::IfcAsymmetricIShapeProfileDef*) l;
x2 = assym->TopFlangeWidth() / 2. * getValue(GV_LENGTH_UNIT);
doFillet2 = assym->hasTopFlangeFilletRadius();
if (doFillet2) {
f2 = assym->TopFlangeFilletRadius() * getValue(GV_LENGTH_UNIT);
}
if (assym->hasTopFlangeThickness()) {
dy2 = assym->TopFlangeThickness() * getValue(GV_LENGTH_UNIT);
}
}
if ( x1 < ALMOST_ZERO || x2 < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || dy1 < ALMOST_ZERO || dy2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
return false;
}
gp_Trsf2d trsf2d;
IfcGeom::convert(l->Position(),trsf2d);
convert(l->Position(),trsf2d);
double coords[24] = {-x,-y,x,-y,x,-y+d2,d1,-y+d2,d1,y-d2,x,y-d2,x,y,-x,y,-x,y-d2,-d1,y-d2,-d1,-y+d2,-x,-y+d2};
double coords[24] = {-x1,-y, x1,-y, x1,-y+dy1, d1,-y+dy1, d1,y-dy2, x2,y-dy2, x2,y, -x2,y, -x2,y-dy2, -d1,y-dy2, -d1,-y+dy1, -x1,-y+dy1};
int fillets[4] = {3,4,9,10};
double radii[4] = {f,f,f,f};
return IfcGeom::profile_helper(12,coords,doFillet ? 4 : 0,fillets,radii,trsf2d,face);
double radii[4] = {f1,f1,f2,f2};
return profile_helper(12,coords,(doFillet1||doFillet2) ? 4 : 0,fillets,radii,trsf2d,face);
}
bool IfcGeom::convert(const IfcSchema::IfcZShapeProfileDef::ptr l, TopoDS_Shape& face) {
const double x = l->FlangeWidth() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double y = l->Depth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double dx = l->WebThickness() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double dy = l->FlangeThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcZShapeProfileDef* l, TopoDS_Shape& face) {
const double x = l->FlangeWidth() * getValue(GV_LENGTH_UNIT);
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double dx = l->WebThickness() / 2.0f * getValue(GV_LENGTH_UNIT);
const double dy = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
bool doFillet = l->hasFilletRadius();
bool doEdgeFillet = l->hasEdgeRadius();
@@ -355,74 +477,74 @@ bool IfcGeom::convert(const IfcSchema::IfcZShapeProfileDef::ptr l, TopoDS_Shape&
double f2 = 0.;
if ( doFillet ) {
f1 = l->FilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
}
if ( doEdgeFillet ) {
f2 = l->EdgeRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
}
if ( x == 0.0f || y == 0.0f || dx == 0.0f || dy == 0.0f ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
return false;
}
gp_Trsf2d trsf2d;
IfcGeom::convert(l->Position(),trsf2d);
IfcGeom::Kernel::convert(l->Position(),trsf2d);
double coords[16] = {-dx,-y, x,-y, x,-y+dy, dx,-y+dy, dx,y, -x,y, -x,y-dy, -dx,y-dy};
int fillets[4] = {2,3,6,7};
double radii[4] = {f2,f1,f2,f1};
return IfcGeom::profile_helper(8,coords,(doFillet || doEdgeFillet) ? 4 : 0,fillets,radii,trsf2d,face);
return profile_helper(8,coords,(doFillet || doEdgeFillet) ? 4 : 0,fillets,radii,trsf2d,face);
}
bool IfcGeom::convert(const IfcSchema::IfcCShapeProfileDef::ptr l, TopoDS_Shape& face) {
const double y = l->Depth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double x = l->Width() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d1 = l->WallThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d2 = l->Girth() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCShapeProfileDef* l, TopoDS_Shape& face) {
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double x = l->Width() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d1 = l->WallThickness() * getValue(GV_LENGTH_UNIT);
const double d2 = l->Girth() * getValue(GV_LENGTH_UNIT);
bool doFillet = l->hasInternalFilletRadius();
double f1 = 0;
double f2 = 0;
if ( doFillet ) {
f1 = l->InternalFilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
f1 = l->InternalFilletRadius() * getValue(GV_LENGTH_UNIT);
f2 = f1 + d1;
}
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
return false;
}
gp_Trsf2d trsf2d;
IfcGeom::convert(l->Position(),trsf2d);
IfcGeom::Kernel::convert(l->Position(),trsf2d);
double coords[24] = {-x,-y,x,-y,x,-y+d2,x-d1,-y+d2,x-d1,-y+d1,-x+d1,-y+d1,-x+d1,y-d1,x-d1,y-d1,x-d1,y-d2,x,y-d2,x,y,-x,y};
int fillets[8] = {0,1,4,5,6,7,10,11};
double radii[8] = {f2,f2,f1,f1,f1,f1,f2,f2};
return IfcGeom::profile_helper(12,coords,doFillet ? 8 : 0,fillets,radii,trsf2d,face);
return profile_helper(12,coords,doFillet ? 8 : 0,fillets,radii,trsf2d,face);
}
bool IfcGeom::convert(const IfcSchema::IfcLShapeProfileDef::ptr l, TopoDS_Shape& face) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Shape& face) {
const bool hasSlope = l->hasLegSlope();
const bool doEdgeFillet = l->hasEdgeRadius();
const bool doFillet = l->hasFilletRadius();
const double y = l->Depth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double x = (l->hasWidth() ? l->Width() : l->Depth()) / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d = l->Thickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double slope = hasSlope ? (l->LegSlope() * IfcGeom::GetValue(GV_PLANEANGLE_UNIT)) : 0.;
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double x = (l->hasWidth() ? l->Width() : l->Depth()) / 2.0f * getValue(GV_LENGTH_UNIT);
const double d = l->Thickness() * getValue(GV_LENGTH_UNIT);
const double slope = hasSlope ? (l->LegSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
double f1 = 0.0f;
double f2 = 0.0f;
if (doFillet) {
f1 = l->FilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
}
if ( doEdgeFillet) {
f2 = l->EdgeRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
}
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
return false;
}
@@ -454,7 +576,7 @@ bool IfcGeom::convert(const IfcSchema::IfcLShapeProfileDef::ptr l, TopoDS_Shape&
const double det = a1*b2 - a2*b1;
if (ALMOST_THE_SAME(det, 0.)) {
Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:",l->entity);
Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:", l);
return false;
}
@@ -463,24 +585,24 @@ bool IfcGeom::convert(const IfcSchema::IfcLShapeProfileDef::ptr l, TopoDS_Shape&
}
gp_Trsf2d trsf2d;
IfcGeom::convert(l->Position(),trsf2d);
convert(l->Position(),trsf2d);
double coords[12] = {-x,-y, x,-y, x,-y+d-dy1, xx, xy, -x+d-dx1,y, -x,y};
int fillets[3] = {2,3,4};
double radii[3] = {f2,f1,f2};
return IfcGeom::profile_helper(6,coords,doFillet ? 3 : 0,fillets,radii,trsf2d,face);
return profile_helper(6,coords,doFillet ? 3 : 0,fillets,radii,trsf2d,face);
}
bool IfcGeom::convert(const IfcSchema::IfcUShapeProfileDef::ptr l, TopoDS_Shape& face) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcUShapeProfileDef* l, TopoDS_Shape& face) {
const bool doEdgeFillet = l->hasEdgeRadius();
const bool doFillet = l->hasFilletRadius();
const bool hasSlope = l->hasFlangeSlope();
const double y = l->Depth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double x = l->FlangeWidth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d2 = l->FlangeThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double slope = hasSlope ? (l->FlangeSlope() * IfcGeom::GetValue(GV_PLANEANGLE_UNIT)) : 0.;
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double x = l->FlangeWidth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() * getValue(GV_LENGTH_UNIT);
const double d2 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
const double slope = hasSlope ? (l->FlangeSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
double dy1 = 0.0f;
double dy2 = 0.0f;
@@ -488,10 +610,10 @@ bool IfcGeom::convert(const IfcSchema::IfcUShapeProfileDef::ptr l, TopoDS_Shape&
double f2 = 0.0f;
if (doFillet) {
f1 = l->FilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
}
if (doEdgeFillet) {
f2 = l->EdgeRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
}
if (hasSlope) {
@@ -500,35 +622,35 @@ bool IfcGeom::convert(const IfcSchema::IfcUShapeProfileDef::ptr l, TopoDS_Shape&
}
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
return false;
}
gp_Trsf2d trsf2d;
IfcGeom::convert(l->Position(),trsf2d);
convert(l->Position(),trsf2d);
double coords[16] = {-x,-y, x,-y, x,-y+d2-dy2, -x+d1,-y+d2+dy1, -x+d1,y-d2-dy1, x,y-d2+dy2, x,y, -x,y};
int fillets[4] = {2,3,4,5};
double radii[4] = {f2,f1,f1,f2};
return IfcGeom::profile_helper(8, coords, (doFillet || doEdgeFillet) ? 4 : 0, fillets, radii, trsf2d, face);
return profile_helper(8, coords, (doFillet || doEdgeFillet) ? 4 : 0, fillets, radii, trsf2d, face);
}
bool IfcGeom::convert(const IfcSchema::IfcTShapeProfileDef::ptr l, TopoDS_Shape& face) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Shape& face) {
const bool doFlangeEdgeFillet = l->hasFlangeEdgeRadius();
const bool doWebEdgeFillet = l->hasWebEdgeRadius();
const bool doFillet = l->hasFilletRadius();
const bool hasFlangeSlope = l->hasFlangeSlope();
const bool hasWebSlope = l->hasWebSlope();
const double y = l->Depth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double x = l->FlangeWidth() / 2.0f * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double d2 = l->FlangeThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double flangeSlope = hasFlangeSlope ? (l->FlangeSlope() * IfcGeom::GetValue(GV_PLANEANGLE_UNIT)) : 0.;
const double webSlope = hasWebSlope ? (l->WebSlope() * IfcGeom::GetValue(GV_PLANEANGLE_UNIT)) : 0.;
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double x = l->FlangeWidth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() * getValue(GV_LENGTH_UNIT);
const double d2 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
const double flangeSlope = hasFlangeSlope ? (l->FlangeSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
const double webSlope = hasWebSlope ? (l->WebSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
return false;
}
@@ -541,13 +663,13 @@ bool IfcGeom::convert(const IfcSchema::IfcTShapeProfileDef::ptr l, TopoDS_Shape&
double f3 = 0.0f;
if (doFillet) {
f1 = l->FilletRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
}
if (doWebEdgeFillet) {
f2 = l->WebEdgeRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
f2 = l->WebEdgeRadius() * getValue(GV_LENGTH_UNIT);
}
if (doFlangeEdgeFillet) {
f3 = l->FlangeEdgeRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
f3 = l->FlangeEdgeRadius() * getValue(GV_LENGTH_UNIT);
}
double xx, xy;
@@ -576,7 +698,7 @@ bool IfcGeom::convert(const IfcSchema::IfcTShapeProfileDef::ptr l, TopoDS_Shape&
const double det = a1*b2 - a2*b1;
if (ALMOST_THE_SAME(det, 0.)) {
Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:",l->entity);
Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:", l);
return false;
}
@@ -588,23 +710,23 @@ bool IfcGeom::convert(const IfcSchema::IfcTShapeProfileDef::ptr l, TopoDS_Shape&
}
gp_Trsf2d trsf2d;
IfcGeom::convert(l->Position(),trsf2d);
convert(l->Position(),trsf2d);
double coords[16] = {d1/2.-dx2,-y, xx,xy, x,y-d2+dy2, x,y, -x,y, -x,y-d2+dy2, -xx,xy, -d1/2.+dx2,-y};
int fillets[6] = {0,1,2,5,6,7};
double radii[6] = {f2,f1,f3,f3,f1,f2};
return IfcGeom::profile_helper(8, coords, (doFillet || doWebEdgeFillet || doFlangeEdgeFillet) ? 6 : 0, fillets, radii, trsf2d, face);
return profile_helper(8, coords, (doFillet || doWebEdgeFillet || doFlangeEdgeFillet) ? 6 : 0, fillets, radii, trsf2d, face);
}
bool IfcGeom::convert(const IfcSchema::IfcCircleProfileDef::ptr l, TopoDS_Shape& face) {
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleProfileDef* l, TopoDS_Shape& face) {
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
if ( r == 0.0f ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
return false;
}
gp_Trsf2d trsf;
IfcGeom::convert(l->Position(),trsf);
convert(l->Position(),trsf);
BRepBuilderAPI_MakeWire w;
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
@@ -613,22 +735,22 @@ bool IfcGeom::convert(const IfcSchema::IfcCircleProfileDef::ptr l, TopoDS_Shape&
w.Add(edge);
TopoDS_Face f;
bool success = IfcGeom::convert_wire_to_face(w, f);
bool success = convert_wire_to_face(w, f);
if (success) face = f;
return success;
}
bool IfcGeom::convert(const IfcSchema::IfcCircleHollowProfileDef::ptr l, TopoDS_Shape& face) {
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double t = l->WallThickness() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, TopoDS_Shape& face) {
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
const double t = l->WallThickness() * getValue(GV_LENGTH_UNIT);
if ( r == 0.0f || t == 0.0f ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
return false;
}
gp_Trsf2d trsf;
IfcGeom::convert(l->Position(),trsf);
convert(l->Position(),trsf);
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
BRepBuilderAPI_MakeWire outer;
@@ -647,18 +769,18 @@ bool IfcGeom::convert(const IfcSchema::IfcCircleHollowProfileDef::ptr l, TopoDS_
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcEllipseProfileDef::ptr l, TopoDS_Shape& face) {
double rx = l->SemiAxis1() * IfcGeom::GetValue(GV_LENGTH_UNIT);
double ry = l->SemiAxis2() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipseProfileDef* l, TopoDS_Shape& face) {
double rx = l->SemiAxis1() * getValue(GV_LENGTH_UNIT);
double ry = l->SemiAxis2() * getValue(GV_LENGTH_UNIT);
if ( rx < ALMOST_ZERO || ry < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", l);
return false;
}
const bool rotated = ry > rx;
gp_Trsf2d trsf;
IfcGeom::convert(l->Position(),trsf);
convert(l->Position(),trsf);
gp_Ax2 ax = gp_Ax2();
if (rotated) {
@@ -673,16 +795,16 @@ bool IfcGeom::convert(const IfcSchema::IfcEllipseProfileDef::ptr l, TopoDS_Shape
w.Add(edge);
TopoDS_Face f;
bool success = IfcGeom::convert_wire_to_face(w, f);
bool success = convert_wire_to_face(w, f);
if (success) face = f;
return success;
}
bool IfcGeom::convert(const IfcSchema::IfcCenterLineProfileDef::ptr l, TopoDS_Shape& face) {
const double d = l->Thickness() * IfcGeom::GetValue(GV_LENGTH_UNIT) / 2.;
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCenterLineProfileDef* l, TopoDS_Shape& face) {
const double d = l->Thickness() * getValue(GV_LENGTH_UNIT) / 2.;
TopoDS_Wire wire;
if (!IfcGeom::convert_wire(l->Curve(), wire)) return false;
if (!convert_wire(l->Curve(), wire)) return false;
// BRepOffsetAPI_MakeOffset insists on creating circular arc
// segments for joining the curves that constitute the center
@@ -727,18 +849,18 @@ bool IfcGeom::convert(const IfcSchema::IfcCenterLineProfileDef::ptr l, TopoDS_Sh
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcCompositeProfileDef::ptr l, TopoDS_Shape& face) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeProfileDef* l, TopoDS_Shape& face) {
// BRepBuilderAPI_MakeFace mf;
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
IfcSchema::IfcProfileDef::list profiles = l->Profiles();
bool first = true;
for (IfcSchema::IfcProfileDef::it it = profiles->begin(); it != profiles->end(); ++it) {
IfcSchema::IfcProfileDef::list::ptr profiles = l->Profiles();
//bool first = true;
for (IfcSchema::IfcProfileDef::list::it it = profiles->begin(); it != profiles->end(); ++it) {
TopoDS_Face f;
if (IfcGeom::convert_face(*it, f)) {
if (convert_face(*it, f)) {
builder.Add(compound, f);
/* TopExp_Explorer exp(f, TopAbs_WIRE);
for (; exp.More(); exp.Next()) {
@@ -757,10 +879,10 @@ bool IfcGeom::convert(const IfcSchema::IfcCompositeProfileDef::ptr l, TopoDS_Sha
return !face.IsNull();
}
bool IfcGeom::convert(const IfcSchema::IfcDerivedProfileDef::ptr l, TopoDS_Shape& face) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcDerivedProfileDef* l, TopoDS_Shape& face) {
TopoDS_Face f;
gp_Trsf2d trsf2d;
if (IfcGeom::convert_face(l->ParentProfile(), f) && IfcGeom::convert(l->Operator(), trsf2d)) {
if (convert_face(l->ParentProfile(), f) && IfcGeom::Kernel::convert(l->Operator(), trsf2d)) {
gp_Trsf trsf = trsf2d;
face = TopoDS::Face(BRepBuilderAPI_Transform(f, trsf));
return true;
@@ -768,3 +890,71 @@ bool IfcGeom::convert(const IfcSchema::IfcDerivedProfileDef::ptr l, TopoDS_Shape
return false;
}
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPlane* l, TopoDS_Shape& face) {
gp_Pln pln;
convert(l, pln);
Handle_Geom_Surface surf = new Geom_Plane(pln);
#if OCC_VERSION_HEX < 0x60502
face = BRepBuilderAPI_MakeFace(surf);
#else
face = BRepBuilderAPI_MakeFace(surf, getValue(GV_PRECISION));
#endif
return true;
}
#ifdef USE_IFC4
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineSurfaceWithKnots* l, TopoDS_Shape& face) {
boost::shared_ptr< IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint> > cps = l->ControlPointsList();
std::vector<double> uknots = l->UKnots();
std::vector<double> vknots = l->VKnots();
std::vector<int> umults = l->UMultiplicities();
std::vector<int> vmults = l->VMultiplicities();
TColgp_Array2OfPnt Poles (0, (int)cps->size() - 1, 0, (int)(*cps->begin()).size() - 1);
TColStd_Array1OfReal UKnots(0, (int)uknots.size() - 1);
TColStd_Array1OfReal VKnots(0, (int)vknots.size() - 1);
TColStd_Array1OfInteger UMults(0, (int)umults.size() - 1);
TColStd_Array1OfInteger VMults(0, (int)vmults.size() - 1);
Standard_Integer UDegree = l->UDegree();
Standard_Integer VDegree = l->VDegree();
int i = 0, j;
for (IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint>::outer_it it = cps->begin(); it != cps->end(); ++it, ++i) {
j = 0;
for (IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint>::inner_it jt = (*it).begin(); jt != (*it).end(); ++jt, ++j) {
IfcSchema::IfcCartesianPoint* p = *jt;
gp_Pnt pnt;
if (!convert(p, pnt)) return false;
Poles(i, j) = pnt;
}
}
i = 0;
for (std::vector<double>::const_iterator it = uknots.begin(); it != uknots.end(); ++it, ++i) {
UKnots(i) = *it;
}
i = 0;
for (std::vector<double>::const_iterator it = vknots.begin(); it != vknots.end(); ++it, ++i) {
VKnots(i) = *it;
}
i = 0;
for (std::vector<int>::const_iterator it = umults.begin(); it != umults.end(); ++it, ++i) {
UMults(i) = *it;
}
i = 0;
for (std::vector<int>::const_iterator it = vmults.begin(); it != vmults.end(); ++it, ++i) {
VMults(i) = *it;
}
Handle_Geom_Surface surf = new Geom_BSplineSurface(Poles, UKnots, VKnots, UMults, VMults, UDegree, VDegree);
#if OCC_VERSION_HEX < 0x60502
face = BRepBuilderAPI_MakeFace(surf);
#else
face = BRepBuilderAPI_MakeFace(surf, getValue(GV_PRECISION));
#endif
return true;
}
#endif
File diff suppressed because it is too large Load Diff
+54 -71
View File
@@ -77,29 +77,19 @@
#include "../ifcgeom/IfcGeom.h"
namespace IfcGeom {
namespace Cache {
#include "IfcRegisterCreateCache.h"
}
}
#define IN_CACHE(T,E,t,e) std::map<int,t>::const_iterator it = Cache::T.find(E->entity->id());\
if ( it != Cache::T.end() ) { e = it->second; return true; }
#define CACHE(T,E,e) Cache::T[E->entity->id()] = e;
bool IfcGeom::convert(const IfcSchema::IfcCartesianPoint::ptr l, gp_Pnt& point) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianPoint* l, gp_Pnt& point) {
IN_CACHE(IfcCartesianPoint,l,gp_Pnt,point)
std::vector<double> xyz = l->Coordinates();
point = gp_Pnt(
xyz.size() ? (xyz[0]*IfcGeom::GetValue(GV_LENGTH_UNIT)) : 0.0f,
xyz.size() > 1 ? (xyz[1]*IfcGeom::GetValue(GV_LENGTH_UNIT)) : 0.0f,
xyz.size() > 2 ? (xyz[2]*IfcGeom::GetValue(GV_LENGTH_UNIT)) : 0.0f
xyz.size() ? (xyz[0]*getValue(GV_LENGTH_UNIT)) : 0.0f,
xyz.size() > 1 ? (xyz[1]*getValue(GV_LENGTH_UNIT)) : 0.0f,
xyz.size() > 2 ? (xyz[2]*getValue(GV_LENGTH_UNIT)) : 0.0f
);
CACHE(IfcCartesianPoint,l,point)
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcDirection::ptr l, gp_Dir& dir) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcDirection* l, gp_Dir& dir) {
IN_CACHE(IfcDirection,l,gp_Dir,dir)
std::vector<double> xyz = l->DirectionRatios();
dir = gp_Dir(
@@ -111,22 +101,22 @@ bool IfcGeom::convert(const IfcSchema::IfcDirection::ptr l, gp_Dir& dir) {
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcVector::ptr l, gp_Vec& v) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcVector* l, gp_Vec& v) {
IN_CACHE(IfcVector,l,gp_Vec,v)
gp_Dir d;
IfcGeom::convert(l->Orientation(),d);
v = l->Magnitude() * IfcGeom::GetValue(GV_LENGTH_UNIT) * d;
IfcGeom::Kernel::convert(l->Orientation(),d);
v = l->Magnitude() * getValue(GV_LENGTH_UNIT) * d;
CACHE(IfcVector,l,v)
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcAxis2Placement3D::ptr l, gp_Trsf& trsf) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement3D* l, gp_Trsf& trsf) {
IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf)
gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);gp_Dir refDirection;
IfcGeom::convert(l->Location(),o);
IfcGeom::Kernel::convert(l->Location(),o);
bool hasRef = l->hasRefDirection();
if ( l->hasAxis() ) IfcGeom::convert(l->Axis(),axis);
if ( hasRef ) IfcGeom::convert(l->RefDirection(),refDirection);
if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(),axis);
if ( hasRef ) IfcGeom::Kernel::convert(l->RefDirection(),refDirection);
gp_Ax3 ax3;
if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection);
else ax3 = gp_Ax3(o,axis);
@@ -135,27 +125,26 @@ bool IfcGeom::convert(const IfcSchema::IfcAxis2Placement3D::ptr l, gp_Trsf& trsf
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcAxis1Placement::ptr l, gp_Ax1& ax) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis1Placement* l, gp_Ax1& ax) {
IN_CACHE(IfcAxis1Placement,l,gp_Ax1,ax)
gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);
IfcGeom::convert(l->Location(),o);
if ( l->hasAxis() ) IfcGeom::convert(l->Axis(), axis);
IfcGeom::Kernel::convert(l->Location(),o);
if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(), axis);
ax = gp_Ax1(o, axis);
CACHE(IfcAxis1Placement,l,ax)
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator3D::ptr l, gp_Trsf& trsf) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator3D* l, gp_Trsf& trsf) {
IN_CACHE(IfcCartesianTransformationOperator3D,l,gp_Trsf,trsf)
gp_Pnt origin;
IfcGeom::convert(l->LocalOrigin(),origin);
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
gp_Dir axis1 (1.,0.,0.);
gp_Dir axis2 (0.,1.,0.);
gp_Dir axis3;
if ( l->hasAxis1() ) IfcGeom::convert(l->Axis1(),axis1);
if ( l->hasAxis2() ) IfcGeom::convert(l->Axis2(),axis2);
if ( l->hasAxis3() ) IfcGeom::convert(l->Axis3(),axis3);
else axis3 = axis1.Crossed(axis2);
gp_Dir axis3 (0.,0.,1.);
if ( l->hasAxis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1);
if ( l->hasAxis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2);
if ( l->hasAxis3() ) IfcGeom::Kernel::convert(l->Axis3(),axis3);
gp_Ax3 ax3 (origin,axis3,axis1);
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
trsf.SetTransformation(ax3);
@@ -165,16 +154,16 @@ bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator3D::ptr
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator2D::ptr l, gp_Trsf2d& trsf) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator2D* l, gp_Trsf2d& trsf) {
IN_CACHE(IfcCartesianTransformationOperator2D,l,gp_Trsf2d,trsf)
gp_Pnt origin;
gp_Dir axis1 (1.,0.,0.);
gp_Dir axis2 (0.,1.,0.);
IfcGeom::convert(l->LocalOrigin(),origin);
if ( l->hasAxis1() ) IfcGeom::convert(l->Axis1(),axis1);
if ( l->hasAxis2() ) IfcGeom::convert(l->Axis2(),axis2);
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
if ( l->hasAxis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1);
if ( l->hasAxis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2);
const gp_Pnt2d origin2d(origin.X(), origin.Y());
const gp_Dir2d axis12d(axis1.X(), axis1.Y());
@@ -199,18 +188,17 @@ bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator2D::ptr
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform::ptr l, gp_GTrsf& gtrsf) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* l, gp_GTrsf& gtrsf) {
IN_CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gp_GTrsf,gtrsf)
gp_Trsf trsf;
gp_Pnt origin;
IfcGeom::convert(l->LocalOrigin(),origin);
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
gp_Dir axis1 (1.,0.,0.);
gp_Dir axis2 (0.,1.,0.);
gp_Dir axis3;
if ( l->hasAxis1() ) IfcGeom::convert(l->Axis1(),axis1);
if ( l->hasAxis2() ) IfcGeom::convert(l->Axis2(),axis2);
if ( l->hasAxis3() ) IfcGeom::convert(l->Axis3(),axis3);
else axis3 = axis1.Crossed(axis2);
gp_Dir axis3 (0.,0.,1.);
if ( l->hasAxis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1);
if ( l->hasAxis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2);
if ( l->hasAxis3() ) IfcGeom::Kernel::convert(l->Axis3(),axis3);
gp_Ax3 ax3 (origin,axis3,axis1);
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
trsf.SetTransformation(ax3);
@@ -227,7 +215,7 @@ bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator3DnonUn
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform::ptr l, gp_GTrsf2d& gtrsf) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* l, gp_GTrsf2d& gtrsf) {
IN_CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gp_GTrsf2d,gtrsf)
gp_Trsf2d trsf;
@@ -235,9 +223,9 @@ bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUn
gp_Dir axis1 (1.,0.,0.);
gp_Dir axis2 (0.,1.,0.);
IfcGeom::convert(l->LocalOrigin(),origin);
if ( l->hasAxis1() ) IfcGeom::convert(l->Axis1(),axis1);
if ( l->hasAxis2() ) IfcGeom::convert(l->Axis2(),axis2);
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
if ( l->hasAxis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1);
if ( l->hasAxis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2);
const gp_Pnt2d origin2d(origin.X(), origin.Y());
const gp_Dir2d axis12d(axis1.X(), axis1.Y());
@@ -263,14 +251,14 @@ bool IfcGeom::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUn
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcPlane::ptr pln, gp_Pln& plane) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPlane* pln, gp_Pln& plane) {
IN_CACHE(IfcPlane,pln,gp_Pln,plane)
IfcSchema::IfcAxis2Placement3D::ptr l = pln->Position();
IfcSchema::IfcAxis2Placement3D* l = pln->Position();
gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);gp_Dir refDirection;
IfcGeom::convert(l->Location(),o);
IfcGeom::Kernel::convert(l->Location(),o);
bool hasRef = l->hasRefDirection();
if ( l->hasAxis() ) IfcGeom::convert(l->Axis(),axis);
if ( hasRef ) IfcGeom::convert(l->RefDirection(),refDirection);
if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(),axis);
if ( hasRef ) IfcGeom::Kernel::convert(l->RefDirection(),refDirection);
gp_Ax3 ax3;
if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection);
else ax3 = gp_Ax3(o,axis);
@@ -279,12 +267,12 @@ bool IfcGeom::convert(const IfcSchema::IfcPlane::ptr pln, gp_Pln& plane) {
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcAxis2Placement2D::ptr l, gp_Trsf2d& trsf) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d& trsf) {
IN_CACHE(IfcAxis2Placement2D,l,gp_Trsf2d,trsf)
gp_Pnt P; gp_Dir V (1,0,0);
IfcGeom::convert(l->Location(),P);
IfcGeom::Kernel::convert(l->Location(),P);
if ( l->hasRefDirection() )
IfcGeom::convert(l->RefDirection(),V);
IfcGeom::Kernel::convert(l->RefDirection(),V);
gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()),gp_Dir2d(V.X(),V.Y()));
trsf.SetTransformation(axis,gp_Ax2d());
@@ -292,32 +280,27 @@ bool IfcGeom::convert(const IfcSchema::IfcAxis2Placement2D::ptr l, gp_Trsf2d& tr
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcObjectPlacement::ptr l, gp_Trsf& trsf) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf) {
IN_CACHE(IfcObjectPlacement,l,gp_Trsf,trsf)
if ( ! l->is(IfcSchema::Type::IfcLocalPlacement) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity);
if ( ! l->declaration().is(IfcSchema::Type::IfcLocalPlacement) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l);
return false;
}
IfcSchema::IfcLocalPlacement::ptr current = reinterpret_pointer_cast<IfcSchema::IfcObjectPlacement,IfcSchema::IfcLocalPlacement>(l);
while (1) {
IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l;
for (;;) {
gp_Trsf trsf2;
IfcSchema::IfcAxis2Placement relplacement = current->RelativePlacement();
if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) {
IfcGeom::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2);
IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement();
if ( relplacement->declaration().is(IfcSchema::Type::IfcAxis2Placement3D) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2);
trsf.PreMultiply(trsf2);
}
if ( current->hasPlacementRelTo() ) {
IfcSchema::IfcObjectPlacement::ptr relto = current->PlacementRelTo();
if ( relto->is(IfcSchema::Type::IfcLocalPlacement) )
current = reinterpret_pointer_cast<IfcSchema::IfcObjectPlacement,IfcSchema::IfcLocalPlacement>(current->PlacementRelTo());
IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo();
if ( relto->declaration().is(IfcSchema::Type::IfcLocalPlacement) )
current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo();
else break;
} else break;
}
CACHE(IfcObjectPlacement,l,trsf)
return true;
}
void IfcGeom::Cache::Purge() {
#include "IfcRegisterPurgeCache.h"
IfcGeom::Cache::PurgeShapeCache();
}
+513
View File
@@ -0,0 +1,513 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) *
* and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). *
* *
* IfcGeom::Representation::Triangulation is a class that represents a *
* triangulated IfcShapeRepresentation. *
* Triangulation.verts is a 1 dimensional vector of float defining the *
* cartesian coordinates of the vertices of the triangulated shape in the *
* format of [x1,y1,z1,..,xn,yn,zn] *
* Triangulation.faces is a 1 dimensional vector of int containing the *
* indices of the triangles referencing positions in Triangulation.verts *
* Triangulation.edges is a 1 dimensional vector of int in {0,1} that dictates*
* the visibility of the edges that span the faces in Triangulation.faces *
* *
* IfcGeom::Element represents the actual IfcBuildingElements. *
* IfcGeomObject.name is the GUID of the element *
* IfcGeomObject.type is the datatype of the element e.g. IfcWindow *
* IfcGeomObject.mesh is a pointer to an IfcMesh *
* IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the *
* orientation and translation of the mesh in relation to the world origin *
* *
* IfcGeom::Iterator::initialize() *
* finds the most suitable representation contexts. Returns true iff *
* at least a single representation will process successfully *
* *
* IfcGeom::Iterator::get() *
* returns a pointer to the current IfcGeom::Element *
* *
* IfcGeom::Iterator::next() *
* returns true iff a following entity is available for a successive call to *
* IfcGeom::Iterator::get() *
* *
* IfcGeom::Iterator::progress() *
* returns an int in [0..100] that indicates the overall progress *
* *
********************************************************************************/
#ifndef IFCGEOMITERATOR_H
#define IFCGEOMITERATOR_H
#include <map>
#include <set>
#include <vector>
#include <limits>
#include <algorithm>
#include <boost/algorithm/string.hpp>
#include <gp_Mat.hxx>
#include <gp_Mat2d.hxx>
#include <gp_GTrsf.hxx>
#include <gp_GTrsf2d.hxx>
#include <gp_Trsf.hxx>
#include <gp_Trsf2d.hxx>
#include "../ifcparse/IfcFile.h"
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom/IfcGeomElement.h"
#include "../ifcgeom/IfcGeomMaterial.h"
#include "../ifcgeom/IfcGeomIteratorSettings.h"
#include "../ifcgeom/IfcRepresentationShapeItem.h"
namespace IfcGeom {
template <typename P>
class Iterator {
private:
Kernel kernel;
IteratorSettings settings;
IfcParse::IfcFile* ifc_file;
// A container and iterator for IfcRepresentations
IfcSchema::IfcRepresentation::list::ptr representations;
IfcSchema::IfcRepresentation::list::it representation_iterator;
// The object is fetched beforehand to be sure that get() returns a valid element
TriangulationElement<P>* current_triangulation;
BRepElement<P>* current_shape_model;
SerializedElement<P>* current_serialization;
// A container and iterator for IfcBuildingElements for the current IfcRepresentation referenced by *representation_iterator
IfcSchema::IfcProduct::list::ptr ifcproducts;
IfcSchema::IfcProduct::list::it ifcproduct_iterator;
int done;
int total;
std::string unit_name;
// double?
P unit_magnitude;
void initUnits() {
IfcSchema::IfcProject::list::ptr projects = ifc_file->entitiesByType<IfcSchema::IfcProject>();
if (projects->size() == 1) {
IfcSchema::IfcProject* project = *projects->begin();
std::pair<std::string, double> length_unit = kernel.initializeUnits(project->UnitsInContext());
unit_name = length_unit.first;
unit_magnitude = static_cast<P>(length_unit.second);
}
}
std::set<IfcSchema::Type::Enum> entities_to_include_or_exclude;
bool include_entities_in_processing;
void populate_set(const std::set<std::string>& include_or_ignore) {
entities_to_include_or_exclude.clear();
for (std::set<std::string>::const_iterator it = include_or_ignore.begin(); it != include_or_ignore.end(); ++it) {
const std::string uppercase_type = boost::to_upper_copy(*it);
IfcSchema::Type::Enum ty;
try {
ty = IfcSchema::Type::FromString(uppercase_type);
} catch (const IfcParse::IfcException&) {
std::stringstream ss;
ss << "'" << *it << "' does not name a valid IFC entity";
throw IfcParse::IfcException(ss.str());
}
entities_to_include_or_exclude.insert(ty);
// TODO: Add child classes so that containment in set can be in O(log n)
}
}
public:
bool initialize() {
try {
initUnits();
} catch (...) {}
std::set<std::string> context_types;
if (!settings.exclude_solids_and_surfaces()) {
// Really this should only be 'Model', as per
// the standard 'Design' is deprecated. So,
// just for backwards compatibility:
context_types.insert("model");
context_types.insert("design");
// DDS likes to output 'model view'
context_types.insert("model view");
}
if (settings.include_curves()) {
context_types.insert("plan");
}
double lowest_precision_encountered = std::numeric_limits<double>::infinity();
bool any_precision_encountered = false;
representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
IfcSchema::IfcGeometricRepresentationContext::list::it it;
IfcSchema::IfcGeometricRepresentationSubContext::list::it jt;
IfcSchema::IfcGeometricRepresentationContext::list::ptr contexts =
ifc_file->entitiesByType<IfcSchema::IfcGeometricRepresentationContext>();
IfcSchema::IfcGeometricRepresentationContext::list::ptr filtered_contexts (new IfcSchema::IfcGeometricRepresentationContext::list);
for (it = contexts->begin(); it != contexts->end(); ++it) {
IfcSchema::IfcGeometricRepresentationContext* context = *it;
if (context->declaration().is(IfcSchema::Type::IfcGeometricRepresentationSubContext)) {
// Continue, as the list of subcontexts will be considered
// by the parent's context inverse attributes.
continue;
}
try {
if (context->hasContextType()) {
std::string context_type = context->ContextType();
boost::to_lower(context_type);
if (context_types.find(context_type) != context_types.end()) {
filtered_contexts->push(context);
}
}
} catch (const IfcParse::IfcException&) {}
}
// In case no contexts are identified based on their ContextType, all contexts are
// considered. Note that sub contexts are excluded as they are considered later on.
if (filtered_contexts->size() == 0) {
for (it = contexts->begin(); it != contexts->end(); ++it) {
IfcSchema::IfcGeometricRepresentationContext* context = *it;
if (!context->declaration().is(IfcSchema::Type::IfcGeometricRepresentationSubContext)) {
filtered_contexts->push(context);
}
}
}
for (it = filtered_contexts->begin(); it != filtered_contexts->end(); ++it) {
IfcSchema::IfcGeometricRepresentationContext* context = *it;
representations->push(context->RepresentationsInContext());
try {
if (context->hasPrecision() && context->Precision() < lowest_precision_encountered) {
lowest_precision_encountered = context->Precision();
any_precision_encountered = true;
}
} catch (const IfcParse::IfcException&) {}
IfcSchema::IfcGeometricRepresentationSubContext::list::ptr sub_contexts = context->HasSubContexts();
for (jt = sub_contexts->begin(); jt != sub_contexts->end(); ++jt) {
representations->push((*jt)->RepresentationsInContext());
}
// There is no need for full recursion as the following is governed by the schema:
// WR31: The parent context shall not be another geometric representation sub context.
}
if (any_precision_encountered) {
// Some arbitrary factor that has proven to work better for the models in the set of test files.
lowest_precision_encountered *= 10.;
lowest_precision_encountered *= unit_magnitude;
if (lowest_precision_encountered < 1.e-7) {
Logger::Message(Logger::LOG_WARNING, "Precision lower than 0.0000001 meter not enforced");
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-7);
} else {
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, lowest_precision_encountered);
}
} else {
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-5);
}
if (representations->size() == 0) return false;
representation_iterator = representations->begin();
ifcproducts.reset();
if (!create()) {
return false;
}
done = 0;
total = representations->size();
return true;
}
int progress() {
return 100 * done / total;
}
const std::string& getUnitName() {
return unit_name;
}
const P getUnitMagnitude() {
return unit_magnitude;
}
const std::string getLog() {
return Logger::GetLog();
}
IfcParse::IfcFile* getFile() {
return ifc_file;
}
void includeEntities(const std::set<std::string>& entities) {
populate_set(entities);
include_entities_in_processing = true;
}
void excludeEntities(const std::set<std::string>& entities) {
populate_set(entities);
include_entities_in_processing = false;
}
private:
// Move to the next IfcRepresentation
void _nextShape() {
ifcproducts.reset();
++ representation_iterator;
++ done;
}
BRepElement<P>* create_shape_model_for_next_entity() {
for (;;) {
IfcSchema::IfcRepresentation* representation;
// Have we reached the end of our list of representations?
if ( representation_iterator == representations->end() ) {
representations.reset();
return 0;
}
representation = *representation_iterator;
// Has the list of IfcProducts for this representation been initialized?
if (!ifcproducts) {
IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation();
ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list);
IfcSchema::IfcProduct::list::ptr unfiltered_products(new IfcSchema::IfcProduct::list);
for ( IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it ) {
if ( (*it)->declaration().is(IfcSchema::Type::IfcProductDefinitionShape) ) {
IfcSchema::IfcProductDefinitionShape* pds = (IfcSchema::IfcProductDefinitionShape*)*it;
unfiltered_products->push(pds->ShapeOfProduct());
} else {
// http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm
// IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards.
// It will be changed into an ABSTRACT supertype in future releases of IFC.
// IfcProductRepresentation also lacks the INVERSE relation to IfcProduct
// Let's find the IfcProducts that reference the IfcProductRepresentation anyway
unfiltered_products->push((*it)->data().getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>());
}
// Filter the products based on the set of entities being included or excluded for
// processing. The set is iterated over te able to filter on subtypes.
for ( IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin(); jt != unfiltered_products->end(); ++jt ) {
bool found = false;
for (std::set<IfcSchema::Type::Enum>::const_iterator kt = entities_to_include_or_exclude.begin(); kt != entities_to_include_or_exclude.end(); ++kt) {
if ((*jt)->declaration().is(*kt)) {
found = true;
break;
}
}
if (found == include_entities_in_processing) {
ifcproducts->push(*jt);
}
}
}
// Does this representation have any IfcProducts?
if (!ifcproducts->size()) {
_nextShape();
continue;
}
ifcproduct_iterator = ifcproducts->begin();
}
// Have we reached the end of our list of IfcProducts?
if ( ifcproduct_iterator == ifcproducts->end() ) {
_nextShape();
continue;
}
IfcSchema::IfcProduct* product = *ifcproduct_iterator;
BRepElement<P>* element = kernel.create_brep_for_representation_and_product<P>(settings, representation, product);
if ( !element ) {
_nextShape();
continue;
}
return element;
}
}
public:
bool next() {
// Free all possible representations of the current geometrical entity
delete current_triangulation;
current_triangulation = 0;
delete current_serialization;
current_serialization = 0;
delete current_shape_model;
current_shape_model = 0;
// Increment the iterator over the list of products using the current
// shape representation
if (ifcproducts) {
++ifcproduct_iterator;
}
return create();
}
Element<P>* get() {
// TODO: Test settings and throw
if (current_triangulation) return current_triangulation;
else if (current_serialization) return current_serialization;
else if (current_shape_model) return current_shape_model;
else return 0;
}
const Element<P>* getObject(int id) {
gp_Trsf trsf;
int parent_id = -1;
std::string instance_type, product_name, product_guid;
try {
const IfcUtil::IfcBaseClass* ifc_entity = ifc_file->entityById(id);
instance_type = IfcSchema::Type::ToString(ifc_entity->declaration().type());
if ( ifc_entity->declaration().is(IfcSchema::Type::IfcProduct) ) {
IfcSchema::IfcProduct* ifc_product = (IfcSchema::IfcProduct*)ifc_entity;
product_guid = ifc_product->GlobalId();
product_name = ifc_product->hasName() ? ifc_product->Name() : "";
parent_id = -1;
try {
IfcSchema::IfcObjectDefinition* parent_object = kernel.get_decomposing_entity(ifc_product);
if (parent_object) {
parent_id = parent_object->data().id();
}
} catch (...) {}
try {
kernel.convert(ifc_product->ObjectPlacement(), trsf);
} catch (...) {}
}
} catch(...) {}
ElementSettings element_settings(settings, unit_magnitude, instance_type);
Element<P>* ifc_object = new Element<P>(element_settings, id, parent_id, product_name, instance_type, product_guid, "", trsf);
return ifc_object;
}
bool create() {
try {
current_shape_model = create_shape_model_for_next_entity();
} catch (...) {}
if (!current_shape_model) return false;
if (settings.use_brep_data()) {
try {
current_serialization = new SerializedElement<P>(*current_shape_model);
} catch (...) {}
return !!current_serialization;
} else if (!settings.disable_triangulation()) {
try {
current_triangulation = new TriangulationElement<P>(*current_shape_model);
} catch (...) {}
return !!current_triangulation;
} else {
return true;
}
}
private:
void _initialize() {
current_triangulation = 0;
current_shape_model = 0;
current_serialization = 0;
// Upon initialisation, the (empty) set of entity names,
// should be excluded, or no products would be processed.
include_entities_in_processing = false;
unit_name = "METER";
unit_magnitude = 1.f;
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.sew_shells() ? 1000 : -1);
kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.include_curves() ? (settings.exclude_solids_and_surfaces() ? -1. : 0.) : +1.));
}
bool owns_ifc_file;
public:
Iterator(const IteratorSettings& settings, IfcParse::IfcFile* file)
: settings(settings)
, ifc_file(file)
, owns_ifc_file(false)
{
_initialize();
}
Iterator(const IteratorSettings& settings, const std::string& filename)
: settings(settings)
, ifc_file(new IfcParse::IfcFile)
, owns_ifc_file(true)
{
ifc_file->Init(filename);
_initialize();
}
Iterator(const IteratorSettings& settings, void* data, int length)
: settings(settings)
, ifc_file(new IfcParse::IfcFile)
, owns_ifc_file(true)
{
ifc_file->Init(data, length);
_initialize();
}
Iterator(const IteratorSettings& settings, std::istream& filestream, int length)
: settings(settings)
, ifc_file(new IfcParse::IfcFile)
, owns_ifc_file(true)
{
ifc_file->Init(filestream, length);
_initialize();
}
~Iterator() {
if (owns_ifc_file) {
delete ifc_file;
}
delete current_triangulation;
current_triangulation = 0;
delete current_serialization;
current_serialization = 0;
delete current_shape_model;
current_shape_model = 0;
}
};
}
#endif
+179
View File
@@ -0,0 +1,179 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef IFCGEOMITERATORSETTINGS_H
#define IFCGEOMITERATORSETTINGS_H
#include <string>
#include "../ifcparse/IfcException.h"
namespace IfcGeom {
class IteratorSettings {
public:
// Enumeration of setting identifiers. These settings define the
// behaviour of various aspects of IfcOpenShell.
// Specifies whether vertices are welded, meaning that the coordinates
// vector will only contain unique xyz-triplets. This results in a
// manifold mesh which is useful for modelling applications, but might
// result in unwanted shading artifacts in rendering applications.
static const int WELD_VERTICES = 1;
// Specifies whether to apply the local placements of building elements
// directly to the coordinates of the representation mesh rather than
// to represent the local placement in the 4x3 matrix, which will in that
// case be the identity matrix.
static const int USE_WORLD_COORDS = 2;
// Internally IfcOpenShell measures everything in meters. This settings
// specifies whether to convert IfcGeomObjects back to the units in which
// the geometry in the IFC file is specified.
static const int CONVERT_BACK_UNITS = 3;
// Specifies whether to use the Open Cascade BREP format for representation
// items rather than to create triangle meshes. This is useful is IfcOpenShell
// is used as a library in an application that is also built on Open Cascade.
static const int USE_BREP_DATA = 4;
// Specifies whether to sew IfcConnectedFaceSets (open and closed shells) to
// TopoDS_Shells or whether to keep them as a loose collection of faces.
static const int SEW_SHELLS = 5;
// Specifies whether to compose IfcOpeningElements into a single compound
// in order to speed up the processing of opening subtractions.
static const int FASTER_BOOLEANS = 6;
// Disables the subtraction of IfcOpeningElement representations from
// the related building element representations.
static const int DISABLE_OPENING_SUBTRACTIONS = 8;
// Disables the triangulation of the topological representations. Useful if
// the client application understands Open Cascade's native format.
static const int DISABLE_TRIANGULATION = 9;
// Applies default materials to entity instances without a surface style.
static const int APPLY_DEFAULT_MATERIALS = 10;
// Specifies whether to include subtypes of IfcCurve.
static const int INCLUDE_CURVES = 11;
// Specifies whether to exclude subtypes of IfcSolidModel and IfcSurface.
static const int EXCLUDE_SOLIDS_AND_SURFACES = 12;
// End of settings enumeration.
private:
bool _weld_vertices, _use_world_coords, _convert_back_units, _use_brep_data, _sew_shells, _faster_booleans, _disable_opening_subtractions, _disable_triangulation, _apply_default_materials, _include_curves, _exclude_solids_and_surfaces;
double _deflection_tolerance;
public:
IteratorSettings()
: _weld_vertices(true)
, _use_world_coords(false)
, _convert_back_units(false)
, _use_brep_data(false)
, _sew_shells(false)
, _faster_booleans(false)
, _disable_opening_subtractions(false)
, _disable_triangulation(false)
, _apply_default_materials(false)
, _include_curves(false)
, _exclude_solids_and_surfaces(false)
// TODO: Make deflection tolerance into a command line argument
// For now, stick to one millimeter. Note that this is independent of the IFC length unit.
, _deflection_tolerance(1.e-3)
{}
const bool& weld_vertices() const { return _weld_vertices; }
bool& weld_vertices() { return _weld_vertices; }
const bool& use_world_coords() const { return _use_world_coords; }
bool& use_world_coords() { return _use_world_coords; }
const bool& convert_back_units() const { return _convert_back_units; }
bool& convert_back_units() { return _convert_back_units; }
const bool& use_brep_data() const { return _use_brep_data; }
bool& use_brep_data() { return _use_brep_data; }
const bool& sew_shells() const { return _sew_shells; }
bool& sew_shells() { return _sew_shells; }
const bool& faster_booleans() const { return _faster_booleans; }
bool& faster_booleans() { return _faster_booleans; }
const bool& disable_opening_subtractions() const { return _disable_opening_subtractions; }
bool& disable_opening_subtractions() { return _disable_opening_subtractions; }
const bool& disable_triangulation() const { return _disable_triangulation; }
bool& disable_triangulation() { return _disable_triangulation; }
const bool& apply_default_materials() const { return _apply_default_materials; }
bool& apply_default_materials() { return _apply_default_materials; }
const bool& include_curves() const { return _include_curves; }
bool& include_curves() { return _include_curves; }
const bool& exclude_solids_and_surfaces() const { return _exclude_solids_and_surfaces; }
bool& exclude_solids_and_surfaces() { return _exclude_solids_and_surfaces; }
const double& deflection_tolerance() const { return _deflection_tolerance; }
double& deflection_tolerance() { return _deflection_tolerance; }
void set(int setting, bool value) {
switch (setting) {
case USE_WORLD_COORDS:
_use_world_coords = value;
break;
case WELD_VERTICES:
_weld_vertices = value;
break;
case CONVERT_BACK_UNITS:
_convert_back_units = value;
break;
case USE_BREP_DATA:
_use_brep_data = value;
break;
case FASTER_BOOLEANS:
_faster_booleans = value;
break;
case SEW_SHELLS:
_sew_shells = value;
break;
case DISABLE_OPENING_SUBTRACTIONS:
_disable_opening_subtractions = value;
break;
case DISABLE_TRIANGULATION:
_disable_triangulation = value;
break;
case APPLY_DEFAULT_MATERIALS:
_apply_default_materials = value;
break;
case INCLUDE_CURVES:
_include_curves = value;
break;
case EXCLUDE_SOLIDS_AND_SURFACES:
_exclude_solids_and_surfaces = value;
break;
default: throw IfcParse::IfcException("Invalid IteratorSetting");
}
}
};
class ElementSettings : public IteratorSettings {
private:
double _unit_magnitude;
std::string _element_type;
public:
ElementSettings(const IteratorSettings& settings,
double unit_magnitude,
const std::string& element_type)
: IteratorSettings(settings)
, _unit_magnitude(unit_magnitude)
, _element_type(element_type)
{}
const double& unit_magnitude() const { return _unit_magnitude; }
const std::string& element_type() const { return _element_type; }
};
}
#endif
+34
View File
@@ -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; }
+50
View File
@@ -0,0 +1,50 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef IFCGEOMMATERIAL_H
#define IFCGEOMMATERIAL_H
#include <string>
#include "../ifcgeom/IfcGeomRenderStyles.h"
namespace IfcGeom {
class Material {
private:
const IfcGeom::SurfaceStyle* style;
public:
explicit Material(const IfcGeom::SurfaceStyle* style = 0); // TODO default constructor for vector?
// Material(const Material& other);
// Material& operator=(const Material& other);
bool hasDiffuse() const;
bool hasSpecular() const;
bool hasTransparency() const;
bool hasSpecularity() const;
const double* diffuse() const;
const double* specular() const;
double transparency() const;
double specularity() const;
const std::string name() const;
bool operator==(const Material& other) const;
};
}
#endif
-727
View File
@@ -1,727 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include <map>
#include <stdexcept>
#include <limits>
#include <gp_Mat.hxx>
#include <gp_Mat2d.hxx>
#include <gp_GTrsf.hxx>
#include <gp_GTrsf2d.hxx>
#include <gp_Trsf.hxx>
#include <gp_Trsf2d.hxx>
#include <TopoDS_Compound.hxx>
#include <BRep_Builder.hxx>
#include <BRepTools.hxx>
#include <BRep_Tool.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepMesh.hxx>
#include <Poly_Triangulation.hxx>
#include <Poly_PolygonOnTriangulation.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <TShort_Array1OfShortReal.hxx>
#include <Poly_Array1OfTriangle.hxx>
#include <StdFail_NotDone.hxx>
#include <BRepGProp_Face.hxx>
#include <BRepBuilderAPI_GTransform.hxx>
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcFile.h"
#include "../ifcgeom/IfcGeomObjects.h"
#include "../ifcgeom/IfcGeom.h"
// Welds vertices that belong to different faces
static bool weld_vertices = true;
static bool convert_back_units = false;
static bool use_faster_booleans = false;
static bool disable_subtractions = false;
static bool disable_triangulation = false;
int IfcGeomObjects::IfcRepresentationTriangulation::addvert(int material_index, const gp_XYZ& p) {
const float X = convert_back_units ? (float) (p.X() / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)) : (float)p.X();
const float Y = convert_back_units ? (float) (p.Y() / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)) : (float)p.Y();
const float Z = convert_back_units ? (float) (p.Z() / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)) : (float)p.Z();
int i = (int) _verts.size() / 3;
if ( weld_vertices ) {
const VertKey key = std::make_pair(material_index, std::make_pair(X, std::make_pair(Y, Z)));
VertKeyMap::const_iterator it = welds.find(key);
if ( it != welds.end() ) return it->second;
i = (int) welds.size();
welds[key] = i;
}
_verts.push_back(X);
_verts.push_back(Y);
_verts.push_back(Z);
return i;
}
static bool use_world_coords = false;
static bool use_brep_data = false;
static IfcParse::IfcFile* ifc_file = 0;
IfcGeomObjects::IfcRepresentationBrepData::IfcRepresentationBrepData(const IfcRepresentationShapeModel& shapes)
: _id(shapes.getId())
{
try {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) {
const TopoDS_Shape& s = it->Shape();
gp_GTrsf trsf = it->Placement();
if (convert_back_units) {
gp_Trsf scale;
scale.SetScaleFactor(1.0 / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT));
trsf.PreMultiply(scale);
}
bool trsf_valid = false;
gp_Trsf _trsf;
try {
_trsf = trsf.Trsf();
trsf_valid = true;
} catch (...) {}
const TopoDS_Shape moved_shape = trsf_valid ? s.Moved(_trsf) :
BRepBuilderAPI_GTransform(s,trsf,true).Shape();
builder.Add(compound,moved_shape);
}
std::stringstream sstream;
BRepTools::Write(compound,sstream);
_brep_data = sstream.str();
} catch(...) {
Logger::Message(Logger::LOG_ERROR,"Failed to serialize shape:",ifc_file->EntityById(_id)->entity);
}
}
IfcGeomObjects::IfcRepresentationTriangulation::IfcRepresentationTriangulation(const IfcRepresentationShapeModel& shapes)
: _id(shapes.getId())
{
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) {
int surface_style_id = -1;
if (it->hasStyle()) {
Material adapter(&it->Style());
std::vector<Material>::const_iterator jt = std::find(_materials.begin(), _materials.end(), adapter);
if (jt == _materials.end()) {
surface_style_id = _materials.size();
_materials.push_back(adapter);
} else {
surface_style_id = jt - _materials.begin();
}
}
const TopoDS_Shape& s = it->Shape();
const gp_GTrsf& trsf = it->Placement();
// Triangulate the shape
try {
// BRepTools::Clean(s);
BRepMesh::Mesh(s, IfcGeom::GetValue(IfcGeom::GV_DEFLECTION_TOLERANCE));
} catch(...) {
Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape:",ifc_file->EntityById(_id)->entity);
continue;
}
TopExp_Explorer exp;
// Iterates over the faces of the shape
for ( exp.Init(s,TopAbs_FACE); exp.More(); exp.Next() ) {
TopoDS_Face face = TopoDS::Face(exp.Current());
TopLoc_Location loc;
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face,loc);
if ( ! tri.IsNull() ) {
// A 3x3 matrix to rotate the vertex normals
const gp_Mat rotation_matrix = trsf.VectorialPart();
// Keep track of the number of times an edge is used
// Manifold edges (i.e. edges used twice) are deemed invisible
std::map<std::pair<int,int>,int> edgecount;
std::vector<std::pair<int,int> > edges_temp;
const TColgp_Array1OfPnt& nodes = tri->Nodes();
const TColgp_Array1OfPnt2d& uvs = tri->UVNodes();
std::vector<gp_XYZ> coords;
BRepGProp_Face prop(face);
std::map<int,int> dict;
// Vertex normals are only calculated if vertices are not welded
const bool calculate_normals = ! weld_vertices;
for( int i = 1; i <= nodes.Length(); ++ i ) {
coords.push_back(nodes(i).Transformed(loc).XYZ());
trsf.Transforms(*coords.rbegin());
dict[i] = addvert(surface_style_id, *coords.rbegin());
if ( calculate_normals ) {
const gp_Pnt2d& uv = uvs(i);
gp_Pnt p;
gp_Vec normal_direction;
prop.Normal(uv.X(),uv.Y(),p,normal_direction);
gp_Vec normal(0., 0., 0.);
if (normal_direction.Magnitude() > ALMOST_ZERO) {
normal = gp_Dir(normal_direction.XYZ() * rotation_matrix);
}
_normals.push_back((float)normal.X());
_normals.push_back((float)normal.Y());
_normals.push_back((float)normal.Z());
}
}
const Poly_Array1OfTriangle& triangles = tri->Triangles();
for( int i = 1; i <= triangles.Length(); ++ i ) {
int n1,n2,n3;
if ( face.Orientation() == TopAbs_REVERSED )
triangles(i).Get(n3,n2,n1);
else triangles(i).Get(n1,n2,n3);
/* An alternative would be to calculate normals based
* on the coordinates of the mesh vertices */
/*
const gp_XYZ pt1 = coords[n1-1];
const gp_XYZ pt2 = coords[n2-1];
const gp_XYZ pt3 = coords[n3-1];
const gp_XYZ v1 = pt2-pt1;
const gp_XYZ v2 = pt3-pt2;
gp_Dir normal = gp_Dir(v1^v2);
_normals.push_back((float)normal.X());
_normals.push_back((float)normal.Y());
_normals.push_back((float)normal.Z());
*/
_faces.push_back(dict[n1]);
_faces.push_back(dict[n2]);
_faces.push_back(dict[n3]);
_material_ids.push_back(surface_style_id);
addedge(n1,n2,edgecount,edges_temp);
addedge(n2,n3,edgecount,edges_temp);
addedge(n3,n1,edgecount,edges_temp);
}
for ( std::vector<std::pair<int,int> >::const_iterator it = edges_temp.begin(); it != edges_temp.end(); ++it ) {
_edges.push_back(edgecount[*it]==1);
}
}
}
}
}
IfcGeomObjects::IfcObject::IfcObject(
int id,
int parent_id,
const std::string& name,
const std::string& type,
const std::string& guid,
const gp_Trsf& trsf)
: _id(id)
, _parent_id(parent_id)
, _name(name)
, _type(type)
, _guid(guid)
{
// Convert the gp_Trsf into a 4x3 Matrix
// Note that in case the CONVERT_BACK_UNITS setting is enabled
// the translation component of the matrix needs to be divided
// by the magnitude of the IFC model length unit because
// internally in IfcOpenShell everything is measured in meters.
for(int i = 1; i < 5; ++i) {
for (int j = 1; j < 4; ++j) {
const double trsf_value = trsf.Value(j,i);
const double matrix_value = i == 4 && convert_back_units
? trsf_value / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)
: trsf_value;
_matrix.push_back(static_cast<float>(matrix_value));
}
}
}
IfcGeomObjects::IfcGeomShapeModelObject::IfcGeomShapeModelObject(
int id,
int parent_id,
const std::string& name,
const std::string& type,
const std::string& guid,
const gp_Trsf& trsf,
IfcRepresentationShapeModel* shapes)
: IfcObject(id,parent_id,name,type,guid,trsf)
, _mesh(shapes)
{}
IfcGeomObjects::IfcGeomBrepDataObject::IfcGeomBrepDataObject(
const IfcGeomShapeModelObject& shape_model)
: IfcObject(shape_model)
, _mesh(new IfcRepresentationBrepData(shape_model.mesh()))
{}
IfcGeomObjects::IfcGeomObject::IfcGeomObject(
const IfcGeomShapeModelObject& shape_model)
: IfcObject(shape_model)
, _mesh(new IfcRepresentationTriangulation(shape_model.mesh()))
{}
// A container and iterator for IfcShapeRepresentations
static IfcSchema::IfcShapeRepresentation::list shapereps;
static IfcSchema::IfcShapeRepresentation::it shaperep_iterator;
// The object is fetched beforehand to be positive an entity actually exists
static IfcGeomObjects::IfcGeomObject* current_geom_obj = 0;
static IfcGeomObjects::IfcGeomShapeModelObject* current_shape_model_obj = 0;
static IfcGeomObjects::IfcGeomBrepDataObject* current_brep_data_obj = 0;
// A container and iterator for IfcBuildingElements for the current IfcShapeRepresentation referenced by *shaperep_iterator
static IfcSchema::IfcProduct::list entities;
static IfcSchema::IfcProduct::it ifcproduct_iterator;
static int done;
static int total;
// Move the the next IfcShapeRepresentation
void _nextShape() {
entities.reset();
++ shaperep_iterator;
++ done;
}
int _getParentId(const IfcSchema::IfcProduct::ptr ifc_product) {
int parent_id = -1;
// In case of an opening element, parent to the RelatingBuildingElement
if ( ifc_product->is(IfcSchema::Type::IfcOpeningElement ) ) {
IfcSchema::IfcOpeningElement::ptr opening = reinterpret_pointer_cast<IfcSchema::IfcProduct,IfcSchema::IfcOpeningElement>(ifc_product);
IfcSchema::IfcRelVoidsElement::list voids = opening->VoidsElements();
if ( voids->Size() ) {
IfcSchema::IfcRelVoidsElement::ptr ifc_void = *voids->begin();
parent_id = ifc_void->RelatingBuildingElement()->entity->id();
}
} else if ( ifc_product->is(IfcSchema::Type::IfcElement ) ) {
IfcSchema::IfcElement::ptr element = reinterpret_pointer_cast<IfcSchema::IfcProduct,IfcSchema::IfcElement>(ifc_product);
IfcSchema::IfcRelFillsElement::list fills = element->FillsVoids();
// Incase of a RelatedBuildingElement parent to the opening element
if ( fills->Size() ) {
for ( IfcSchema::IfcRelFillsElement::it it = fills->begin(); it != fills->end(); ++ it ) {
IfcSchema::IfcRelFillsElement::ptr fill = *it;
IfcSchema::IfcObjectDefinition* ifc_objectdef = fill->RelatingOpeningElement();
if ( ifc_product == ifc_objectdef ) continue;
parent_id = ifc_objectdef->entity->id();
}
}
// Else simply parent to the containing structure
if ( parent_id == -1 ) {
IfcSchema::IfcRelContainedInSpatialStructure::list parents = element->ContainedInStructure();
if ( parents->Size() ) {
IfcSchema::IfcRelContainedInSpatialStructure::ptr parent = *parents->begin();
parent_id = parent->RelatingStructure()->entity->id();
}
}
}
// Parent decompositions to the RelatingObject
if ( parent_id == -1 ) {
IfcEntities parents = ifc_product->entity->getInverse(IfcSchema::Type::IfcRelAggregates);
parents->push(ifc_product->entity->getInverse(IfcSchema::Type::IfcRelNests));
for ( IfcEntityList::it it = parents->begin(); it != parents->end(); ++ it ) {
IfcSchema::IfcRelDecomposes::ptr decompose = reinterpret_pointer_cast<IfcUtil::IfcBaseClass,IfcSchema::IfcRelDecomposes>(*it);
IfcSchema::IfcObjectDefinition* ifc_objectdef;
#ifdef USE_IFC4
if (decompose->is(IfcSchema::Type::IfcRelAggregates)) {
ifc_objectdef = ((IfcSchema::IfcRelAggregates*)decompose)->RelatingObject();
} else {
continue;
}
#else
ifc_objectdef = decompose->RelatingObject();
#endif
if ( ifc_product == ifc_objectdef ) continue;
parent_id = ifc_objectdef->entity->id();
}
}
return parent_id;
}
IfcGeomObjects::IfcGeomShapeModelObject* create_shape_model_for_next_entity() {
while ( true ) {
IfcSchema::IfcShapeRepresentation::ptr shaperep;
// Have we reached the end of our list of representations?
if ( shaperep_iterator == shapereps->end() ) {
shapereps.reset();
return 0;
}
shaperep = *shaperep_iterator;
// Has the list of IfcProducts for this representation been initialized?
if ( ! entities ) {
if ( shaperep->hasRepresentationIdentifier() ) {
const std::string representation_identifier = shaperep->RepresentationIdentifier();
if ( shaperep->hasRepresentationType() && representation_identifier == "IAI" && shaperep->RepresentationType() != "BoundingBox" ) {
// Allow for Ifc 2x compatibility
} else if ( representation_identifier != "Body" &&
representation_identifier != "Facetation" ) {
_nextShape();
continue;
}
}
IfcSchema::IfcProductRepresentation::list prodreps = shaperep->OfProductRepresentation();
entities = IfcSchema::IfcProduct::list( new IfcTemplatedEntityList<IfcSchema::IfcProduct>() );
for ( IfcSchema::IfcProductRepresentation::it it = prodreps->begin(); it != prodreps->end(); ++it ) {
if ( (*it)->is(IfcSchema::Type::IfcProductDefinitionShape) ) {
IfcSchema::IfcProductDefinitionShape::ptr pds = reinterpret_pointer_cast<IfcSchema::IfcProductRepresentation,IfcSchema::IfcProductDefinitionShape>(*it);
entities->push(pds->ShapeOfProduct());
} else {
// http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm
// IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards.
// It will be changed into an ABSTRACT supertype in future releases of IFC.
// IfcProductRepresentation also lacks the INVERSE relation to IfcProduct
// Let's find the IfcProducts that reference the IfcProductRepresentation anyway
IfcEntities products = (*it)->entity->getInverse(IfcSchema::Type::IfcProduct);
for ( IfcEntityList::it it = products->begin(); it != products->end(); ++ it ) {
entities->push(reinterpret_pointer_cast<IfcUtil::IfcBaseClass,IfcSchema::IfcProduct>(*it));
}
}
}
// Does this representation have any IfcProducts?
if ( ! entities->Size() ) {
_nextShape();
continue;
}
ifcproduct_iterator = entities->begin();
}
// Have we reached the end of our list of IfcProducts?
if ( ifcproduct_iterator == entities->end() ) {
_nextShape();
continue;
}
IfcGeomObjects::IfcRepresentationShapeModel* shape;
IfcGeom::IfcRepresentationShapeItems shapes;
if ( !IfcGeom::convert_shapes(shaperep,shapes) ) {
_nextShape();
continue;
}
IfcSchema::IfcProduct::ptr ifc_product = *ifcproduct_iterator;
int parent_id = -1;
try {
parent_id = _getParentId(ifc_product);
} catch (...) {}
const std::string name = ifc_product->hasName() ? ifc_product->Name() : "";
const std::string guid = ifc_product->GlobalId();
gp_Trsf trsf;
try {
IfcGeom::convert(ifc_product->ObjectPlacement(),trsf);
} catch (...) {}
// Does the IfcElement have any IfcOpenings?
// Note that openings for IfcOpeningElements are not processed
IfcSchema::IfcRelVoidsElement::list openings = IfcSchema::IfcRelVoidsElement::list();
if ( ifc_product->is(IfcSchema::Type::IfcElement) && !ifc_product->is(IfcSchema::Type::IfcOpeningElement) ) {
IfcSchema::IfcElement::ptr element = reinterpret_pointer_cast<IfcSchema::IfcProduct,IfcSchema::IfcElement>(ifc_product);
openings = element->HasOpenings();
}
// Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements?
if ( ifc_product->is(IfcSchema::Type::IfcBuildingElementPart ) ) {
IfcSchema::IfcBuildingElementPart::ptr part = reinterpret_pointer_cast<IfcSchema::IfcProduct,IfcSchema::IfcBuildingElementPart>(ifc_product);
#ifdef USE_IFC4
IfcSchema::IfcRelAggregates::list decomposes = part->Decomposes();
for ( IfcSchema::IfcRelAggregates::it it = decomposes->begin(); it != decomposes->end(); ++ it ) {
#else
IfcSchema::IfcRelDecomposes::list decomposes = part->Decomposes();
for ( IfcSchema::IfcRelDecomposes::it it = decomposes->begin(); it != decomposes->end(); ++ it ) {
#endif
IfcSchema::IfcObjectDefinition::ptr obdef = (*it)->RelatingObject();
if ( obdef->is(IfcSchema::Type::IfcElement) ) {
IfcSchema::IfcElement::ptr element = reinterpret_pointer_cast<IfcSchema::IfcObjectDefinition,IfcSchema::IfcElement>(obdef);
openings->push(element->HasOpenings());
}
}
}
if ( !disable_subtractions && openings && openings->Size() ) {
IfcGeom::IfcRepresentationShapeItems opened_shapes;
try {
if ( use_faster_booleans ) {
bool succes = IfcGeom::convert_openings_fast(ifc_product,openings,shapes,trsf,opened_shapes);
if ( ! succes ) {
opened_shapes.clear();
IfcGeom::convert_openings(ifc_product,openings,shapes,trsf,opened_shapes);
}
} else {
IfcGeom::convert_openings(ifc_product,openings,shapes,trsf,opened_shapes);
}
} catch(...) {
Logger::Message(Logger::LOG_ERROR,"Error processing openings for:",ifc_product->entity);
}
if ( use_world_coords ) {
for ( IfcGeom::IfcRepresentationShapeItems::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) {
it->prepend(trsf);
}
trsf = gp_Trsf();
}
shape = new IfcGeomObjects::IfcRepresentationShapeModel(shaperep->entity->id(),opened_shapes);
} else if ( use_world_coords ) {
for ( IfcGeom::IfcRepresentationShapeItems::iterator it = shapes.begin(); it != shapes.end(); ++ it ) {
it->prepend(trsf);
}
trsf = gp_Trsf();
shape = new IfcGeomObjects::IfcRepresentationShapeModel(shaperep->entity->id(),shapes);
} else {
shape = new IfcGeomObjects::IfcRepresentationShapeModel(shaperep->entity->id(),shapes);
}
return new IfcGeomObjects::IfcGeomShapeModelObject(ifc_product->entity->id(), parent_id, name,
IfcSchema::Type::ToString(ifc_product->type()), guid, trsf, shape);
}
}
bool try_and_create_representations_for_current_entity() {
current_shape_model_obj = create_shape_model_for_next_entity();
if (current_shape_model_obj == 0) {
return false;
}
if (use_brep_data) {
current_brep_data_obj = new IfcGeomObjects::IfcGeomBrepDataObject(*current_shape_model_obj);
if (current_brep_data_obj == 0) {
return false;
}
}
if (!disable_triangulation) {
current_geom_obj = new IfcGeomObjects::IfcGeomObject(*current_shape_model_obj);
if (current_geom_obj == 0) {
return false;
}
}
return true;
}
bool IfcGeomObjects::Next() {
// Free all possible representations of the current geometrical entity
delete current_geom_obj;
delete current_brep_data_obj;
delete current_shape_model_obj;
current_geom_obj = 0;
current_brep_data_obj = 0;
current_shape_model_obj = 0;
// Increment the iterator over the list of products using the current
// shape representation
if (entities) {
++ifcproduct_iterator;
}
return try_and_create_representations_for_current_entity();
}
static std::vector<IfcGeomObjects::IfcObject*> returned_objects;
bool IfcGeomObjects::CleanUp() {
// TODO: Correctly implement destructor for IfcFile
delete ifc_file;
IfcGeom::Cache::Purge();
std::vector<IfcGeomObjects::IfcObject*>::const_iterator it;
for (it = returned_objects.begin(); it != returned_objects.end(); ++ it ) {
delete *it;
}
returned_objects.clear();
return true;
}
const IfcGeomObjects::IfcObject* IfcGeomObjects::GetObject(int id) {
IfcObject* ifc_object = 0;
try {
const IfcParse::IfcEntity& ifc_entity = ifc_file->EntityById(id);
if ( ifc_entity->is(IfcSchema::Type::IfcProduct) ) {
IfcSchema::IfcProduct::ptr ifc_product = reinterpret_pointer_cast<IfcUtil::IfcBaseClass,IfcSchema::IfcProduct>(ifc_entity);
int parent_id = -1;
try {
parent_id = _getParentId(ifc_product);
} catch (...) {}
const std::string name = ifc_product->hasName() ? ifc_product->Name() : "";
gp_Trsf trsf;
try {
IfcGeom::convert(ifc_product->ObjectPlacement(),trsf);
} catch (...) {}
ifc_object = new IfcObject(ifc_product->entity->id(),parent_id,name,
IfcSchema::Type::ToString(ifc_product->type()),ifc_product->GlobalId(),trsf);
}
} catch(...) {}
if ( !ifc_object ) ifc_object = new IfcObject(-1,-1,"","","",gp_Trsf());
returned_objects.push_back(ifc_object);
return ifc_object;
}
const IfcGeomObjects::IfcGeomObject* IfcGeomObjects::Get() {
if (disable_triangulation) {
throw std::runtime_error("No triangulation available");
}
return current_geom_obj;
}
const IfcGeomObjects::IfcGeomShapeModelObject* IfcGeomObjects::GetShapeModel() {
return current_shape_model_obj;
}
const IfcGeomObjects::IfcGeomBrepDataObject* IfcGeomObjects::GetBrepData() {
if (!use_brep_data) {
throw std::runtime_error("No BRep data available");
}
return current_brep_data_obj;
}
static std::string unit_name = "METER";
static float unit_magnitude = 1.0f;
void IfcGeomObjects::InitUnits() {
IfcSchema::IfcProject::list projects = ifc_file->EntitiesByType<IfcSchema::IfcProject>();
if (projects->Size() == 1) {
double unit_magnitude_double;
IfcGeom::initialize_units_and_precision(*projects->begin(), unit_magnitude_double, unit_name);
unit_magnitude = static_cast<float>(unit_magnitude_double);
}
}
bool IfcGeomObjects::Init(const std::string fn) {
return IfcGeomObjects::Init(fn, 0, 0);
}
bool _Init() {
IfcGeomObjects::InitUnits();
shapereps = ifc_file->EntitiesByType<IfcSchema::IfcShapeRepresentation>();
if ( ! shapereps ) return false;
shaperep_iterator = shapereps->begin();
entities.reset();
if (!try_and_create_representations_for_current_entity()) {
return false;
}
done = 0;
total = shapereps->Size();
return true;
}
bool IfcGeomObjects::Init(const std::string fn, std::ostream* log1, std::ostream* log2) {
Logger::SetOutput(log1,log2);
ifc_file = new IfcParse::IfcFile();
if ( !ifc_file->Init(fn) ) return false;
return _Init();
}
bool IfcGeomObjects::Init(std::istream& f, int len, std::ostream* log1, std::ostream* log2) {
Logger::SetOutput(log1,log2);
ifc_file = new IfcParse::IfcFile();
if ( !ifc_file->Init(f, len) ) return false;
return _Init();
}
bool IfcGeomObjects::Init(void* data, int len) {
Logger::SetOutput(0,0);
ifc_file = new IfcParse::IfcFile();
if ( !ifc_file->Init(data, len) ) return false;
return _Init();
}
void IfcGeomObjects::Settings(int setting, bool value) {
switch ( setting ) {
case USE_WORLD_COORDS:
use_world_coords = value;
break;
case WELD_VERTICES:
weld_vertices = value;
break;
case CONVERT_BACK_UNITS:
convert_back_units = value;
break;
case USE_BREP_DATA:
use_brep_data = value;
break;
case FASTER_BOOLEANS:
use_faster_booleans = value;
break;
case SEW_SHELLS:
IfcGeom::SetValue(IfcGeom::GV_MAX_FACES_TO_SEW,value ? 1000 : -1);
break;
case FORCE_CCW_FACE_ORIENTATION:
IfcGeom::SetValue(IfcGeom::GV_FORCE_CCW_FACE_ORIENTATION,value ? 1 : -1);
break;
case DISABLE_OPENING_SUBTRACTIONS:
disable_subtractions = value;
break;
case DISABLE_TRIANGULATION:
disable_triangulation = value;
break;
}
}
int IfcGeomObjects::Progress() {
return 100 * done / total;
}
const std::string& IfcGeomObjects::GetUnitName() {
return unit_name;
}
const float IfcGeomObjects::GetUnitMagnitude() {
return unit_magnitude;
}
const std::string IfcGeomObjects::GetLog() {
return Logger::GetLog();
}
IfcParse::IfcFile* IfcGeomObjects::GetFile() {
return ifc_file;
}
static double black[3] = {0,0,0};
IfcGeomObjects::Material::Material(const IfcGeom::SurfaceStyle* style) : style(style) {}
bool IfcGeomObjects::Material::hasDiffuse() const { return style->Diffuse(); }
bool IfcGeomObjects::Material::hasSpecular() const { return style->Specular(); }
bool IfcGeomObjects::Material::hasTransparency() const { return style->Transparency(); }
bool IfcGeomObjects::Material::hasSpecularity() const { return style->Specularity(); }
const double* IfcGeomObjects::Material::diffuse() const { if (hasDiffuse()) return &((*style->Diffuse()).R()); else return black; }
const double* IfcGeomObjects::Material::specular() const { if (hasSpecular()) return &((*style->Specular()).R()); else return black; }
double IfcGeomObjects::Material::transparency() const { if (hasTransparency()) return *style->Transparency(); else return 0; }
double IfcGeomObjects::Material::specularity() const { if (hasSpecularity()) return *style->Specularity(); else return 0; }
const std::string IfcGeomObjects::Material::name() const { return style->Name(); }
bool IfcGeomObjects::Material::operator==(const IfcGeomObjects::Material& other) const { return style == other.style; }
int IfcGeomObjects::IfcRepresentationBrepData::id() const { return _id; }
const std::string& IfcGeomObjects::IfcRepresentationBrepData::brep_data() const { return _brep_data; }
int IfcGeomObjects::IfcRepresentationTriangulation::id() const { return _id; }
const std::vector<float>& IfcGeomObjects::IfcRepresentationTriangulation::verts() const { return _verts; }
const std::vector<int>& IfcGeomObjects::IfcRepresentationTriangulation::faces() const { return _faces; }
const std::vector<int>& IfcGeomObjects::IfcRepresentationTriangulation::edges() const { return _edges; }
const std::vector<float>& IfcGeomObjects::IfcRepresentationTriangulation::normals() const { return _normals; }
const std::vector<int>& IfcGeomObjects::IfcRepresentationTriangulation::material_ids() const { return _material_ids; }
const std::vector<IfcGeomObjects::Material>& IfcGeomObjects::IfcRepresentationTriangulation::materials() const { return _materials; }
int IfcGeomObjects::IfcObject::id() const { return _id; }
int IfcGeomObjects::IfcObject::parent_id() const { return _parent_id; }
const std::string& IfcGeomObjects::IfcObject::name() const { return _name; }
const std::string& IfcGeomObjects::IfcObject::type() const { return _type; }
const std::string& IfcGeomObjects::IfcObject::guid() const { return _guid; }
const std::vector<float>& IfcGeomObjects::IfcObject::matrix() const { return _matrix; }
const IfcGeomObjects::IfcRepresentationShapeModel& IfcGeomObjects::IfcGeomShapeModelObject::mesh() const { return *_mesh; }
const IfcGeomObjects::IfcRepresentationTriangulation& IfcGeomObjects::IfcGeomObject::mesh() const { return *_mesh; }
const IfcGeomObjects::IfcRepresentationBrepData& IfcGeomObjects::IfcGeomBrepDataObject::mesh() const { return *_mesh; }
-286
View File
@@ -1,286 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) *
* and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). *
* *
* IfcMesh is a class that represents a triangulated IfcShapeRepresentation. *
* IfcMesh.verts is a 1 dimensional vector of float defining the cartesian *
* coordinates of the vertices of the triangulated shape in the format of *
* [x1,y1,z1,..,xn,yn,zn] *
* IfcMesh.faces is a 1 dimensional vector of int containing the indices of *
* the triangles referencing positions in IfcMesh.verts *
* IfcMesh.edges is a 1 dimensional vector of int in {0,1} that dictates *
* the visibility of the edges that span the faces in IfcMesh.faces *
* *
* IfcGeomObject represents the actual IfcBuildingElements. *
* IfcGeomObject.name is the GUID of the element *
* IfcGeomObject.type is the datatype of the element e.g. IfcWindow *
* IfcGeomObject.mesh is a pointer to an IfcMesh *
* IfcGeomObject.matrix is a 4x3 matrix that defines the orientation and *
* translation of the mesh in relation to the world origin *
* *
* Init(char* fn) parses the IFC file in fn, returns true on succes. *
* *
* Get() returns a pointer to the current IfcGeomObject *
* *
* Next() returns true if there is an entity yet available *
* *
* Progress() returns an int in [0..100] that indicates the overall progress *
* *
********************************************************************************/
#ifndef IFCOBJECTS_H
#define IFCOBJECTS_H
#include <map>
#include <vector>
#include <algorithm>
#include <gp_Mat.hxx>
#include <gp_Mat2d.hxx>
#include <gp_GTrsf.hxx>
#include <gp_GTrsf2d.hxx>
#include <gp_Trsf.hxx>
#include <gp_Trsf2d.hxx>
#include "../ifcparse/IfcParse.h"
#include "../ifcgeom/IfcRepresentationShapeItem.h"
namespace IfcGeomObjects {
// Enumeration of setting identifiers. These settings define the
// behaviour of various aspects of IfcOpenShell.
// Specifies whether vertices are welded, meaning that the coordinates
// vector will only contain unique xyz-triplets. This results in a
// manifold mesh which is useful for modelling applications, but might
// result in unwanted shading artifacts in rendering applications.
const int WELD_VERTICES = 1;
// Specifies whether to apply the local placements of building elements
// directly to the coordinates of the representation mesh rather than
// to represent the local placement in the 4x3 matrix, which will in that
// case be the identity matrix.
const int USE_WORLD_COORDS = 2;
// Internally IfcOpenShell measures everything in meters. This settings
// specifies whether to convert IfcGeomObjects back to the units in which
// the geometry in the IFC file is specified.
const int CONVERT_BACK_UNITS = 3;
// Specifies whether to use the Open Cascade BREP format for representation
// items rather than to create triangle meshes. This is useful is IfcOpenShell
// is used as a library in an application that is also built on Open Cascade.
const int USE_BREP_DATA = 4;
// Specifies whether to sew IfcConnectedFaceSets (open and closed shells) to
// TopoDS_Shells or whether to keep them as a loose collection of faces.
const int SEW_SHELLS = 5;
// Specifies whether to compose IfcOpeningElements into a single compound
// in order to speed up the processing of opening subtractions.
const int FASTER_BOOLEANS = 6;
// By default singular faces have no explicitly defined orientation, to
// force faces to be defined CounterClockWise set this to true.
const int FORCE_CCW_FACE_ORIENTATION = 7;
// Disables the subtraction of IfcOpeningElement representations from
// the related building element representations.
const int DISABLE_OPENING_SUBTRACTIONS = 8;
// Disables the triangulation of the topological representations. Useful if
// the client application understands Open Cascade's native format.
const int DISABLE_TRIANGULATION = 9;
// End of settings enumeration.
// A nested pair of floats and a material index to be able to store an XYZ coordinate in a map.
// TODO: Make this a std::tuple when compilers add support for that.
typedef std::pair<int, std::pair<float,std::pair<float,float> > > VertKey;
typedef std::map<VertKey,int> VertKeyMap;
typedef std::pair<int,int> Edge;
class Material {
private:
const IfcGeom::SurfaceStyle* style;
public:
explicit Material(const IfcGeom::SurfaceStyle* style);
// Material(const Material& other);
// Material& operator=(const Material& other);
bool hasDiffuse() const;
bool hasSpecular() const;
bool hasTransparency() const;
bool hasSpecularity() const;
const double* diffuse() const;
const double* specular() const;
double transparency() const;
double specularity() const;
const std::string name() const;
bool operator==(const Material& other) const;
};
class IfcRepresentationShapeModel {
private:
unsigned int id;
const IfcGeom::IfcRepresentationShapeItems shapes;
IfcRepresentationShapeModel(const IfcRepresentationShapeModel& other);
IfcRepresentationShapeModel& operator=(const IfcRepresentationShapeModel& other);
public:
IfcRepresentationShapeModel(unsigned int id, const IfcGeom::IfcRepresentationShapeItems& shapes)
: id(id)
, shapes(shapes)
{}
virtual ~IfcRepresentationShapeModel() {}
IfcGeom::IfcRepresentationShapeItems::const_iterator begin() const { return shapes.begin(); }
IfcGeom::IfcRepresentationShapeItems::const_iterator end() const { return shapes.end(); }
const unsigned int& getId() const { return id; }
};
class IfcRepresentationBrepData {
private:
int _id;
std::string _brep_data;
public:
int id() const;
const std::string& brep_data() const;
IfcRepresentationBrepData(const IfcRepresentationShapeModel& s);
virtual ~IfcRepresentationBrepData() {}
private:
IfcRepresentationBrepData();
IfcRepresentationBrepData(const IfcRepresentationBrepData&);
IfcRepresentationBrepData& operator=(const IfcRepresentationBrepData&);
};
class IfcRepresentationTriangulation {
private:
int _id;
std::vector<float> _verts;
std::vector<int> _faces;
std::vector<int> _edges;
std::vector<float> _normals;
std::vector<int> _material_ids;
std::vector<Material> _materials;
VertKeyMap welds;
public:
int id() const;
const std::vector<float>& verts() const;
const std::vector<int>& faces() const;
const std::vector<int>& edges() const;
const std::vector<float>& normals() const;
const std::vector<int>& material_ids() const;
const std::vector<Material>& materials() const;
IfcRepresentationTriangulation(const IfcRepresentationShapeModel& s);
virtual ~IfcRepresentationTriangulation() {}
private:
int addvert(int material_index, const gp_XYZ& p);
inline void addedge(int n1, int n2, std::map<std::pair<int,int>,int>& edgecount, std::vector<std::pair<int,int> >& edges_temp) {
const Edge e = Edge( (std::min)(n1,n2),(std::max)(n1,n2) );
if ( edgecount.find(e) == edgecount.end() ) edgecount[e] = 1;
else edgecount[e] ++;
edges_temp.push_back(e);
}
IfcRepresentationTriangulation();
IfcRepresentationTriangulation(const IfcRepresentationTriangulation&);
IfcRepresentationTriangulation& operator=(const IfcRepresentationTriangulation&);
};
class IfcObject {
private:
int _id;
int _parent_id;
std::string _name;
std::string _type;
std::string _guid;
std::vector<float> _matrix;
public:
int id() const;
int parent_id() const;
const std::string& name() const;
const std::string& type() const;
const std::string& guid() const;
const std::vector<float>& matrix() const;
IfcObject(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf);
virtual ~IfcObject() {}
};
class IfcGeomShapeModelObject : public IfcObject {
private:
IfcRepresentationShapeModel* _mesh;
public:
const IfcRepresentationShapeModel& mesh() const;
IfcGeomShapeModelObject(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf, IfcRepresentationShapeModel* mesh);
virtual ~IfcGeomShapeModelObject() {
delete _mesh;
}
private:
IfcGeomShapeModelObject(const IfcGeomShapeModelObject& other);
IfcGeomShapeModelObject& operator=(const IfcGeomShapeModelObject& other);
};
class IfcGeomObject : public IfcObject {
private:
IfcRepresentationTriangulation* _mesh;
public:
const IfcRepresentationTriangulation& mesh() const;
IfcGeomObject(const IfcGeomShapeModelObject& shape_model);
virtual ~IfcGeomObject() {
delete _mesh;
}
private:
IfcGeomObject(const IfcGeomObject& other);
IfcGeomObject& operator=(const IfcGeomObject& other);
};
class IfcGeomBrepDataObject : public IfcObject {
private:
IfcRepresentationBrepData* _mesh;
public:
const IfcRepresentationBrepData& mesh() const;
IfcGeomBrepDataObject(const IfcGeomShapeModelObject& shape_model);
virtual ~IfcGeomBrepDataObject() {
delete _mesh;
}
private:
IfcGeomBrepDataObject(const IfcGeomBrepDataObject& other);
IfcGeomBrepDataObject& operator=(const IfcGeomBrepDataObject& other);
};
bool Init(const std::string fn);
bool Init(void* data, int len);
bool Init(const std::string fn, std::ostream* log1= 0, std::ostream* log2= 0);
bool Init(std::istream& f, int len, std::ostream* log1= 0, std::ostream* log2= 0);
void Settings(int setting, bool value);
void InitUnits();
void InitPrecision();
const IfcGeomObject* Get();
const IfcObject* GetObject(int id);
const IfcGeomBrepDataObject* GetBrepData();
const IfcGeomShapeModelObject* GetShapeModel();
bool Next();
int Progress();
const std::string& GetUnitName();
const float GetUnitMagnitude();
const std::string GetLog();
IfcParse::IfcFile* GetFile();
bool CleanUp();
}
#endif
+30 -29
View File
@@ -19,18 +19,9 @@
#include <map>
#include "IfcGeomRenderStyles.h"
#include "IfcGeom.h"
namespace IfcGeom {
namespace Cache {
std::map<int,SurfaceStyle> Style;
void PurgeStyleCache() {
Style.clear();
}
}
}
bool process_colour(IfcSchema::IfcColourRgb* colour, std::tr1::array<double, 3>& rgb) {
bool process_colour(IfcSchema::IfcColourRgb* colour, double* rgb) {
if (colour != 0) {
rgb[0] = colour->Red();
rgb[1] = colour->Green();
@@ -39,34 +30,34 @@ bool process_colour(IfcSchema::IfcColourRgb* colour, std::tr1::array<double, 3>&
return colour != 0;
}
bool process_colour(IfcUtil::IfcBaseEntity* factor, std::tr1::array<double, 3>& rgb) {
bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, double* rgb) {
if (factor != 0) {
const double f = *factor->entity->getArgument(0);
const double f = *factor;
rgb[0] = rgb[1] = rgb[2] = f;
}
return factor != 0;
}
bool process_colour(IfcSchema::IfcColourOrFactor colour_or_factor, std::tr1::array<double, 3>& rgb) {
bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, double* rgb) {
if (colour_or_factor == 0) {
return false;
} else if (colour_or_factor->is(IfcSchema::Type::IfcColourRgb)) {
} else if (colour_or_factor->declaration().is(IfcSchema::Type::IfcColourRgb)) {
return process_colour(static_cast<IfcSchema::IfcColourRgb*>(colour_or_factor), rgb);
} else if (colour_or_factor->is(IfcSchema::Type::IfcNormalisedRatioMeasure)) {
return process_colour(static_cast<IfcUtil::IfcBaseEntity*>(colour_or_factor), rgb);
} else if (colour_or_factor->declaration().is(IfcSchema::Type::IfcNormalisedRatioMeasure)) {
return process_colour(static_cast<IfcSchema::IfcNormalisedRatioMeasure*>(colour_or_factor), rgb);
} else {
return false;
}
}
const IfcGeom::SurfaceStyle* IfcGeom::get_style(IfcSchema::IfcRepresentationItem* item) {
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepresentationItem* item) {
std::pair<IfcSchema::IfcSurfaceStyle*, IfcSchema::IfcSurfaceStyleShading*> shading_styles = get_surface_style<IfcSchema::IfcSurfaceStyleShading>(item);
if (shading_styles.second == 0) {
return 0;
}
int surface_style_id = shading_styles.first->entity->id();
std::map<int,SurfaceStyle>::const_iterator it = Cache::Style.find(surface_style_id);
if (it != Cache::Style.end()) {
int surface_style_id = shading_styles.first->data().id();
std::map<int,SurfaceStyle>::const_iterator it = cache.Style.find(surface_style_id);
if (it != cache.Style.end()) {
return &(it->second);
}
SurfaceStyle surface_style;
@@ -75,11 +66,11 @@ const IfcGeom::SurfaceStyle* IfcGeom::get_style(IfcSchema::IfcRepresentationItem
} else {
surface_style = SurfaceStyle(surface_style_id);
}
std::tr1::array<double, 3> rgb;
double rgb[3];
if (process_colour(shading_styles.second->SurfaceColour(), rgb)) {
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
}
if (shading_styles.second->is(IfcSchema::Type::IfcSurfaceStyleRendering)) {
if (shading_styles.second->declaration().is(IfcSchema::Type::IfcSurfaceStyleRendering)) {
IfcSchema::IfcSurfaceStyleRendering* rendering_style = static_cast<IfcSchema::IfcSurfaceStyleRendering*>(shading_styles.second);
if (rendering_style->hasDiffuseColour() && process_colour(rendering_style->DiffuseColour(), rgb)) {
SurfaceStyle::ColorComponent diffuse = surface_style.Diffuse().get_value_or(SurfaceStyle::ColorComponent(1,1,1));
@@ -95,7 +86,15 @@ const IfcGeom::SurfaceStyle* IfcGeom::get_style(IfcSchema::IfcRepresentationItem
surface_style.Specular().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
}
if (rendering_style->hasSpecularHighlight()) {
// Not supported
IfcSchema::IfcSpecularHighlightSelect* highlight = rendering_style->SpecularHighlight();
if (highlight->declaration().is(IfcSchema::Type::IfcSpecularRoughness)) {
double roughness = *((IfcSchema::IfcSpecularRoughness*)highlight);
if (roughness >= 1e-9) {
surface_style.Specularity().reset(1.0 / roughness);
}
} else if (highlight->declaration().is(IfcSchema::Type::IfcSpecularExponent)) {
surface_style.Specularity().reset(*((IfcSchema::IfcSpecularExponent*)highlight));
}
}
if (rendering_style->hasTransmissionColour()) {
// Not supported
@@ -105,7 +104,7 @@ const IfcGeom::SurfaceStyle* IfcGeom::get_style(IfcSchema::IfcRepresentationItem
surface_style.Transparency().reset(d);
}
}
return &(Cache::Style[surface_style_id] = surface_style);
return &(cache.Style[surface_style_id] = surface_style);
}
static std::map<std::string, IfcGeom::SurfaceStyle> default_materials;
@@ -153,9 +152,11 @@ void InitDefaultMaterials() {
const IfcGeom::SurfaceStyle* IfcGeom::get_default_style(const std::string& s) {
if (!default_materials_initialized) InitDefaultMaterials();
std::map<std::string, IfcGeom::SurfaceStyle>::const_iterator it = default_materials.find(s);
if (it == default_materials.end()) return &default_material;
else {
const IfcGeom::SurfaceStyle& surface_style = it->second;
return &surface_style;
if (it == default_materials.end()) {
default_materials.insert(std::make_pair(s, IfcGeom::SurfaceStyle(s)));
default_materials[s].Diffuse().reset(*default_material.Diffuse());
it = default_materials.find(s);
}
const IfcGeom::SurfaceStyle& surface_style = it->second;
return &surface_style;
}
+18 -70
View File
@@ -20,12 +20,6 @@
#ifndef IFCGEOMRENDERSTYLES_H
#define IFCGEOMRENDERSTYLES_H
#ifdef __GNUC__
#include <tr1/array>
#else
#include <array>
#endif
#ifdef USE_IFC4
#include "../ifcparse/Ifc4.h"
#else
@@ -37,7 +31,7 @@ namespace IfcGeom {
public:
class ColorComponent {
private:
std::tr1::array<double, 3> data;
double data[3];
public:
ColorComponent(double r, double g, double b) {
data[0] = r; data[1] = g; data[2] = b;
@@ -56,10 +50,23 @@ namespace IfcGeom {
boost::optional<double> transparency;
boost::optional<double> specularity;
public:
SurfaceStyle() {}
SurfaceStyle(int id) : id(id) {}
SurfaceStyle() {
this->name = "surface-style";
}
SurfaceStyle(int id) : id(id) {
std::stringstream sstr;
sstr << "surface-style-" << id;
this->name = sstr.str();
}
SurfaceStyle(const std::string& name) : name(name) {}
SurfaceStyle(int id, const std::string& name) : id(id), name(name) {}
SurfaceStyle(int id, const std::string& name) : id(id) {
std::stringstream sstr;
std::string sanitized = name;
std::transform(sanitized.begin(), sanitized.end(), sanitized.begin(), ::tolower);
std::replace(sanitized.begin(), sanitized.end(), ' ', '-');
sstr << "surface-style-" << id << "-" << sanitized;
this->name = sstr.str();
}
// Not used at this point. In fact, equality testing in the current
// architecture can just as easily be accomplished by comparing the
@@ -75,21 +82,7 @@ namespace IfcGeom {
}
}
const std::string Name() const {
if (name && id) {
std::stringstream sstr;
sstr << (*id) << "_" << (*name);
return sstr.str();
} else if (name) {
return *name;
} else if (id) {
std::stringstream sstr;
sstr << "IfcSurfaceStyleShading_" << (*id);
return sstr.str();
} else {
return "IfcSurfaceStyleShading";
}
}
const std::string& Name() const { return *name; }
const boost::optional<ColorComponent>& Diffuse() const { return diffuse; }
const boost::optional<ColorComponent>& Specular() const { return specular; }
@@ -101,52 +94,7 @@ namespace IfcGeom {
boost::optional<double>& Specularity() { return specularity; }
};
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> get_surface_style(IfcSchema::IfcRepresentationItem* representation_item) {
IfcSchema::IfcStyledItem::list styled_items = representation_item->StyledByItem();
for (IfcSchema::IfcStyledItem::it jt = styled_items->begin(); jt != styled_items->end(); ++jt) {
#ifdef USE_IFC4
IfcUtil::IfcAbstractSelect::list style_assignments = (*jt)->Styles();
for (IfcUtil::IfcAbstractSelect::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
if (!(*kt)->is(IfcSchema::Type::IfcPresentationStyleAssignment)) {
continue;
}
IfcSchema::IfcPresentationStyleAssignment::ptr style_assignment = (IfcSchema::IfcPresentationStyleAssignment::ptr) *kt;
#else
IfcSchema::IfcPresentationStyleAssignment::list style_assignments = (*jt)->Styles();
for (IfcSchema::IfcPresentationStyleAssignment::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
IfcSchema::IfcPresentationStyleAssignment::ptr style_assignment = *kt;
#endif
IfcUtil::IfcAbstractSelect::list styles = style_assignment->Styles();
for (IfcUtil::IfcAbstractSelect::it lt = styles->begin(); lt != styles->end(); ++lt) {
IfcUtil::IfcAbstractSelect::ptr style = *lt;
if (style->is(IfcSchema::Type::IfcSurfaceStyle)) {
IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style;
if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) {
IfcUtil::IfcAbstractSelect::list styles_elements = surface_style->Styles();
for (IfcUtil::IfcAbstractSelect::it mt = styles_elements->begin(); mt != styles_elements->end(); ++mt) {
if ((*mt)->is(T::Class())) {
return std::make_pair(surface_style, (T*) *mt);
}
}
}
}
}
}
// StyledByItem is a SET [0:1] OF IfcStyledItem, so we
// break after encountering the first IfcStyledItem
break;
}
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0,0);
}
const SurfaceStyle* get_style(IfcSchema::IfcRepresentationItem* representation_item);
const SurfaceStyle* get_default_style(const std::string& ifc_type);
namespace Cache {
void PurgeStyleCache();
}
}
#endif
+59
View File
@@ -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();
}
+309
View File
@@ -0,0 +1,309 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef IFCGEOMREPRESENTATION_H
#define IFCGEOMREPRESENTATION_H
#include <BRepMesh_IncrementalMesh.hxx>
#include <BRepGProp_Face.hxx>
#include <Poly_Triangulation.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <GCPnts_QuasiUniformDeflection.hxx>
#include "../ifcgeom/IfcGeomIteratorSettings.h"
#include "../ifcgeom/IfcGeomMaterial.h"
#include "../ifcgeom/IfcRepresentationShapeItem.h"
namespace IfcGeom {
namespace Representation {
class Representation {
Representation(const Representation&); //N/A
Representation& operator =(const Representation&); //N/A
protected:
const ElementSettings _settings;
public:
explicit Representation(const ElementSettings& settings)
: _settings(settings)
{}
const ElementSettings& settings() const { return _settings; }
virtual ~Representation() {}
};
class BRep : public Representation {
private:
unsigned int id;
const IfcGeom::IfcRepresentationShapeItems _shapes;
BRep(const BRep& other);
BRep& operator=(const BRep& other);
public:
BRep(const ElementSettings& settings, unsigned int id, const IfcGeom::IfcRepresentationShapeItems& shapes)
: Representation(settings)
, id(id)
, _shapes(shapes)
{}
virtual ~BRep() {}
IfcGeom::IfcRepresentationShapeItems::const_iterator begin() const { return _shapes.begin(); }
IfcGeom::IfcRepresentationShapeItems::const_iterator end() const { return _shapes.end(); }
const IfcGeom::IfcRepresentationShapeItems& shapes() const { return _shapes; }
const unsigned int& getId() const { return id; }
};
class Serialization : public Representation {
private:
int _id;
std::string _brep_data;
public:
int id() const { return _id; }
const std::string& brep_data() const { return _brep_data; }
Serialization(const BRep& brep);
virtual ~Serialization() {}
private:
Serialization();
Serialization(const Serialization&);
Serialization& operator=(const Serialization&);
};
template <typename P>
class Triangulation : public Representation {
private:
// A nested pair of floats and a material index to be able to store an XYZ coordinate in a map.
// TODO: Make this a std::tuple when compilers add support for that.
typedef typename std::pair<P, std::pair<P, P> > Coordinate;
typedef typename std::pair<int, Coordinate> VertexKey;
typedef std::map<VertexKey, int> VertexKeyMap;
typedef std::pair<int, int> Edge;
int _id;
std::vector<P> _verts;
std::vector<int> _faces;
std::vector<int> _edges;
std::vector<P> _normals;
std::vector<int> _material_ids;
std::vector<Material> _materials;
VertexKeyMap welds;
public:
int id() const { return _id; }
const std::vector<P>& verts() const { return _verts; }
const std::vector<int>& faces() const { return _faces; }
const std::vector<int>& edges() const { return _edges; }
const std::vector<P>& normals() const { return _normals; }
const std::vector<int>& material_ids() const { return _material_ids; }
const std::vector<Material>& materials() const { return _materials; }
Triangulation(const BRep& shape_model)
: Representation(shape_model.settings())
, _id(shape_model.getId())
{
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++ iit ) {
int surface_style_id = -1;
if (iit->hasStyle()) {
Material adapter(&iit->Style());
std::vector<Material>::const_iterator jt = std::find(_materials.begin(), _materials.end(), adapter);
if (jt == _materials.end()) {
surface_style_id = (int)_materials.size();
_materials.push_back(adapter);
} else {
surface_style_id = (int)(jt - _materials.begin());
}
}
if (settings().apply_default_materials() && surface_style_id == -1) {
Material material(IfcGeom::get_default_style(settings().element_type()));
std::vector<Material>::const_iterator mit = std::find(_materials.begin(), _materials.end(), material);
if (mit == _materials.end()) {
surface_style_id = (int)_materials.size();
_materials.push_back(material);
} else {
surface_style_id = (int)(mit - _materials.begin());
}
}
const TopoDS_Shape& s = iit->Shape();
const gp_GTrsf& trsf = iit->Placement();
// Triangulate the shape
try {
BRepMesh_IncrementalMesh(s, settings().deflection_tolerance());
} catch(...) {
// TODO: Catch outside
Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape");
continue;
}
// Iterates over the faces of the shape
int num_faces = 0;
TopExp_Explorer exp;
for ( exp.Init(s,TopAbs_FACE); exp.More(); exp.Next(), ++num_faces ) {
TopoDS_Face face = TopoDS::Face(exp.Current());
TopLoc_Location loc;
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face,loc);
if ( ! tri.IsNull() ) {
// A 3x3 matrix to rotate the vertex normals
const gp_Mat rotation_matrix = trsf.VectorialPart();
// Keep track of the number of times an edge is used
// Manifold edges (i.e. edges used twice) are deemed invisible
std::map<std::pair<int,int>,int> edgecount;
std::vector<std::pair<int,int> > edges_temp;
const TColgp_Array1OfPnt& nodes = tri->Nodes();
const TColgp_Array1OfPnt2d& uvs = tri->UVNodes();
std::vector<gp_XYZ> coords;
BRepGProp_Face prop(face);
std::map<int,int> dict;
// Vertex normals are only calculated if vertices are not welded
const bool calculate_normals = !settings().weld_vertices();
for( int i = 1; i <= nodes.Length(); ++ i ) {
coords.push_back(nodes(i).Transformed(loc).XYZ());
trsf.Transforms(*coords.rbegin());
dict[i] = addVertex(surface_style_id, *coords.rbegin());
if ( calculate_normals ) {
const gp_Pnt2d& uv = uvs(i);
gp_Pnt p;
gp_Vec normal_direction;
prop.Normal(uv.X(),uv.Y(),p,normal_direction);
gp_Vec normal(0., 0., 0.);
if (normal_direction.Magnitude() > ALMOST_ZERO) {
normal = gp_Dir(normal_direction.XYZ() * rotation_matrix);
}
_normals.push_back(static_cast<P>(normal.X()));
_normals.push_back(static_cast<P>(normal.Y()));
_normals.push_back(static_cast<P>(normal.Z()));
}
}
const Poly_Array1OfTriangle& triangles = tri->Triangles();
for( int i = 1; i <= triangles.Length(); ++ i ) {
int n1,n2,n3;
if ( face.Orientation() == TopAbs_REVERSED )
triangles(i).Get(n3,n2,n1);
else triangles(i).Get(n1,n2,n3);
/* An alternative would be to calculate normals based
* on the coordinates of the mesh vertices */
/*
const gp_XYZ pt1 = coords[n1-1];
const gp_XYZ pt2 = coords[n2-1];
const gp_XYZ pt3 = coords[n3-1];
const gp_XYZ v1 = pt2-pt1;
const gp_XYZ v2 = pt3-pt2;
gp_Dir normal = gp_Dir(v1^v2);
_normals.push_back((float)normal.X());
_normals.push_back((float)normal.Y());
_normals.push_back((float)normal.Z());
*/
_faces.push_back(dict[n1]);
_faces.push_back(dict[n2]);
_faces.push_back(dict[n3]);
_material_ids.push_back(surface_style_id);
addEdge(dict[n1], dict[n2], edgecount, edges_temp);
addEdge(dict[n2], dict[n3], edgecount, edges_temp);
addEdge(dict[n3], dict[n1], edgecount, edges_temp);
}
for ( std::vector<std::pair<int,int> >::const_iterator jt = edges_temp.begin(); jt != edges_temp.end(); ++jt ) {
if (edgecount[*jt] == 1) {
// non manifold edge, face boundary
_edges.push_back(jt->first);
_edges.push_back(jt->second);
}
}
}
}
if (num_faces == 0) {
// Edges are only emitted if there are no faces. A mixed representation of faces
// and loose edges is discouraged by the standard. An alternative would be to use
// TopExp::MapShapesAndAncestors() to find edges that do not belong to any face.
for (TopExp_Explorer texp(s, TopAbs_EDGE); texp.More(); texp.Next()) {
BRepAdaptor_Curve crv(TopoDS::Edge(texp.Current()));
GCPnts_QuasiUniformDeflection tessellater(crv, settings().deflection_tolerance());
int n = tessellater.NbPoints();
int start = (int)_verts.size() / 3;
for (int i = 1; i <= n; ++i) {
gp_XYZ p = tessellater.Value(i).XYZ();
trsf.Transforms(p);
_material_ids.push_back(surface_style_id);
_verts.push_back(static_cast<P>(p.X()));
_verts.push_back(static_cast<P>(p.Y()));
_verts.push_back(static_cast<P>(p.Z()));
if (i > 1) {
_edges.push_back(start + i - 2);
_edges.push_back(start + i - 1);
}
}
}
}
}
}
virtual ~Triangulation() {}
private:
// Welds vertices that belong to different faces
int addVertex(int material_index, const gp_XYZ& p) {
const P X = static_cast<P>(settings().convert_back_units() ? (p.X() / settings().unit_magnitude()) : p.X());
const P Y = static_cast<P>(settings().convert_back_units() ? (p.Y() / settings().unit_magnitude()) : p.Y());
const P Z = static_cast<P>(settings().convert_back_units() ? (p.Z() / settings().unit_magnitude()) : p.Z());
int i = (int) _verts.size() / 3;
if (settings().weld_vertices()) {
const VertexKey key = std::make_pair(material_index, std::make_pair(X, std::make_pair(Y, Z)));
typename VertexKeyMap::const_iterator it = welds.find(key);
if ( it != welds.end() ) return it->second;
i = (int) welds.size();
welds[key] = i;
}
_verts.push_back(X);
_verts.push_back(Y);
_verts.push_back(Z);
return i;
}
inline void addEdge(int n1, int n2, std::map<std::pair<int,int>,int>& edgecount, std::vector<std::pair<int,int> >& edges_temp) {
const Edge e = Edge( (std::min)(n1,n2),(std::max)(n1,n2) );
if ( edgecount.find(e) == edgecount.end() ) edgecount[e] = 1;
else edgecount[e] ++;
edges_temp.push_back(e);
}
Triangulation();
Triangulation(const Triangulation&);
Triangulation& operator=(const Triangulation&);
};
}
}
#endif
+38
View File
@@ -0,0 +1,38 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef IFCGEOMSHAPETYPE_H
#define IFCGEOMSHAPETYPE_H
namespace IfcGeom {
enum ShapeType {
ST_SHAPELIST,
ST_SHAPE,
ST_FACE,
ST_WIRE,
ST_CURVE,
ST_EDGE,
ST_VERTEX,
ST_OTHER
};
}
#endif
+453 -183
View File
@@ -65,6 +65,8 @@
#include <TopoDS.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_CompSolid.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepPrimAPI_MakePrism.hxx>
@@ -74,6 +76,7 @@
#include <BRepPrimAPI_MakeCylinder.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <BRepPrimAPI_MakeWedge.hxx>
#include <BRepBuilderAPI_MakePolygon.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepBuilderAPI_MakeShell.hxx>
@@ -91,35 +94,71 @@
#include <TopLoc_Location.hxx>
#include <BRepCheck_Analyzer.hxx>
#include <BRepClass3d_SolidClassifier.hxx>
#include <Standard_Version.hxx>
#include "../ifcgeom/IfcGeom.h"
bool IfcGeom::convert(const IfcSchema::IfcExtrudedAreaSolid::ptr l, TopoDS_Shape& shape) {
TopoDS_Face face;
if ( ! IfcGeom::convert_face(l->SweptArea(),face) ) return false;
const double height = l->Depth() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_Shape& shape) {
const double height = l->Depth() * getValue(GV_LENGTH_UNIT);
if (height < getValue(GV_PRECISION)) {
Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l);
return false;
}
TopoDS_Shape face;
if ( !convert_face(l->SweptArea(),face) ) return false;
gp_Trsf trsf;
IfcGeom::convert(l->Position(),trsf);
IfcGeom::Kernel::convert(l->Position(),trsf);
gp_Dir dir;
convert(l->ExtrudedDirection(),dir);
shape = BRepPrimAPI_MakePrism(face,height*dir);
shape.Nullify();
if (face.ShapeType() == TopAbs_COMPOUND) {
// For compounds (most likely the result of a IfcCompositeProfileDef)
// create a compound solid shape.
TopExp_Explorer exp(face, TopAbs_FACE);
TopoDS_CompSolid compound;
BRep_Builder builder;
builder.MakeCompSolid(compound);
int num_faces_extruded = 0;
for (; exp.More(); exp.Next(), ++num_faces_extruded) {
builder.Add(compound, BRepPrimAPI_MakePrism(exp.Current(), height*dir));
}
if (num_faces_extruded) {
shape = compound;
}
}
if (shape.IsNull()) {
shape = BRepPrimAPI_MakePrism(face, height*dir);
}
shape.Move(trsf);
return ! shape.IsNull();
}
bool IfcGeom::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion::ptr l, TopoDS_Shape& shape) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion* l, TopoDS_Shape& shape) {
TopoDS_Wire wire;
if ( !IfcGeom::convert_wire(l->SweptCurve(), wire) ) {
if ( !convert_wire(l->SweptCurve(), wire) ) {
TopoDS_Face face;
if ( !IfcGeom::convert_face(l->SweptCurve(),face) ) return false;
if ( !convert_face(l->SweptCurve(),face) ) return false;
TopExp_Explorer exp(face, TopAbs_WIRE);
wire = TopoDS::Wire(exp.Current());
}
const double height = l->Depth() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double height = l->Depth() * getValue(GV_LENGTH_UNIT);
gp_Trsf trsf;
IfcGeom::convert(l->Position(),trsf);
IfcGeom::Kernel::convert(l->Position(),trsf);
gp_Dir dir;
convert(l->ExtrudedDirection(),dir);
@@ -129,20 +168,20 @@ bool IfcGeom::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion::ptr l, TopoD
return !shape.IsNull();
}
bool IfcGeom::convert(const IfcSchema::IfcSurfaceOfRevolution::ptr l, TopoDS_Shape& shape) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfRevolution* l, TopoDS_Shape& shape) {
TopoDS_Wire wire;
if ( !IfcGeom::convert_wire(l->SweptCurve(), wire) ) {
if ( !convert_wire(l->SweptCurve(), wire) ) {
TopoDS_Face face;
if ( !IfcGeom::convert_face(l->SweptCurve(),face) ) return false;
if ( !convert_face(l->SweptCurve(),face) ) return false;
TopExp_Explorer exp(face, TopAbs_WIRE);
wire = TopoDS::Wire(exp.Current());
}
gp_Ax1 ax1;
IfcGeom::convert(l->AxisPosition(), ax1);
IfcGeom::Kernel::convert(l->AxisPosition(), ax1);
gp_Trsf trsf;
IfcGeom::convert(l->Position(),trsf);
IfcGeom::Kernel::convert(l->Position(),trsf);
shape = BRepPrimAPI_MakeRevol(wire, ax1);
@@ -150,17 +189,17 @@ bool IfcGeom::convert(const IfcSchema::IfcSurfaceOfRevolution::ptr l, TopoDS_Sha
return !shape.IsNull();
}
bool IfcGeom::convert(const IfcSchema::IfcRevolvedAreaSolid::ptr l, TopoDS_Shape& shape) {
const double ang = l->Angle() * IfcGeom::GetValue(GV_PLANEANGLE_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRevolvedAreaSolid* l, TopoDS_Shape& shape) {
const double ang = l->Angle() * getValue(GV_PLANEANGLE_UNIT);
TopoDS_Face face;
if ( ! IfcGeom::convert_face(l->SweptArea(),face) ) return false;
if ( ! convert_face(l->SweptArea(),face) ) return false;
gp_Ax1 ax1;
IfcGeom::convert(l->Axis(), ax1);
IfcGeom::Kernel::convert(l->Axis(), ax1);
gp_Trsf trsf;
IfcGeom::convert(l->Position(),trsf);
IfcGeom::Kernel::convert(l->Position(),trsf);
if (ang >= M_PI * 2. - ALMOST_ZERO) {
shape = BRepPrimAPI_MakeRevol(face, ax1);
@@ -172,10 +211,10 @@ bool IfcGeom::convert(const IfcSchema::IfcRevolvedAreaSolid::ptr l, TopoDS_Shape
return !shape.IsNull();
}
bool IfcGeom::convert(const IfcSchema::IfcFacetedBrep::ptr l, IfcRepresentationShapeItems& shape) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFacetedBrep* l, IfcRepresentationShapeItems& shape) {
TopoDS_Shape s;
const SurfaceStyle* collective_style = get_style(l);
if (IfcGeom::convert_shape(l->Outer(),s) ) {
if (convert_shape(l->Outer(),s) ) {
const SurfaceStyle* indiv_style = get_style(l->Outer());
shape.push_back(IfcRepresentationShapeItem(s, indiv_style ? indiv_style : collective_style));
return true;
@@ -183,39 +222,49 @@ bool IfcGeom::convert(const IfcSchema::IfcFacetedBrep::ptr l, IfcRepresentationS
return false;
}
bool IfcGeom::convert(const IfcSchema::IfcFaceBasedSurfaceModel::ptr l, IfcRepresentationShapeItems& shapes) {
IfcSchema::IfcConnectedFaceSet::list facesets = l->FbsmFaces();
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFaceBasedSurfaceModel* l, IfcRepresentationShapeItems& shapes) {
IfcSchema::IfcConnectedFaceSet::list::ptr facesets = l->FbsmFaces();
const SurfaceStyle* collective_style = get_style(l);
for( IfcSchema::IfcConnectedFaceSet::it it = facesets->begin(); it != facesets->end(); ++ it ) {
for( IfcSchema::IfcConnectedFaceSet::list::it it = facesets->begin(); it != facesets->end(); ++ it ) {
TopoDS_Shape s;
const SurfaceStyle* shell_style = get_style(*it);
if (IfcGeom::convert_shape(*it,s)) {
if (convert_shape(*it,s)) {
shapes.push_back(IfcRepresentationShapeItem(s, shell_style ? shell_style : collective_style));
}
}
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcHalfSpaceSolid::ptr l, TopoDS_Shape& shape) {
IfcSchema::IfcSurface::ptr surface = l->BaseSurface();
if ( ! surface->is(IfcSchema::Type::IfcPlane) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface->entity);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, TopoDS_Shape& shape) {
IfcSchema::IfcSurface* surface = l->BaseSurface();
if ( ! surface->declaration().is(IfcSchema::Type::IfcPlane) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface);
return false;
}
gp_Pln pln;
IfcGeom::convert(reinterpret_pointer_cast<IfcSchema::IfcSurface,IfcSchema::IfcPlane>(surface),pln);
IfcGeom::Kernel::convert((IfcSchema::IfcPlane*)surface,pln);
const gp_Pnt pnt = pln.Location().Translated( l->AgreementFlag() ? -pln.Axis().Direction() : pln.Axis().Direction());
shape = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln),pnt).Solid();
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace::ptr l, TopoDS_Shape& shape) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l, TopoDS_Shape& shape) {
TopoDS_Shape halfspace;
if ( ! IfcGeom::convert(reinterpret_pointer_cast<IfcSchema::IfcPolygonalBoundedHalfSpace,IfcSchema::IfcHalfSpaceSolid>(l),halfspace) ) return false;
if ( ! IfcGeom::Kernel::convert((IfcSchema::IfcHalfSpaceSolid*)l,halfspace) ) return false;
TopoDS_Wire wire;
if ( ! IfcGeom::convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false;
if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false;
gp_Trsf trsf;
convert(l->Position(),trsf);
if ( ! convert(l->Position(),trsf) ) return false;
TColgp_SequenceOfPnt points;
if (wire_to_sequence_of_point(wire, points)) {
remove_duplicate_points_from_loop(points, wire.Closed()); // Note: wire always closed, as per if statement above
remove_collinear_points_from_loop(points, wire.Closed());
sequence_of_point_to_wire(points, wire, wire.Closed());
}
TopoDS_Shape prism = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,200));
gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-100.0));
prism.Move(trsf*down);
@@ -223,60 +272,117 @@ bool IfcGeom::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace::ptr l, Topo
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcShellBasedSurfaceModel::ptr l, IfcRepresentationShapeItems& shapes) {
IfcUtil::IfcAbstractSelect::list shells = l->SbsmBoundary();
bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, IfcRepresentationShapeItems& shapes) {
IfcEntityList::ptr shells = l->SbsmBoundary();
const SurfaceStyle* collective_style = get_style(l);
for( IfcUtil::IfcAbstractSelect::it it = shells->begin(); it != shells->end(); ++ it ) {
for( IfcEntityList::it it = shells->begin(); it != shells->end(); ++ it ) {
TopoDS_Shape s;
const SurfaceStyle* shell_style = 0;
if ((*it)->is(IfcSchema::Type::IfcRepresentationItem)) {
if ((*it)->declaration().is(IfcSchema::Type::IfcRepresentationItem)) {
shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it);
}
if (IfcGeom::convert_shape(*it,s)) {
if (convert_shape(*it,s)) {
shapes.push_back(IfcRepresentationShapeItem(s, shell_style ? shell_style : collective_style));
}
}
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcBooleanResult::ptr l, TopoDS_Shape& shape) {
TopoDS_Shape s1, s2;
TopoDS_Wire boundary_wire;
IfcSchema::IfcBooleanOperand operand1 = l->FirstOperand();
IfcSchema::IfcBooleanOperand operand2 = l->SecondOperand();
bool is_halfspace = operand2->is(IfcSchema::Type::IfcHalfSpaceSolid);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) {
if ( ! IfcGeom::convert_shape(operand1,s1) )
TopoDS_Shape s1, s2;
IfcRepresentationShapeItems items1, items2;
TopoDS_Wire boundary_wire;
IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand();
IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand();
bool is_halfspace = operand2->declaration().is(IfcSchema::Type::IfcHalfSpaceSolid);
if ( shape_type(operand1) == ST_SHAPELIST ) {
if (!(convert_shapes(operand1, items1) && flatten_shape_list(items1, s1, true))) {
return false;
}
} else if ( shape_type(operand1) == ST_SHAPE ) {
if ( ! convert_shape(operand1, s1) ) {
return false;
}
{ TopoDS_Solid temp_solid;
s1 = ensure_fit_for_subtraction(s1, temp_solid); }
} else {
Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", operand1);
return false;
}
const double first_operand_volume = shape_volume(s1);
if ( first_operand_volume <= ALMOST_ZERO )
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand()->entity);
Logger::Message(Logger::LOG_WARNING, "Empty solid for:", l->FirstOperand());
if ( !IfcGeom::convert_shape(l->SecondOperand(),s2) ) {
bool shape2_processed = false;
if ( shape_type(operand2) == ST_SHAPELIST ) {
shape2_processed = convert_shapes(operand2, items2) && flatten_shape_list(items2, s2, true);
} else if ( shape_type(operand2) == ST_SHAPE ) {
shape2_processed = convert_shape(operand2,s2);
if (shape2_processed && !is_halfspace) {
TopoDS_Solid temp_solid;
s2 = ensure_fit_for_subtraction(s2, temp_solid);
}
} else {
Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", operand2);
}
if (!shape2_processed) {
shape = s1;
Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l->entity);
Logger::Message(Logger::LOG_ERROR, "Failed to convert SecondOperand of:", l);
return true;
}
if ( ! is_halfspace ) {
if (!is_halfspace) {
const double second_operand_volume = shape_volume(s2);
if ( second_operand_volume <= ALMOST_ZERO )
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2->entity);
Logger::Message(Logger::LOG_WARNING, "Empty solid for:", operand2);
}
const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator();
/*
// TK: A little debugging trick to output both operands for visual inspection
BRep_Builder builder;
TopoDS_Compound compound;
builder.MakeCompound(compound);
builder.Add(compound, s1);
builder.Add(compound, s2);
shape = compound;
return true;
*/
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
bool valid_cut = false;
BRepAlgoAPI_Cut brep_cut(s1,s2);
#if OCC_VERSION_HEX < 0x60900
BRepAlgoAPI_Cut brep_cut(s1, s2);
#else
BRepAlgoAPI_Cut brep_cut;
TopTools_ListOfShape s1s;
s1s.Append(s1);
TopTools_ListOfShape s2s;
s2s.Append(s2);
brep_cut.SetFuzzyValue(getValue(GV_PRECISION));
brep_cut.SetArguments(s1s);
brep_cut.SetTools(s2s);
brep_cut.Build();
#endif
if ( brep_cut.IsDone() ) {
TopoDS_Shape result = brep_cut;
ShapeFix_Shape fix(result);
fix.Perform();
result = fix.Shape();
try {
fix.Perform();
result = fix.Shape();
} catch (...) {
Logger::Message(Logger::LOG_WARNING, "Shape healing failed on boolean result", l);
}
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if ( is_valid ) {
@@ -288,9 +394,9 @@ bool IfcGeom::convert(const IfcSchema::IfcBooleanResult::ptr l, TopoDS_Shape& sh
if ( valid_cut ) {
const double volume_after_subtraction = shape_volume(shape);
if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) )
Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",l->entity);
Logger::Message(Logger::LOG_WARNING, "Subtraction yields unchanged volume:", l);
} else {
Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",l->entity);
Logger::Message(Logger::LOG_ERROR, "Failed to process subtraction:", l);
shape = s1;
}
@@ -309,10 +415,9 @@ bool IfcGeom::convert(const IfcSchema::IfcBooleanResult::ptr l, TopoDS_Shape& sh
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if ( is_valid ) {
shape = result;
return true;
}
}
return true;
}
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) {
@@ -327,53 +432,74 @@ bool IfcGeom::convert(const IfcSchema::IfcBooleanResult::ptr l, TopoDS_Shape& sh
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if ( is_valid ) {
shape = result;
return true;
}
}
return true;
} else {
return false;
}
return false;
}
bool IfcGeom::convert(const IfcSchema::IfcConnectedFaceSet::ptr l, TopoDS_Shape& shape) {
IfcSchema::IfcFace::list faces = l->CfsFaces();
bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Shape& shape) {
IfcSchema::IfcFace::list::ptr faces = l->CfsFaces();
bool facesAdded = false;
const unsigned int num_faces = faces->Size();
if ( num_faces < GetValue(GV_MAX_FACES_TO_SEW) ) {
const unsigned int num_faces = (unsigned)faces->size();
bool valid_shell = false;
if ( num_faces < getValue(GV_MAX_FACES_TO_SEW) ) {
BRepOffsetAPI_Sewing builder;
builder.SetTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMaxTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMinTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
for( IfcSchema::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) {
builder.SetTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMaxTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMinTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
for( IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++ it ) {
TopoDS_Face face;
if ( IfcGeom::convert_face(*it,face) && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) {
bool converted_face = false;
try {
converted_face = convert_face(*it,face);
} catch (...) {}
if ( converted_face && face_area(face) > getValue(GV_MINIMAL_FACE_AREA) ) {
builder.Add(face);
facesAdded = true;
} else {
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
Logger::Message(Logger::LOG_WARNING, "Invalid face:", *it);
}
}
if ( ! facesAdded ) return false;
builder.Perform();
shape = builder.SewedShape();
try {
ShapeFix_Solid solid;
solid.LimitTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
shape = solid.SolidFromShell(TopoDS::Shell(shape));
builder.Perform();
shape = builder.SewedShape();
valid_shell = BRepCheck_Analyzer(shape).IsValid();
} catch(...) {}
} else {
if (valid_shell) {
try {
ShapeFix_Solid solid;
solid.LimitTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
TopoDS_Solid solid_shape = solid.SolidFromShell(TopoDS::Shell(shape));
if (!solid_shape.IsNull()) {
try {
BRepClass3d_SolidClassifier classifier(solid_shape);
shape = solid_shape;
} catch (...) {}
}
} catch(...) {}
} else {
Logger::Message(Logger::LOG_WARNING, "Failed to sew faceset:", l);
}
}
if (!valid_shell) {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
for( IfcSchema::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) {
for( IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++ it ) {
TopoDS_Face face;
if ( IfcGeom::convert_face(*it,face) && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) {
bool converted_face = false;
try {
converted_face = convert_face(*it,face);
} catch (...) {}
if ( converted_face && face_area(face) > getValue(GV_MINIMAL_FACE_AREA) ) {
builder.Add(compound,face);
facesAdded = true;
} else {
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
Logger::Message(Logger::LOG_WARNING, "Invalid face:", *it);
}
}
if ( ! facesAdded ) return false;
@@ -382,162 +508,185 @@ bool IfcGeom::convert(const IfcSchema::IfcConnectedFaceSet::ptr l, TopoDS_Shape&
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcMappedItem::ptr l, IfcRepresentationShapeItems& shapes) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentationShapeItems& shapes) {
gp_GTrsf gtrsf;
IfcSchema::IfcCartesianTransformationOperator::ptr transform = l->MappingTarget();
if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) {
IfcGeom::convert(reinterpret_pointer_cast<IfcSchema::IfcCartesianTransformationOperator,
IfcSchema::IfcCartesianTransformationOperator3DnonUniform>(transform),gtrsf);
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity);
IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget();
if ( transform->declaration().is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf);
} else if ( transform->declaration().is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform);
return false;
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) {
} else if ( transform->declaration().is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) {
gp_Trsf trsf;
IfcGeom::convert(reinterpret_pointer_cast<IfcSchema::IfcCartesianTransformationOperator,
IfcSchema::IfcCartesianTransformationOperator3D>(transform),trsf);
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf);
gtrsf = trsf;
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) {
} else if ( transform->declaration().is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) {
gp_Trsf2d trsf_2d;
IfcGeom::convert(reinterpret_pointer_cast<IfcSchema::IfcCartesianTransformationOperator,
IfcSchema::IfcCartesianTransformationOperator2D>(transform),trsf_2d);
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,trsf_2d);
gtrsf = (gp_Trsf) trsf_2d;
}
IfcSchema::IfcRepresentationMap::ptr map = l->MappingSource();
IfcSchema::IfcAxis2Placement placement = map->MappingOrigin();
IfcSchema::IfcRepresentationMap* map = l->MappingSource();
IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin();
gp_Trsf trsf;
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
IfcGeom::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
if (placement->declaration().is(IfcSchema::Type::IfcAxis2Placement3D)) {
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
} else {
gp_Trsf2d trsf_2d;
IfcGeom::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf_2d);
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf_2d);
trsf = trsf_2d;
}
gtrsf.Multiply(trsf);
const IfcGeom::SurfaceStyle* mapped_item_style = get_style(l);
const unsigned int previous_size = (const unsigned int) shapes.size();
bool b = IfcGeom::convert_shapes(map->MappedRepresentation(),shapes);
bool b = convert_shapes(map->MappedRepresentation(), shapes);
for ( unsigned int i = previous_size; i < shapes.size(); ++ i ) {
shapes[i].append(gtrsf);
// Apply styles assigned to the mapped item only if on
// a more granular level no styles have been applied
if (!shapes[i].hasStyle()) {
shapes[i].setStyle(mapped_item_style);
}
}
return b;
}
bool IfcGeom::convert(const IfcSchema::IfcShapeRepresentation::ptr l, IfcRepresentationShapeItems& shapes) {
IfcSchema::IfcRepresentationItem::list items = l->Items();
if ( ! items->Size() ) return false;
for ( IfcSchema::IfcRepresentationItem::it it = items->begin(); it != items->end(); ++ it ) {
IfcSchema::IfcRepresentationItem* representation_item = *it;
if ( IfcGeom::is_shape_collection(representation_item) ) IfcGeom::convert_shapes(*it,shapes);
else {
TopoDS_Shape s;
if (IfcGeom::convert_shape(representation_item,s)) {
shapes.push_back(IfcRepresentationShapeItem(s, get_style(representation_item)));
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRepresentation* l, IfcRepresentationShapeItems& shapes) {
IfcSchema::IfcRepresentationItem::list::ptr items = l->Items();
bool part_succes = false;
if ( items->size() ) {
for ( IfcSchema::IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++ it ) {
IfcSchema::IfcRepresentationItem* representation_item = *it;
if ( shape_type(representation_item) == ST_SHAPELIST ) {
part_succes |= convert_shapes(*it, shapes);
} else {
TopoDS_Shape s;
if (convert_shape(representation_item,s)) {
shapes.push_back(IfcRepresentationShapeItem(s, get_style(representation_item)));
part_succes |= true;
}
}
}
}
return true;
return part_succes;
}
bool IfcGeom::convert(const IfcSchema::IfcGeometricSet::ptr l, IfcRepresentationShapeItems& shapes) {
IfcUtil::IfcAbstractSelect::list elements = l->Elements();
if ( !elements->Size() ) return false;
bool IfcGeom::Kernel::convert(const IfcSchema::IfcGeometricSet* l, IfcRepresentationShapeItems& shapes) {
IfcEntityList::ptr elements = l->Elements();
if ( !elements->size() ) return false;
bool part_succes = false;
const IfcGeom::SurfaceStyle* parent_style = get_style(l);
for ( IfcUtil::IfcAbstractSelect::it it = elements->begin(); it != elements->end(); ++ it ) {
IfcSchema::IfcGeometricSetSelect element = *it;
if (element->is(IfcSchema::Type::IfcSurface)) {
IfcSchema::IfcSurface* surface = (IfcSchema::IfcSurface*) element;
TopoDS_Shape s;
if (IfcGeom::convert_shape(surface, s)) {
const IfcGeom::SurfaceStyle* style = get_style(surface);
shapes.push_back(IfcRepresentationShapeItem(s, style ? style : parent_style));
for ( IfcEntityList::it it = elements->begin(); it != elements->end(); ++ it ) {
IfcSchema::IfcGeometricSetSelect* element = *it;
TopoDS_Shape s;
if (convert_shape(element, s)) {
part_succes = true;
const IfcGeom::SurfaceStyle* style = 0;
if (element->declaration().is(IfcSchema::Type::IfcPoint)) {
style = get_style((IfcSchema::IfcPoint*) element);
} else if (element->declaration().is(IfcSchema::Type::IfcCurve)) {
style = get_style((IfcSchema::IfcCurve*) element);
} else if (element->declaration().is(IfcSchema::Type::IfcSurface)) {
style = get_style((IfcSchema::IfcSurface*) element);
}
shapes.push_back(IfcRepresentationShapeItem(s, style ? style : parent_style));
}
}
return true;
return part_succes;
}
bool IfcGeom::convert(const IfcSchema::IfcBlock::ptr l, TopoDS_Shape& shape) {
const double dx = l->XLength() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double dy = l->YLength() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double dz = l->ZLength() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBlock* l, TopoDS_Shape& shape) {
const double dx = l->XLength() * getValue(GV_LENGTH_UNIT);
const double dy = l->YLength() * getValue(GV_LENGTH_UNIT);
const double dz = l->ZLength() * getValue(GV_LENGTH_UNIT);
BRepPrimAPI_MakeBox builder(dx, dy, dz);
gp_Trsf trsf;
IfcGeom::convert(l->Position(),trsf);
IfcGeom::Kernel::convert(l->Position(),trsf);
shape = builder.Solid().Moved(trsf);
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcRectangularPyramid::ptr l, TopoDS_Shape& shape) {
const double dx = l->XLength() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double dy = l->YLength() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double dz = l->Height() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularPyramid* l, TopoDS_Shape& shape) {
const double dx = l->XLength() * getValue(GV_LENGTH_UNIT);
const double dy = l->YLength() * getValue(GV_LENGTH_UNIT);
const double dz = l->Height() * getValue(GV_LENGTH_UNIT);
BRepPrimAPI_MakeWedge builder(dx, dz, dy, dx / 2., dy / 2., dx / 2., dy / 2.);
gp_Trsf trsf1, trsf2;
trsf2.SetValues(1, 0, 0, 0,
0, 0, 1, 0,
0, 1, 0, 0, Precision::Confusion(), Precision::Confusion());
trsf2.SetValues(
1, 0, 0, 0,
0, 0, 1, 0,
0, 1, 0, 0
#if OCC_VERSION_HEX < 0x60800
, Precision::Angular(), Precision::Confusion()
#endif
);
IfcGeom::convert(l->Position(), trsf1);
IfcGeom::Kernel::convert(l->Position(), trsf1);
shape = BRepBuilderAPI_Transform(builder.Solid(), trsf1 * trsf2);
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcRightCircularCylinder::ptr l, TopoDS_Shape& shape) {
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double h = l->Height() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRightCircularCylinder* l, TopoDS_Shape& shape) {
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
const double h = l->Height() * getValue(GV_LENGTH_UNIT);
BRepPrimAPI_MakeCylinder builder(r, h);
gp_Trsf trsf;
IfcGeom::convert(l->Position(),trsf);
IfcGeom::Kernel::convert(l->Position(),trsf);
shape = builder.Solid().Moved(trsf);
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcRightCircularCone::ptr l, TopoDS_Shape& shape) {
const double r = l->BottomRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double h = l->Height() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRightCircularCone* l, TopoDS_Shape& shape) {
const double r = l->BottomRadius() * getValue(GV_LENGTH_UNIT);
const double h = l->Height() * getValue(GV_LENGTH_UNIT);
BRepPrimAPI_MakeCone builder(r, 0., h);
gp_Trsf trsf;
IfcGeom::convert(l->Position(),trsf);
IfcGeom::Kernel::convert(l->Position(),trsf);
shape = builder.Solid().Moved(trsf);
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcSphere::ptr l, TopoDS_Shape& shape) {
const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSphere* l, TopoDS_Shape& shape) {
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
BRepPrimAPI_MakeSphere builder(r);
gp_Trsf trsf;
IfcGeom::convert(l->Position(),trsf);
IfcGeom::Kernel::convert(l->Position(),trsf);
shape = builder.Solid().Moved(trsf);
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcCsgSolid::ptr l, TopoDS_Shape& shape) {
return IfcGeom::convert_shape(l->TreeRootExpression(), shape);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCsgSolid* l, TopoDS_Shape& shape) {
return convert_shape(l->TreeRootExpression(), shape);
}
bool IfcGeom::convert(const IfcSchema::IfcCurveBoundedPlane::ptr l, TopoDS_Shape& face) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_Shape& face) {
gp_Pln pln;
IfcGeom::convert(l->BasisSurface(), pln);
IfcGeom::Kernel::convert(l->BasisSurface(), pln);
gp_Trsf trsf;
trsf.SetTransformation(pln.Position());
trsf.SetTransformation(pln.Position(), gp::XOY());
TopoDS_Wire outer;
IfcGeom::convert_wire(l->OuterBoundary(), outer);
convert_wire(l->OuterBoundary(), outer);
BRepBuilderAPI_MakeFace mf (outer);
mf.Add(outer);
IfcSchema::IfcCurve::list inner = l->InnerBoundaries();
IfcSchema::IfcCurve::list::ptr boundaries = l->InnerBoundaries();
for (IfcSchema::IfcCurve::it it = inner->begin(); it != inner->end(); ++it) {
for (IfcSchema::IfcCurve::list::it it = boundaries->begin(); it != boundaries->end(); ++it) {
TopoDS_Wire inner;
IfcGeom::convert_wire(*it, inner);
convert_wire(*it, inner);
mf.Add(inner);
}
@@ -549,13 +698,13 @@ bool IfcGeom::convert(const IfcSchema::IfcCurveBoundedPlane::ptr l, TopoDS_Shape
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcRectangularTrimmedSurface::ptr l, TopoDS_Shape& face) {
if (!l->BasisSurface()->is(IfcSchema::Type::IfcPlane)) {
Logger::Message(Logger::LOG_ERROR, "Unsupported BasisSurface:", l->BasisSurface()->entity);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularTrimmedSurface* l, TopoDS_Shape& face) {
if (!l->BasisSurface()->declaration().is(IfcSchema::Type::IfcPlane)) {
Logger::Message(Logger::LOG_ERROR, "Unsupported BasisSurface:", l->BasisSurface());
return false;
}
gp_Pln pln;
IfcGeom::convert((IfcSchema::IfcPlane*) l->BasisSurface(), pln);
IfcGeom::Kernel::convert((IfcSchema::IfcPlane*) l->BasisSurface(), pln);
BRepBuilderAPI_MakeFace mf(pln, l->U1(), l->U2(), l->V1(), l->V2());
@@ -564,19 +713,19 @@ bool IfcGeom::convert(const IfcSchema::IfcRectangularTrimmedSurface::ptr l, Topo
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid::ptr l, TopoDS_Shape& shape) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, TopoDS_Shape& shape) {
gp_Trsf directrix, position;
TopoDS_Shape face;
TopoDS_Wire wire, section;
if (!l->ReferenceSurface()->is(IfcSchema::Type::IfcPlane)) {
Logger::Message(Logger::LOG_WARNING, "Reference surface not supported", l->ReferenceSurface()->entity);
if (!l->ReferenceSurface()->declaration().is(IfcSchema::Type::IfcPlane)) {
Logger::Message(Logger::LOG_WARNING, "Reference surface not supported", l->ReferenceSurface());
return false;
}
if (!IfcGeom::convert(l->Position(), position) ||
!IfcGeom::convert_face(l->SweptArea(), face) ||
!IfcGeom::convert_wire(l->Directrix(), wire) ) {
if (!IfcGeom::Kernel::convert(l->Position(), position) ||
!convert_face(l->SweptArea(), face) ||
!convert_wire(l->Directrix(), wire) ) {
return false;
}
@@ -584,7 +733,7 @@ bool IfcGeom::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid::ptr l, Top
gp_Pnt directrix_origin;
gp_Vec directrix_tangent;
bool directrix_on_plane = true;
IfcGeom::convert((IfcSchema::IfcPlane*) l->ReferenceSurface(), pln);
IfcGeom::Kernel::convert((IfcSchema::IfcPlane*) l->ReferenceSurface(), pln);
// As per Informal propositions 2: The Directrix shall lie on the ReferenceSurface.
// This is not always the case with the test files in the repository. I am not sure
@@ -595,7 +744,7 @@ bool IfcGeom::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid::ptr l, Top
for (TopExp_Explorer exp(wire, TopAbs_VERTEX); exp.More(); exp.Next()) {
if (pln.Distance(BRep_Tool::Pnt(TopoDS::Vertex(exp.Current()))) > ALMOST_ZERO) {
directrix_on_plane = false;
Logger::Message(Logger::LOG_WARNING, "The Directrix does not lie on the ReferenceSurface", l->entity);
Logger::Message(Logger::LOG_WARNING, "The Directrix does not lie on the ReferenceSurface", l);
break;
}
}
@@ -637,12 +786,12 @@ bool IfcGeom::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid::ptr l, Top
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcSweptDiskSolid::ptr l, TopoDS_Shape& shape) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shape& shape) {
TopoDS_Wire wire, section1, section2;
const bool hasInnerRadius = l->hasInnerRadius();
bool hasInnerRadius = l->hasInnerRadius();
if (!IfcGeom::convert_wire(l->Directrix(), wire)) {
if (!convert_wire(l->Directrix(), wire)) {
return false;
}
@@ -658,14 +807,19 @@ bool IfcGeom::convert(const IfcSchema::IfcSweptDiskSolid::ptr l, TopoDS_Shape& s
directrix = gp_Ax2(directrix_origin, directrix_tangent);
}
const double r1 = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
const double r1 = l->Radius() * getValue(GV_LENGTH_UNIT);
Handle(Geom_Circle) circle = new Geom_Circle(directrix, r1);
section1 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle));
if (hasInnerRadius) {
const double r2 = l->InnerRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
Handle(Geom_Circle) circle = new Geom_Circle(directrix, r2);
section2 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle));
const double r2 = l->InnerRadius() * getValue(GV_LENGTH_UNIT);
if (r2 < getValue(GV_PRECISION)) {
// Subtraction of pipes with small radii is unstable.
hasInnerRadius = false;
} else {
Handle(Geom_Circle) circle2 = new Geom_Circle(directrix, r2);
section2 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle2));
}
}
// NB: Note that StartParam and EndParam param are ignored and the assumption is
@@ -705,7 +859,7 @@ bool IfcGeom::convert(const IfcSchema::IfcSweptDiskSolid::ptr l, TopoDS_Shape& s
}
if (!is_valid) {
Logger::Message(Logger::LOG_WARNING, "Failed to subtract inner radius void for:", l->entity);
Logger::Message(Logger::LOG_WARNING, "Failed to subtract inner radius void for:", l);
}
}
@@ -714,12 +868,128 @@ bool IfcGeom::convert(const IfcSchema::IfcSweptDiskSolid::ptr l, TopoDS_Shape& s
#ifdef USE_IFC4
bool IfcGeom::convert(const IfcSchema::IfcCylindricalSurface::ptr l, TopoDS_Shape& face) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCylindricalSurface* l, TopoDS_Shape& face) {
gp_Trsf trsf;
IfcGeom::convert(l->Position(),trsf);
IfcGeom::Kernel::convert(l->Position(),trsf);
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius()), GetValue(GV_PRECISION)).Face().Moved(trsf);
#if OCC_VERSION_HEX < 0x60502
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius())).Face().Moved(trsf);
#else
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius()), getValue(GV_PRECISION)).Face().Moved(trsf);
#endif
return true;
}
#endif
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAdvancedBrep* l, TopoDS_Shape& shape) {
return convert(l->Outer(), shape);
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, TopoDS_Shape& shape) {
IfcSchema::IfcCartesianPointList3D* point_list = l->Coordinates();
const std::vector< std::vector<double> > coordinates = point_list->CoordList();
std::vector<gp_Pnt> points;
points.reserve(coordinates.size());
for (std::vector< std::vector<double> >::const_iterator it = coordinates.begin(); it != coordinates.end(); ++it) {
const std::vector<double>& coords = *it;
if (coords.size() != 3) {
Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on Coordinates", l);
return false;
}
points.push_back(gp_Pnt(coords[0] * getValue(GV_LENGTH_UNIT),
coords[1] * getValue(GV_LENGTH_UNIT),
coords[2] * getValue(GV_LENGTH_UNIT)));
}
std::vector< std::vector<int> > indices = l->CoordIndex();
std::vector<TopoDS_Face> faces;
faces.reserve(indices.size());
for(std::vector< std::vector<int> >::const_iterator it = indices.begin(); it != indices.end(); ++ it) {
const std::vector<int>& tri = *it;
if (tri.size() != 3) {
Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on CoordIndex", l);
return false;
}
const int min_index = *std::min_element(tri.begin(), tri.end());
const int max_index = *std::max_element(tri.begin(), tri.end());
if (min_index < 1 || max_index > points.size()) {
Logger::Message(Logger::LOG_ERROR, "Contents of CoordIndex out of bounds", l);
return false;
}
const gp_Pnt& a = points[tri[0] - 1]; // account for zero- vs
const gp_Pnt& b = points[tri[1] - 1]; // one-based indices in
const gp_Pnt& c = points[tri[2] - 1]; // c++ and express
TopoDS_Wire wire = BRepBuilderAPI_MakePolygon(a, b, c, true).Wire();
TopoDS_Face face = BRepBuilderAPI_MakeFace(wire).Face();
TopoDS_Iterator face_it(face, false);
const TopoDS_Wire& w = TopoDS::Wire(face_it.Value());
const bool reversed = w.Orientation() == TopAbs_REVERSED;
if (reversed) {
face.Reverse();
}
if (face_area(face) > getValue(GV_MINIMAL_FACE_AREA)) {
faces.push_back(face);
}
}
if (faces.empty()) return false;
const unsigned int num_faces = (unsigned)indices.size();
bool valid_shell = false;
if (faces.size() < getValue(GV_MAX_FACES_TO_SEW)) {
BRepOffsetAPI_Sewing builder;
builder.SetTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMaxTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMinTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
for (std::vector<TopoDS_Face>::const_iterator it = faces.begin(); it != faces.end(); ++it) {
builder.Add(*it);
}
try {
builder.Perform();
shape = builder.SewedShape();
valid_shell = BRepCheck_Analyzer(shape).IsValid();
} catch(...) {}
if (valid_shell) {
try {
ShapeFix_Solid solid;
solid.LimitTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
TopoDS_Solid solid_shape = solid.SolidFromShell(TopoDS::Shell(shape));
if (!solid_shape.IsNull()) {
try {
BRepClass3d_SolidClassifier classifier(solid_shape);
shape = solid_shape;
} catch (...) {}
}
} catch(...) {}
} else {
Logger::Message(Logger::LOG_WARNING, "Failed to sew faceset:", l);
}
}
if (!valid_shell) {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
for (std::vector<TopoDS_Face>::const_iterator it = faces.begin(); it != faces.end(); ++it) {
builder.Add(compound, *it);
}
shape = compound;
}
return true;
}
#endif
+278 -88
View File
@@ -47,47 +47,50 @@
#include <TColgp_Array1OfPnt2d.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <Geom_Line.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Ellipse.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <BRepOffsetAPI_Sewing.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRepBuilderAPI_MakeShell.hxx>
#include <BRepBuilderAPI_MakeSolid.hxx>
#include <BRepBuilderAPI_MakePolygon.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepPrimAPI_MakePrism.hxx>
#include <BRepBuilderAPI_MakeShell.hxx>
#include <BRepBuilderAPI_MakeSolid.hxx>
#include <BRepPrimAPI_MakeHalfSpace.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopLoc_Location.hxx>
#include <TopTools_ListOfShape.hxx>
#include <BRepAlgoAPI_Cut.hxx>
#include <BRepOffsetAPI_Sewing.hxx>
#include <BRepPrimAPI_MakePrism.hxx>
#include <BRepPrimAPI_MakeHalfSpace.hxx>
#include <BRepFilletAPI_MakeFillet2d.hxx>
#include <BRep_Tool.hxx>
#include <ShapeFix_Shape.hxx>
#include <ShapeFix_ShapeTolerance.hxx>
#include <ShapeFix_Solid.hxx>
#include <BRepFilletAPI_MakeFillet2d.hxx>
#include <TopLoc_Location.hxx>
#include <BRep_Tool.hxx>
#include "../ifcgeom/IfcGeom.h"
bool IfcGeom::convert(const IfcSchema::IfcCompositeCurve::ptr l, TopoDS_Wire& wire) {
if ( IfcGeom::GetValue(GV_PLANEANGLE_UNIT)<0 ) {
Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l->entity);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire& wire) {
if ( getValue(GV_PLANEANGLE_UNIT)<0 ) {
Logger::Message(Logger::LOG_WARNING, "Creating a composite curve without unit information:", l);
// Temporarily pretend we do have unit information
IfcGeom::SetValue(GV_PLANEANGLE_UNIT,1.0);
setValue(GV_PLANEANGLE_UNIT,1.0);
bool succes_radians = false;
bool succes_degrees = false;
@@ -97,17 +100,17 @@ bool IfcGeom::convert(const IfcSchema::IfcCompositeCurve::ptr l, TopoDS_Wire& wi
// First try radians
TopoDS_Wire wire_radians, wire_degrees;
try {
succes_radians = IfcGeom::convert(l,wire_radians);
succes_radians = IfcGeom::Kernel::convert(l,wire_radians);
} catch (...) {}
// Now try degrees
IfcGeom::SetValue(GV_PLANEANGLE_UNIT,0.0174532925199433);
setValue(GV_PLANEANGLE_UNIT,0.0174532925199433);
try {
succes_degrees = IfcGeom::convert(l,wire_degrees);
succes_degrees = IfcGeom::Kernel::convert(l,wire_degrees);
} catch (...) {}
// Restore to unknown unit state
IfcGeom::SetValue(GV_PLANEANGLE_UNIT,-1.0);
setValue(GV_PLANEANGLE_UNIT,-1.0);
if ( succes_degrees && ! succes_radians ) {
use_degrees = true;
@@ -138,19 +141,19 @@ bool IfcGeom::convert(const IfcSchema::IfcCompositeCurve::ptr l, TopoDS_Wire& wi
return use_radians || use_degrees;
}
IfcSchema::IfcCompositeCurveSegment::list segments = l->Segments();
IfcSchema::IfcCompositeCurveSegment::list::ptr segments = l->Segments();
BRepBuilderAPI_MakeWire w;
//TopoDS_Vertex last_vertex;
for( IfcSchema::IfcCompositeCurveSegment::it it = segments->begin(); it != segments->end(); ++ it ) {
const IfcSchema::IfcCurve::ptr curve = (*it)->ParentCurve();
for( IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++ it ) {
IfcSchema::IfcCurve* curve = (*it)->ParentCurve();
TopoDS_Wire wire2;
if ( ! IfcGeom::convert_wire(curve,wire2) ) {
Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve->entity);
if ( !convert_wire(curve,wire2) ) {
Logger::Message(Logger::LOG_ERROR, "Failed to convert curve:", curve);
continue;
}
if ( ! (*it)->SameSense() ) wire2.Reverse();
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(wire2, GetValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_WIRE);
FTol.SetTolerance(wire2, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_WIRE);
/*if ( it != segments->begin() ) {
TopExp_Explorer exp (wire2,TopAbs_VERTEX);
const TopoDS_Vertex& first_vertex = TopoDS::Vertex(exp.Current());
@@ -164,48 +167,66 @@ bool IfcGeom::convert(const IfcSchema::IfcCompositeCurve::ptr l, TopoDS_Wire& wi
w.Add(wire2);
//last_vertex = w.Vertex();
if ( w.Error() != BRepBuilderAPI_WireDone ) {
Logger::Message(Logger::LOG_ERROR,"Failed to join curve segments:",l->entity);
Logger::Message(Logger::LOG_ERROR, "Failed to join curve segments:", l);
TopoDS_Vertex v1, v2, last;
last = w.Vertex();
if (!last.IsNull()) {
std::stringstream ss;
gp_Pnt p = BRep_Tool::Pnt(last);
ss << std::setprecision(4) << "Last vertex at (" << p.X() << " " << p.Y() << " " << p.Z() << ")";
Logger::Message(Logger::LOG_NOTICE, ss.str());
}
TopExp::Vertices(wire2, v1, v2);
if (!v1.IsNull()) {
std::stringstream ss;
gp_Pnt p = BRep_Tool::Pnt(v1);
ss << std::setprecision(4) << "Segment starts at (" << p.X() << " " << p.Y() << " " << p.Z() << ") for:";
Logger::Message(Logger::LOG_NOTICE, ss.str(), *it);
}
return false;
}
}
wire = w.Wire();
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcTrimmedCurve::ptr l, TopoDS_Wire& wire) {
IfcSchema::IfcCurve::ptr basis_curve = l->BasisCurve();
bool isConic = basis_curve->is(IfcSchema::Type::IfcConic);
double parameterFactor = isConic ? IfcGeom::GetValue(GV_PLANEANGLE_UNIT) : IfcGeom::GetValue(GV_LENGTH_UNIT);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& wire) {
IfcSchema::IfcCurve* basis_curve = l->BasisCurve();
bool isConic = basis_curve->declaration().is(IfcSchema::Type::IfcConic);
double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT);
Handle(Geom_Curve) curve;
if ( ! IfcGeom::convert_curve(basis_curve,curve) ) return false;
if ( !convert_curve(basis_curve,curve) ) return false;
bool trim_cartesian = l->MasterRepresentation() == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN;
IfcUtil::IfcAbstractSelect::list trims1 = l->Trim1();
IfcUtil::IfcAbstractSelect::list trims2 = l->Trim2();
bool trimmed1 = false;
bool trimmed2 = false;
IfcEntityList::ptr trims1 = l->Trim1();
IfcEntityList::ptr trims2 = l->Trim2();
unsigned sense_agreement = l->SenseAgreement() ? 0 : 1;
double flts[2];
gp_Pnt pnts[2];
bool has_flts[2] = {false,false};
bool has_pnts[2] = {false,false};
BRepBuilderAPI_MakeWire w;
for ( IfcUtil::IfcAbstractSelect::it it = trims1->begin(); it != trims1->end(); it ++ ) {
const IfcUtil::IfcAbstractSelect::ptr i = *it;
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
IfcGeom::convert(reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,IfcSchema::IfcCartesianPoint>(i), pnts[sense_agreement] );
for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) {
IfcUtil::IfcBaseClass* i = *it;
if ( i->declaration().is(IfcSchema::Type::IfcCartesianPoint) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] );
has_pnts[sense_agreement] = true;
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
const double value = *((IfcUtil::IfcBaseEntity*)i)->entity->getArgument(0);
} else if ( i->declaration().is(IfcSchema::Type::IfcParameterValue) ) {
const double value = *((IfcSchema::IfcParameterValue*)i);
flts[sense_agreement] = value * parameterFactor;
has_flts[sense_agreement] = true;
}
}
for ( IfcUtil::IfcAbstractSelect::it it = trims2->begin(); it != trims2->end(); it ++ ) {
const IfcUtil::IfcAbstractSelect::ptr i = *it;
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
IfcGeom::convert(reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,IfcSchema::IfcCartesianPoint>(i), pnts[1-sense_agreement] );
for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) {
IfcUtil::IfcBaseClass* i = *it;
if ( i->declaration().is(IfcSchema::Type::IfcCartesianPoint) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] );
has_pnts[1-sense_agreement] = true;
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
const double value = *((IfcUtil::IfcBaseEntity*)i)->entity->getArgument(0);
} else if ( i->declaration().is(IfcSchema::Type::IfcParameterValue) ) {
const double value = *((IfcSchema::IfcParameterValue*)i);
flts[1-sense_agreement] = value * parameterFactor;
has_flts[1-sense_agreement] = true;
}
@@ -213,20 +234,20 @@ bool IfcGeom::convert(const IfcSchema::IfcTrimmedCurve::ptr l, TopoDS_Wire& wire
trim_cartesian &= has_pnts[0] && has_pnts[1];
bool trim_cartesian_failed = !trim_cartesian;
if ( trim_cartesian ) {
if ( pnts[0].Distance(pnts[1]) < GetValue(GV_WIRE_CREATION_TOLERANCE) ) {
Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l->entity);
if ( pnts[0].Distance(pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE) ) {
Logger::Message(Logger::LOG_WARNING, "Skipping segment with length below tolerance level:", l);
return false;
}
ShapeFix_ShapeTolerance FTol;
TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(pnts[0]);
TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(pnts[1]);
FTol.SetTolerance(v1, GetValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
FTol.SetTolerance(v2, GetValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
FTol.SetTolerance(v1, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
FTol.SetTolerance(v2, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
BRepBuilderAPI_MakeEdge e (curve,v1,v2);
if ( ! e.IsDone() ) {
BRepBuilderAPI_EdgeError err = e.Error();
if ( err == BRepBuilderAPI_PointProjectionFailed ) {
Logger::Message(Logger::LOG_WARNING,"Point projection failed for:",l->entity);
Logger::Message(Logger::LOG_WARNING, "Point projection failed for:", l);
trim_cartesian_failed = true;
}
} else {
@@ -238,22 +259,22 @@ bool IfcGeom::convert(const IfcSchema::IfcTrimmedCurve::ptr l, TopoDS_Wire& wire
// is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because
// the vector is normalised when passed to Geom_Line constructor the magnitude
// needs to be factored in with the IfcParameterValue here.
if ( basis_curve->is(IfcSchema::Type::IfcLine) ) {
if ( basis_curve->declaration().is(IfcSchema::Type::IfcLine) ) {
IfcSchema::IfcLine* line = static_cast<IfcSchema::IfcLine*>(basis_curve);
const double magnitude = line->Dir()->Magnitude();
flts[0] *= magnitude; flts[1] *= magnitude;
}
if ( basis_curve->is(IfcSchema::Type::IfcEllipse) ) {
if ( basis_curve->declaration().is(IfcSchema::Type::IfcEllipse) ) {
IfcSchema::IfcEllipse* ellipse = static_cast<IfcSchema::IfcEllipse*>(basis_curve);
double x = ellipse->SemiAxis1() * IfcGeom::GetValue(GV_LENGTH_UNIT);
double y = ellipse->SemiAxis2() * IfcGeom::GetValue(GV_LENGTH_UNIT);
double x = ellipse->SemiAxis1() * getValue(GV_LENGTH_UNIT);
double y = ellipse->SemiAxis2() * getValue(GV_LENGTH_UNIT);
const bool rotated = y > x;
if (rotated) {
flts[0] -= M_PI / 2.;
flts[1] -= M_PI / 2.;
}
}
if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],(double)(M_PI*2.0)),0.0f) ) {
if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],M_PI*2.),0.) ) {
w.Add(BRepBuilderAPI_MakeEdge(curve));
} else {
BRepBuilderAPI_MakeEdge e (curve,flts[0],flts[1]);
@@ -269,44 +290,213 @@ bool IfcGeom::convert(const IfcSchema::IfcTrimmedCurve::ptr l, TopoDS_Wire& wire
return false;
}
}
bool IfcGeom::convert(const IfcSchema::IfcPolyline::ptr l, TopoDS_Wire& result) {
IfcSchema::IfcCartesianPoint::list points = l->Points();
BRepBuilderAPI_MakeWire w;
gp_Pnt P1;gp_Pnt P2;
for( IfcSchema::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it ) {
IfcGeom::convert(*it,P2);
if ( it != points->begin() && ( !P1.IsEqual(P2,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) )
w.Add(BRepBuilderAPI_MakeEdge(P1,P2));
P1 = P2;
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& result) {
IfcSchema::IfcCartesianPoint::list::ptr points = l->Points();
// Parse and store the points in a sequence
TColgp_SequenceOfPnt polygon;
for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) {
gp_Pnt pnt;
IfcGeom::Kernel::convert(*it, pnt);
polygon.Append(pnt);
}
// Remove points that are too close to one another
remove_duplicate_points_from_loop(polygon, false);
BRepBuilderAPI_MakePolygon w;
for (int i = 1; i <= polygon.Length(); ++i) {
w.Add(polygon.Value(i));
}
result = w.Wire();
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcPolyLoop::ptr l, TopoDS_Wire& result) {
IfcSchema::IfcCartesianPoint::list points = l->Polygon();
BRepBuilderAPI_MakeWire w;
gp_Pnt P1;gp_Pnt P2;gp_Pnt F;
int count = 0;
for( IfcSchema::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it ) {
IfcGeom::convert(*it,P2);
if ( it != points->begin() && ( !P1.IsEqual(P2,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) ) {
w.Add(BRepBuilderAPI_MakeEdge(P1,P2));
count ++;
} else if ( ! count ) F = P2;
P1 = P2;
}
if ( !P1.IsEqual(F,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) {
w.Add(BRepBuilderAPI_MakeEdge(P1,F));
count ++;
}
if ( count < 3 ) return false;
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& result) {
IfcSchema::IfcCartesianPoint::list::ptr points = l->Polygon();
result = w.Wire();
// Parse and store the points in a sequence
TColgp_SequenceOfPnt polygon;
for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) {
gp_Pnt pnt;
IfcGeom::Kernel::convert(*it, pnt);
polygon.Append(pnt);
}
// A loop should consist of at least three vertices
int original_count = polygon.Length();
if (original_count < 3) {
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l);
return false;
}
// Remove points that are too close to one another
remove_duplicate_points_from_loop(polygon, true);
int count = polygon.Length();
if (original_count - count != 0) {
std::stringstream ss; ss << (original_count - count) << " edges removed for:";
Logger::Message(Logger::LOG_WARNING, ss.str(), l);
}
if (count < 3) {
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l);
return false;
}
BRepBuilderAPI_MakePolygon w;
for (int i = 1; i <= polygon.Length(); ++i) {
w.Add(polygon.Value(i));
}
w.Close();
result = w.Wire();
return true;
}
bool IfcGeom::convert(const IfcSchema::IfcArbitraryOpenProfileDef::ptr l, TopoDS_Wire& result) {
return IfcGeom::convert_wire(l->Curve(), result);
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryOpenProfileDef* l, TopoDS_Wire& result) {
return convert_wire(l->Curve(), result);
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeCurve* l, TopoDS_Wire& result) {
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry();
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry();
if (!pnt1->declaration().is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->declaration().is(IfcSchema::Type::IfcCartesianPoint)) {
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l);
return false;
}
gp_Pnt p1, p2;
if (!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
{
return false;
}
BRepBuilderAPI_MakeWire mw;
Handle_Geom_Curve crv;
// The lack of a clear separation between topological and geometrical entities
// is starting to get problematic. If the underlying curve is bounded it is
// assumed that a topological wire can be crafted from it. After which an
// attempt is made to reconstruct it from the individual curves and the vertices
// of the IfcEdgeCurve.
const bool is_bounded = l->EdgeGeometry()->declaration().is(IfcSchema::Type::IfcBoundedCurve);
if (!is_bounded && convert_curve(l->EdgeGeometry(), crv)) {
mw.Add(BRepBuilderAPI_MakeEdge(crv, p1, p2));
result = mw;
return true;
} else if (is_bounded && convert_wire(l->EdgeGeometry(), result)) {
if (!l->SameSense()) std::swap(pnt1, pnt2);
TopExp_Explorer exp(result, TopAbs_EDGE);
bool first = true;
while (exp.More()) {
const TopoDS_Edge& ed = TopoDS::Edge(exp.Current());
Standard_Real u1, u2;
Handle(Geom_Curve) ecrv = BRep_Tool::Curve(ed, u1, u2);
exp.Next();
const bool last = !exp.More();
first = false;
if (first && last) {
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, p1, p2));
} else if (first) {
gp_Pnt pu;
ecrv->D0(u2, pu);
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, p1, pu));
} else if (last) {
gp_Pnt pu;
ecrv->D0(u1, pu);
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, pu, p2));
} else {
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, u1, u2));
}
}
result = mw;
return true;
} else {
return false;
}
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeLoop* l, TopoDS_Wire& result) {
IfcSchema::IfcOrientedEdge::list::ptr li = l->EdgeList();
BRepBuilderAPI_MakeWire mw;
for (IfcSchema::IfcOrientedEdge::list::it it = li->begin(); it != li->end(); ++it) {
TopoDS_Wire w;
if (convert_wire(*it, w)) {
if (!(*it)->Orientation()) w.Reverse();
TopoDS_Iterator topoit(w, false);
for (; topoit.More(); topoit.Next()) {
const TopoDS_Edge& e = TopoDS::Edge(topoit.Value());
mw.Add(e);
}
// mw.Add(w);
}
}
result = mw;
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdge* l, TopoDS_Wire& result) {
if (!l->EdgeStart()->declaration().is(IfcSchema::Type::IfcVertexPoint) || !l->EdgeEnd()->declaration().is(IfcSchema::Type::IfcVertexPoint)) {
Logger::Message(Logger::LOG_ERROR, "Only IfcVertexPoints are supported for EdgeStart and -End", l);
return false;
}
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry();
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry();
if (!pnt1->declaration().is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->declaration().is(IfcSchema::Type::IfcCartesianPoint)) {
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l);
return false;
}
gp_Pnt p1, p2;
if (!convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
!convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
{
return false;
}
BRepBuilderAPI_MakeWire mw;
mw.Add(BRepBuilderAPI_MakeEdge(p1, p2));
result = mw.Wire();
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcOrientedEdge* l, TopoDS_Wire& result) {
if (convert_wire(l->EdgeElement(), result)) {
if (!l->Orientation()) {
result.Reverse();
}
return true;
} else {
return false;
}
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSubedge* l, TopoDS_Wire& result) {
TopoDS_Wire temp;
if (convert_wire(l->ParentEdge(), result) && convert((IfcSchema::IfcEdge*) l, temp)) {
TopExp_Explorer exp(result, TopAbs_EDGE);
TopoDS_Edge edge = TopoDS::Edge(exp.Current());
Standard_Real u1, u2;
Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u1, u2);
TopoDS_Vertex v1, v2;
TopExp::Vertices(temp, v1, v2);
BRepBuilderAPI_MakeWire mw;
mw.Add(BRepBuilderAPI_MakeEdge(crv, v1, v2));
result = mw.Wire();
return true;
} else {
return false;
}
}
+73 -32
View File
@@ -18,60 +18,101 @@
********************************************************************************/
#include "IfcGeom.h"
namespace IfcGeom {
namespace Cache {
std::map<int,TopoDS_Shape> Shape;
void PurgeShapeCache() {
Shape.clear();
}
}
}
#include "IfcGeomShapeType.h"
using namespace IfcSchema;
using namespace IfcUtil;
bool IfcGeom::convert_shapes(const IfcBaseClass* l, IfcRepresentationShapeItems& r) {
bool IfcGeom::Kernel::convert_shapes(const IfcBaseClass* l, IfcRepresentationShapeItems& r) {
if (shape_type(l) != ST_SHAPELIST) {
TopoDS_Shape shp;
if (convert_shape(l, shp)) {
r.push_back(IfcGeom::IfcRepresentationShapeItem(shp, get_style(l->as<IfcSchema::IfcRepresentationItem>())));
return true;
}
return false;
}
#include "IfcRegisterConvertShapes.h"
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l);
return false;
}
bool IfcGeom::is_shape_collection(const IfcBaseClass* l) {
#include "IfcRegisterIsShapeCollection.h"
return false;
IfcGeom::ShapeType IfcGeom::Kernel::shape_type(const IfcBaseClass* l) {
#include "IfcRegisterShapeType.h"
return ST_OTHER;
}
bool IfcGeom::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) {
const unsigned int id = l->entity->id();
bool IfcGeom::Kernel::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) {
const unsigned int id = l->data().id();
bool success = false;
bool processed = false;
std::map<int,TopoDS_Shape>::const_iterator it = Cache::Shape.find(id);
if ( it != Cache::Shape.end() ) { r = it->second; return true; }
bool ignored = false;
std::map<int,TopoDS_Shape>::const_iterator it = cache.Shape.find(id);
if ( it != cache.Shape.end() ) { r = it->second; return true; }
const bool include_curves = getValue(GV_DIMENSIONALITY) != +1;
const bool include_solids_and_surfaces = getValue(GV_DIMENSIONALITY) != -1;
IfcGeom::ShapeType st = shape_type(l);
ignored = (!include_solids_and_surfaces && (st == ST_SHAPE || st == ST_FACE)) || (!include_curves && (st == ST_WIRE || st == ST_CURVE));
if (st == ST_SHAPELIST) {
processed = true;
IfcRepresentationShapeItems items;
success = convert_shapes(l, items) && flatten_shape_list(items, r, false);
} else if (st == ST_SHAPE && include_solids_and_surfaces) {
#include "IfcRegisterConvertShape.h"
if ( processed ) {
const double precision = IfcGeom::GetValue(GV_PRECISION);
IfcGeom::apply_tolerance(r, precision);
Cache::Shape[id] = r;
} else {
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
} else if (st == ST_FACE && include_solids_and_surfaces) {
processed = true;
success = convert_face(l, r);
} else if (st == ST_WIRE && include_curves) {
processed = true;
TopoDS_Wire w;
success = convert_wire(l, w);
if (success) {
r = w;
}
} else if (st == ST_CURVE && include_curves) {
processed = true;
Handle(Geom_Curve) crv;
TopoDS_Wire w;
success = convert_curve(l, crv) && convert_curve_to_wire(crv, w);
if (success) {
r = w;
}
}
if ( processed && success ) {
const double precision = getValue(GV_PRECISION);
apply_tolerance(r, precision);
cache.Shape[id] = r;
} else if (!ignored) {
const char* const msg = processed
? "Failed to convert:"
: "No operation defined for:";
Logger::Message(Logger::LOG_ERROR, msg, l);
}
return success;
}
bool IfcGeom::convert_wire(const IfcBaseClass* l, TopoDS_Wire& r) {
bool IfcGeom::Kernel::convert_wire(const IfcBaseClass* l, TopoDS_Wire& r) {
#include "IfcRegisterConvertWire.h"
Handle(Geom_Curve) curve;
if (IfcGeom::convert_curve(l, curve)) {
return IfcGeom::convert_curve_to_wire(curve, r);
if (IfcGeom::Kernel::convert_curve(l, curve)) {
return IfcGeom::Kernel::convert_curve_to_wire(curve, r);
}
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l);
return false;
}
bool IfcGeom::convert_face(const IfcBaseClass* l, TopoDS_Shape& r) {
bool IfcGeom::Kernel::convert_face(const IfcBaseClass* l, TopoDS_Shape& r) {
#include "IfcRegisterConvertFace.h"
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l);
return false;
}
bool IfcGeom::convert_curve(const IfcBaseClass* l, Handle(Geom_Curve)& r) {
bool IfcGeom::Kernel::convert_curve(const IfcBaseClass* l, Handle(Geom_Curve)& r) {
#include "IfcRegisterConvertCurve.h"
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l);
return false;
}
+21 -6
View File
@@ -41,21 +41,28 @@
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcParse.h"
using namespace IfcSchema;
SHAPES(IfcShellBasedSurfaceModel);
SHAPES(IfcFaceBasedSurfaceModel);
SHAPES(IfcShapeRepresentation);
SHAPES(IfcRepresentation);
SHAPES(IfcMappedItem);
SHAPES(IfcFacetedBrep);
SHAPES(IfcGeometricSet);
#ifdef USE_IFC4
SHAPE(IfcCylindricalSurface);
SHAPE(IfcAdvancedBrep);
// FIXME: Surfaces should have a shape type of their own
SHAPE(IfcBSplineSurfaceWithKnots);
SHAPE(IfcTriangulatedFaceSet);
#endif
SHAPE(IfcPlane);
SHAPE(IfcExtrudedAreaSolid);
SHAPE(IfcRevolvedAreaSolid);
SHAPE(IfcConnectedFaceSet);
SHAPE(IfcBooleanResult);
SHAPE(IfcPolygonalBoundedHalfSpace);
SHAPE(IfcHalfSpaceSolid);
// FIXME: Surfaces should have a shape type of their own
SHAPE(IfcSurfaceOfLinearExtrusion);
SHAPE(IfcSurfaceOfRevolution);
SHAPE(IfcBlock);
@@ -68,9 +75,6 @@ SHAPE(IfcCurveBoundedPlane);
SHAPE(IfcRectangularTrimmedSurface);
SHAPE(IfcSurfaceCurveSweptAreaSolid);
SHAPE(IfcSweptDiskSolid);
#ifdef USE_IFC4
SHAPE(IfcCylindricalSurface);
#endif
FACE(IfcArbitraryProfileDefWithVoids);
FACE(IfcArbitraryClosedProfileDef);
@@ -79,6 +83,7 @@ FACE(IfcRectangleHollowProfileDef);
FACE(IfcRectangleProfileDef);
FACE(IfcTrapeziumProfileDef)
FACE(IfcCShapeProfileDef);
// IfcAsymmetricIShapeProfileDef included
FACE(IfcIShapeProfileDef);
FACE(IfcLShapeProfileDef);
FACE(IfcTShapeProfileDef);
@@ -90,8 +95,15 @@ FACE(IfcEllipseProfileDef);
FACE(IfcCenterLineProfileDef);
FACE(IfcCompositeProfileDef);
FACE(IfcDerivedProfileDef);
// IfcFaceSurface included
// IfcAdvancedFace included in case of IFC4
FACE(IfcFace);
WIRE(IfcEdgeCurve);
WIRE(IfcSubedge);
WIRE(IfcOrientedEdge);
WIRE(IfcEdge);
WIRE(IfcEdgeLoop);
WIRE(IfcPolyline);
WIRE(IfcPolyLoop);
WIRE(IfcCompositeCurve);
@@ -101,6 +113,9 @@ WIRE(IfcArbitraryOpenProfileDef);
CURVE(IfcCircle);
CURVE(IfcEllipse);
CURVE(IfcLine);
#ifdef USE_IFC4
CURVE(IfcBSplineCurveWithKnots);
#endif
CLASS(IfcCartesianPoint,gp_Pnt);
CLASS(IfcDirection,gp_Dir);
+1 -1
View File
@@ -1,6 +1,6 @@
#include "IfcRegisterUndef.h"
#define CURVE(T) \
if ( l->is(T::Class()) ) return convert((T*)l,r);
if ( l->declaration().is(T::Class()) ) return convert(l->as<T>(), r);
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
+1 -1
View File
@@ -1,6 +1,6 @@
#include "IfcRegisterUndef.h"
#define FACE(T) \
if ( l->is(T::Class()) ) return convert((T*)l,r);
if ( l->declaration().is(T::Class()) ) return convert(l->as<T>(), r);
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
+3 -3
View File
@@ -1,14 +1,14 @@
#include "IfcRegisterUndef.h"
#define SHAPE(T) \
if ( !processed && l->is(T::Class()) ) { \
if ( !processed && l->declaration().is(T::Class()) ) { \
processed = true; \
try { \
if ( convert((T*)l,r) ) { \
if ( convert(l->as<T>(), r) ) { \
success = true; \
} \
} catch(...) { } \
if ( !success) { \
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
Logger::Message(Logger::LOG_ERROR, "Failed to convert:", l); \
return false; \
} \
}
+3 -3
View File
@@ -1,10 +1,10 @@
#include "IfcRegisterUndef.h"
#define SHAPES(T) \
if ( l->is(T::Class()) ) { \
if ( l->declaration().is(T::Class()) ) { \
try { \
return IfcGeom::convert((T*)l,r); \
return convert(l->as<T>(), r); \
} catch (...) { } \
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
Logger::Message(Logger::LOG_ERROR, "Failed to convert:", l); \
return false; \
}
#include "IfcRegisterDef.h"
+1 -1
View File
@@ -1,6 +1,6 @@
#include "IfcRegisterUndef.h"
#define WIRE(T) \
if ( l->is(T::Class()) ) return convert((T*)l,r);
if ( l->declaration().is(T::Class()) ) return convert((T*)l,r);
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
+1 -1
View File
@@ -1,5 +1,5 @@
#include "IfcRegisterUndef.h"
#define CLASS(T,V) bool convert(const T::ptr L, V& r);
#define CLASS(T,V) bool convert(const IfcSchema::T* L, V& r);
#define SHAPES(T) CLASS(T,IfcRepresentationShapeItems)
#define SHAPE(T) CLASS(T,TopoDS_Shape)
#define WIRE(T) CLASS(T,TopoDS_Wire)
@@ -1,6 +0,0 @@
#include "IfcRegisterUndef.h"
#define SHAPES(T) \
if ( l->is(T::Class()) ) return true;
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
+14
View File
@@ -0,0 +1,14 @@
#include "IfcRegisterUndef.h"
#define SHAPES(T) \
if ( l->declaration().is(T::Class()) ) return ST_SHAPELIST;
#define SHAPE(T) \
if ( l->declaration().is(T::Class()) ) return ST_SHAPE;
#define WIRE(T) \
if ( l->declaration().is(T::Class()) ) return ST_WIRE;
#define FACE(T) \
if ( l->declaration().is(T::Class()) ) return ST_FACE;
#define CURVE(T) \
if ( l->declaration().is(T::Class()) ) return ST_CURVE;
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
+1
View File
@@ -46,6 +46,7 @@ namespace IfcGeom {
const gp_GTrsf& Placement() const { return placement; }
bool hasStyle() const { return style != 0; }
const SurfaceStyle& Style() const { return *style; }
void setStyle(const SurfaceStyle* style) { this->style = style; }
};
typedef std::vector<IfcRepresentationShapeItem> IfcRepresentationShapeItems;
}
+75 -44
View File
@@ -35,7 +35,11 @@
#include <fcntl.h>
#endif
#include "../ifcgeom/IfcGeomObjects.h"
#include "../ifcgeom/IfcGeomIterator.h"
#if USE_VLD
#include <vld.h>
#endif
using namespace boost;
@@ -69,7 +73,7 @@ void swrite(std::ostream& s, T t) {
template <>
void swrite(std::ostream& s, std::string t) {
int32_t len = t.size();
int32_t len = (int32_t)t.size();
swrite(s, len);
s.write(t.c_str(), len);
while (len++ % 4) s.put(0);
@@ -156,16 +160,16 @@ public:
class Get : public Command {
protected:
void read_content(std::istream& s) {}
void write_content(std::ostream& s) {}
void read_content(std::istream& /*s*/) {}
void write_content(std::ostream& /*s*/) {}
public:
Get() : Command(GET) {};
};
class GetLog : public Command {
protected:
void read_content(std::istream& s) {}
void write_content(std::ostream& s) {}
void read_content(std::istream& /*s*/) {}
void write_content(std::ostream& /*s*/) {}
public:
GetLog() : Command(GET_LOG) {};
};
@@ -186,16 +190,17 @@ public:
class Entity : public Command {
private:
const IfcGeomObjects::IfcGeomObject* geom;
const IfcGeom::TriangulationElement<float>* geom;
bool append_line_data;
protected:
void read_content(std::istream& s) {}
void read_content(std::istream& /*s*/) {}
void write_content(std::ostream& s) {
swrite<int32_t>(s, geom->id());
swrite(s, geom->guid());
swrite(s, geom->name());
swrite(s, geom->type());
swrite<int32_t>(s, geom->parent_id());
const std::vector<float>& m = geom->matrix();
const std::vector<float>& m = geom->transformation().matrix().data();
const float matrix_array[16] = {
m[0], m[3], m[6], m[ 9],
m[1], m[4], m[7], m[10],
@@ -203,19 +208,43 @@ protected:
0, 0, 0, 1
};
swrite(s, std::string((char*)matrix_array, 16 * sizeof(float)));
swrite<int32_t>(s, geom->mesh().id());
swrite(s, std::string((char*)geom->mesh().verts().data(), geom->mesh().verts().size() * sizeof(float)));
swrite(s, std::string((char*)geom->mesh().normals().data(), geom->mesh().normals().size() * sizeof(float)));
{ std::vector<int32_t> indices;
for (std::vector<int>::const_iterator it = geom->mesh().faces().begin(); it != geom->mesh().faces().end(); ++it) {
indices.push_back(*it);
}
swrite(s, std::string((char*) indices.data(), indices.size() * sizeof(int32_t))); }
swrite<int32_t>(s, geom->geometry().id());
swrite(s, std::string((char*)geom->geometry().verts().data(), geom->geometry().verts().size() * sizeof(float)));
swrite(s, std::string((char*)geom->geometry().normals().data(), geom->geometry().normals().size() * sizeof(float)));
{
std::vector<int32_t> indices;
const std::vector<int>& faces = geom->geometry().faces();
indices.reserve(faces.size());
for (std::vector<int>::const_iterator it = indices.begin(); it != indices.end(); ++it) {
indices.push_back(*it);
}
swrite(s, std::string((char*) indices.data(), indices.size() * sizeof(int32_t)));
if (append_line_data) {
std::vector<int32_t> lines;
std::set<int32_t> faces_set (indices.begin(), indices.end());
const std::vector<int>& edges = geom->geometry().edges();
for ( std::vector<int>::const_iterator it = edges.begin(); it != edges.end(); ) {
const int32_t i1 = *(it++);
const int32_t i2 = *(it++);
if (faces_set.find(i1) != faces_set.end() || faces_set.find(i2) != faces_set.end()) {
continue;
}
lines.push_back(i1);
lines.push_back(i2);
}
swrite(s, std::string((char*) lines.data(), lines.size() * sizeof(int32_t)));
}
}
{ std::vector<float> diffuse_color_array;
for (std::vector<IfcGeomObjects::Material>::const_iterator it = geom->mesh().materials().begin(); it != geom->mesh().materials().end(); ++it) {
const IfcGeomObjects::Material& m = *it;
if (m.hasDiffuse()) {
const double* color = m.diffuse();
for (std::vector<IfcGeom::Material>::const_iterator it = geom->geometry().materials().begin(); it != geom->geometry().materials().end(); ++it) {
const IfcGeom::Material& mat = *it;
if (mat.hasDiffuse()) {
const double* color = mat.diffuse();
diffuse_color_array.push_back(static_cast<float>(color[0]));
diffuse_color_array.push_back(static_cast<float>(color[1]));
diffuse_color_array.push_back(static_cast<float>(color[2]));
@@ -224,44 +253,40 @@ protected:
diffuse_color_array.push_back(0.f);
diffuse_color_array.push_back(0.f);
}
if (m.hasTransparency()) {
diffuse_color_array.push_back(static_cast<float>(1. - m.transparency()));
if (mat.hasTransparency()) {
diffuse_color_array.push_back(static_cast<float>(1. - mat.transparency()));
} else {
diffuse_color_array.push_back(1.f);
}
}
swrite(s, std::string((char*) diffuse_color_array.data(), diffuse_color_array.size() * sizeof(float))); }
{ std::vector<int32_t> material_indices;
for (std::vector<int>::const_iterator it = geom->mesh().material_ids().begin(); it != geom->mesh().material_ids().end(); ++it) {
for (std::vector<int>::const_iterator it = geom->geometry().material_ids().begin(); it != geom->geometry().material_ids().end(); ++it) {
material_indices.push_back(*it);
}
swrite(s, std::string((char*) material_indices.data(), material_indices.size() * sizeof(int32_t))); }
}
public:
Entity(const IfcGeomObjects::IfcGeomObject* geom) : Command(ENTITY), geom(geom) {};
Entity(const IfcGeom::TriangulationElement<float>* geom) : Command(ENTITY), geom(geom), append_line_data(true) {};
};
class Next : public Command {
protected:
void read_content(std::istream& s) {}
void write_content(std::ostream& s) {}
void read_content(std::istream& /*s*/) {}
void write_content(std::ostream& /*s*/) {}
public:
Next() : Command(NEXT) {};
};
class Bye : public Command {
protected:
void read_content(std::istream& s) {}
void write_content(std::ostream& s) {}
void read_content(std::istream& /*s*/) {}
void write_content(std::ostream& /*s*/) {}
public:
Bye() : Command(BYE) {};
};
int main (int argc, char** argv) {
if (sizeof(float) != 4 || sizeof(int32_t) != 4) {
return 1;
}
int main () {
// Redirect stdout to this stream, so that involuntary
// writes to stdout do not interfere with our protocol.
std::ostringstream oss;
@@ -278,10 +303,12 @@ int main (int argc, char** argv) {
bool has_more = false;
IfcGeom::Iterator<float>* iterator = 0;
Hello().write(std::cout);
int exit_code = 0;
while (1) {
for (;;) {
const int32_t msg_type = sread<int32_t>(std::cin);
switch (msg_type) {
case IFC_MODEL: {
@@ -290,12 +317,15 @@ int main (int argc, char** argv) {
char* data = new char[len];
memcpy(data, m.string().c_str(), len);
IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS, false);
IfcGeomObjects::Settings(IfcGeomObjects::WELD_VERTICES, false);
IfcGeomObjects::Settings(IfcGeomObjects::CONVERT_BACK_UNITS, true);
IfcGeomObjects::Settings(IfcGeomObjects::FORCE_CCW_FACE_ORIENTATION, true);
IfcGeom::IteratorSettings settings;
settings.use_world_coords() = false;
settings.weld_vertices() = false;
settings.convert_back_units() = true;
settings.include_curves() = true;
iterator = new IfcGeom::Iterator<float>(settings, data, (int)len);
has_more = iterator->initialize();
has_more = IfcGeomObjects::Init(data, len);
More(has_more).write(std::cout);
continue;
}
@@ -305,22 +335,23 @@ int main (int argc, char** argv) {
exit_code = 1;
break;
}
const IfcGeomObjects::IfcGeomObject* geom = IfcGeomObjects::Get();
const IfcGeom::TriangulationElement<float>* geom = static_cast<const IfcGeom::TriangulationElement<float>*>(iterator->get());
Entity(geom).write(std::cout);
continue;
}
case NEXT: {
Next n; n.read(std::cin);
has_more = IfcGeomObjects::Next();
has_more = iterator->next();
if (!has_more) {
IfcGeomObjects::CleanUp();
delete iterator;
iterator = 0;
}
More(has_more).write(std::cout);
continue;
}
case GET_LOG: {
GetLog gl; gl.read(std::cin);
WriteLog(IfcGeomObjects::GetLog()).write(std::cout);
WriteLog(iterator->getLog()).write(std::cout);
continue;
}
case BYE: {
+54 -24
View File
@@ -17,12 +17,15 @@
* *
********************************************************************************/
#include <map>
#include <set>
#include <Max.h>
#include <stdmat.h>
#include <istdplug.h>
#include "../ifcmax/IfcMax.h"
#include "../ifcgeom/IfcGeomObjects.h"
#include "../ifcgeom/IfcGeomIterator.h"
static const int NUM_MATERIAL_SLOTS = 24;
@@ -119,7 +122,7 @@ Mtl* FindMaterialByName(MtlBaseLib* library, const std::string& material_name) {
return m;
}
Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& slot, const IfcGeomObjects::Material& material) {
Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& slot, const IfcGeom::Material& material) {
Mtl* m = FindMaterialByName(library, material.name());
if (m == 0) {
StdMat2* stdm = NewDefaultStdMat();
@@ -148,7 +151,7 @@ Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& sl
return m;
}
Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi_mats, MtlBaseLib* library, Interface* max_interface, int& slot, const std::vector<IfcGeomObjects::Material>& materials, const std::string& object_type, const std::vector<int>& material_ids) {
Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi_mats, MtlBaseLib* library, Interface* max_interface, int& slot, const std::vector<IfcGeom::Material>& materials, const std::string& object_type, const std::vector<int>& material_ids) {
std::vector<std::string> material_names;
bool needs_default = std::find(material_ids.begin(), material_ids.end(), -1) != material_ids.end();
if (needs_default) {
@@ -200,9 +203,10 @@ Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi_mats,
int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, BOOL suppressPrompts) {
IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS,false);
IfcGeomObjects::Settings(IfcGeomObjects::WELD_VERTICES,true);
IfcGeomObjects::Settings(IfcGeomObjects::SEW_SHELLS,true);
IfcGeom::IteratorSettings settings;
settings.use_world_coords() = false;
settings.weld_vertices() = true;
settings.sew_shells() = true;
#ifdef _UNICODE
int fn_buffer_size = WideCharToMultiByte(CP_UTF8, 0, name, -1, 0, 0, 0, 0);
@@ -212,7 +216,9 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
const char* fn_mb = name;
#endif
if ( ! IfcGeomObjects::Init(fn_mb,0,0) ) return false;
IfcGeom::Iterator<float> iterator(settings, fn_mb);
if (!iterator.initialize()) return false;
itfc->ProgressStart(_T("Importing file..."), TRUE, fn, NULL);
@@ -222,31 +228,56 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
std::map<std::vector<std::string>, Mtl*> material_cache;
do{
const IfcGeomObjects::IfcGeomObject* o = IfcGeomObjects::Get();
const IfcGeom::TriangulationElement<float>* o = static_cast<const IfcGeom::TriangulationElement<float>*>(iterator.get());
TSTR o_type = S(o->type());
TSTR o_guid = S(o->guid());
Mtl *m = ComposeMultiMaterial(material_cache, mats, itfc, slot, o->mesh().materials(), o->type(), o->mesh().material_ids());
Mtl *m = ComposeMultiMaterial(material_cache, mats, itfc, slot, o->geometry().materials(), o->type(), o->geometry().material_ids());
TriObject* tri = CreateNewTriObject();
const int numVerts = o->mesh().verts().size()/3;
const int numVerts = o->geometry().verts().size()/3;
tri->mesh.setNumVerts(numVerts);
for( int i = 0; i < numVerts; i ++ ) {
tri->mesh.setVert(i,o->mesh().verts()[3*i+0],o->mesh().verts()[3*i+1],o->mesh().verts()[3*i+2]);
tri->mesh.setVert(i,o->geometry().verts()[3*i+0],o->geometry().verts()[3*i+1],o->geometry().verts()[3*i+2]);
}
const int numFaces = o->mesh().faces().size()/3;
const int numFaces = o->geometry().faces().size()/3;
tri->mesh.setNumFaces(numFaces);
bool needs_default = std::find(o->mesh().material_ids().begin(), o->mesh().material_ids().end(), -1) != o->mesh().material_ids().end();
bool needs_default = std::find(o->geometry().material_ids().begin(), o->geometry().material_ids().end(), -1) != o->geometry().material_ids().end();
typedef std::pair<int, int> edge_t;
std::set<edge_t> face_boundaries;
for(std::vector<int>::const_iterator it = o->geometry().edges().begin(); it != o->geometry().edges().end();) {
const int v1 = *it++;
const int v2 = *it++;
const edge_t e((std::min)(v1, v2), (std::max)(v1, v2));
face_boundaries.insert(e);
}
for( int i = 0; i < numFaces; i ++ ) {
tri->mesh.faces[i].setVerts(o->mesh().faces()[3*i+0],o->mesh().faces()[3*i+1],o->mesh().faces()[3*i+2]);
tri->mesh.faces[i].setEdgeVisFlags(o->mesh().edges()[3*i+0],o->mesh().edges()[3*i+1],o->mesh().edges()[3*i+2]);
MtlID mtlid = o->mesh().material_ids()[i];
if (needs_default) mtlid ++;
const int v1 = o->geometry().faces()[3*i+0];
const int v2 = o->geometry().faces()[3*i+1];
const int v3 = o->geometry().faces()[3*i+2];
const edge_t e1((std::min)(v1, v2), (std::max)(v1, v2));
const edge_t e2((std::min)(v2, v3), (std::max)(v2, v3));
const edge_t e3((std::min)(v3, v1), (std::max)(v3, v1));
const bool b1 = face_boundaries.find(e1) != face_boundaries.end();
const bool b2 = face_boundaries.find(e2) != face_boundaries.end();
const bool b3 = face_boundaries.find(e3) != face_boundaries.end();
tri->mesh.faces[i].setVerts(v1, v2, v3);
tri->mesh.faces[i].setEdgeVisFlags(b1, b2, b3);
MtlID mtlid = o->geometry().material_ids()[i];
if (needs_default) {
mtlid ++;
}
tri->mesh.faces[i].setMatID(mtlid);
}
@@ -267,15 +298,14 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
if (m) {
node->GetINode()->SetMtl(m);
}
node->SetTransform(0,Matrix3 ( Point3(o->matrix()[0],o->matrix()[1],o->matrix()[2]),Point3(o->matrix()[3],o->matrix()[4],o->matrix()[5]),
Point3(o->matrix()[6],o->matrix()[7],o->matrix()[8]),Point3(o->matrix()[9],o->matrix()[10],o->matrix()[11]) ));
const std::vector<float>& matrix_data = o->transformation().matrix().data();
node->SetTransform(0,Matrix3 ( Point3(matrix_data[0],matrix_data[1],matrix_data[2]),Point3(matrix_data[3],matrix_data[4],matrix_data[5]),
Point3(matrix_data[6],matrix_data[7],matrix_data[8]),Point3(matrix_data[9],matrix_data[10],matrix_data[11]) ));
impitfc->AddNodeToScene(node);
itfc->ProgressUpdate(IfcGeomObjects::Progress(),true,_T(""));
itfc->ProgressUpdate(iterator.progress(), true, _T(""));
} while ( IfcGeomObjects::Next() );
IfcGeomObjects::CleanUp();
} while (iterator.next());
itfc->ProgressEnd();
-48
View File
@@ -1,48 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* This file defines materials for use in 3ds Max for several IFC datatypes *
* *
********************************************************************************/
#include <string>
#include "Max.h"
#include "stdmat.h"
StdMat2* GetMaterial(const std::string& s) {
StdMat2* mat = NewDefaultStdMat();
TimeValue t (-1);
mat->SetSpecular(Color(0.2f,0.2f,0.2f),t);
mat->SetAmbient(Color(0.1f,0.1f,0.1f),t);
mat->SetWire( s == "IfcSpace" || s == "IfcOpeningElement" );
if ( s == "IfcSite" ) { mat->SetDiffuse(Color(0.75f,0.8f,0.65f),t); }
if ( s == "IfcSlab" ) { mat->SetDiffuse(Color(0.4f,0.4f,0.4f),t); }
if ( s == "IfcWallStandardCase" ) { mat->SetDiffuse(Color(0.9f,0.9f,0.9f),t); }
if ( s == "IfcWall" ) { mat->SetDiffuse(Color(0.9f,0.9f,0.9f),t); }
if ( s == "IfcWindow" ) { mat->SetDiffuse(Color(0.75f,0.8f,0.75f),t); mat->SetSpecular(Color(1.0f,1.0f,1.0f),t);
mat->SetAmbient(Color(0.0f,0.0f,0.0f),t); mat->SetShininess(500.0f,t); mat->SetOpacity(0.3f,t); }
if ( s == "IfcDoor" ) { mat->SetDiffuse(Color(0.55f,0.3f,0.15f),t); }
if ( s == "IfcBeam" ) { mat->SetDiffuse(Color(0.75f,0.7f,0.7f),t); }
if ( s == "IfcRailing" ) { mat->SetDiffuse(Color(0.75f,0.7f,0.7f),t); }
if ( s == "IfcMember" ) { mat->SetDiffuse(Color(0.75f,0.7f,0.7f),t); }
return mat;
}
-127
View File
@@ -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 );
}
-5
View File
@@ -1,5 +0,0 @@
#include "../IfcObj/Materials.h"
void InitMaterials() {
materials["IFCSITE"] = ObjMaterial("IFCSITE",0.7f,0.8f,0.5f);
}
-64
View File
@@ -1,64 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* This file defines materials in .mtl format for several IFC datatypes *
* *
********************************************************************************/
#include <string>
#include <sstream>
class ObjMaterial {
private:
std::string data;
public:
ObjMaterial(const std::string& name,
double Kd_r = 0.7f,double Kd_g = 0.7f,double Kd_b = 0.7f,
double Ks_r = 0.2f,double Ks_g = 0.2f,double Ks_b = 0.2f,
double Ka_r = 0.1f,double Ka_g = 0.1f,double Ka_b = 0.1f,
double Ns = 10.0f, double Tr = 1.0f) {
std::stringstream ss;
ss << "newmtl " << name << std::endl;
ss << "Kd " << Kd_r << " " << Kd_g << " " << Kd_b << std::endl;
ss << "Ks " << Ks_r << " " << Ks_g << " " << Ks_b << std::endl;
ss << "Ka " << Ka_r << " " << Ka_g << " " << Ka_b << std::endl;
ss << "Ns " << Ns << std::endl;
ss << "Tr " << Tr << std::endl;
ss << "d " << Tr << std::endl;
ss << "D " << Tr << std::endl;
data = ss.str();
}
friend ostream& operator<<(ostream& o, const ObjMaterial& m) {o << m.data; return o;}
};
ObjMaterial GetMaterial(const std::string& s) {
if ( s == "IfcSite" ) { return ObjMaterial("IfcSite",0.75f,0.8f,0.65f); }
if ( s == "IfcSlab" ) { return ObjMaterial("IfcSlab",0.4f,0.4f,0.4f); }
if ( s == "IfcWallStandardCase" ) { return ObjMaterial("IfcWallStandardCase",0.9f,0.9f,0.9f); }
if ( s == "IfcWall" ) { return ObjMaterial("IfcWall",0.9f,0.9f,0.9f); }
if ( s == "IfcWindow" ) { return ObjMaterial("IfcWindow",0.75f,0.8f,0.75f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,500.0f,0.3f); }
if ( s == "IfcDoor" ) { return ObjMaterial("IfcDoor",0.55f,0.3f,0.15f); }
if ( s == "IfcBeam" ) { return ObjMaterial("IfcBeam",0.75f,0.7f,0.7f); }
if ( s == "IfcRailing" ) { return ObjMaterial("IfcRailing",0.65f,0.6f,0.6f); }
if ( s == "IfcMember" ) { return ObjMaterial("IfcMember",0.65f,0.6f,0.6f); }
if ( s == "IfcPlate" ) { return ObjMaterial("IfcPlate",0.8f,0.8f,0.8f); }
return ObjMaterial(s);
}
@@ -0,0 +1,149 @@
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
import os
import sys
import numbers
import platform
import functools
import itertools
from functools import reduce
from . import guid
python_distribution = os.path.join(platform.system().lower(),
platform.architecture()[0],
'python%s.%s' % platform.python_version_tuple()[:2])
sys.path.append(os.path.abspath(os.path.join(
os.path.dirname(__file__),
'lib', python_distribution)))
try:
from . import ifcopenshell_wrapper
except:
raise ImportError("IfcOpenShell not built for '%s'" % python_distribution)
class entity_instance(object):
def __init__(self, e):
super(entity_instance, self).__setattr__('wrapped_data', e)
def __getattr__(self, name):
INVALID, FORWARD, INVERSE = range(3)
attr_cat = self.wrapped_data.get_attribute_category(name)
if attr_cat == FORWARD:
return entity_instance.wrap_value(self.wrapped_data.get_argument(self.wrapped_data.get_argument_index(name)))
elif attr_cat == INVERSE:
return entity_instance.wrap_value(self.wrapped_data.get_inverse(name))
else: raise AttributeError("entity instance of type '%s' has no attribute '%s'"%(self.wrapped_data.is_a(), name))
@staticmethod
def walk(f, g, value):
if isinstance(value, (tuple, list)): return tuple(map(functools.partial(entity_instance.walk, f, g), value))
elif f(value): return g(value)
else: return value
@staticmethod
def wrap_value(v):
wrap = lambda e: entity_instance(e)
is_instance = lambda e: isinstance(e, ifcopenshell_wrapper.entity_instance)
return entity_instance.walk(is_instance, wrap, v)
@staticmethod
def unwrap_value(v):
unwrap = lambda e: e.wrapped_data
is_instance = lambda e: isinstance(e, entity_instance)
return entity_instance.walk(is_instance, unwrap, v)
def attribute_type(self, attr):
attr_idx = attr if isinstance(attr, numbers.Integral) else self.wrapped_data.get_argument_index(attr)
return self.wrapped_data.get_argument_type(attr_idx)
def attribute_name(self, attr_idx):
return self.wrapped_data.get_argument_name(attr_idx)
def __setattr__(self, key, value):
self[self.wrapped_data.get_argument_index(key)] = value
def __getitem__(self, key):
return entity_instance.wrap_value(self.wrapped_data.get_argument(key))
def __setitem__(self, idx, value):
if value is None:
self.wrapped_data.setArgumentAsNull(idx)
else:
attr_type = self.attribute_type(idx).title().replace(' ', '')
attr_type = attr_type.replace('Binary', 'String')
attr_type = attr_type.replace('Enumeration', 'String')
try:
if isinstance(value, unicode): value = value.encode("utf-8")
except: pass
getattr(self.wrapped_data, "setArgumentAs%s" % attr_type)(idx, entity_instance.unwrap_value(value))
return value
def __len__(self): return len(self.wrapped_data)
def __repr__(self): return repr(self.wrapped_data)
def is_a(self, *args): return self.wrapped_data.is_a(*args)
def id(self): return self.wrapped_data.id()
def __dir__(self):
return sorted(set(itertools.chain(
dir(type(self)),
self.wrapped_data.get_attribute_names(),
self.wrapped_data.get_inverse_attribute_names()
)))
class file(object):
def __init__(self, f=None):
self.wrapped_data = f or ifcopenshell_wrapper.file(True)
def create_entity(self,type,*args,**kwargs):
e = entity_instance(ifcopenshell_wrapper.entity_instance(type))
attrs = list(enumerate(args)) + \
[(e.wrapped_data.get_argument_index(name), arg) for name, arg in kwargs.items()]
for idx, arg in attrs: e[idx] = arg
self.wrapped_data.add(e.wrapped_data)
e.wrapped_data.this.disown()
return e
def __getattr__(self, attr):
if attr[0:6] == 'create': return functools.partial(self.create_entity,attr[6:])
else: return getattr(self.wrapped_data, attr)
def __getitem__(self, key):
if isinstance(key, numbers.Integral):
return entity_instance(self.wrapped_data.by_id(key))
elif isinstance(key, str):
return entity_instance(self.wrapped_data.by_guid(key))
def by_id(self, id): return self[id]
def by_guid(self, guid): return self[guid]
def add(self, inst):
inst.wrapped_data.this.disown()
return entity_instance(self.wrapped_data.add(inst.wrapped_data))
def by_type(self, type):
return [entity_instance(e) for e in self.wrapped_data.by_type(type)]
def traverse(self, inst):
return [entity_instance(e) for e in self.wrapped_data.traverse(inst.wrapped_data)]
def remove(self, inst):
return self.wrapped_data.remove(inst.wrapped_data)
def __iter__(self):
return iter(self[id] for id in self.wrapped_data.entity_names())
def open(fn=None):
return file(ifcopenshell_wrapper.open(os.path.abspath(fn))) if fn else file()
def create_entity(type,*args,**kwargs):
e = entity_instance(ifcopenshell_wrapper.entity_instance(type))
attrs = list(enumerate(args)) + \
[(e.wrapped_data.get_argument_index(name), arg) for name, arg in kwargs.items()]
for idx, arg in attrs: e[idx] = arg
return e
version = ifcopenshell_wrapper.version()
schema_identifier = ifcopenshell_wrapper.schema_identifier()
@@ -0,0 +1,88 @@
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
import os
import sys
from .. import ifcopenshell_wrapper
def has_occ():
try: import OCC.BRepTools
except: return False
return True
has_occ = has_occ()
wrap_shape_creation = lambda settings, shape: shape
if has_occ:
from . import occ_utils as utils
wrap_shape_creation = lambda settings, shape: utils.create_shape_from_serialization(shape) if getattr(settings, 'use_python_opencascade', False) else shape
# Subclass the settings module to provide an additional
# setting to enable pythonOCC when available
class settings(ifcopenshell_wrapper.settings):
if has_occ:
USE_PYTHON_OPENCASCADE = -1
def set(self, *args):
setting, value = args
if setting == settings.USE_PYTHON_OPENCASCADE:
self.set(settings.USE_BREP_DATA, value)
self.set(settings.USE_WORLD_COORDS, value)
self.set(settings.DISABLE_TRIANGULATION, value)
self.use_python_opencascade = value
else:
ifcopenshell_wrapper.settings.set(self, *args)
# Hide templating precision to the user by choosing based on Python's
# internal float type. This is probably always going to be a double.
for ty in (ifcopenshell_wrapper.iterator_single_precision, ifcopenshell_wrapper.iterator_double_precision):
if ty.mantissa_size() == sys.float_info.mant_dig:
_iterator = ty
# Make sure people are able to use python's platform agnostic paths
class iterator(_iterator):
def __init__(self, settings, filename):
self.settings = settings
_iterator.__init__(self, settings, os.path.abspath(filename))
if has_occ:
def get(self):
return wrap_shape_creation(self.settings, _iterator.get(self))
def create_shape(settings, inst, repr=None):
return wrap_shape_creation(
settings,
ifcopenshell_wrapper.create_shape(
settings,
inst.wrapped_data,
repr.wrapped_data if repr is not None else None
))
def iterate(settings, filename):
it = iterator(settings, filename)
if it.initialize():
while True:
yield it.get()
if not it.next(): break
@@ -0,0 +1,94 @@
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
import random
from collections import namedtuple
import OCC.gp
import OCC.V3d
import OCC.Quantity
import OCC.BRepTools
import OCC.Display.SimpleGui
tuple = namedtuple('shape', ('data', 'geometry'))
handle, main_loop, add_menu, add_function_to_menu = None, None, None, None
def initialize_display():
global handle, main_loop, add_menu, add_function_to_menu
handle, main_loop, add_menu, add_function_to_menu = OCC.Display.SimpleGui.init_display()
def setup():
viewer_handle = handle.GetViewer()
viewer = viewer_handle.GetObject()
while True:
viewer.InitActiveLights()
try: active_light = viewer.ActiveLight()
except: break
viewer.DelLight(active_light)
viewer.NextActiveLights()
for dir in [(1,2,-3), (-2,-1,1)]:
light = OCC.V3d.V3d_DirectionalLight(viewer_handle)
light.SetDirection(*dir)
viewer.SetLightOn(light.GetHandle())
setup()
return handle
def display_shape(shape, clr=None):
if not clr:
r = lambda: random.random() * 0.3 + 0.7
clr = OCC.Quantity.Quantity_Color(r(), r(), r(), OCC.Quantity.Quantity_TOC_RGB)
return handle.DisplayShape(shape, color=clr, update=True)
def set_shape_transparency(ais, t):
handle.Context.SetTransparency(ais, t)
def get_bounding_box_center(bbox):
bbmin = [0.]*3; bbmax = [0.]*3
bbmin[0], bbmin[1], bbmin[2], bbmax[0], bbmax[1], bbmax[2] = bbox.Get()
return OCC.gp.gp_Pnt(*map(lambda xy: (xy[0]+xy[1])/2., zip(bbmin, bbmax)))
def create_shape_from_serialization(brep_object):
brep_data, occ_shape = None, None
is_product_shape = True
try:
brep_data = brep_object.geometry.brep_data
except:
try:
brep_data = brep_object.brep_data
is_product_shape = False
except: pass
if not brep_data: return tuple(brep_object, None)
try:
ss = OCC.BRepTools.BRepTools_ShapeSet()
ss.ReadFromString(brep_data)
occ_shape = ss.Shape(ss.NbShapes())
except: pass
if is_product_shape:
return tuple(brep_object, occ_shape)
else:
return occ_shape
@@ -0,0 +1,43 @@
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
import string
from functools import reduce
chars = string.digits + string.ascii_uppercase + string.ascii_lowercase + '_$'
def compress(g):
bs = [int(g[i:i+2], 16) for i in range(0, len(g), 2)]
def b64(v, l=4):
return ''.join([chars[(v // (64**i))%64] for i in range(l)][::-1])
return ''.join([b64(bs[0], 2)] + [b64((bs[i] << 16) + (bs[i+1] << 8) + bs[i+2]) for i in range(1,16,3)])
def expand(g):
def b64(v):
return reduce(lambda a, b: a * 64 + b, map(lambda c: chars.index(c), v))
bs = [b64(g[0:2])]
for i in range(5):
d = b64(g[2+4*i:6+4*i])
bs += [(d >> (8*(2-j)))%256 for j in range(3)]
return ''.join(['%02x'%b for b in bs])
def split(g):
return '{%s-%s-%s-%s-%s}'%(g[:8], g[8:12], g[12:16], g[16:20], g[20:])
+89
View File
@@ -0,0 +1,89 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef HDF5SETTINGS_H
#define HDF5SETTINGS_H
#include <string>
#include <vector>
#include <stdexcept>
namespace IfcParse {
struct Hdf5Settings {
private:
bool compress_, fix_cartesian_point_, fix_global_id_, instantiate_select_, instantiate_inverse_;
unsigned int chunk_size_;
std::vector<std::string> ref_attributes_;
public:
enum Profile {
standard,
padded,
standard_referenced,
padded_referenced
};
static Profile ProfileFromString(const std::string& s) {
if (s == "standard") return standard;
if (s == "padded") return padded;
if (s == "referenced") return standard_referenced;
if (s == "padded-referenced") return padded_referenced;
throw std::runtime_error("Unrecognized profile");
}
private:
Profile profile_;
public:
Hdf5Settings()
: compress_(false)
, fix_cartesian_point_(false)
, fix_global_id_(false)
, instantiate_select_(false)
, instantiate_inverse_(false)
, chunk_size_(false)
, profile_(standard)
{}
bool compress() const { return compress_; }
bool fix_cartesian_point() const { return fix_cartesian_point_; }
bool fix_global_id() const { return fix_global_id_; }
bool instantiate_select() const { return instantiate_select_; }
bool instantiate_inverse() const { return instantiate_inverse_; }
bool& compress() { return compress_; }
bool& fix_cartesian_point() { return fix_cartesian_point_; }
bool& fix_global_id() { return fix_global_id_; }
bool& instantiate_select() { return instantiate_select_; }
bool& instantiate_inverse() { return instantiate_inverse_; }
unsigned int chunk_size() const { return chunk_size_; }
unsigned int& chunk_size() { return chunk_size_; }
Profile profile() const { return profile_; }
Profile& profile() { return profile_; }
const std::vector<std::string>& ref_attributes() const { return ref_attributes_; }
std::vector<std::string>& ref_attributes() { return ref_attributes_; }
};
}
#endif
File diff suppressed because it is too large Load Diff
@@ -23,7 +23,9 @@
* but instead modify the python script that has been used to generate this. *
* *
********************************************************************************/
#ifndef USE_IFC4
#ifndef IFC2X3RT_H
#define IFC2X3RT_H
@@ -38,13 +40,15 @@ namespace Type {
int GetAttributeCount(Enum t);
int GetAttributeIndex(Enum t, const std::string& a);
IfcUtil::ArgumentType GetAttributeType(Enum t, unsigned char a);
Enum GetAttributeEntity(Enum t, unsigned char a);
const std::string& GetAttributeName(Enum t, unsigned char a);
bool GetAttributeOptional(Enum t, unsigned char a);
bool GetAttributeDerived(Enum t, unsigned char a);
std::pair<const char*, int> GetEnumerationIndex(Enum t, const std::string& a);
std::pair<Enum, unsigned> GetInverseAttribute(Enum t, const std::string& a);
Enum GetAttributeEnumerationClass(Enum t, unsigned char a);
std::set<std::string> GetInverseAttributeNames(Enum t);
void PopulateDerivedFields(IfcWrite::IfcWritableEntity* e);
}}
#endif
#endif
File diff suppressed because it is too large Load Diff
+8368 -6113
View File
File diff suppressed because one or more lines are too long

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