Compare commits

...

1373 Commits

Author SHA1 Message Date
Thomas Krijnen 60b160461e Update README 2020-02-01 11:23:01 +01:00
Thomas Krijnen df6852d2ac space boundaries 2020-02-01 11:16:09 +01:00
Thomas Krijnen 6b250b3ccf manifold solid brep 2020-02-01 11:15:40 +01:00
Thomas Krijnen bca78e086d Storey containment fuzziness 2020-01-31 11:58:14 +01:00
Thomas Krijnen cbf147b9f9 area overlap 2020-01-31 11:57:52 +01:00
Thomas Krijnen a805496895 Disable polyline point removal 2020-01-29 17:29:33 +01:00
Thomas Krijnen b91a34c8c6 Track time; fixes for wall connectivity check 2020-01-29 14:57:49 +01:00
Thomas Krijnen e448312d41 Reporting for wall connectivity 2020-01-27 10:42:01 +01:00
Thomas Krijnen 1d6f20c48d Fix wall connectivity 2020-01-26 17:11:14 +01:00
Thomas Krijnen 7a8a5e2ebb Dont close polylines automatically 2020-01-26 17:11:02 +01:00
Thomas Krijnen b6a7ba1e1c Fix for open polyhedra 2020-01-26 13:58:02 +01:00
Thomas Krijnen 060c35939a Wall connectivity 2020-01-26 13:12:19 +01:00
Thomas Krijnen 030ea06aac Fix placement on containment case 2020-01-25 14:24:18 +01:00
Thomas Krijnen 3575aded90 containment check 2020-01-21 16:26:00 +01:00
Thomas Krijnen 487be4b65e Correct projection to middle surface 2019-12-14 16:17:36 +01:00
Thomas Krijnen 612fb8d8d5 Average space boundary construction in Nef polyhedra 2019-12-14 14:50:20 +01:00
Thomas Krijnen a729f489ee Fix double free 2019-12-14 14:41:41 +01:00
Thomas Krijnen 59b04c7857 Validation work using Nef 2019-12-14 13:25:30 +01:00
Thomas Krijnen a5de17228a Work towards space boundaries fix 2019-10-06 19:03:31 +02:00
Thomas Krijnen f391b425ba dilate as boolean 2019-10-06 09:11:44 +02:00
Thomas Krijnen 389964c9f4 cgal boolean result and minkowski sum for dilation 2019-09-25 15:30:11 +02:00
Thomas Krijnen 11ad1b2cc5 cgal extrusion 2019-09-24 15:46:50 +02:00
Thomas Krijnen d91ac7363f Mark loops from profile_helper as external 2019-09-22 16:02:48 +02:00
Thomas Krijnen 0085393884 Take into account vertex welding 2019-09-22 16:02:22 +02:00
Thomas Krijnen 61403e878e Try catch face normal computation 2019-09-22 16:02:05 +02:00
Thomas Krijnen a1671448db Default static runtime to off. 2019-09-22 15:05:14 +02:00
Thomas Krijnen 474786c4c5 IfcArbitraryProfileDefWithVoids 2019-09-22 10:32:03 +02:00
Thomas Krijnen 1f4bc28e2b Product placements and openings 2019-09-19 10:11:01 +02:00
Thomas Krijnen 3cde411e1b halfspaces and boolean ops 2019-09-18 16:35:26 +02:00
Thomas Krijnen a447dc6208 Work towards trimmed curves 2019-09-16 19:30:11 +02:00
Thomas Krijnen 3731c95728 Mapped item 2019-09-16 17:40:55 +02:00
Thomas Krijnen d59f3e9932 Polyline 2019-09-16 15:40:13 +02:00
Thomas Krijnen 04bce57e80 Fix placements 2019-09-16 10:25:39 +02:00
Thomas Krijnen e3041219b5 Further work on profiles 2019-09-15 15:59:05 +02:00
Thomas Krijnen 0c54bdcd54 Cleanup 2019-09-04 09:10:57 +02:00
Thomas Krijnen bed9c44883 mark bounds as external based on entity type 2019-09-01 18:46:11 +02:00
Thomas Krijnen 8efb86420e Compilation errors 2019-09-01 16:48:50 +02:00
Thomas Krijnen 7f8bed9922 Begin reenable CGAL kernel 2019-09-01 16:29:00 +02:00
Thomas Krijnen 816c0d3618 Fix placements 2019-09-01 13:36:46 +02:00
Thomas Krijnen 2e7c43f590 Work on placements 2019-09-01 10:36:49 +02:00
Thomas Krijnen ca2a4f243d initialize units in mapping 2019-09-01 09:18:29 +02:00
Thomas Krijnen 64ee3e9af3 closed shell; placements; faceset_helper 2019-08-28 09:54:20 +02:00
Thomas Krijnen 3bfe3b9ab5 Seperate map() and map_impl() for automatic taxonomy item <> ifc instance mapping 2019-08-28 09:24:00 +02:00
Thomas Krijnen 640b08159f Work on shells 2019-08-27 18:59:19 +02:00
Thomas Krijnen f17036313d Work on face boundaries 2019-08-26 17:19:06 +02:00
Thomas Krijnen 8b4900b0e1 Work on shell conversino 2019-08-25 16:07:10 +02:00
Thomas Krijnen 41d7fb32da Provide collection implementation in abstract_kernel 2019-08-25 12:00:04 +02:00
Thomas Krijnen 8ec2019003 Fix enumeration order 2019-08-25 11:50:40 +02:00
Thomas Krijnen 26d7af1450 Implement additional mappings 2019-08-24 18:32:30 +02:00
Thomas Krijnen 2f1861db7b Declare conversions for reuse detection 2019-08-24 17:36:17 +02:00
Thomas Krijnen 94aa7dfab4 Close to working executable 2019-08-18 15:53:26 +02:00
Thomas Krijnen 8f88c601c6 IfcConvert links on windows 2019-08-18 14:31:22 +02:00
Thomas Krijnen 85171bb5df Remove ConversionResultPlacement, fix some errors 2019-08-18 08:37:59 +02:00
Thomas Krijnen 585b89be87 Fix compilation of serializers and convert 2019-08-17 09:47:07 +02:00
Thomas Krijnen ddeaf5a375 More work 2019-08-16 17:40:13 +02:00
Thomas Krijnen dae35f59ce Implement mapping of IfcExtrudedAreaSolid 2019-08-04 11:27:10 +02:00
Thomas Krijnen 467ebb68a3 First step at reorganizing 2019-08-04 09:36:31 +02:00
Thomas Krijnen c8def0474e Update examples 2019-08-03 16:11:02 +02:00
Thomas Krijnen f6aa7c8930 Additional merge issues 2019-08-03 15:43:14 +02:00
Thomas Krijnen 92f7d26835 Work on Python wrapper 2019-08-03 15:09:50 +02:00
Thomas Krijnen 5ccc7213a0 Merge remote-tracking branch 'origin/v0.6.0' into v0.7.0 2019-08-03 14:50:08 +02:00
Thomas Krijnen 188b20533b Only pull when on a branch 2019-08-03 14:48:01 +02:00
Thomas Krijnen fd9c57b77d Merge branch 'v0.6.0' into v0.7.0 2019-08-02 17:56:45 +02:00
Thomas Krijnen f32e034963 Merge pull request #639 from aothms/multithreaded
Multithreaded
2019-08-02 15:37:00 +02:00
Thomas Krijnen fd3469029f -pthread on unix 2019-08-02 14:55:55 +02:00
Thomas Krijnen 88a5dc3053 fix po::value 2019-08-02 13:27:33 +02:00
Thomas Krijnen b08e52bd9b Merge remote-tracking branch 'origin/v0.6.0' into v0.7.0 2019-08-02 13:23:41 +02:00
Thomas Krijnen 6e4a692de3 Threads in python app 2019-07-19 15:55:22 +02:00
Thomas Krijnen a6835360e4 Guarantee get_decomposing(IfcProject*) == nullptr 2019-07-12 10:43:35 +02:00
Thomas Krijnen 4ec9ab52f1 Remove IfcFileWithSchema 2019-07-10 16:34:57 +02:00
Thomas Krijnen 7ee6cdeeab Add missing header 2019-07-10 16:17:11 +02:00
Thomas Krijnen c9530999f7 Update CMakeLists.txt 2019-07-10 15:44:38 +02:00
Thomas Krijnen 2154e24af1 GLTF_SUPPORT depends on BUILD_CONVERT 2019-07-10 14:35:56 +02:00
Thomas Krijnen 1cd2287d86 Cleanup concurrently created breps and triangulations 2019-07-09 16:34:35 +02:00
Thomas Krijnen 40937b3c72 Write progress for threaded conversion 2019-07-09 16:12:12 +02:00
Thomas Krijnen 3bcced7baa Some fixes to threading work 2019-07-09 16:00:29 +02:00
Thomas Krijnen 3ebca0516e Implement multi_threaded implementation in Iterator 2019-07-03 12:10:27 +02:00
Thomas Krijnen ae2feb2848 Merge remote-tracking branch 'origin/pr/638' into multithreaded 2019-07-02 15:21:46 +02:00
Thomas Krijnen 2a447039d0 Merge remote-tracking branch 'sander/multithreaded' into multithreaded 2019-07-02 15:21:24 +02:00
You Yue 0dec407dbe Last commit for multithreading, Airsquire implementation 2019-07-02 12:30:40 +02:00
You Yue a286598e55 Sander boer's change for multithreading
1. Added multithread for create element
2. Added support function in IfcConvert.cpp for multithreading at bottom
2019-07-02 12:10:08 +02:00
Thomas Krijnen 869cc25061 rollback prcre version due to https://github.com/KhronosGroup/OpenCOLLADA/issues/570 2019-07-01 11:15:12 +02:00
Thomas Krijnen b4ce5be86d Fix error after merge 2019-06-30 15:46:36 +02:00
Thomas Krijnen 1341be223b Merge branch 'master' into v0.6.0 2019-06-30 10:52:21 +02:00
Thomas Krijnen 1103f545a2 Double braces for older version of g++ 2019-06-30 10:51:45 +02:00
Thomas Krijnen 51cf52c388 Build script: Don't use wget or curl, just urlretrieve 2019-06-30 09:44:40 +02:00
Thomas Krijnen c29cc87660 Revert cmake version due to build errors, more careful json install 2019-06-28 08:38:24 +02:00
Thomas Krijnen 839b5a2699 Minor cleanups, 4x1 and 4x2 geom lib, granular schema macros 2019-06-26 13:50:46 +02:00
Thomas Krijnen 73f7c34c8d Update build-all.py 2019-06-26 12:44:56 +02:00
Andrej Tibaut 636b2aafdf 1) Added support for IFC4x1 (see issue https://github.com/IfcOpenShell/IfcOpenShell/issues/504#issuecomment-505051675).
2) New build parameters (flags) introduced for use of IFC4x1 and IFC4x2: USE_IFC4X2 (for use of IfcBridge), USE_IFC4X1 (for use of IfcAlignment)

This explains new parameters (flags):
#ifdef USE_IFC4X2
#include "../ifcparse/Ifc4x2enum.h"
#elif USE_IFC4X1
#include "../ifcparse/Ifc4x1enum.h"
#elif USE_IFC4
#include "../ifcparse/Ifc4enum.h"
#else
#include "../ifcparse/Ifc2x3enum.h"
#endif

3) Added comment block  "This file is part of IfcOpenShell. ..." at the beggining of the Ifc4x2* files.
2019-06-26 12:44:26 +02:00
Andrej Tibaut cee2c4e748 Reverted from SWIG_VERSION=4.0.0 back to SWIG_VERSION=3.0.12 because of https://github.com/IfcOpenShell/IfcOpenShell/issues/582#issuecomment-497789849 as recommended by @aothms. 2019-06-26 12:44:26 +02:00
Andrej Tibaut e7a08a3de6 #634 solved:
- new method to_pystring(...) added to solve the TypeError: Can't mix strings and bytes in path components:
- import "urlib" changed to "urlib.urlretrieve"
- JSON version extracted to a constant
2019-06-26 12:44:26 +02:00
Andrej Tibaut 827c6ac6b4 Motivated by issue #608 to improve the method def git_clone(...) to the def git_clone_or_pull_repository(...).
Also, dependencies versions were updated.
2019-06-26 12:44:26 +02:00
Andrej Tibaut d371f1a6be UnicodeDecodeError problem solved (#630)
* UnicodeDecodeError problem solved

UnicodeDecodeError problem described in #626 solved.

* UnicodeDecodeError solved (2)

UnicodeDecodeError problem described in #626 changed (fname replaced with fn) and solved.
2019-06-21 11:43:53 +02:00
Otso Alho a851a25ddc catch Standard_ConstructionError when serialising xml attributes 2019-06-21 11:21:33 +02:00
Thomas Krijnen 35160e5a94 Update some code comments 2019-06-19 12:41:54 +02:00
Mathias Artus a9a6cfabca Added support for Ifc 4x2 2019-06-19 11:31:11 +02:00
Thomas Krijnen ecb0fee0cd Fix latebound enumeration writing in IfcConvert 2019-06-18 14:28:57 +02:00
Thomas Krijnen 12e9f7b941 Merge branch 'master' into v0.6.0 2019-06-15 15:24:53 +02:00
ninichki 443b8c2079 Boolean Operands like ST_SHAPELIST should not append all shapes 2019-06-14 17:33:30 +02:00
Thomas Krijnen 826316cb2b Remove duplicate faces in faceset_helper. Fixes #600 2019-06-14 11:32:59 +02:00
Thomas Krijnen 491dc57098 Update README.md 2019-06-14 10:00:42 +02:00
Otso Alho 19ed074b4a inverse thicknesses 2019-06-07 11:17:51 +02:00
Otso Alho 2cfe74ce09 reverse styles also when reversing surfaces 2019-06-07 11:17:51 +02:00
Thomas Krijnen b0b844ea5a Provide node names in gltf serializer 2019-06-07 10:38:52 +02:00
Thomas Krijnen 2d0812d46e Update test file submodule 2019-06-05 16:59:04 +02:00
Thomas Krijnen f5b7d0db59 Remove additional fuzz markup on halfspace operands and initially process with smaller fuzz. Fixes #601 2019-06-05 16:58:08 +02:00
Thomas Krijnen 68068cb816 Fix merge error: bring back assignment to Logger::max_severity 2019-06-04 17:24:59 +02:00
Thomas Krijnen 40d2c237fc Merge master 2019-06-04 17:07:35 +02:00
Thomas Krijnen 7e089ab8b5 Fix cleanup of temp files in case of failed initialization 2019-06-04 17:06:13 +02:00
Thomas Krijnen 8ee86f9968 Clean up glb tempfiles in case of error 2019-06-04 17:03:58 +02:00
Thomas Krijnen 2590bd01d5 Fix gltf max accessor meta-data 2019-06-04 16:55:19 +02:00
Thomas Krijnen ef9b9e743f Typo 2019-06-04 16:34:57 +02:00
Thomas Krijnen 532f129458 Tolerance tweaks on unification prior to boolean ops 2019-06-04 14:24:19 +02:00
Thomas Krijnen d535cf0222 Merge master 2019-05-31 14:33:40 +02:00
Thomas Krijnen 77e02ddae4 Remove all references to _newclass from wrapper code 2019-05-31 14:31:31 +02:00
Thomas Krijnen 98bf6c2d95 Merge branch 'master' into v0.6.0
# Conflicts:
#	src/ifcconvert/IfcConvert.cpp
2019-05-28 12:50:38 +02:00
Thomas Krijnen b27482db46 Correct change_extension after unicode changes 2019-05-28 12:48:40 +02:00
Thomas Krijnen 3d2e99b5fa Correct change_extension after unicode changes 2019-05-28 12:44:58 +02:00
Thomas Krijnen 8b382df7cc CMake IFCOPENSHELL_LIBRARIES depending on configuration options 2019-05-28 12:04:13 +02:00
Thomas Krijnen 1a57162873 Do unify boolean operands, especially after new triangulation logic. 2019-05-24 17:16:31 +02:00
Thomas Krijnen 69f25a563c Merge branch 'master' into v0.6.0 2019-05-24 15:39:52 +02:00
Thomas Krijnen 9a85fbc225 Fix static/const declaration 2019-05-24 15:38:35 +02:00
Thomas Krijnen dd71abc672 Fix enum name in geom wrapper 2019-05-24 15:11:09 +02:00
Thomas Krijnen aa493f5987 Merge branch 'master' into v0.6.0 2019-05-24 14:53:50 +02:00
Thomas Krijnen 784c1724d5 Check shell validity in accordance with https://github.com/IfcOpenShell/IfcOpenShell/commit/342cce89d70a5ded5fb1bf52d87383bfce5021ca#commitcomment-31511282 2019-05-24 14:49:14 +02:00
Thomas Krijnen 901e805d24 Revert 13d2cf3357 2019-05-24 14:29:21 +02:00
Thomas Krijnen 41972bba7d Merge branch 'master' into v0.6.0 2019-05-24 12:10:00 +02:00
Thomas Krijnen 17077c74a9 Unify transitionmode for swept disk and swept area 2019-05-24 12:09:33 +02:00
Thomas Krijnen 825a493d7a Add an additional reuse_ok check to the products associated to the *mapped* representation 2019-05-24 12:08:39 +02:00
Thomas Krijnen 6f5e4ec655 Fix iterator constructor in ifcblender 2019-05-24 10:38:31 +02:00
Thomas Krijnen de3f8cdaf4 Merge branch 'master' into v0.6.0 2019-05-24 10:36:43 +02:00
Thomas Krijnen 241c95e6df Some fixes for Blender 2.8? 2019-05-24 10:34:54 +02:00
Thomas Krijnen 8015ea217e codecvt fallback for g++4.8 2019-05-22 22:13:12 +02:00
Thomas Krijnen 285d40d586 add to_string() method in ifcopenshell.file 2019-05-22 16:18:48 +02:00
Thomas Krijnen 80e166302a Fix SVG exporer in 0.6 branch 2019-05-22 14:44:06 +02:00
Thomas Krijnen bcf8cadc30 Correct Y-UP transform in gltf serializer 2019-05-21 18:02:10 +02:00
Thomas Krijnen 26621cbcd5 Update version string to 0.6.0b0 2019-05-21 13:33:59 +02:00
Thomas Krijnen 703c69fdde Update nix build script to default GLTF_SUPPORT to ON 2019-05-21 13:31:43 +02:00
Thomas Krijnen 21981403c7 Merge branch 'master' into v0.6.0
# Conflicts:
#	nix/build-all.py
2019-05-21 13:30:58 +02:00
Daniel Smith c61bc29f06 Relocate random header include 2019-05-21 13:12:27 +02:00
Thomas Krijnen 90ac50f210 Document libffi dependency in nix build script for installing py37 2019-05-21 12:53:54 +02:00
Thomas Krijnen 4e21298009 Merge branch 'master' into v0.6.0 2019-05-19 13:25:14 +02:00
Thomas Krijnen a5cc0f1cef Add python version 3.7.3 2019-05-19 13:22:24 +02:00
Thomas Krijnen d106f178d5 Merge branch 'master' into v0.6.0 2019-05-18 11:07:13 +02:00
Thomas Krijnen a98ab72f67 Update version number 2019-05-18 11:06:27 +02:00
Thomas Krijnen 62e4bf8fb3 Update to OCCT 7.3.0p3 2019-05-18 11:05:12 +02:00
Thomas Krijnen e532a2ead2 Merge branch 'master' into v0.6.0 2019-05-18 11:01:45 +02:00
Thomas Krijnen fd9ba0d243 char wchar_t compatibility 2019-05-18 11:01:17 +02:00
Thomas Krijnen 9a9422bea6 Use ASCII temp name for DAE on nix as well 2019-05-18 10:53:45 +02:00
Thomas Krijnen f10b4bdecc Use ASCII temp name for DAE on nix as well 2019-05-17 16:52:15 +02:00
Thomas Krijnen fd6de77577 Smaller markup on fuzziness for boolean result interference checks 2019-05-17 14:25:28 +02:00
Thomas Krijnen 1d5e560e66 Large refactoring of convert(IfcFace*) to support triangulation of non-planar faces with inner boundaries 2019-05-17 12:31:23 +02:00
Thomas Krijnen fa8ff0d878 Travis: reverse grep command order 2019-05-15 19:43:36 +02:00
Thomas Krijnen 7296bd1382 Try to fix python encoding test error 2019-05-15 17:38:46 +02:00
Thomas Krijnen d60b9df40c Add back ICU as a libxml2 dependency on Travis 2019-05-15 17:20:23 +02:00
Thomas Krijnen 0cb2c81227 Rough draft of a client application for the C++ IfcGeomServer binary 2019-05-15 17:13:29 +02:00
Thomas Krijnen bbf271a10e Fix volume calculation with voxels in geom server 2019-05-15 17:07:16 +02:00
Thomas Krijnen d45d843173 Fix CMake error 2019-05-15 14:27:31 +02:00
Thomas Krijnen 4fa283fb3c Write voxelization logic in geom server 2019-05-15 13:57:50 +02:00
Thomas Krijnen 4400a6ea4f Make use of cgal configurable 2019-05-15 11:13:58 +02:00
Thomas Krijnen 9cb321e73d Move include up for M_PI def on MSVC 2019-05-10 14:38:42 +02:00
Thomas Krijnen e566af84c2 Fix geom server for schema agnosticism 2019-05-10 14:35:42 +02:00
Thomas Krijnen 310013dfe4 Fix compilation error from merge 2019-05-10 14:35:20 +02:00
Thomas Krijnen de3633e742 Cmake find voxels 2019-05-10 14:35:00 +02:00
Thomas Krijnen a24ad023a5 CGAL win build script 2019-05-10 13:46:13 +02:00
Thomas Krijnen adc0e92528 Fix remaining conflict 2019-05-10 13:42:16 +02:00
Thomas Krijnen 46ba5661d6 Merge branch 'v0.6.0' into v0.7.0 2019-05-10 13:37:42 +02:00
Thomas Krijnen 373934f993 Update submodule 2019-05-10 12:09:46 +02:00
Thomas Krijnen a8f6444cad Option to build -static on *nix 2019-05-10 12:04:32 +02:00
Thomas Krijnen 0b2bd5d0e8 Eliminate ICU dependency 2019-05-10 11:59:00 +02:00
Thomas Krijnen c15120e0ae Process string encoding test on travis 2019-05-10 11:56:40 +02:00
Thomas Krijnen 96cb6a73a2 Update .travis.yml 2019-05-08 14:27:00 +02:00
Thomas Krijnen 92b7ca15cf Update .travis.yml 2019-05-08 14:12:40 +02:00
Thomas Krijnen db65678f5e Setup glTF-Validator 2019-05-08 14:06:29 +02:00
Thomas Krijnen f3a7a6594a Small gcc fixes 2019-05-08 13:46:21 +02:00
Thomas Krijnen a786c9a9ee Validate glTF glb 2019-05-08 13:31:51 +02:00
Thomas Krijnen ab1d34fe1d Update CMakeLists.txt 2019-05-08 13:16:50 +02:00
Thomas Krijnen ff542d7381 Update .travis.yml 2019-05-08 13:16:29 +02:00
Thomas Krijnen 3023e084a6 Initial implementation of a direct binary glTF serializer 2019-05-07 17:06:45 +02:00
Sander Boer 0b02f7fb2b .clang-format settings indent=2 for me, temporarily. style=allman width=80 2019-05-03 17:30:48 +02:00
Sander Boer 66508876a5 builds nicely, but chokes immediately on serializer- first element, needs debugging 2019-05-03 17:28:08 +02:00
Thomas Krijnen 33bcf786fd MPIR and MPFR in win build script 2019-05-03 10:46:59 +02:00
Sander Boer 8ea77bdeca Linearizing the use of IfcGeomIterator by integrating it into IfcConvert in full, atm it does not build. 2019-05-01 18:34:01 +02:00
Thomas Krijnen 8e6a6ec56d Add voxelization_toolkit to win build script 2019-04-30 14:36:55 +02:00
Sander Boer 6468329f01 merge with ifcopenshell 2019-04-30 14:26:27 +02:00
Thomas Krijnen b862f633db Fix voxel library in nix build script 2019-04-30 13:24:28 +02:00
Thomas Krijnen 0fd3c69579 FindFromKey() backwards compat 2019-04-30 11:54:56 +02:00
Thomas Krijnen f9e839817d Add opensourceBIM/voxel to nix build script 2019-04-27 14:37:31 +02:00
Thomas Krijnen a0c01ff756 Merge branch 'v0.6.0' into v0.7.0
# Conflicts:
#	cmake/CMakeLists.txt
#	src/ifcconvert/IfcConvert.cpp
#	src/ifcgeom/IfcGeomRepresentation.h
#	src/ifcgeom/IfcRepresentationShapeItem.h
#	src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp
#	src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp
#	src/ifcgeom/schema_agnostic/Kernel.cpp
#	src/ifcgeom/schema_agnostic/Kernel.h
#	src/ifcgeomserver/IfcGeomServer.cpp
#	src/serializers/schema_dependent/XmlSerializer.cpp
2019-04-26 15:07:50 +02:00
Sander Boer 513d5d0666 Merge branch 'master' of https://github.com/IfcOpenShell/IfcOpenShell 2019-04-26 11:22:36 +02:00
Thomas Krijnen 4792fd9efe Don't do brute-force edge sewing in case of non-manifold faceset from wire intersections or triangulations 2019-04-24 17:15:18 +02:00
Thomas Krijnen 587edca99f Don't log empty error messages from boolean op 2019-04-24 17:01:02 +02:00
Thomas Krijnen 71118fb126 Retain topology information when triangulating face boundaries. #574 2019-04-24 16:32:06 +02:00
Thomas Krijnen 80bdb36ccc Reduce face triangulation message severity to warning 2019-04-09 17:09:27 +02:00
Thomas Krijnen 013b7a763d Some fixes to make sure that non-planar faces get explicitly triangulated 2019-04-09 17:03:24 +02:00
Thomas Krijnen f0fa9ca736 Install python module files using glob 2019-04-05 11:18:22 +02:00
Thomas Krijnen 8a197a6305 Work on 3ds max plug-in 2019-04-03 15:08:14 +02:00
Thomas Krijnen 91d10a1465 Provide basic validation utility in Python 2019-04-03 14:41:25 +02:00
Thomas Krijnen 1314209a89 Map empty aggregate to empty tuple in python 2019-04-03 14:40:09 +02:00
Thomas Krijnen 45c3c27fb5 Fixes for mapping declaration subtypes to SWIG 2019-04-03 13:55:29 +02:00
Thomas Krijnen 6e42f82e1a Merge branch 'master' into v0.6.0 2019-03-29 09:32:22 +01:00
Thomas Krijnen 0ae1c90797 --ignore-whitespace in patch Fixes #565 2019-03-29 09:31:39 +01:00
Thomas Krijnen 94bf798168 Merge branch 'master' into v0.6.0 2019-03-24 14:26:14 +01:00
Thomas Krijnen 8c1924084a Don't consider openings as children in geom filters 2019-03-24 12:36:33 +01:00
Thomas Krijnen 2bf3648966 Add MVD subrepo 2019-03-19 11:04:24 +01:00
Thomas Krijnen 5e54e84a92 Delete MVD module now separate repo 2019-03-19 11:02:24 +01:00
Thomas Krijnen e43e02c003 Vector of bool type conversion in python wrapper. 2019-03-13 13:32:24 +01:00
Thomas Krijnen 2a026e93d5 Fix errors after merge 2019-03-08 17:22:05 +01:00
paul dafa304936 Update Python to 2.7.16 - So Fedora 29 Compile 2019-03-08 15:03:20 +01:00
Thomas Krijnen ac4be43170 Merge branch 'master' into v0.6.0
# Conflicts:
#	src/ifcconvert/IfcConvert.cpp
#	src/ifcgeom/IfcGeomRenderStyles.cpp
#	src/ifcgeom/IfcGeomWires.cpp
#	src/ifcparse/IfcLogger.cpp
#	src/ifcparse/IfcLogger.h
#	src/ifcparse/IfcParse.cpp
#	src/ifcparse/IfcUtil.cpp
#	src/serializers/ColladaSerializer.cpp
#	src/serializers/schema_dependent/XmlSerializer.cpp
2019-03-08 11:40:16 +01:00
Thomas Krijnen e4fdfd2eb3 Apply length unit to IfcCylindricalSurface Radius. Fixes #553 2019-03-04 17:23:15 +01:00
johltn a800a9e7c7 FIx MVD module 2019-03-04 12:50:28 +01:00
Thomas Krijnen 9052721a00 Preliminary work on MVD parser/converter/checker 2019-03-04 10:20:42 +01:00
Thomas Krijnen 2538eeea87 Fixes for latebound inverse attributes in Python 2019-02-27 17:18:19 +01:00
Thomas Krijnen dbc3c5ebef Mark abstract entities in latebound schema 2019-02-20 15:35:19 +01:00
Thomas Krijnen 45136fce6c GeomServer: precision on double formatting, compound in meters, bounding box also from compound 2019-02-20 12:29:44 +01:00
Thomas Krijnen bf1623975c Merge remote-tracking branch 'dleverton/master' 2019-02-15 14:30:55 +01:00
hlg df49f1bc1b prevent index out of bound in case of a single point 2019-02-15 14:22:02 +01:00
hlg acde878946 process IfcIndexedPolyCurve without segments #549 2019-02-15 14:22:02 +01:00
Thomas Krijnen 33cbcc2510 Provide LARGEST_FACE_DIRECTION in geom server quantities 2019-02-15 13:46:13 +01:00
Thomas Krijnen d583bf5284 Populate entity subtypes, get schema info in Python 2019-02-15 13:09:54 +01:00
David Leverton d12cacbd2e Fix Position handling for IfcSurfaceCurveSweptAreaSolid 2019-02-13 15:34:50 +00:00
Thomas Krijnen 8d65086e01 Fix #540. Fix XML serializer schema registration. 2019-02-13 14:16:58 +01:00
Thomas Krijnen 4822b57584 Process binary trees of boolean ops in a single call. Fixes #546 2019-02-13 10:08:55 +01:00
Thomas Krijnen 94c3261ba8 Geomserver positions in 64bit 2019-02-12 16:31:38 +01:00
Thomas Krijnen 5db91e52da Fixes to logger templates 2019-02-12 14:55:03 +01:00
Thomas Krijnen 68151b970a Conditionally sew faces based on detection of shared edges 2019-02-12 13:59:49 +01:00
Thomas Krijnen 826752ca6c Geomserver bounding box sizes 2019-02-12 12:47:01 +01:00
Thomas Krijnen c3adcf631a Fix previous commit 2019-02-08 16:53:09 +01:00
Thomas Krijnen a4c2aa8f42 IfcConvert Windows unicode support (#258) 2019-02-08 15:18:55 +01:00
Thomas Krijnen 7f9d418112 Add LARGEST_FACE_AREA to geom server 2019-02-06 16:24:17 +01:00
Dawid Huczyński 9b0be0fb4e Delete intersection.py 2019-02-06 16:23:22 +01:00
Dawid Huczyński 3fdd92dc84 Create intersection.py 2019-02-06 16:23:22 +01:00
Dawid Huczynski 9f7a7a2c5b basic update to blender2.8, use of existing mesh if id match, 2019-02-06 16:23:22 +01:00
Thomas Krijnen 4df526f023 Merge branch 'master' into v0.6.0 2019-02-06 15:39:43 +01:00
Thomas Krijnen 6bac067488 Keep behaviour of returned null pointers for now 2019-02-06 13:33:38 +01:00
Stinkfist0 000d11daab IfcFile: possibility to mark an entity as modified so that potential cache is invalidated. 2019-02-06 13:30:33 +01:00
Stinkfist0 3bef32bb87 IfcGeom::Kernel::get_layers: remove what would appear to be unnecessary code (yields 0 layers in my tests).
The LayerAssignments() calls can take up to 95 % of the function's execution time yielding no results.
2019-02-06 13:30:33 +01:00
Stinkfist0 9211f80625 IfcFile::entitiesByReference: cache loaded references. Profiling shows around 3x speed-up (avg. of first 5000 calls to this function). 2019-02-06 13:30:33 +01:00
Stinkfist0 910cdb3754 IfcConvert: print durations of file parsing and XML conversion. 2019-02-06 13:30:33 +01:00
Stinkfist0 38f7ccdc20 Optimize IfcFile::entitiesByReference() by reserving capacity for IfcEntityList in advance.
Around 18.4 % speed-up (avg. of first 2000 calls) when converting a somewhat large (176 MB) file to XML.
2019-02-06 13:30:33 +01:00
Thomas Krijnen 40c2602b0e Fix discrepancy with v06 2019-02-06 13:29:56 +01:00
Thomas Krijnen 42e00581cd Merge branch 'master' into v0.6.0
# Conflicts:
#	src/ifcgeom/IfcRepresentationShapeItem.h
#	src/ifcgeom_schema_agnostic/IfcGeomFilter.h
2019-02-06 12:22:48 +01:00
Thomas Krijnen 81f978f101 Changes to Axis with missing refDirection 2019-02-06 12:18:10 +01:00
Xavier Lamorlette 3e041a1fb2 Migrate deprecated bind1st and mem_fun to C++11 bind 2019-02-06 11:01:23 +01:00
Xavier Lamorlette bd3118b4a3 Fix a "declaration of 'identifier' hides class member" warning 2019-02-06 11:01:23 +01:00
Thomas Krijnen 4b57a7bdd6 Set a lower bound tot faceset_helper::epsilon 2019-01-26 15:00:20 +01:00
Thomas Krijnen 5b066c9f95 Don't convert to Nef if there are no voids 2019-01-25 15:19:52 +01:00
Thomas Krijnen 3afb9169b1 Implement missing virtual function in CgalKernel 2019-01-25 14:25:34 +01:00
Thomas Krijnen 24b552a822 Merge fixes 2019-01-23 17:27:13 +01:00
Thomas Krijnen 884064f213 Merge remote-tracking branch 'cgal/cgal' into v0.7.0 2019-01-23 15:44:19 +01:00
Thomas Krijnen 4d39dbca2a Build static cgal, fix null pointer access 2019-01-23 15:10:20 +01:00
Thomas Krijnen 30479ca0a6 Fixes for compilation of cgal kernel 2019-01-23 12:34:21 +01:00
Thomas Krijnen a7a1ad129e Merge commit '6b47e9ca1d18df4b1cd2c66e488ad91f9730ecdf' into v0.7.0
# Conflicts:
#	cmake/CMakeLists.txt
#	nix/build-all.py
#	test/input
2019-01-22 13:00:49 +01:00
Thomas Krijnen bea627d01e Merge commit '6b47e9ca1d18df4b1cd2c66e488ad91f9730ecdf' into v0.7.0 2019-01-22 12:47:21 +01:00
Thomas Krijnen 059a1cb14b Merge commit '4d12bf7e8df4bd144526eeb5994802d308b40297' into v0.7.0 2019-01-22 12:38:02 +01:00
Thomas Krijnen 6a5bfefce9 Merge branch 'master' into v0.6.0
# Conflicts:
#	src/ifcparse/Ifc4-latebound.cpp
#	src/ifcparse/Ifc4.cpp
#	src/ifcparse/Ifc4.h
#	src/ifcparse/Ifc4enum.h
2019-01-20 14:27:09 +01:00
Thomas Krijnen ef7eee411b Update to IFC4Add2TC1 2019-01-20 13:47:12 +01:00
Thomas Krijnen 8c5349feaa Introduce AbstractKernel 2019-01-20 13:16:42 +01:00
Thomas Krijnen fa0a33f3c0 Option to select Kernel from IfcConvert 2019-01-19 12:39:47 +01:00
Thomas Krijnen 5a7c7ed048 Shuffle project structure 2019-01-18 16:43:38 +01:00
Thomas Krijnen 16d6420352 More work on enabling cgal kernel 2019-01-18 15:19:00 +01:00
Thomas Krijnen d804575974 Cgal kernel skeleton 2019-01-18 12:10:18 +01:00
Thomas Krijnen ad24b6be0f Isolate (most of the) geometry processing code into separate opencascade kernel 2019-01-18 11:23:19 +01:00
Thomas Krijnen 0072e1f247 CMake CGAL version of IfcGeom 2019-01-16 14:44:43 +01:00
Thomas Krijnen 116b80cf91 Fix MPFR download location 2019-01-16 14:41:34 +01:00
Thomas Krijnen 208f6d4d74 Small fixes to build script 2019-01-16 14:18:36 +01:00
Thomas Krijnen a0dfdc78ef Add cgal to IfcGeom deps 2019-01-16 14:06:17 +01:00
Thomas Krijnen cf2dd2aa8d Add GMP MPFR CGAL to build script 2019-01-16 14:04:05 +01:00
Thomas Krijnen 6737b54457 Add GMP MPFR CGAL to build script 2019-01-16 13:59:10 +01:00
Thomas Krijnen 5ee32fb945 Merge branch 'master' into v0.6.0 2019-01-16 12:30:12 +01:00
Thomas Krijnen 944813146e Close polylines on closed profile def. Fixes #538 2019-01-16 12:28:58 +01:00
Thomas Krijnen 16cafb9f8b Fix #534 2019-01-11 16:22:53 +01:00
Thomas Krijnen b1754f7b26 Remove debug prints 2019-01-05 13:45:54 +01:00
Thomas Krijnen 55ac6e760d Merge branch 'master' into v0.6.0 2019-01-05 13:43:19 +01:00
Thomas Krijnen 9d6eec0f5a Update suprepo 2019-01-05 13:42:51 +01:00
Thomas Paviot 9048ce4857 Fixed BRepAlgoAPI_BooleanOperation::DumpErrors method only available for OCC version > 7 2019-01-02 10:26:03 +01:00
Thomas Krijnen f24944be48 Merge branch 'master' into v0.6.0 2018-12-31 11:40:16 +01:00
Thomas Krijnen dec0c646cc Only round corners on discontinuous spines. Fixes #358. 2018-12-31 11:39:35 +01:00
Thomas Krijnen 421daa3d19 Work-around for invalid IfcOrganization instances 2018-12-30 12:55:17 +01:00
Thomas Krijnen 7bf9f637e7 Fix some warnings 2018-12-30 12:51:13 +01:00
Thomas Krijnen 9a2623953b Merge branch 'master' into v0.6.0 2018-12-30 12:50:27 +01:00
Thomas Krijnen 382efc0255 Fix some warnings 2018-12-30 12:50:04 +01:00
Thomas Krijnen 93a80c6148 Merge branch 'master' into v0.6.0 2018-12-29 14:35:41 +01:00
Thomas Krijnen bf50d0534b Fixes for edge curves and non-planar faces with inner boundaries. #338 2018-12-29 14:34:47 +01:00
Thomas Krijnen b1ab829c14 Merge branch 'master' into v0.6.0 2018-12-29 14:26:16 +01:00
Thomas Krijnen 7022e842bf Update subproject 2018-12-29 14:18:51 +01:00
Thomas Krijnen 65b5453ef1 More verbosity adjustments 2018-12-29 13:48:20 +01:00
Thomas Krijnen 5e32c1e55c More verbosity adjustments 2018-12-29 13:37:51 +01:00
Thomas Krijnen e6f523a2b8 Adjust verbosity of several log messages 2018-12-29 12:34:32 +01:00
Thomas Krijnen 2c8a79e186 Re-enable some disabled functionality in the 0.6 branch 2018-12-28 16:02:03 +01:00
Thomas Krijnen 13d2cf3357 Remove --sew-shells option, always on now 2018-12-28 15:36:10 +01:00
Thomas Krijnen 427720f369 Addendum to previous merge 2018-12-28 15:18:41 +01:00
Thomas Krijnen d20f4a5af6 Merge branch 'master' into v0.6.0 2018-12-28 15:18:14 +01:00
Thomas Krijnen 4936ea3ac3 Document boolean operation failure reasons, correct min len check and manifoldness check. Fix #478 2018-12-28 15:15:41 +01:00
Thomas Krijnen 4101407b43 Small changes to convert(face) 2018-12-24 16:04:51 +01:00
Thomas Krijnen 29d3b436b4 Merge branch 'master' into v0.6.0 2018-12-24 16:03:20 +01:00
Thomas Krijnen a2231605a5 Take into account edge orientation; small fixes to convert(face) 2018-12-24 16:02:00 +01:00
Thomas Krijnen 4380e1d86a Merge branch 'master' into v0.6.0 2018-12-22 14:06:28 +01:00
Thomas Krijnen 161deeb4e0 Fix warnings and compilation on clang 2018-12-22 14:05:49 +01:00
Thomas Krijnen 31eac564f6 Detect self-intersections in faceset helper and clamp bounding box eps factor to 1. 2018-12-21 15:58:21 +01:00
Thomas Krijnen 99b865bbd9 Some layerset processing comments 2018-12-21 14:40:58 +01:00
Thomas Krijnen 4de617e398 Merge branch 'master' into v0.6.0 2018-12-21 11:53:36 +01:00
Thomas Krijnen 1a1b7e93ab Changes to no-material message 2018-12-19 16:54:02 +01:00
Thomas Krijnen f5af6ee6c0 speed-up min_vertex_edge_distance(). Fixes #518 2018-12-19 16:39:54 +01:00
Thomas Krijnen 94f49af00b Fix header order 2018-12-19 16:30:05 +01:00
Thomas Krijnen 39b8680f64 Improve performance of layerset slicing 2018-12-19 16:10:33 +01:00
Thomas Krijnen 26282437cc Layerset processing error message 2018-12-19 15:15:28 +01:00
Thomas Krijnen 6911b48a46 project() more efficiently onto planar surfaces 2018-12-19 15:15:00 +01:00
Sander Boer de416eca49 Too lazy to comment 2018-12-18 12:49:11 +01:00
Thomas Krijnen acd3564429 Remove some warnings for open shells 2018-12-17 13:25:28 +01:00
Thomas Krijnen 20471bd33e Check comcurve segments extent before creating iterator 2018-12-17 10:56:26 +01:00
Thomas Krijnen bb15446822 Make std::map inheritance private. #512 #517 2018-12-17 10:37:48 +01:00
Thomas Krijnen e3b415ad54 Use miimal bounding box edge length for faceset relative epsilon 2018-12-14 17:14:55 +01:00
Thomas Krijnen 27b9689e14 Work-around gcc issue 2018-12-14 12:14:12 +01:00
Thomas Krijnen 32338e2490 Make std::map inheritance private. #512 #517 2018-12-14 11:56:09 +01:00
Thomas Krijnen e104d1aac3 Travis: max log length 2018-12-12 17:01:11 +01:00
Thomas Krijnen 632d36e2ba Sync subrepo 2018-12-12 16:40:43 +01:00
stephassoria 9a9475adcb Exclude parse_ifcxml.cpp content from build when WITH_IFCXML is not define 2018-12-12 16:29:37 +01:00
Thomas Krijnen f307f39023 Fix remaining merge conflict 2018-12-12 16:29:10 +01:00
Thomas Krijnen f526277a7d Fix some warnings 2018-12-12 16:26:49 +01:00
Thomas Krijnen 0c8e9e7040 Merge branch 'master' into v0.6.0
# Conflicts:
#	src/ifcgeom/IfcGeomIteratorImplementation.h
2018-12-12 16:20:50 +01:00
Thomas Krijnen a0f37cf9ea Fix some warnings 2018-12-12 16:12:38 +01:00
Thomas Krijnen 49c6346af7 Travis: fix shell syntax 2018-12-12 15:57:38 +01:00
Thomas Krijnen eb166da930 Travis: pin py version 2018-12-12 15:53:48 +01:00
Thomas Krijnen d5216c8201 Travis: Build succeeds regardless of conversion result 2018-12-12 15:43:04 +01:00
Thomas Krijnen 027226fb96 Travis: compile on two cores 2018-12-12 14:43:25 +01:00
Thomas Krijnen 5dbd0249b4 Travis: newer gcc for c++11 compat with package manager 2018-12-12 14:40:14 +01:00
Thomas Krijnen 4821226ec2 Travis: xenial, occt 7.3, run IfcConvert 2018-12-12 14:07:13 +01:00
Thomas Krijnen 72c96905b9 Option to validate created geometries based on explicit quantities 2018-12-12 12:33:09 +01:00
Thomas Krijnen a8f4f0270a Don't double quote boost dependency dir #515 2018-12-11 13:01:28 +01:00
Thomas Krijnen 336601a7ae Missing FindFromKey() overload on older versions of occt 2018-12-11 10:55:03 +01:00
Thomas Krijnen d39c7bd641 Postfix integers 2018-12-10 17:26:41 +01:00
Thomas Krijnen d3092090df Substitute tiny trimmed curves with linear approximation when deflection within tolerance 2018-12-10 17:15:39 +01:00
Thomas Krijnen b88c5ee930 Missing include for older occt versions 2018-12-10 12:12:23 +01:00
Thomas Krijnen 645f88a313 Calculate quantities more defensively 2018-12-10 11:51:54 +01:00
Thomas Krijnen a7c7a684ee Emit surface genus for representation items 2018-12-10 11:33:54 +01:00
Thomas Krijnen 20b3a8af3e Faceset_helper: no recursive clustering, epsilon relative to bounds 2018-12-10 10:45:58 +01:00
Thomas Krijnen 0fcf1f14c8 Merge branch 'master' into v0.6.0 2018-12-10 10:41:58 +01:00
Stinkfist0 327be7030f ColladaSerializer minor tweaks and to-dos. 2018-12-09 12:23:44 +01:00
Michael Sundqvist 06589ca1c6 Refactor ColladaSerializer.cpp, encode material names only once, decode them before passing to OpenCollada functions that take URI parameters 2018-12-09 12:23:44 +01:00
Michael Sundqvist 1c83b2db53 Remove object name from no material log message, raise level to warning 2018-12-09 12:23:44 +01:00
Michael Sundqvist 6f3eb84f66 Fix instance_material missing material names as well. 2018-12-09 12:23:44 +01:00
Michael Sundqvist e7a8a97639 If material name is empty when writing collada file, name it as a missing material. Logger::Notice() objects that do not have a material assigned. 2018-12-09 12:23:44 +01:00
Otso Alho fe1cb9e92b default to blank material with IfcMaterial name 2018-12-09 12:23:44 +01:00
Thomas Krijnen f849434f24 More defensive IfcCurveBoundedPlane processing 2018-12-09 11:59:49 +01:00
Thomas Krijnen 8c0c216a1d Check boolean result manifoldness for shells individually. Fixes #516. 2018-12-08 10:37:54 +01:00
Thomas Krijnen 7ed47dee67 Faceset helper: check whether edge has been created 2018-12-03 12:36:30 +01:00
Thomas Krijnen 4f8b430040 Improvements to faceset_helper in case of nearby verts 2018-11-30 11:08:19 +01:00
Thomas Krijnen b48d17c690 Merge branch 'master' into v0.6.0
# Conflicts:
#	src/ifcgeom/IfcGeomFunctions.cpp
#	src/ifcparse/IfcCharacterDecoder.cpp
2018-11-28 14:18:58 +01:00
Thomas Krijnen 3d240deed1 Extended data backwards compatibility 2018-11-28 10:50:09 +01:00
Thomas Krijnen 747ddeb20c Apply openings in batches sorted by increasing detail 2018-11-23 11:45:23 +01:00
Thomas Krijnen 4afd104f3d fit_halfspace() correct padding 2018-11-21 11:28:22 +01:00
Thomas Krijnen 4ed9166e8a Check for null pointers returned by find_representation() 2018-11-20 12:10:44 +01:00
Bernd Hahnebach 64eb5b4d1d namespace fix for debian buster, fixes issue #506 2018-11-20 11:59:08 +01:00
Thomas Krijnen 116de5daec Test powershell v5 or higher 2018-11-20 11:53:11 +01:00
Thomas Krijnen 0016256f57 Merge branch 'master' into v0.6.0 2018-11-19 17:13:28 +01:00
Thomas Krijnen 0018224da7 Handle python positional arguments in case of derived fields more explicitly 2018-11-19 16:38:52 +01:00
Thomas Krijnen 334d867873 Fix #498 2018-11-19 14:56:21 +01:00
Thomas Krijnen 9caa753d27 Fix geom server quantities 2018-11-14 12:14:00 +01:00
Thomas Krijnen ba274bb164 Merge branch 'master' into v0.6.0 2018-11-13 14:46:41 +01:00
Thomas Krijnen 50e5d5f4d5 Sort instances before emitting to file 2018-11-13 14:46:15 +01:00
Thomas Krijnen e7daf871b8 Disallow adding instances from different schema 2018-11-04 15:16:08 +01:00
Thomas Krijnen f7e66d1e7f make_unique<>() is C++14 2018-11-03 16:55:41 +01:00
Thomas Krijnen 6cf214d2e0 Missing header on Travis 2018-11-03 11:34:12 +01:00
Thomas Krijnen 1590ffd6ec Missing header on Travis 2018-11-03 09:59:37 +01:00
Thomas Krijnen 752bda71af Missing header on Travis 2018-11-02 17:01:15 +01:00
Thomas Krijnen e463dca0df Absolute value for dot product in projected areas 2018-11-02 16:37:54 +01:00
Thomas Krijnen 66859c7140 Missing option 2018-11-02 16:24:32 +01:00
Thomas Krijnen 3ff619c7ed Quantities in convert and geomserver. Faceset helper for creating edge pairs. 2018-11-02 16:10:06 +01:00
Thomas Krijnen ad41f04f11 Merge branch 'master' into v0.6.0
# Conflicts:
#	src/ifcconvert/IfcConvert.cpp
#	src/ifcgeom/IfcGeomRenderStyles.cpp
#	src/ifcparse/IfcParse.cpp
2018-10-30 14:32:28 +01:00
Thomas Krijnen e64d8750e1 Use all representations if no representations found through context check 2018-10-30 12:15:35 +01:00
Thomas Krijnen 342cce89d7 #487 perform fix after sewing if not valid 2018-10-30 09:05:18 +01:00
Stinkfist0 ffa282af9d IfcGeomIterator: check the filtered products, not unfiltered ones, for reusability. Speeds up things significantly and also fixes geometry reusability in many cases. 2018-10-15 15:22:44 +02:00
Stinkfist0 fbc0215ef1 IfcGeomIterator: optimize filtering by performing it prior to geometry reuse inspections.
Improves the iteration speed immensely, especially on very large files when only a fraction of the content is wanted to be converted.
2018-10-15 15:22:44 +02:00
Stinkfist0 58759cf365 IfcConvert: prevent memory leaks and clean up code by utilizing shared_ptr. 2018-10-15 14:02:17 +02:00
Stinkfist0 2024a24e31 IfcConvert: proper "exit routine" if initialization of input fails when trying to create geometry files. 2018-10-15 14:02:17 +02:00
Stinkfist0 c420cc1abb IfcFile::Init: return false if unexpected schema encountered. 2018-10-15 14:02:17 +02:00
Jean Niklas L'orange e39835d25e Make API more consistent 2018-10-15 11:25:17 +02:00
Jean Niklas L'orange 9c1660a84b Catch and inform about errors
The changes in how specular roughness and transparency is read in was
done to ensure type safety. If you added

    "transparency": "0.8"

to the file, then that would be silently ignored. In the new style, it
instead errors out if the type cannot be converted to a double.
2018-10-15 11:25:17 +02:00
Jean Niklas L'orange 7e9e56cd2c Support setting default "fallback" material style
Specifying a fallback default material style is added by specifying a
style for "*" in the --default-material-file.
2018-10-15 11:25:17 +02:00
Jean Niklas L'orange a6d3619449 Fix bug where default material was not initialised
We kind-of sort-of do double work here, but I think it is better to
always assume that InitDefaultMaterials when setting the defaults, to
avoid too many code paths.
2018-10-15 11:25:17 +02:00
Jean Niklas L'orange dab3382b29 Implement support for custom default materials
The support for custom default materials is implemented as a JSON
file passed via the command line. The default material specification
will override the defaults, except the toplevel default value.
2018-10-15 11:25:17 +02:00
Stinkfist0 882d27fe25 Use /permissive- introduced in VS 2017 to enforce standards-conformance.
https://docs.microsoft.com/en-us/cpp/build/reference/permissive-standards-conformance?view=vs-2017
2018-10-01 10:30:04 +02:00
paul 81a9d0e747 Changing opencollada version to "v1.6.63"
Discussion:
https://github.com/IfcOpenShell/IfcOpenShell/issues/480

Summary:
"... Compiling OpenCOLLADA  fail on fedora 27... changing  opencollada version to "v1.6.63" (since some time now they do proper tagging over there, the commit we track now is from 19 Dec 2013, probably worth updating as newer compilers might rightfully complain)...

Probably best to rm -rf ... IfcOpenShell/build/Linux/x86_64/build/OpenCOLLADA before restarting."
2018-10-01 10:29:01 +02:00
Thomas Krijnen cb535b4ba8 Merge branch 'master' into v0.6.0 2018-09-25 12:47:31 +02:00
Thomas Krijnen 3102a1c179 Check for empty bounding boxes in boolean op filter 2018-09-25 12:47:06 +02:00
Thomas Krijnen a8effa8289 No need to cast to TopoDS_Face anymore 2018-09-25 12:46:20 +02:00
Thomas Krijnen bf3ec5e507 Add comment 2018-09-24 12:56:07 +02:00
Thomas Krijnen 5526f421f0 Merge branch 'master' into v0.6.0 2018-09-21 14:55:20 +02:00
Thomas Krijnen e24ddae064 Forgot to update code generator 2018-09-21 14:55:10 +02:00
Thomas Krijnen 92f4d76c81 Check for empty list of boolean operands 2018-09-21 14:53:39 +02:00
Thomas Krijnen 59be8f742d Merge branch 'master' into v0.6.0 2018-09-21 12:06:32 +02:00
Thomas Krijnen d2337dc692 Missing FindFromKey() overload on older versions of occt 2018-09-21 12:06:10 +02:00
Thomas Krijnen 2b501a93c9 Merge branch 'master' into v0.6.0
# Conflicts:
#	src/ifcgeom/IfcGeomFunctions.cpp
#	src/ifcgeom/IfcGeomWires.cpp
2018-09-21 12:02:22 +02:00
Thomas Krijnen 6b8681b74a That was bad 2018-09-21 11:45:36 +02:00
Thomas Krijnen 297812d4e2 Better handling of consecutive circular arc segments 2018-09-21 11:43:06 +02:00
Thomas Krijnen 7205f0165e Work around private copy constructor on older versions of occt 2018-09-21 11:21:51 +02:00
Thomas Krijnen bf4b5928dd Fail on empty face early 2018-09-21 10:22:37 +02:00
Thomas Krijnen 3840bd1154 Limit tolerance on wire self-intersection to edge segment length 2018-09-21 10:22:24 +02:00
Thomas Krijnen 47ec4e2240 Merge branch 'master' into v0.6.0 2018-09-19 20:27:03 +02:00
Thomas Krijnen 622853d73d Filter boolean subtraction operands by intial bounding box test 2018-09-19 16:42:34 +02:00
Thomas Krijnen e8b28a099f Some fixes for clang 2018-09-19 14:05:19 +02:00
Thomas Krijnen 9a3039765f Merge remote-tracking branch 'origin/master' into v0.6.0 2018-09-19 10:09:48 +02:00
Unknown bef9bd25f7 Fix dll export on Windows
Fix dll export on Windows
2018-09-19 10:09:05 +02:00
Thomas Krijnen 53577d9da9 Fix ifcopenshell-python build on nix build script 2018-09-18 19:42:01 +02:00
Thomas Krijnen 55d07f8bba Merge branch 'master' into v0.6.0
# Conflicts:
#	nix/build-all.py
2018-09-18 13:42:06 +02:00
Thomas Krijnen 34b3ca307f Enable exception handling on occt release builds Fix #462 2018-09-18 13:39:44 +02:00
Thomas Krijnen 028e8fb926 Merge branch 'master' into v0.6.0
# Conflicts:
#	nix/build-all.py
#	src/ifcgeom/IfcGeomFunctions.cpp
#	src/ifcparse/IfcLogger.cpp
2018-09-17 17:46:13 +02:00
Thomas Krijnen 08557c2664 Don't fail on empty bounding box during halfspace processing 2018-09-17 15:21:12 +02:00
Thomas Krijnen a54b7863cd Fail early on duplicate (non consecutive) points in face loops 2018-09-17 14:59:15 +02:00
Thomas Krijnen 3101ccb83a Fixes for degenerate polylines 2018-09-17 14:42:22 +02:00
Thomas Krijnen 394a7f14ad Emit unopened shapes in case of exceptions during subtraction 2018-09-17 14:11:03 +02:00
Thomas Krijnen 983745b508 More careful face orientation check 2018-09-17 12:05:30 +02:00
Thomas Krijnen b05b62f440 Perform additional check on boolean result output for small edges or distances 2018-09-17 12:02:41 +02:00
Thomas Krijnen 51a9bb0ac1 Retry boolean operations if output is non-manifold on manifold input 2018-09-17 12:00:49 +02:00
Thomas Krijnen 452ab6e5bc Fix flaw in vertex-edge distance used to limit tolerance in boolean ops 2018-09-17 11:33:40 +02:00
Thomas Krijnen 0df2bfadef Don't sew overly complex geometries even as part of boolean operations #455 2018-09-12 16:44:30 +02:00
Thomas Krijnen 12623dd1e5 Only install/strip on Release build 2018-09-12 13:57:41 +02:00
Thomas Krijnen 2eaae2bda8 Use BVH tree for wire intersections 2018-09-12 13:26:11 +02:00
Thomas Krijnen a3141b2acc Make nix build script more granular 2018-09-08 13:23:36 +02:00
Thomas Krijnen 3a4fa2e6dd Merge commit '58ce86d538971fc1815d56368d7077aa85e0592c' into v0.6.0 2018-09-08 13:07:09 +02:00
Thomas Krijnen 472c3478e0 Emit error messages on missing units 2018-09-08 08:27:45 +02:00
Thomas Krijnen 54d96fe167 Merge branch 'master' into v0.6.0
# Conflicts:
#	src/ifcconvert/IfcConvert.cpp
#	src/ifcgeom/IfcGeom.h
2018-09-07 14:42:15 +02:00
Thomas Krijnen 229a708fc3 Emit error messages on missing units 2018-09-07 14:25:46 +02:00
Thomas Krijnen 0df4edff01 Revive some temporarily disabled features in de 0.6 branch 2018-09-07 14:08:56 +02:00
luz.paz d78c9171db Misc. typos
Found via `codespell -q 3`
2018-09-07 11:52:01 +02:00
Thomas Krijnen 03da7bc6e4 Fix missing schema identifier in geometry function 2018-09-05 14:43:25 +02:00
Thomas Krijnen 34d28e8b3a Prefix Kernel factory struct as well 2018-09-05 14:42:59 +02:00
Thomas Krijnen 6e8f5c84e6 Still no working submodule 2018-09-04 15:52:51 +02:00
Thomas Krijnen 08d003ddcd Something went wrong merging submodule 2018-09-04 15:07:14 +02:00
Thomas Krijnen bdf22856e4 Add explicit cast to attribute value 2018-09-04 13:59:57 +02:00
Thomas Krijnen 4d33ed5cb8 Merge branch 'master' into v0.6.0
# Conflicts:
#	src/ifcconvert/IfcConvert.cpp
#	src/ifcgeom/IfcGeomShapes.cpp
#	src/serializers/ColladaSerializer.cpp
#	src/serializers/schema_dependent/XmlSerializer.cpp
2018-09-04 13:23:11 +02:00
Thomas Krijnen 4babe84941 Force decltype using for boost::resulf_of 2018-09-02 13:55:36 +02:00
Thomas Krijnen 4138103541 Fix libxml2 directives on travis 2018-09-02 11:59:54 +02:00
Thomas Krijnen a3894cdcda Fix libxml2 directives on travis 2018-09-02 11:59:54 +02:00
Thomas Krijnen 840f1463e5 Fix libxml2 directives on travis 2018-09-02 11:59:54 +02:00
Thomas Krijnen ad5444b974 Inverse attributes with 0-1 cardinality not as ifcXML aggregates 2018-09-02 11:59:54 +02:00
Thomas Krijnen c0d41103fa add missing file 2018-09-02 11:59:54 +02:00
Thomas Krijnen 3e80d3646c Work on ifcxml parsere 2018-09-02 11:59:54 +02:00
Thomas Krijnen c2f4c2cf74 Add missing patch files. Fix #448 2018-09-02 10:51:16 +02:00
Thomas Krijnen 45be79443f Prefix typename for iteratorimplementation factory function struct 2018-08-29 12:55:27 +02:00
Thomas Krijnen dbc3577497 Test files in submodule 2018-08-26 17:09:01 +02:00
Thomas Krijnen 0a45a82109 Move test files to separate repo 2018-08-26 12:30:18 +02:00
Stinkfist0 07f5ac6994 IfcGeomIterator: compute model's bounding box only if needed (IfcConvert --center-model used). 2018-08-26 12:17:24 +02:00
johanrd 0eb6c597f0 Create 443--segfault-beam.ifc 2018-08-26 12:12:48 +02:00
Thomas Krijnen b13c912c47 Work on #426 2018-08-20 11:46:26 +02:00
Thomas Krijnen 683cadeb76 occt 7.3 2018-08-19 10:29:01 +02:00
Thomas Krijnen b023f6a31d Fix sillyness preventing install of IfcGeomServer 2018-08-16 13:58:50 +02:00
Thomas Krijnen 891448e902 Fix #343 2018-08-15 17:10:29 +02:00
Michael Sundqvist 82718fad30 Catch some ifc file header exceptions to prevent crashing during xml serialization 2018-08-15 16:15:25 +02:00
Stinkfist0 9f03a78652 ColladaSerializer::differentiateSlabTypes: IfcSlab.PredefinedType is optional so check for its existence.
https://github.com/Tridify/IfcOpenShell/commit/c4f426392cfc021b8a9c617f21d258759b289d6a#diff-cca49440331fb4c1363204028192c459
2018-08-15 16:09:15 +02:00
Stinkfist0 505d234ea2 Unify GeometrySerializers' object ID logic. Fixes #397. 2018-08-15 16:09:15 +02:00
Robbe Derks bd5e25889a Added command-line option to output progress to stderr stream 2018-08-15 14:45:43 +02:00
Thomas Krijnen 5609cbdde9 Fix missing symbols for boost 1.67 and BOOST_ALL_NO_LIB 2018-08-15 09:07:40 +02:00
Thomas Krijnen caa6056f01 Conda bld.bat python version 2018-08-14 17:09:00 +02:00
Thomas Krijnen 3ea3627639 Conda bld.bat python version 2018-08-14 16:15:32 +02:00
Thomas Krijnen 175387bd88 Fix IfcOpenHouse 2018-08-13 11:43:28 +02:00
Thomas Krijnen ba5049a7eb Break out of loop in case of attribute count mismatch 2018-08-10 14:57:33 +02:00
Felipe Mesquita 40b70b1815 Workaround wrong argument count. Fix #419 2018-08-10 14:55:47 +02:00
Thomas Krijnen 54d9edfee5 Fix build on gcc 2018-07-12 12:33:35 +02:00
Thomas Krijnen 1c2587ba19 Fix for inverse update on delete 2018-07-12 11:37:23 +02:00
Thomas Krijnen d09abbd260 Merge pull request #409 from IfcOpenShell/master
Additional potential occt lib location
2018-07-08 15:08:32 +02:00
Thomas Krijnen 5359e88f0e Additional potential occt lib location 2018-07-08 15:07:30 +02:00
Thomas Krijnen 2dc01aec2d Update conda meta 2018-07-08 15:06:12 +02:00
Thomas Krijnen 20b35ec4ea Preprocessor stuff for stp and igs serializers 2018-07-08 11:08:07 +02:00
Thomas Krijnen 5245341cdc Correct previous commit 2018-07-08 11:06:45 +02:00
Thomas Krijnen 49932ba5c0 Python wrapper precision updates 2018-07-08 10:32:26 +02:00
Thomas Krijnen 7a7aab01bb IfcGeomServer matrices in double precision 2018-07-07 21:14:27 +02:00
Thomas Krijnen d105292817 Merge branch 'master' into v0.6.0
# Conflicts:
#	src/ifcconvert/IfcConvert.cpp
#	src/ifcgeom/IfcGeomFilter.h
#	src/ifcgeom/IfcGeomIteratorImplementation.h
#	src/ifcgeom/IfcGeomWires.cpp
#	src/ifcparse/IfcFile.h
#	src/ifcparse/IfcLogger.cpp
#	src/ifcparse/IfcLogger.h
#	src/ifcparse/IfcParse.cpp
#	src/serializers/SvgSerializer.cpp
#	src/serializers/schema_dependent/XmlSerializer.cpp
2018-07-07 17:15:54 +02:00
Thomas Krijnen 6fdd2049a2 Restore previous boost version on nix 2018-07-01 11:37:36 +02:00
Thomas Krijnen 8428b93451 nix cmake download url 2018-07-01 09:16:34 +02:00
Thomas Krijnen 8e2a074d70 Correct accidentally committed lines 2018-06-30 18:53:16 +02:00
Thomas Krijnen 1b809ed849 Update boost version 2018-06-30 15:36:51 +02:00
Thomas Krijnen 8c0bcc4ce7 Silent extraction in build-deps.cmd 2018-06-30 10:21:11 +02:00
Victor Haefner 11d0c6ef56 compiles under ubuntu 18.04 2018-06-22 17:16:11 +02:00
Stefan Boeykens 58ce86d538 Pushing cmake to enforce C++ 11
To be able to compile with a recent ICU version (for Unicode) C++11 is required. This enforces this in the main CMakeLists.txt
2018-06-19 09:45:16 +02:00
Stefan Boeykens 0ba1ac7df3 Add ICU header and namespace in IfcCharacterDecoder
To compile on macOS with a recent ICU, we have to add the correct header and refer to the right namespace in IfcCharacterDecoder
2018-06-17 15:15:52 +02:00
Thomas Krijnen 4cfb2f1027 SetNonDestructive does not exist prior to OCCT 7.0 2018-06-15 12:39:29 +02:00
Thomas Krijnen 6d25047c6b higher fuzz on half spaces 2018-06-12 16:15:28 +02:00
Thomas Krijnen 136ec5b224 'nondestructive' boolean ops 2018-06-12 16:15:12 +02:00
Thomas Krijnen 3ac8379187 Set precision on fix after boolean op 2018-06-08 14:12:01 +02:00
Thomas Krijnen 6c1ad47481 Additional improvements for comp curve wire building 2018-06-01 15:38:08 +02:00
thorade 20cd383504 triple double-quoted docstring
and do not use builtin names for variables
2018-05-30 11:32:47 +02:00
Thomas Krijnen 5aebfe9f22 Fix for setting type decl instances 2018-05-29 10:34:38 +02:00
Thomas Krijnen fd821d08cd Dont fail on missing AIS_MultipleConnectedShape in earlier versions of pyocc 2018-05-17 15:54:12 +02:00
Thomas Krijnen 6b772d18b8 Fixes to qt5 port of viewer app 2018-05-17 15:53:40 +02:00
civilx64 33635c2c40 Port viewer app to PyQt5 2018-05-17 00:11:09 -04:00
civilx64 7e6b758450 Add instructions for install via conda. 2018-05-16 23:05:07 -04:00
Yorik van Havre 127bcaf96e adding exception for OCCT 7.3 2018-05-16 16:10:40 +02:00
Yorik van Havre 2d59f9d53a Removed one last remaining BOPCol_ListOfShapes
Replaced one last remaining BOPCol_ListOfShapes with TopTools_ListOfShapes (deprecated in OCC7.3)
2018-05-16 16:10:40 +02:00
Otso Alho 1014049b05 use unordered map for entity by id 2018-05-14 13:36:38 +02:00
Otso Alho 37460d3df9 do not calculate reuse_ok multiple times for mapped representations 2018-05-14 13:36:38 +02:00
Thomas Krijnen 637d3e2eb6 Optimize generation of faces with large (n > 128) number of edges. 2018-05-14 11:06:07 +02:00
Thomas Krijnen 2ed2e9cf86 Add include, missing depending on occt version 2018-05-13 18:52:53 +02:00
Thomas Krijnen c1635d65eb Add include, missing depending on occt version 2018-05-13 16:04:15 +02:00
Thomas Krijnen 495ad75b14 Proper scope around goto labels 2018-05-13 15:30:20 +02:00
Thomas Krijnen 966e57e94a #332 2018-05-13 14:41:39 +02:00
Thomas Krijnen ef7a1ab421 Limit boolean fuzz to edge length 2018-05-13 09:15:06 +02:00
Thomas Krijnen 089bb95c9f Fix previous commit on gcc 2018-05-13 08:45:33 +02:00
Thomas Krijnen 7786b89269 Machine readable progress with -q and --log-format json 2018-05-12 20:12:25 +02:00
Thomas Krijnen 589f4bda2e ... but keep close point removal at 10 times precision 2018-05-08 16:19:47 +02:00
Thomas Krijnen 8ffc12e6cd Reduce radius on wire intersections 2018-05-08 09:41:19 +02:00
thorade bd9875fae5 set TLS to 1.2 2018-05-07 10:53:03 +02:00
thorade 7994bcbb80 https plus original URL 2018-05-07 10:53:03 +02:00
thorade baa0211562 append download to the URL
https://sourceforge.net/p/forge/documentation/Downloading%20files%20via%20the%20command%20line/
2018-05-07 10:53:03 +02:00
thorade a24333486a use SF instead of mirror 2018-05-07 10:53:03 +02:00
thorade 452ba651d0 update SF.net download URL 2018-05-07 10:53:03 +02:00
Thomas Krijnen 161f24d804 Copy operands prior to boolean operation 2018-05-05 16:09:12 +02:00
Thomas Krijnen 6ee283dbae Don't fail on parse errors while resolving inverse attributes 2018-05-04 10:25:57 +02:00
Thomas Krijnen c748c8dcea Better instance not found error messages 2018-04-23 10:51:59 +02:00
Thomas Krijnen 1f68d9d5bc TColgp_SequenceOfPnt::Upper() does not exist on all versions of occt 2018-04-18 11:57:38 +02:00
Thomas Krijnen 120ff2f629 Fix download of occt in nix build 2018-04-18 11:50:59 +02:00
Thomas Krijnen 656346741e #288 #297 2018-04-18 11:33:57 +02:00
Thomas Krijnen e21277e80a nix: use and patch occt 7.2 2018-04-15 14:01:37 +02:00
Thomas Krijnen 9f55444d2e win: apply patch for HLR 2018-04-15 09:27:16 +02:00
Thomas Krijnen 05fd266a65 gcc compatibility 2018-04-14 20:06:25 +02:00
Thomas Krijnen 42c09deb8c #354 loose faces in SewedShape 2018-04-11 12:26:01 +02:00
Thomas Krijnen cb61873179 conda osx build 2018-04-10 19:55:56 +02:00
Thomas Krijnen dbf9f213fd Dont fail on adding length measure instances to empty files 2018-04-04 14:40:10 +02:00
Thomas Krijnen 77e0d9cca7 Freeing of lazily loaded inst attrs 2018-03-21 17:29:37 +01:00
Thomas Krijnen 0cbe984c71 Default to 2x3 for older schemas 2018-03-21 17:18:38 +01:00
Thomas Krijnen 93cca8f7b7 Update README.md 2018-03-16 16:36:36 +01:00
Thomas Krijnen 5082fe8be4 Revive XML serializer 2018-03-16 16:04:48 +01:00
Thomas Krijnen 834780b726 Schema dependent serializers 2018-03-16 13:49:11 +01:00
Thomas Krijnen d374fd3778 More changes to conda build 2018-03-16 12:17:49 +01:00
Thomas Krijnen b86b359563 Schema independent layer and transformation conv functions 2018-03-16 12:10:05 +01:00
Thomas Krijnen 6685ea6d7a Schema dependent serializers 2018-03-16 12:10:05 +01:00
Thomas Krijnen 0a809ba127 Schema dependent serializers 2018-03-16 12:10:05 +01:00
Thomas Krijnen 14be6b49fe #348 2018-03-16 11:03:02 +01:00
Thomas Krijnen e87a1a0b32 #329 Only auto close IfcCompositeCurve when used for profile 2018-03-09 10:41:22 +01:00
Thomas Krijnen 768f49dcc7 Update meta.yaml 2018-03-04 10:50:17 +01:00
Thomas Krijnen 27e335343e Win build script occt7.2 2018-03-04 10:45:44 +01:00
Thomas Krijnen 0920116178 Fix prompt 2018-03-04 10:45:05 +01:00
Thomas Krijnen 1a7a4bdc3e Update boost download path 2018-02-27 18:09:43 +01:00
Thomas Krijnen 5d0c04a077 Fix geometry reuse in case of IfcTypeProducts with maps 2018-02-21 14:54:38 +01:00
Anders Granskogen Bjørnstad 8a316e45ed IfcConvert: Add --building-local-placement argument
Similar to --site-local-placement. Motivated by dealing with at least
two examples where IFC files for the same construction site have
inconsistent ObjectPlacement hierarchy:

- MEP models exported from MagiCAD for Revit:
   ObjectPlacement.PlacementRelTo of IfcBuilding is empty
- Regular construction models exported from Revit:
   ObjectPlacement.PlacementRelTo of IfcBuilding is pointing to
   IfcSite's placement
2018-02-19 16:17:12 +01:00
Thomas Krijnen ef97ea0593 Properly toposort type decl instantiation 2018-01-29 15:03:12 +01:00
Thomas Krijnen 19d834b19e Fix python wrapper 2018-01-29 15:02:36 +01:00
Thomas Krijnen bc64b339a7 Bump version identifier 2018-01-29 15:02:16 +01:00
Thomas Krijnen af93f2a64d Use naked pointer for attribute list and derive size from schema type to reduce mem usage 2018-01-29 12:11:50 +01:00
Thomas Krijnen a3b7a25866 conda yaml: add space before version spec 2018-01-26 14:36:51 +01:00
Thomas Krijnen 25bae21a42 Merge pull request #322 from 3drepo/Convert_Server_Optional
Make IFCConvert and IFCGeomServer optional
2018-01-25 12:50:18 +01:00
Thomas Krijnen d9679d6905 Merge branch 'v0.6.0' into Convert_Server_Optional 2018-01-25 12:49:55 +01:00
carmenfan 7a4059fbfd Adding ifcgeom_schema_agnostic headers in include directory 2018-01-25 12:46:52 +01:00
carmenfan 623e95cefe Add Options on Cmake to selectively compile IFCConvert and IFCGeomServer 2018-01-24 15:55:44 +00:00
Thomas Krijnen 9f91109e66 Update conda 2018-01-21 15:58:36 +01:00
Thomas Krijnen 162b665d07 Update blender addon for str geometry.id 2018-01-15 11:00:25 +01:00
Thomas Krijnen 7b728b9e6d Fix ambiguous call to overloaded function
(`std::exception` has a `char*` constructor?)
2018-01-08 12:33:27 +01:00
Thomas Krijnen 6240191980 Conda build script 2018-01-08 12:19:36 +01:00
Thomas Krijnen c7329497a6 Don't use static boost libs with conda build 2018-01-08 12:02:34 +01:00
Thomas Krijnen 4bed639d9c Python wrapper geometry handling 2018-01-01 11:22:12 +01:00
Thomas Krijnen 5739fa7239 Single threaded compilation on travis 2017-12-31 13:06:18 +01:00
Thomas Krijnen e2f79ec1ba Work on python wrapper 2017-12-31 12:20:13 +01:00
Thomas Krijnen 05e6f56911 Linker errors, geom server, warnings 2017-12-29 13:48:08 +01:00
Thomas Krijnen 19aebacbd8 Initialize kernel base class 2017-12-29 12:25:29 +01:00
Thomas Krijnen aeabe87779 Disable optimization for schema instantiation on gcc as well 2017-12-29 12:21:20 +01:00
Thomas Krijnen 7b3d334472 Warnings and errors 2017-12-29 12:09:07 +01:00
Thomas Krijnen 93c3afa1ae Schema dependent names for serialization functions 2017-12-29 11:23:46 +01:00
Thomas Krijnen 21e53d24e0 Fixes to examples 2017-12-28 18:44:50 +01:00
Thomas Krijnen f5d6f4f7f9 No anonymous structs to work around gcc 5 issue 2017-12-28 16:33:07 +01:00
Thomas Krijnen 24b46c1f43 Work on serialization 2017-12-22 17:37:58 +01:00
Thomas Krijnen ddde7bc367 Fix hierarchy helper 2017-12-22 17:34:13 +01:00
Thomas Krijnen 5f6a18c212 Fixes for hierarchy helper 2017-12-22 17:04:19 +01:00
Thomas Krijnen 5e23086947 Sprinkle with template and typename keywords 2017-12-22 16:45:02 +01:00
Thomas Krijnen 472fde5599 Fixes 2017-12-22 15:19:09 +01:00
Thomas Krijnen b3458c872f Work on python wrapper 2017-12-22 13:51:11 +01:00
stefkeB 5bf7f53fd8 BaseQuantities support in IfcConvert XmlSerializer
Added the export of BaseQuantities in the XML export of IfcConvert.
Very similar to the export of properties.
2017-12-22 11:33:28 +01:00
Thomas Krijnen 4d325e026e Fix compilation and execution of IfcConvert 2017-12-21 14:14:04 +01:00
Thomas Krijnen 6622afd93a Rename 2017-12-20 17:09:42 +01:00
Thomas Krijnen 8b4650b169 Fix compilation on msvc 2017-12-20 16:38:55 +01:00
Thomas Krijnen 6e525662c3 Disable XML serializer for the time being 2017-12-20 12:41:39 +01:00
Thomas Krijnen d46dfb6061 Work on serializers 2017-12-20 12:40:15 +01:00
Thomas Krijnen 830a03ffcd Schema agnostic iterator 2017-12-20 11:10:27 +01:00
Thomas Krijnen f4463d2935 Crazy factory implementation 2017-12-19 20:24:00 +01:00
Thomas Krijnen e3a7e6137d Update SvgSerializer.cpp 2017-12-19 14:58:56 +01:00
Xsoiou 01d261e168 SVG storey elevation (#315)
IfcConvert SVG does not generate <path d=""> for IfcSpace. #313
2017-12-19 12:10:19 +01:00
Thomas Krijnen a792a7e2c7 Two simultaneous IfcGeom implementations 2017-12-18 15:25:09 +01:00
civilx64 c4e56f670d Corrected name of *nix build script. 2017-12-18 15:17:21 +01:00
civilx64 4e28caaf8d Corrected name of *nix build script. 2017-12-18 15:17:21 +01:00
Xsoiou b7992d6a12 This closes #309 and it also fixes #310 2017-12-16 09:25:08 +01:00
Xsoiou efe765f71f Changed from http to https on ICU download 2017-12-16 09:25:08 +01:00
Thomas Krijnen 5eba7af791 Use struct instead of namespace to represent schema 2017-12-13 18:05:10 +01:00
Thomas Krijnen 761e9d7248 Continuing. 2017-12-13 13:58:58 +01:00
Thomas Krijnen 85515e904e Begin phasing out type enumeration in favour of declaration pointers 2017-12-13 13:16:49 +01:00
Thomas Krijnen 33fc2080df Runtime schema by name 2017-12-12 11:00:42 +01:00
Thomas Krijnen 33e1fa6a14 Update python wrapper 2017-12-11 17:20:22 +01:00
Thomas Krijnen e7ccf7269a Remove limited latebound schema representation in favour of full runtime schema representation 2017-12-11 15:46:57 +01:00
Thomas Krijnen 322dec6fd0 Update ifcconvert 2017-12-11 15:46:17 +01:00
Thomas Krijnen c099234796 Update ifcgeom 2017-12-11 15:07:40 +01:00
Thomas Krijnen 0468f12051 Address conflicts in ifcparse 2017-12-11 14:47:30 +01:00
Thomas Krijnen 988094b796 Resolving merge conflicts 2017-12-11 14:20:30 +01:00
Thomas Krijnen f36d27f7af Run codegen 2017-12-11 13:44:01 +01:00
Thomas Krijnen 3763ae18b2 Rough merge of schema runtime representation 2017-12-11 13:43:06 +01:00
Thomas Krijnen be5bd2e735 optional building storey argument added to setSectionHeight() 2017-12-11 11:19:15 +01:00
Thomas Krijnen ce782cc784 2d edges in svg serializer 2017-12-11 11:18:37 +01:00
tymokvo 39b0d11746 fixed missing bracket 2017-12-06 12:20:22 +01:00
tymokvo e06105e878 added some documentation/examples 2017-12-06 12:20:22 +01:00
Anders Granskogen Bjørnstad 34e2ff31bb SvgSerializer: Fix bug in ellipse writeout
Add a missing "=" to create a valid SVG for ellipses.

I accidentally stumbled upon a way to actually get an ellipse in SVG by
tilting a cylinder. If I tilt the cylinder via the `ObjectPlacement` of
the `IfcProduct` I get an ellipse. If I set the `ExtrudedDirection` of
the `IfcExtrudedAreasolid`, however, I get a sampled path.
2017-12-04 17:23:32 +01:00
Thomas Krijnen c0a2e3395f Triangulate non-planar wires when invoked with --sew-shells 2017-11-27 16:27:36 +01:00
Thomas Krijnen 7cd354ee7d Eliminate warning 2017-11-27 16:24:29 +01:00
Thomas Krijnen 95be422d4f Grep for command line arg name in ld stderr output 2017-11-25 19:15:25 +01:00
Thomas Krijnen 111569ec1b Approx other curve types in SVG, hollow circles 2017-11-25 13:08:34 +01:00
Anders Granskogen Bjørnstad 9c88a35173 SvgSerializer: Support full circles and ellipses
Use <circle> and <ellipse> to create a valid SVG for these geometries.

Limit to only the *first* edge. I am not sure whether there are
scenarios with multiple edges like this:
1. One or more straight line pieces or arc segments
2. A full closed circle
3. More straight lines or arc segments

If there is, we are keeping the original behavior here.
2017-11-25 13:06:03 +01:00
Anders Granskogen Bjørnstad 2647eacb74 test: Add {cylinders,ellipses}.ifc samples
A bare-bones IFC with four cylinders/ellipses. Used for SVG conversion
testing.
2017-11-25 13:06:03 +01:00
Anders Granskogen Bjørnstad df942f6460 SvgSerializer: Fix bounding box for arc segments
Not necessarily minimal, but better to be conservative w.r.t. getting
all geometry inside bounds.
2017-11-25 13:06:03 +01:00
Anders Granskogen Bjørnstad 7de877823b SvgSerializer: Add closed circle warning
Only refactoring, adding a warning.
2017-11-25 13:06:03 +01:00
Thomas Krijnen ea3318ae2e Don't rely on man for ld feature detection 2017-11-18 16:51:59 +01:00
Thomas Krijnen fb37899b26 Don't pass empty arguments to boost build 2017-11-18 16:50:38 +01:00
Thomas Krijnen 6463690a8b Fix typo 2017-11-13 13:01:59 +01:00
Thomas Krijnen 148432c011 Fixes for boolean ops on recent OCCT versions 2017-11-13 12:41:37 +01:00
Anders Granskogen Bjørnstad 478da8f658 IfcConvert: Add section-height argument for SVG
Enabling user specified overriding the default (zmin + 1 meter) value.
2017-11-11 10:02:41 +01:00
Anders Granskogen Bjørnstad 9be413a308 SvgSerializer: Use storey elevation if available
For the scenario where we a building storey and it has an elevation:
Instead taking the cross section of every product 1 meter above it's
lowest, take the cross section at storey elevation + 1 meter.
2017-11-11 10:02:41 +01:00
Anders Granskogen Bjørnstad a9606b3044 SvgSerializer: Name storeys properly too
- Fix correct "storey-" prefix for stories
- Follow user settings on names/guids/notset
2017-11-11 10:02:41 +01:00
Anders Granskogen Bjørnstad c419885329 SvgSerializer: Fix error message logic
If we have no storeys *and* we didn't find any suitable fall-back, then
the error message makes sense.
2017-11-11 10:02:41 +01:00
civilx64 b6b41e920f Create docstrings for generated python code. 2017-11-08 13:29:09 +01:00
Thomas Krijnen b7ce547a0c Fill holes in composite curves, fixes #282 2017-11-08 13:27:45 +01:00
thorade 6cd59aa121 autopep8 aggressive
autopep8 --in-place --recursive  --max-line-length=200 --aggressive --aggressive --aggressive ifcopenshell
2017-11-07 15:28:45 +01:00
thorade 8439e5b46d autopep8
autopep8 --in-place --recursive  --max-line-length=200 ifcopenshell
2017-11-07 15:28:45 +01:00
Stinkfist0 403f64a0d0 build-deps.cmd: fix boost build configuration for VS 2015. Fixes #279. [ci skip] 2017-11-05 16:18:00 +01:00
thorade 6bffee83fe identical from __future__ import in ALL py files 2017-11-05 16:17:27 +01:00
Anders Granskogen Bjørnstad f3e20ae450 geom/app.py: ConfigParser py2/py3 fix
When running the viewer app in python3, I got the following crash:
Traceback (most recent call last):
  File "geom_app.py", line 2, in <module>
    ifcopenshell.geom.app.application().start()
  File "/usr/lib/python3/dist-packages/ifcopenshell/geom/app.py", line 534, in __init__
    self.editor = code_edit(self.canvas, configuration().options('snippets'))
  File "/usr/lib/python3/dist-packages/ifcopenshell/geom/app.py", line 68, in __init__
    config = Cfg()
TypeError: 'ConfigParser' object is not callable

Unify configparser usage for py2 and py3 by making sure the py3 path
also gives a callable Cfg
2017-11-05 16:16:49 +01:00
thorade 352b14f07d ignore *.py.bak files 2017-11-03 11:05:02 +01:00
thorade d7bcd00904 also ignoe files generated by PyCharm 2017-11-03 11:05:02 +01:00
Matthis Thorade afce8b37c4 py 2 and 3
http://python3porting.com/noconv.html#handling-exceptions

this is the first error i get when i try to start th eviewer from python 3
using the two-line from https://github.com/IfcOpenShell/IfcOpenShell/commit/1d1fb6d27a5bb1f221aed4dc290c1dc99a324e0f#commitcomment-17161165
2017-10-30 10:31:35 +01:00
Thomas Krijnen a2b575eec8 update SWIG to latest release
#277
2017-10-30 10:26:27 +01:00
Matthis Thorade eb87d50548 update SWIG to latest release
because SWIG 3.0.7 is two years old and the intermediate releases all mention minor Python fixes.
http://www.swig.org/

I have used this for the last couple of builds and did not notice any negative effects.
2017-10-30 10:23:53 +01:00
Thomas Krijnen f64246f7c5 Use building or site placement for SVG section height if file has no storeys 2017-10-23 14:17:54 +02:00
Thomas Krijnen c5495d83e4 Invalid empty SVG file 2017-10-23 13:58:07 +02:00
Thomas Krijnen 095801faa1 Fix warning 2017-10-23 13:47:37 +02:00
Thomas Krijnen 07954122fb Fix #275 2017-10-23 13:32:57 +02:00
Stinkfist0 b347a488af build-deps.cmd: update Boost to latest 1.65.1. Fixes #249. 2017-10-18 13:58:32 +02:00
Campbell Barton 0429e765b5 Validate mesh input
This report comes from a but reported to Blender, where invalid geometry is apparently created by this importer.

https://developer.blender.org/T52921
2017-10-15 12:32:49 +02:00
Thomas Krijnen 33220fa78c Update python module install script 2017-10-06 16:37:22 +02:00
Thomas Krijnen effcecc75f ifcopenshell.template.create() 2017-10-06 16:05:55 +02:00
Thomas Krijnen 85f872d3b8 ifcopenshell.guid.new() 2017-10-06 16:03:04 +02:00
Thomas Krijnen f3b3e2a441 More meaningful error message setting attributes in python 2017-10-06 16:02:34 +02:00
Thomas Krijnen 25d68d320d Remove auto keyword 2017-10-06 16:01:18 +02:00
Matthis Thorade c38ac108cc basestring for py3
this closes #262
2017-10-06 15:49:19 +02:00
Anders Granskogen Bjørnstad d14d63dd5c IfcConvert: Fix bug with --bounds for SVG
`if(bounding_width)` evaluates to true as long as `bounding_width` is
non-zero (including negative values). Since `bounding_width` and
`bounding_height` are default initialized to -1.0, we were erroneously
setting a bounding rectangle of (-1.0, -1.0) here. This means the SVG
output has been broken/malformed if we didn't specify --bounds.
2017-10-06 15:49:07 +02:00
Thomas Krijnen 34d04c0da7 Add test case 2017-10-06 15:41:39 +02:00
Thomas Krijnen 6c4fee1028 Color elements by material association. Reimplement reuse detection. Fix #265 2017-10-06 15:36:51 +02:00
Thomas Krijnen ada503dbf1 Fix #266 2017-10-02 10:22:57 +02:00
Thomas Krijnen 8d0c95a939 Fix typo 2017-09-26 21:16:44 +02:00
Thomas Krijnen 7ba0b04031 Set mmacosx-version-min to 10.9 for OCCT
See https://github.com/openMVG/openMVG/issues/316#issuecomment-332142824
2017-09-26 11:43:03 +02:00
Thomas Krijnen 688a652bc1 Fix #261 2017-09-25 14:57:49 +02:00
Thomas Krijnen d839238949 Yet another repetition for cyclic symbol references 2017-09-24 22:15:33 +02:00
Thomas Krijnen f91ac2b375 Add py 3.6.2 to build-all.py 2017-09-24 13:37:14 +02:00
thomas.guenet 8792a8d750 CMakeLists.txt: add icui18n library for linux compilation 2017-09-22 11:56:10 +02:00
Thomas Krijnen f981c43042 More robust file download 2017-09-18 14:51:58 +02:00
Thomas Krijnen 8c26037f84 Fix null dereference 2017-09-17 20:22:29 +02:00
Thomas Krijnen 96ec925f31 Spatial Querying: Implementation of BVH tree for IFC files using NCollection_UBTree (#130)
* Implementation of BVH tree for IFC files using NCollection_UBTree

* Fixes for gcc and OCCT < v6.8

* Enable BVH selection by TopoDS_Shape

* Small fixes to tree

* Merge conflicted files and other changes

* Eliminate one warning (some remain) + add tree test
2017-09-13 13:16:58 +02:00
Thomas Krijnen ee16deabe5 Fix #38 2017-09-10 17:15:04 +02:00
Thomas Krijnen 4f31b9467a Fix #248 2017-09-10 16:59:05 +02:00
elmir f6645b19ef don't assign ID to Simple types
When adding entities, don't assign ID to Simple types.
Otherwise that type will be serialized incorrectly.

This fixes the issue with IFCPLANEANGLEMEASURE being serilzed
incorrectly when used as attribute to IFCMEASUREWITHUNIT.

With ID assigned, it will look like this:

  #10=IFCMEASUREWITHUNIT(#9=IFCPLANEANGLEMEASURE(0.017453293),#8);

The correct way to serialze is:

  #10=IFCMEASUREWITHUNIT(IFCPLANEANGLEMEASURE(0.017453293),#8);
2017-09-09 14:00:57 +02:00
Thomas Krijnen f2dbf7d063 Improve composite curve error message 2017-09-09 13:29:39 +02:00
Thomas Krijnen 49e5f2944c Rebuild generated source files 2017-09-08 17:26:24 +02:00
youaresoomean fae9661efd Update IfcParse.h (#256) 2017-09-08 17:18:11 +02:00
youaresoomean b90b39a894 Update templates.py 2017-09-08 17:17:50 +02:00
Stinkfist0 c7c5e692d3 IfcConvert --version: print also OCC version. 2017-08-27 16:11:54 +02:00
Stinkfist0 93c2ca6267 CMakeLists.txt: Add ws2_32.lib to OPENCASCADE_LIBRARIES on Win32 as OCCT might require this depending on the used version and build configuration. Closes #250. 2017-08-27 16:11:54 +02:00
Thomas Krijnen 430ab54602 ifcopenshell.file.from_string() 2017-08-22 10:16:07 +02:00
Luke Brooks 08522c9fd7 ifcopenshell.file.from_string() (#246) 2017-08-22 10:15:02 +02:00
Anders Granskogen Bjørnstad 475b8554a8 Site local placement (#240)
* ifcgeom: Add placement_rel_to for convert()

Change geometry conversion in `convert()` for `ObjectPlacement` such
that we can stop the `PlacementRelTo()` recursion when we hit an
`ObjectPlacement` that places a certain type, e.g. a `IfcSite'.

Introduce a new IteratorSetting `SITE_LOCAL_PLACEMENT` which will be
exposed in `IfcConvert`.

* IfcConvert: Add --site-local-placement

Some IFC authoring tools may put the global origo at a large distance
away from the actual building geometry. Also, the global X- and Y-axes
may be at arbitrary angles with natural building axes. Using
--center-model or --model-offset may place the converted geometry closer
to origo, but will still use the global IFC definition of axis
directions. Also, in a scenario with multiple IFC files for one
construction site, using --center-model on each of them would not
generate consistent geometry across OBJ or DAE files.

Solve this by introducing --site-local-placement which will disregard
the ObjectPlacement at the IfcSite level.
2017-08-19 17:21:10 +02:00
Thomas Krijnen 7bea054c1e get_log in python 2017-08-19 16:54:06 +02:00
Thomas Krijnen 490c35bf60 Fix #244 and provide instances by entity type without subtypes 2017-08-16 21:46:39 +02:00
Stinkfist0 b019ff6aed build-deps.cmd: fix URL for Git download (TortoiseGit doesn't contain Git) 2017-08-16 14:12:12 +02:00
Thomas Krijnen 4c6ca83528 Add option to build with OCCT 7.1 in nix build script 2017-08-13 13:13:26 +02:00
Thomas Krijnen 9ba5e8fd88 Add win build script occt patches 2017-08-12 10:53:28 +02:00
Thomas Krijnen 2e36793af2 win build script OCCT 7.1.0 2017-08-12 10:29:23 +02:00
Thomas Krijnen e3d2621ea9 Alternative for CTRL+C in win build script 2017-08-12 10:28:05 +02:00
Thomas Krijnen ebfe8f9c54 Take into account Position is optional in IFC4 when processing layersets on slabs 2017-08-09 17:01:10 +02:00
Thomas Krijnen 132e5d5f6e Disable log_notice message on exceeding tolerance values 2017-08-09 17:00:41 +02:00
Thomas Krijnen 62794d4b07 Unused variable warning 2017-08-09 12:55:03 +02:00
Thomas Krijnen fd7f6e1f26 IfcIndexedPolyCurve 2017-08-05 12:39:15 +02:00
Thomas Krijnen b00acd3f67 only convert length unit if units are present in both files 2017-08-04 16:31:34 +02:00
Thomas Krijnen f12d8eeaa6 by_guid() and unicode in py2 2017-08-04 16:31:10 +02:00
Thomas Krijnen 85524170dd More advanced entity_instance.get_info() 2017-08-04 16:30:43 +02:00
Thomas Krijnen c67de4bbb3 Mark attributes as 'derived in supertype' also in getArgumentType() 2017-08-04 16:29:26 +02:00
Thomas Krijnen 36c52b3bea Update tests 2017-08-02 16:09:20 +02:00
Thomas Krijnen ceff8a8822 Fixes for IfcEntityInstanceData copy construction 2017-08-02 16:09:01 +02:00
Thomas Krijnen a58f23fae2 Missing introspection methods in Python 2017-08-02 16:08:07 +02:00
Thomas Krijnen b696df0da1 Missing semicolons in header 2017-08-02 16:07:30 +02:00
Thomas Krijnen 94224411a9 Recursive get_info() 2017-08-02 16:06:27 +02:00
Thomas Krijnen 5c7e7cab1a Raise IndexError 2017-08-02 16:05:56 +02:00
Thomas Krijnen 29323e4f74 Fix recursion in traverse() 2017-08-01 19:07:46 +02:00
Thomas Krijnen aa0a6aa5d1 Fix #178 2017-08-01 16:45:11 +02:00
Thomas Krijnen d10efe69cd Fix typo in test 2017-07-27 15:53:06 +02:00
Thomas Krijnen fb1fed247e Fix #243 2017-07-27 10:21:37 +02:00
Thomas Krijnen 59d7e0cad3 nix build script: fix compilation of boost.iostreams, disable USE_MMAP 2017-07-25 16:27:13 +02:00
Thomas Krijnen ae0afe2c0a mmap #22 2017-07-25 16:27:13 +02:00
Thomas Krijnen 3edb057178 Bring back id() to python wrapper. Fixes #241 2017-07-17 18:10:28 +02:00
Thomas Krijnen 04e3018f3c Use default logger 2017-07-17 18:09:49 +02:00
Thomas Krijnen f81616a6fb Narrow and wide unicode builds in nix build script 2017-07-03 20:42:18 +02:00
Thomas Krijnen f58539d6d8 Construct not only allocate token buffer 2017-07-03 20:39:40 +02:00
Thomas Krijnen 90bdf03f54 Disable exception 2017-07-03 16:38:04 +02:00
Thomas Krijnen 6e87a21806 Ignore some methods in wrapper to fix build 2017-07-03 15:43:56 +02:00
Thomas Krijnen d94eb9a96e IfcMaterialList in XML output 2017-07-03 15:18:07 +02:00
Thomas Krijnen ac5800326b Fix compilation on gcc 2017-07-03 14:42:08 +02:00
Thomas Krijnen 901ef57d60 Fix #180 2017-07-03 14:18:56 +02:00
Thomas Krijnen b604e5cf99 Fix #204 2017-07-02 19:57:10 +02:00
Thomas Krijnen 1e79eb535a Build comprehensive representation id. Fix #225 2017-06-28 15:59:03 +02:00
Thomas Krijnen 6f7afd4b2a Build comprehensive representation id. Fix #225 2017-06-28 15:24:49 +02:00
Thomas Krijnen a90936a7de Properly initialize parsed simple types 2017-06-24 21:35:38 +02:00
Thomas Krijnen 7c1cf6ebd0 Fix #233 2017-06-24 13:36:26 +02:00
Stinkfist0 7eb1346407 IfcConvert: prevent doing IfcFile::Init() "prematurely", e.g. before some additional program option parsing that might fail. 2017-06-23 14:12:07 +02:00
Stinkfist0 771b1f3d3c IfcConvert: consistent style for user error prints. 2017-06-23 14:12:07 +02:00
Stinkfist0 3fb96cad0b IfcConvert: make sure to delete temp file if no actual conversion occurs. Also fixes serializer memory leaks. Closes #199.
C
2017-06-23 14:12:07 +02:00
Thomas Krijnen 23beb096a0 Remove auto keywords 2017-06-20 19:47:53 +02:00
Thomas Krijnen 101ef69ae9 Fail serialize() if one of the faces cannot be mapped to IFC (2x3) 2017-06-20 18:55:52 +02:00
Thomas Krijnen e60202b738 Unique filter on IfcEntityList 2017-06-20 18:54:55 +02:00
Thomas Krijnen 1e8b1d9c9c traverse() as a global function rather than method on IfcFile 2017-06-20 18:54:30 +02:00
Thomas Krijnen a27e516011 Elided argument in ifcopenshell.file constructor 2017-06-20 18:53:39 +02:00
Thomas Krijnen 69c8b7c1c8 One more boost::blank() refactoring 2017-06-20 18:52:56 +02:00
Thomas Krijnen c25cff6bad Correct setting attributes on lazily loaded instances 2017-06-15 14:12:03 +02:00
Thomas Krijnen 48a61219f7 Fix #228 2017-06-14 12:42:38 +02:00
Thomas Krijnen 9ae55ab303 Small fixes to transformations 2017-06-06 17:12:46 +02:00
Stinkfist0 84813084d0 Fix/suppress signed-unsigned integer conversion warnings. 2017-06-05 19:53:10 +02:00
Thomas Krijnen 5e0da9725a ifcparse refactoring (#190)
Unify attribute containers, provide latebound attribute access on IfcBaseEntity, more basic tests on Travis
2017-06-05 17:26:58 +02:00
Thomas Krijnen 9a43658716 Correct verbosity check 2017-06-05 13:08:07 +02:00
Stinkfist0 f3f4c41f8d IfcConvert: add --no-progress option to suppress possible progress bar type of prints that use carriage return. 2017-06-05 11:41:55 +02:00
Stinkfist0 273c977f66 Remove extraneous spaces in geom filter description prints. 2017-06-05 11:41:55 +02:00
Stinkfist0 0adcb9ae20 IfcConvert --filter-file: Specifies a filter file that describes the used filtering criteria. 2017-06-05 11:41:55 +02:00
Thomas Krijnen 1751cf1c95 Generate example models on Travis 2017-06-05 11:29:23 +02:00
Thomas Krijnen 1704862d0d Correct test for when to reuse representation in iterator 2017-06-05 11:08:07 +02:00
Janus Troelsen d7c275e941 use boost's blank instead of none_t 2017-05-23 12:48:17 +02:00
Stinkfist0 1b9a28d799 CMakeLists.txt: fix Windows/MSVC lib search when only Debug versions of libs are found. 2017-05-20 20:19:15 +02:00
Stinkfist0 68b432f6c0 CMakeLists.txt: fix add_debug_variants() to work on Debug build. Re: #201 [ci skip] 2017-05-20 20:19:15 +02:00
Thomas Krijnen af2799acd4 Matrix multiplication in OCC rather than boost::ublas (re #211) 2017-05-20 19:50:10 +02:00
Thomas Krijnen c093dc0335 Merge pull request #211 from mitmadness/feature/hierarchy
Represent hierarchy in Collada files
2017-05-20 19:46:56 +02:00
Balleux Benjamin 834e05a01c Feature : For each parent element, include the type in the name if --use-element-types if used 2017-05-18 11:26:19 +02:00
Balleux Benjamin 4680298bee Clean : Remove debug logs 2017-05-16 16:34:50 +02:00
Balleux Benjamin be39f30029 Fix : fix build error 2017-05-16 15:54:26 +02:00
Balleux Benjamin 3919c1f32e Feature : Retrieve the full hierarchy
(merged from hierarchyDevelop branch)
2017-05-16 15:30:57 +02:00
Balleux Benjamin e02bbefa68 Clean : Removed debug logs 2017-05-16 15:20:30 +02:00
Balleux Benjamin 5c497c8f6c Fix : Handle the case where the first representation element has 0 parent 2017-05-16 15:01:55 +02:00
Balleux Benjamin 942d34ee39 Feature : Retrieve the full hierarchy. Fix the placement of the objects.
Check slab->HasObjectType before using slab->ObjectType
2017-05-16 14:27:36 +02:00
Balleux Benjamin 45ec08f840 feature (WIP) : retrieve the full hierarchy. The placement of several objects still be incorect 2017-05-16 11:27:45 +02:00
Balleux Benjamin be3dbce9f4 feature (WIP) : retrieve full hierarchy
Bug : the element are not at the right location
2017-05-15 17:45:05 +02:00
Stinkfist0 20c189c321 set-python-to-path.bat: fix for command for quoted filename 2017-05-13 14:03:15 +02:00
arzezniczak 97c5126a77 Authenticated proxy support for DownloadFile
DownloadFile subroutine gets credentials from system settings.
2017-05-13 14:02:42 +02:00
Balleux Benjamin ff64ce1e0e Fix : change wrong namespace 2017-05-11 14:02:34 +02:00
Balleux Benjamin 4f6e8a7d56 Fix : Change wrong namespace 2017-05-11 13:27:00 +02:00
Balleux Benjamin 93ece6b3ea Fix : Add missing include 2017-05-11 11:49:25 +02:00
Balleux Benjamin ced9d8c917 Merge branch 'feature/hierarchyDevelop' into feature/hierarchy 2017-05-11 11:22:11 +02:00
Balleux Benjamin ef0e9d9eb4 Feature : Handle every IfcSlabTypeEnum (3 were missing) and sort the floors by elevation 2017-05-09 15:55:37 +02:00
Balleux Benjamin 3c2fbcc4e1 Feature : Handle every IfcSlabTypeEnum (3 were missing) and sort the floors by elevation 2017-05-09 15:54:21 +02:00
Balleux Benjamin a6ffa7fc42 Fix : fill the storey property of an Element with NULL when we don't find any IfcBuildingStorey parent 2017-05-09 14:40:23 +02:00
Thomas Krijnen 0f825b7050 Fix missing import 2017-05-03 15:10:20 +02:00
Stinkfist0 845dd13870 Windows/MSVC: Fix OCCT deployment on VS 2017. 2017-05-03 14:13:24 +02:00
Thomas Krijnen d713b7e06a Limit retries for boolean op on OCCT 6.9 and higher 2017-05-03 12:07:10 +02:00
Tristan Zimpfer e3e4fba63a Clean of the double declaration of IfcSlabTypeEnum. 2017-04-26 10:59:07 +02:00
Tristan Zimpfer 78b904dfeb Differentiate slab types when option --use-element-types is used. 2017-04-26 10:28:38 +02:00
Thomas Krijnen 00c70fa8fb IfcOpenHouse fixes for IFC4 2017-04-25 17:38:59 +02:00
Ken Arroyo Ohori 8baf6197d5 Merge pull request #16 from kenohori/cgal
Validation code to catch more cases of invalid objects
2017-04-25 10:22:33 -05:00
Thomas Krijnen d34c3b4b20 Example for #209 2017-04-25 16:53:35 +02:00
Thomas Krijnen 033075f809 Fix #208 2017-04-25 16:37:50 +02:00
Balleux Benjamin 1d8f6addf8 Get the information on the IfcSlab (floor or roof..) and put it in the element name.
To be cleaned
2017-04-25 16:27:14 +02:00
Ken Arroyo Ohori 42f23a786f Output all errors as separate files 2017-04-25 13:45:18 +02:00
Ken Arroyo Ohori 8b539d2b93 Requirement for self-intersection tests 2017-04-25 13:44:57 +02:00
Ken Arroyo Ohori b732759388 Comprehensive validation code for opening subtractions 2017-04-25 13:44:34 +02:00
Ken Arroyo Ohori 02244400ab Remove old debug code 2017-04-25 13:43:55 +02:00
Ken Arroyo Ohori 85a36738d2 Comment out triangulation code 2017-04-25 13:42:38 +02:00
Balleux Benjamin 26a9167eea Add coments 2017-04-25 11:55:09 +02:00
Balleux Benjamin 5fae7a5992 Merge branch 'feature/hierarchy' of https://github.com/mitmadness/IfcOpenShell into feature/hierarchy 2017-04-25 10:13:37 +02:00
Balleux Benjamin 7edca081bf Raise an error when the option --use-element-hierarchy is used with a file different of .dae 2017-04-25 10:13:18 +02:00
Tristan Zimpfer 08e4d16f28 Modified the condition checking if the parent had changed so an object without parent isn't placed in a storey. 2017-04-21 18:05:35 +02:00
Tristan Zimpfer 470e8e772e Comments + conditions for sorting the deferred objects added. 2017-04-21 16:15:41 +02:00
Balleux Benjamin ea609af394 comments added 2017-04-21 16:02:13 +02:00
Balleux Benjamin 8ac18752b2 Remove temp file 2017-04-21 15:59:54 +02:00
Balleux Benjamin 95acd4c517 Clean : remove debug lines
Find the floor of an element in the IfcGeomIterator class
2017-04-21 15:49:34 +02:00
Ken Arroyo Ohori 164e67a50b Catching some more CGAL errors, allow non-closed meshes, start of new code to triangulate faces 2017-04-21 15:43:19 +02:00
Balleux Benjamin 7ce795def3 clean WIP 2017-04-20 15:06:49 +02:00
Balleux Benjamin 8e4febecc0 clean : Remove the debug print
debug : don't display the name of the element in unity anymore
2017-04-19 16:38:35 +02:00
Balleux Benjamin 195979d4f0 Merge branch 'feature/hierarchy' of https://github.com/mitmadness/IfcOpenShell into feature/hierarchy
# Conflicts:
#	src/ifcconvert/ColladaSerializer.cpp
2017-04-19 15:09:59 +02:00
Balleux Benjamin ab0e47c55f Options added : --use-element-types and --use-element-hierarchy 2017-04-19 12:07:03 +02:00
Tristan Zimpfer 9f362853d6 Added a matrix for the parent node and a better id. 2017-04-19 11:48:52 +02:00
Tristan Zimpfer 79e1e0ec04 Hierarchy v1 2017-04-13 16:39:36 +02:00
Ken Arroyo Ohori de83633891 Merge pull request #15 from kenohori/cgal
Catching some errors during conversion to/from Nef, tapered extrusions
2017-04-12 23:10:46 -05:00
Tristan Zimpfer f446f25cee Sort DeferredObject. 2017-04-12 17:28:29 +02:00
Balleux Benjamin a02b189f69 Bug Fix : the previous commit made the program crash when an object has no parent 2017-04-12 16:11:37 +02:00
Balleux Benjamin 8312853b99 add parent property to deffered objects 2017-04-12 15:49:05 +02:00
Balleux Benjamin be326e13ed Send Hierarchy data to the serializer 2017-04-12 14:56:00 +02:00
Balleux Benjamin a2aa2bf9eb Send hierarchy data to the serializer WIP 2017-04-12 14:38:54 +02:00
Balleux Benjamin b9e9bfeceb Handle errors : when an object has no parent 2017-04-12 13:36:12 +02:00
Stinkfist0 dd8ee915c3 ifcwrap/CMakeLists.txt: as PYTHONLIBS_FOUND and PYTHONINTERP_FOUND cannot seem to be trusted, perform further checks to see whether the packages were actually found or not.
E.g. one can doo set PYTHONHOME=C:/NoPythonHere
and when running CMake it will happily report:
-- Found PythonLibs: C:/NoPythonHere/libs/python34.lib
2017-04-12 10:39:41 +02:00
Stinkfist0 7fdbc9811d src/ifcwrap/CMakeLists.txt: use PYTHON_INCLUDE_DIRS instead of the deprecated PYTHON_INCLUDE_PATH 2017-04-12 10:39:41 +02:00
Stinkfist0 2edf867818 Use boost functions for string manipulation instead of std ones in order to silence char-int conversion warnings on VS 2017. 2017-04-12 10:39:41 +02:00
Stinkfist0 e4a7d2a149 Windows/MSVC build scripts: support for VS 2017 CMake generators, update Boost to 1.63.0, update ICU download to 58.2 in order to have VS 2107 download available, configure Boost using generic MSVC instead of specific version, make sure to 'git fetch' before 'git checkout <revision>'. 2017-04-12 10:39:41 +02:00
Balleux Benjamin 37f7fbecca Retrieve the type and the hierarchy of the IFC and write it in the .dae files 2017-04-11 17:26:30 +02:00
Ken Arroyo Ohori 9f2a617ad7 Catch a few nasty cases in triangulation, more efficient to only compute face normals 2017-04-10 18:54:30 -05:00
Ken Arroyo Ohori 26bd03e407 Ditto 2017-04-10 18:53:52 -05:00
Ken Arroyo Ohori 248c73c2ab Catch failures to convert Nef to Polyhedron_3 2017-04-10 18:53:28 -05:00
Alexandre Lemire 0f993b32f4 Fix generation of IfcOpenHouse.ifc which doesn't have its ground representation. See #200 2017-04-07 12:29:38 +02:00
Thomas Krijnen 8d9acfa677 Attempt to fix travis build w/ CGAL 2017-04-06 15:23:45 +02:00
Thomas Krijnen 7b7f9b4852 Attempt to fix travis build w/ CGAL 2017-04-06 14:57:10 +02:00
Thomas Krijnen 7189219aa4 Attempt to fix travis build w/ CGAL 2017-04-06 14:44:57 +02:00
Ken Arroyo Ohori f03a228280 Merge pull request #3 from aothms/cgal
Thomas fixed the transformations
2017-04-05 18:07:32 -05:00
Thomas Krijnen 91e5b337d3 Reverse matrix multiplication order 2017-04-05 16:06:07 +02:00
Thomas Krijnen 009f50abe1 Fix compilation on MSVC 2017-04-05 15:57:21 +02:00
Thomas Krijnen f71ee35f57 More 'tolerant' to tolerances higher than the modeling precision 2017-04-03 14:55:34 +02:00
Thomas Krijnen 1856c499b7 Fix misalignment between enum and boost::variant. See #200 2017-04-03 11:41:14 +02:00
Ken Arroyo Ohori c9267d7ace Fixed orientation bug in tapered extrusions 2017-03-30 21:11:05 -06:00
Ken Arroyo Ohori 4a340027bf IfcExtrudedAreaSolidTapered (with problems?) 2017-03-30 20:12:23 -06:00
Ken Arroyo Ohori 612f8f36db Merge pull request #14 from kenohori/cgal
Bugfixes + some validation code when creating New polyhedra
2017-03-30 19:16:48 -06:00
Ken Arroyo Ohori c1887f3f1f And the rest 2017-03-30 19:16:11 -06:00
Ken Arroyo Ohori 71ad7dd4bc Forgot one line 2017-03-30 19:06:47 -06:00
Ken Arroyo Ohori ed9676ed38 Squashed some bugs 2017-03-30 19:04:39 -06:00
Thomas Krijnen 06cad59fa2 Fix missing python module installation 2017-03-24 10:11:44 +01:00
Ken Arroyo Ohori a6195290f5 Merge pull request #13 from kenohori/cgal
Move shapes back to Polyhedron_3, more IFC entities supported, bugfixes
2017-03-23 20:33:52 -06:00
Ken Arroyo Ohori 583c334802 Removed sphere radius at some point 2017-03-23 20:31:41 -06:00
Ken Arroyo Ohori f8f4db72ec IfcDerivedProfileDef 2017-03-23 20:25:54 -06:00
Ken Arroyo Ohori dd206a2a52 A few more simple IFC classes to fill in things 2017-03-23 20:20:43 -06:00
Ken Arroyo Ohori 12967790ba Switched back to Polyhedron_3 for shapes. Should be checked. 2017-03-23 19:49:15 -06:00
Ken Arroyo Ohori d0b71a2e57 Merge pull request #12 from kenohori/cgal
Reorganisation, export of non-simple New polyhedra, (very slow) solution to create open meshes
2017-03-20 20:59:19 -06:00
Ken Arroyo Ohori 4061f93560 Export non-simple Nef too 2017-03-20 20:57:17 -06:00
Ken Arroyo Ohori 71d7bbd6ba Ordering things… 2017-03-20 20:06:48 -06:00
Ken Arroyo Ohori 62ca6f6a7d Checked shapes with styles. Found bug? 2017-03-20 16:45:27 -06:00
Ken Arroyo Ohori 8090bb4c00 Shapes with styles in separate file 2017-03-20 16:35:14 -06:00
Ken Arroyo Ohori cf6bd5a629 Enabled missing Cartesian transformations 2017-03-20 16:31:06 -06:00
Ken Arroyo Ohori cf9605f108 Missing Shapes, support for voids 2017-03-20 15:56:31 -06:00
Thomas Krijnen 8e69f84430 Trigger license redetection 2017-03-19 09:47:28 +01:00
Thomas Krijnen 9e3fe84c66 Trigger license redetection 2017-03-19 09:46:07 +01:00
Ken Arroyo Ohori 507d4778fa Merge pull request #11 from kenohori/cgal
Bugfixes in placements, half space solids and validation code
2017-03-17 19:27:34 -06:00
Ken Arroyo Ohori 95e6c14f39 Hack to solve issues with IfcHalfSpaceSolid. Not ideal. 2017-03-17 19:24:51 -06:00
Ken Arroyo Ohori 2bbe80fd28 Problems with extended kernel experiment, but this should be incorporated in any case 2017-03-17 16:12:24 -06:00
Ken Arroyo Ohori 0ffa633a6d Better validation 2017-03-16 19:30:39 -06:00
Ken Arroyo Ohori 30e88210b2 Simplified code by moving Nef creation outside 2017-03-16 19:20:41 -06:00
Ken Arroyo Ohori 98ce04ed64 Fix logic of transformations 2017-03-16 18:44:25 -06:00
Ken Arroyo Ohori d2aef0fcbd 2D Cartesian transformations (untested) 2017-03-13 22:32:12 -06:00
Ken Arroyo Ohori 38cbdbc0f4 Correct way to create trimmed parametric curves? 2017-03-13 20:22:19 -06:00
Ken Arroyo Ohori 83689a1cec Merge pull request #10 from kenohori/cgal
Basic support for (trimmed) curves
2017-03-13 19:29:20 -06:00
Ken Arroyo Ohori 81cb7f379e Ignore output files in /test/ 2017-03-13 19:26:54 -06:00
Ken Arroyo Ohori 7d16b725a3 IfcTrimmedCurve. Needs projection to closest point in curve? 2017-03-13 19:08:50 -06:00
Ken Arroyo Ohori 54331062c3 Basic curve types 2017-03-13 19:08:23 -06:00
Thomas Krijnen 9ad68db0dc set OCE_VERSION, executable flags in win build script 2017-03-12 11:38:23 +01:00
Ken Arroyo Ohori 4419331710 Merge pull request #9 from kenohori/cgal
Fix issue with opening placements
2017-03-10 18:29:01 -06:00
Ken Arroyo Ohori 81a33309f3 Merge pull request #2 from aothms/cgal
Merge pull request #8 from kenohori/cgal
2017-03-10 18:28:17 -06:00
Ken Arroyo Ohori d02918070d Remove debug code 2017-03-10 18:26:15 -06:00
Ken Arroyo Ohori ac7099ab39 Fixed bug with opening placements 2017-03-10 18:21:15 -06:00
Ken Arroyo Ohori b5e79b2558 Debug code 2017-03-10 17:44:19 -06:00
Ken Arroyo Ohori b1df91ffd9 Merge pull request #8 from kenohori/cgal
More profiles (T, U, Z) and support for openings
2017-03-09 18:45:34 -06:00
Ken Arroyo Ohori 287fb9f0ed Convert openings and subtract them 2017-03-09 18:42:54 -06:00
Ken Arroyo Ohori 06c10dc4da Correct plane creation? 2017-03-09 17:04:37 -06:00
Ken Arroyo Ohori 3972727f9d Z profiles 2017-03-09 16:55:33 -06:00
Ken Arroyo Ohori 3e918180d2 U profiles 2017-03-09 16:46:09 -06:00
Ken Arroyo Ohori 0fbadc2985 T profiles 2017-03-09 16:29:14 -06:00
Ken Arroyo Ohori 8f89498a32 Merge pull request #1 from aothms/cgal
Merging back Thomas' latest changes
2017-03-09 09:46:48 -06:00
Thomas Krijnen 7bcd0d0a8d Apply transformation to IfcExtrudedAreaSolid 2017-03-09 15:35:29 +01:00
Thomas Krijnen 0596827b9d Fix null pointer access in tesselation of opencascade shape 2017-03-09 15:04:54 +01:00
Thomas Krijnen 40f3447ad1 Update dependency versions in nix build script 2017-03-09 14:36:00 +01:00
Thomas Krijnen c8cc8ab1c8 Resolve python library linking issues on OSX 2017-03-09 13:59:54 +01:00
Thomas Krijnen 619b4fbed5 Fix CGAL library linking on windows, conditional IfcTriangulatedFaceSet based on schema 2017-03-09 12:14:00 +01:00
Thomas Krijnen 4faa66f9b8 Fix for python 2.7 2017-03-09 12:04:07 +01:00
Thomas Krijnen 5705f24f3e python: make logging import conditional in case time is not built 2017-03-09 11:47:54 +01:00
Thomas Krijnen 52d035d09a python: don't import platform module as it may depend on select which might be unavailable 2017-03-09 10:16:22 +01:00
Ken Arroyo Ohori deea0f6558 Merge pull request #7 from kenohori/cgal
Composite curves, some profiles (C, I, L)
2017-03-08 20:13:33 -06:00
Ken Arroyo Ohori 15e4e1952f I profiles (untested) 2017-03-08 20:11:45 -06:00
Ken Arroyo Ohori e922212357 L profiles 2017-03-08 19:55:17 -06:00
Ken Arroyo Ohori 0d36693780 C profiles 2017-03-08 19:38:25 -06:00
Stinkfist0 921e343187 Fix assertion. Closes #192 2017-03-08 09:31:51 +01:00
Ken Arroyo Ohori cb7ed51fc6 IfcCartesianTransformationOperator3DnonUniform (untested) 2017-03-07 20:00:32 -06:00
Ken Arroyo Ohori a3df0556aa Composite curves 2017-03-07 19:39:59 -06:00
Ken Arroyo Ohori 3f94d4af37 Skeleton for planes+halfspaces. Might be wrong. 2017-03-07 14:30:48 -06:00
Ken Arroyo Ohori 7f96b3a523 Merge pull request #6 from kenohori/cgal
Added several types of shapes and profiles
2017-03-07 13:55:15 -06:00
Ken Arroyo Ohori 27d8e86024 Hollow rectangle profiles, all tested now 2017-03-07 13:52:29 -06:00
Ken Arroyo Ohori 66048610e2 Rounded rectangles work now, def must be before rectangles 2017-03-07 13:41:04 -06:00
Ken Arroyo Ohori 31d4de228a Extrusions with holes (Nef) 2017-03-07 13:18:49 -06:00
Ken Arroyo Ohori 29021d8b06 Hollow circles 2017-03-07 13:04:22 -06:00
Ken Arroyo Ohori 1fb76a9749 Switched to normals per vertex per face 2017-03-07 12:50:06 -06:00
Ken Arroyo Ohori b299c27473 Switched to Nef_polyhedron_3. Some problems... 2017-03-06 19:28:12 -06:00
Ken Arroyo Ohori 64e385c361 Skeleton for IfcEdgeLoop and IfcOrientedEdge 2017-03-06 17:45:55 -06:00
Ken Arroyo Ohori 27b5fd0fc5 Debug code 2017-03-06 17:29:20 -06:00
Ken Arroyo Ohori 4f5ecee81e Removing duplicate points, IfcCartesianTransformationOperator3D with problems 2017-03-06 16:03:29 -06:00
Ken Arroyo Ohori ca19d447cc Zero-radius rounded rectangles 2017-03-06 15:03:57 -06:00
Ken Arroyo Ohori 484cea968e IfcTriangulatedFaceSet 2017-03-06 11:41:58 -06:00
Ken Arroyo Ohori 033a2e7482 IfcFaceBasedSurfaceModel 2017-03-06 11:28:57 -06:00
Ken Arroyo Ohori 1d3732aa62 IfcEllipseProfileDef 2017-03-06 11:23:37 -06:00
Ken Arroyo Ohori 584b2e5584 IfcTrapeziumProfileDef 2017-03-06 11:18:51 -06:00
Ken Arroyo Ohori 1bcc369c7a Rounded rectangles 2017-03-06 11:12:06 -06:00
Ken Arroyo Ohori 64bc8e9d4f Circular profiles, added missing transformation for rectangles 2017-03-06 10:52:57 -06:00
Thomas Krijnen 50ea73a28f Update IfcConvert help text 2017-03-04 14:16:54 +01:00
Stinkfist0 3275119d1d TokenFunc::asStringRef: protect against null token. 2017-03-04 13:54:19 +01:00
Stinkfist0 026b4853a2 IfcConvert: single point for IFC file parsing and potential parsing error reporting. 2017-03-04 13:54:19 +01:00
Stinkfist0 cd132473f5 IfcConvert: instead of global --traverse option provide --include+ and --exclude+ options that control traversal on per filter basis. 2017-03-04 13:54:19 +01:00
Stinkfist0 06c1ea9d2c Doc tweaks [ci skip] 2017-03-04 13:54:19 +01:00
Stinkfist0 b058647d46 IfcLogger: convenience shorthands Notice(), Warnings() and Error() 2017-03-04 13:54:19 +01:00
Stinkfist0 8e44290341 string_arg_filter: make sure the argument type is string 2017-03-04 13:54:19 +01:00
Stinkfist0 5d7b392415 IfcGeomIterator: use fully qualified symbol for filter_t to fix SWIT code generation + fix getObject() 2017-03-04 13:54:19 +01:00
Stinkfist0 0383221d00 IfcConvert: print information about the used filters. 2017-03-04 13:54:19 +01:00
Stinkfist0 678d422ec8 Fix errors in rebase merge. 2017-03-04 13:54:19 +01:00
Stinkfist0 eade74c919 Fix --traverse --exlucde=<entities|layers> + clean up duplicate code. filter::traverse_match: dynamic_cast instead of static_cast as the decomposing entity is not guaranteed to be IfcProduct 2017-03-04 13:54:19 +01:00
Stinkfist0 9074f25e93 Fix --exclude=arg when --traverse used also. 2017-03-04 13:54:19 +01:00
Stinkfist0 4b5790e83a IfcConvert: minor cleanup + fix guid exclusion filter's value population. 2017-03-04 13:54:19 +01:00
Stinkfist0 470b08cd04 IfcConvert: output regular prints to cout instead of cerr. 2017-03-04 13:54:19 +01:00
Stinkfist0 d88c93a150 Cleaning up geom filters. 2017-03-04 13:54:19 +01:00
Stinkfist0 7101ac22c8 Refactor template class arg_filter into string_arg_filter instead, support for IfcProxy.Tag (untested, did not find suitable test input yet). 2017-03-04 13:54:19 +01:00
Stinkfist0 1b7d38a56d support for IfcConvert -include=arg <Description|Tag> (for IfcElement.Tag, not yet for IfcProxy.Tag). 2017-03-04 13:54:19 +01:00
Stinkfist0 de5864fc72 IfcConvert: change syntax of --<include|exclude>=<names|guids> to --<include|exclude>=arg <Name|GlobalId>. The plan is to support arbitrary arguments in the future. 2017-03-04 13:54:19 +01:00
Stinkfist0 195d68cd0a Generalize IfcGeom::Iterator filtering and move make the filter specification external to the Iterator. 2017-03-04 13:54:19 +01:00
Stinkfist0 d8a11dd096 Refactoring and cleaning up geom iterator filtering. 2017-03-04 13:54:19 +01:00
Stinkfist0 63b0488909 Implement filtering created geometry by layer assignments. 2017-03-04 13:54:19 +01:00
Stinkfist0 3abee03b9b Filtering by entity GUID and layer name w.i.p. 2017-03-04 13:54:19 +01:00
Stinkfist0 f1709dc71a IfcConvert/IfcGeom: Possibility to include and exclude simultaneously by type and name, w.i.p. 2017-03-04 13:54:19 +01:00
Ken Arroyo Ohori b9828b029c Right way to output more than one object 2017-03-03 15:25:45 -06:00
Ken Arroyo Ohori 749071601e Merge pull request #5 from aothms/ken_first_steps
Reorganised code, Boolean ops seem to work
2017-03-03 13:59:58 -06:00
Ken Arroyo Ohori bbe0b74f83 Boolean ops working? 2017-03-03 13:56:08 -06:00
Ken Arroyo Ohori efb8bce25a Didn’t save sphere output 2017-03-03 13:20:47 -06:00
Ken Arroyo Ohori c59ae03cb3 Fixed bug in cylinders/cones 2017-03-03 13:12:05 -06:00
Ken Arroyo Ohori 7145b1ae85 Some debugging code, checking transformations 2017-03-03 12:58:52 -06:00
Ken Arroyo Ohori 596c4f8b77 Adding some validation code 2017-03-03 09:58:17 -06:00
Ken Arroyo Ohori 302e7b2db8 IfcRightCircularCone 2017-03-02 18:42:10 -06:00
Ken Arroyo Ohori bece7053a0 IfcRightCircularCylinder 2017-03-02 18:39:18 -06:00
Ken Arroyo Ohori 82cd4056b7 IfcRectangularPyramid 2017-03-02 18:22:34 -06:00
Ken Arroyo Ohori 6297ff74f1 Boolean ops using Nef polyhedra (untested) 2017-03-02 18:11:11 -06:00
Ken Arroyo Ohori c9633273a6 Several more classes, needs testing 2017-03-02 17:11:58 -06:00
Ken Arroyo Ohori 2cb53a860d Entities for basic CSG 2017-03-02 15:09:05 -06:00
Ken Arroyo Ohori db85bebc1a Merge branch 'cgal' into ken_first_steps 2017-03-01 17:48:37 -06:00
Ken Arroyo Ohori 57fae25de8 Putting functions into files per geometric type 2017-03-01 17:48:19 -06:00
Carles 6b2c8ad23e Update vs-cfg.cmd
prepend win/utils path instead of append it.
It should force the build-deps.cmd to call 7za.exe within utils and not any other old-version that users might already have. 
Discussed in https://sourceforge.net/p/ifcopenshell/discussion/1782717/thread/53803197/
2017-02-23 15:48:37 +01:00
Thomas Krijnen 451ccd4e21 Merge pull request #4 from aothms/ken_first_steps
IfcManifoldSolidBrep and IfcConnectedFaceSet
2017-02-23 13:53:02 +01:00
Ken Arroyo Ohori b893f5a3f0 Take into account extrusion height 2017-02-22 18:15:27 -06:00
Ken Arroyo Ohori 64eb707996 Fixed issue with transformations? 2017-02-21 18:40:27 -06:00
Ken Arroyo Ohori c0732f5197 Trying to find out why placements don’t arrive at Triangulate() 2017-02-21 15:37:38 -06:00
Ken Arroyo Ohori e47d128b18 Brep and swept solid working now 2017-02-20 20:14:49 -06:00
Thomas Krijnen 8ce4bbdf61 Adaptive tolerance boolean ops 2017-02-16 15:54:34 +01:00
Thomas Krijnen e2cf5f4826 Typo in build script 2017-02-16 15:53:58 +01:00
Ken Arroyo Ohori 9d4463b73a Check for NULL placement 2017-02-13 15:26:06 -06:00
Ken Arroyo Ohori d9d5f17725 Should be working now 2017-02-13 11:45:17 -06:00
Ken Arroyo Ohori f4274e4b46 Skeleton for IfcExtrudedAreaSolid 2017-02-13 11:12:04 -06:00
Ken Arroyo Ohori b463dfe88a Changed --kernel parameter to --opencascade. Was conflicting with positional options for input. 2017-02-09 14:46:02 -06:00
Ken Arroyo Ohori 44634eb42d Remove implemented throws, add faces and materials 2017-02-08 17:12:56 -06:00
Ken Arroyo Ohori 1755752ab7 IfcAxis2Placement2D 2017-02-08 16:56:59 -06:00
Ken Arroyo Ohori 7051104bc7 Basic code to output triangulation, something goes wrong when getting materials... 2017-02-08 16:12:19 -06:00
Ken Arroyo Ohori 2894b0cb92 Nothing is a pointer now. Initialisation is easier… 2017-02-07 20:37:47 -06:00
Ken Arroyo Ohori 42b512960b Filling in most of the placement code. To check. 2017-02-07 20:25:04 -06:00
Ken Arroyo Ohori 96e9c8ecc1 Skeleton for IfcObjectPlacement and IfcAxis2Placement3D 2017-02-07 19:51:16 -06:00
Ken Arroyo Ohori bae84b6753 Directions as CGAL Vector_3, more robust points 2017-02-07 19:50:51 -06:00
Ken Arroyo Ohori e1702fc0cf Return value for transformation, still needs to be initialised somewhere… 2017-02-06 16:22:54 -06:00
Ken Arroyo Ohori 6aff3d0f3d Conversion result for breps 2017-02-06 16:22:36 -06:00
Thomas Krijnen 6b47e9ca1d Add GMP MPFR and CGAL include/libs to cmake and build script 2017-02-04 16:38:57 +01:00
Ken Arroyo Ohori 1525cf6bfc Polyhedra built with the incremental builder, IfcConvert crashes 2017-02-02 14:29:26 -06:00
Ken Arroyo Ohori 5724e1ac34 Face from IfcFace 2017-02-01 17:53:12 -06:00
Ken Arroyo Ohori f2a45b7057 Fixed pointer bug, wires seem okay now 2017-02-01 15:57:25 -06:00
Ken Arroyo Ohori 233aaeaca2 Points and wires 2017-01-31 19:03:15 -06:00
Ken Arroyo Ohori 9c21e05184 Skeleton reaching all the way up to points, to be filled in 2017-01-31 18:53:00 -06:00
Ken Arroyo Ohori 0821dd4702 Skeleton for IfcManifoldSolidBrep and IfcConnectedFaceSet 2017-01-27 18:40:38 -06:00
Ken Arroyo Ohori cac9c91c56 Mac metadata 2017-01-27 15:31:37 -06:00
Ken Arroyo Ohori a4264f3143 Replaced macros, added basic CGAL definitions 2017-01-27 15:31:22 -06:00
Thomas Krijnen 332a9a571f Special case the normal at the poles of a spherical surface 2017-01-24 14:56:28 +01:00
Thomas Krijnen ac9505506c Extend IfcGeomServer with calculated quantities 2017-01-22 16:09:14 +01:00
Thomas Krijnen 257c28d450 Take into account IfcTrimmedCurves with unspecified preference 2017-01-22 11:06:36 +01:00
Thomas Krijnen f95ad29c7a Extra check for single-face IfcConnectedFaceSets. Fixes #181. 2017-01-19 10:42:03 +01:00
Thomas Krijnen 93c2f93c44 Download PCRE from sourcefore in nix build script. Fixes #182 2017-01-19 10:24:09 +01:00
Thomas Krijnen 4d12bf7e8d Cgal kernel skeleton (#3)
Cgal kernel skeleton
2017-01-16 14:04:31 +01:00
Stinkfist0 77d53429e3 Make sure to link ifcwrap to Boost libs + fix integer conversion warning. 2017-01-14 20:13:46 +01:00
Stinkfist0 fa76aa9bb0 IfcConvert: add --unicode=utf8|escape when UNICODE_SUPPORT enabled. 2017-01-14 20:13:46 +01:00
Stinkfist0 f0e07f3447 Add status prints for writing XML output. Re: #122 2017-01-14 20:13:46 +01:00
Stinkfist0 80f0ff688d IfcConvert: add --model-ofset x;y;z option. Remove SerializerSettings::CENTER_MODEL as unneeded. 2017-01-14 20:13:46 +01:00
Stinkfist0 222cbe73d3 Use unnamed enum instead of static const member variable for SerializerSettings::DEFAULT_PRECISION in order to fix compilation on GCC & Clang. 2017-01-14 20:13:46 +01:00
Stinkfist0 ecff54c480 IfcConvert --precision option.
Sets the decimal precision to be used to format floating-point values, 15 by default.
Use a negative value to use the system's default precision (should be 6 typically).
Applicable for OBJ and DAE output. For DAE output, value >= 15 means that up to 16 decimals are used,
and any other value means that 6 or 7 decimals are used.
2017-01-14 20:13:46 +01:00
Stinkfist0 2d58a1bc7c Separate serialization-specific settings from IteratorSettings into its own class, SerializerSettings. 2017-01-14 20:13:46 +01:00
Thomas Krijnen 3958204c1c Don't build Python wrapper on Travis 2017-01-13 20:51:12 +01:00
Thomas Krijnen d17f714dc5 Isolate geometry processing code into separate opencascade kernel 2017-01-13 20:51:12 +01:00
Thomas Krijnen 4fa7f293d6 cd to correct repository folder 2017-01-13 18:11:05 +01:00
Thomas Krijnen 7e3f96e410 Add GMP MPFR CGAL to build script 2017-01-09 17:14:49 +01:00
Thomas Krijnen 8018c9cc44 Add GMP MPFR CGAL to build script 2017-01-09 17:14:49 +01:00
Thomas Krijnen 5667f3f94a build script changes for boost 2017-01-09 13:10:01 +01:00
Jelle Feringa 5d6160b47a log exceptions on get_info method
these exceptions currently are actively being hidden, which is
intransparent / could make debugging challenging

improved formatting tot pep8
2017-01-04 10:26:04 +01:00
Stinkfist0 37905c6725 Windows/MSVC: support spaces in the IfcOpenShell build directory's path. re: #171 2017-01-01 18:16:56 +01:00
aahoo 99bde93af5 adds get_info method for class #resolves #175 2017-01-01 18:15:55 +01:00
Thomas Krijnen e6ff78fa29 Size() -> Length() 2016-12-10 15:39:20 +01:00
Thomas Krijnen c08aa3216d Fix #163 Disallow narrow IfcPolygonalBoundedHalfSpace 2016-12-10 14:11:01 +01:00
Thomas Krijnen da0b350378 Fix #140 2016-12-09 16:51:03 +01:00
Thomas Krijnen 4354361a13 More elaborate wire ordering check and shell sewing code (#147) 2016-12-09 16:40:14 +01:00
Thomas Krijnen 51409aff8f Fix #87 2016-12-09 16:33:06 +01:00
Thomas Krijnen c94ed73b8d Incorporate console into main app, fallback to QPlainTextEdit, some styling 2016-11-28 17:46:57 +01:00
jakob-beetz 90e4f21f29 Interactive scripting pane added to pyQt viewer geom.app 2016-11-28 17:46:57 +01:00
jakob-beetz 3ba2f781d8 added a property panel tab to the PyQt geom.app viewer that shows all properties from IfcPropertySets attached to the currently selected object 2016-11-28 17:46:57 +01:00
Ali Kämäräinen aec20057c7 Fix build when USE_IFC4=1 (#160) 2016-11-18 12:43:14 +01:00
Thomas Krijnen 5c107eb165 Merge pull request #161 from IfcOpenShell/aothms-travis-2x3-4
Build Ifc2x3 and Ifc4 on travis
2016-11-18 12:42:50 +01:00
Thomas Krijnen 3d1ea31098 Build Ifc2x3 and Ifc4 on travis 2016-11-18 12:22:02 +01:00
Thomas Krijnen 3d24b67146 Fix #157 2016-11-17 16:05:28 +01:00
Thomas Krijnen 18c87b515b Install ifcopenshell binaries in nix build script 2016-11-13 20:27:22 +01:00
Thomas Krijnen 11a95e7045 Merge pull request #156 from aothms/nix_python_build_script
Nix python build script
2016-11-13 13:45:12 +01:00
Ali Kämäräinen 714a365942 IfcConvert/IfcGeom --traverse option (#159)
geometry filtering option for including/excluding decomposition and containment of filtered entities.
Usage example: IfcConvert Duplex_A_20110907.ifc Level1.dae --include --traverse --names "Level 1"
2016-11-13 13:44:38 +01:00
Thomas Krijnen 739bbcc744 Don't run build script on travis, doesn't complete in under 50m0s 2016-11-11 14:55:07 +01:00
Thomas Krijnen 6a275d04b9 Don't export TARGET_ARCH in nix build script 2016-11-09 11:12:29 +01:00
Thomas Krijnen e8ae491dc3 Type hint from schema when encountering empty aggregate. Fixes #127 2016-11-08 17:24:08 +01:00
Thomas Krijnen 8e2f528a99 Fix python build script 2016-11-06 19:07:25 +01:00
Carmen Fan 00215867c0 Fix matrix multiplication ordering for nested mapped items (#144) 2016-11-06 16:18:30 +01:00
Thomas Krijnen 1e86a31b81 Add nested_mapped_item.ifc test case, based on acad2010_objects.ifc 2016-11-06 16:15:52 +01:00
Ali Kämäräinen f0c4ce5753 Add layer information (IfcPresentationLayerAssignment) to IfcConvert's XML output. Closes #141 (#149)
Add layer information (IfcPresentationLayerAssignment) to IfcConvert's XML output. Closes #141
2016-10-31 18:21:25 +01:00
Thomas Krijnen ea514e9528 Fix #148 catch errors when computing model bounding box from product placements. 2016-10-25 10:11:14 +02:00
Thomas Krijnen 229b123798 Fix potential segfault in hierarchy helper 2016-10-09 12:45:17 +02:00
Thomas Krijnen 86c9d7074b Fix traversal of type relationships in IFC4 XML output 2016-10-09 12:44:37 +02:00
Thomas Krijnen bc000fcbab Fix additional warnings identified in #139 2016-10-09 12:42:39 +02:00
Ali Kämäräinen a171b2b9b0 Couple warning fixes (#139)
* Use -Wno-tautological-constant-out-of-range-compare for Clang (these warnings come from the sanity checks in generated IfcXXX files).

* Remove unused variable and typedefs + suppress uint->bool conversion warnings (MSVC) + add note about Clang in README

* MSVC uint->bool convesion warning fixes when IFC4 is defined
2016-10-09 12:39:47 +02:00
Thomas Krijnen 8a92e1a766 Speed up geometry generation in ifcopenshell.geom.application by using iterator pt2. 2016-09-22 13:45:32 +02:00
Thomas Krijnen efd6eb7f97 Speed up geometry generation in ifcopenshell.geom.application by using iterator 2016-09-22 13:40:39 +02:00
Thomas Krijnen 7ed98869d2 Update ifcopenshell.geom.app for pyocc-0.16.5
https://github.com/tpaviot/pythonocc-core/commit/3d7b9745359b436b4144105f7e17aa0040acb8c6
2016-09-13 14:05:28 +02:00
Karl-Philipp Richter 72d8b5377c ported nix/build-all.sh to python in order to be able to provide any feedback
for the user at all (shell scripts systematically are working against providing
any useful user feedback, so the port is the only option)
2016-09-12 15:50:39 +02:00
Thomas Krijnen 8efd9757b7 Check for null shapes among layer set slicing results 2016-09-01 15:13:48 +02:00
Thomas Krijnen a0f5a422e2 Fix #128. XML serializer. HasPropertySets is an optional attribute. 2016-09-01 14:47:27 +02:00
Thomas Krijnen 8a950b1475 Fix compilation of ifcopenshell-python in nix build script 2016-09-01 12:53:32 +02:00
Thomas Krijnen d2ce8d70b1 Add template disambiguation to make g++ happy 2016-09-01 12:42:12 +02:00
Thomas Krijnen ac1a8f6d16 Add types and placement to XML output 2016-09-01 11:59:43 +02:00
Thomas Krijnen 7883953290 Do not find PCRE in default paths on Windows 2016-09-01 11:40:49 +02:00
Ali Kämäräinen 64dc2ea95c Windows/MSVC + OCCT 7.0.0 (#124)
* Windows/MSVC build scripts: option to build and use official Open CASCADE instead of the community edition.

* Fix C4800 warnings ("'Standard_Boolean': forcing value to bool 'true' or 'false' (performance warning)") + unnecessary integer cast.

* build-deps.cmd: fix OCCT download

* Fix MSVC linking against OCCT 7.0.0. Example executables fail still, needs research.

* occt-V7_0_0-9059ca1_CMakeLists.txt: add_definitions(-DHAVE_NO_DLL) in order to fix static linking to OCCT. Mark IfcOpenShell patches in the OCCT patch files for clarity.

* Patch OCCT in order to fix compliaction when HAVE_NO_DLL is defind. Clean up IfcOpenSHell's linker warnings by defining HAVE_NO_DLL.

* CMakeLists.txt: remove linking to the newly added OCCT libs, these are not needed when HAVE_NO_DLL is defined.

* cmake/CMakeLists.txt: make add_debug_variants() function to handle filenames/paths also. Apply the coding conventions while at it. Fixes #123.

* Patch OCCT's OpenGl_PrimitiveArray.cxx and XCAFDoc_GeomTolerance.cxx in order to fix Debug build. Do not trigger OCCT rebuild each time build-deps.cmd is ran.

* build-deps.cmd: fix OCCT file patch copy.

* Non-MSVC compiler: use -Wextra, suppress/fix -Wignored-qualifiers warnings.

* build-deps.cmd: do not check return values of copy commands as they seem not to be fully reliable.
2016-09-01 11:28:17 +02:00
Ali Kämäräinen e064098f84 Build instructions and PCRE lib dir (#120)
* CMakeLists.txt: show fatal error if PCRE not found if COLLADA_SUPPORT is on.

* Compiling on *nix instruction tweaks.
2016-08-22 11:45:37 +02:00
Bernd Hahnebach 8dadb71648 Add OpenCollada to travis and fix cmake (#119)
* travis: collada support

* travis: opencollada, specify pcre library
2016-08-15 13:14:15 +02:00
Thomas Krijnen 9d757e1b3c Correct typo https://github.com/IfcOpenShell/IfcOpenShell/pull/114/files#r74275264 2016-08-13 10:51:04 +02:00
Thomas Krijnen 92032b6e3b Add travis status 2016-08-09 14:12:12 +02:00
Thomas Krijnen 202b226ea0 Silence compiler warning when without ICU 2016-08-09 14:09:44 +02:00
Bernd Hahnebach 1e8c7ef7f0 Travis 2016-08-09 14:03:26 +02:00
Thomas Krijnen 59035e7ce2 Merge pull request #114 from aothms/cmake_improvements
Cmake improvements: LINK_DIRECTORIES and OCCT 7
2016-08-08 13:40:38 +02:00
Thomas Krijnen 2c332199b1 Merge pull request #115 from aothms/tridify_ifcgeom_dll
Dllimport/export for IfcGeom. Closes #77
2016-08-08 13:40:09 +02:00
Thomas Krijnen ecf67fe939 IFC_PARSE_API for IfcInvalidTokenException after merge 2016-08-08 13:39:43 +02:00
Thomas Krijnen f1099fc3b1 Merge branch 'master' into tridify_ifcgeom_dll
# Conflicts:
#	cmake/CMakeLists.txt
2016-08-08 10:56:06 +02:00
Thomas Krijnen 16e8fff9ca virtual dtor 2016-08-08 10:41:51 +02:00
Stinkfist0 0f857283e8 CMakeLists.txt: append possible extra libraries to OPENCASCADE_LIBRARIES before the variable is used for any target. 2016-08-08 01:40:26 +03:00
Thomas Krijnen 1def5db7e4 Detect OCCT7 and set -std=c++11 accordingly. 2016-08-07 10:38:18 +02:00
Thomas Krijnen e9bd18fd4b Don't search default directories. Use absolute paths to specify libraries. 2016-08-07 10:37:29 +02:00
Stinkfist0 fb98275f50 Typo fix. 2016-08-06 19:08:13 +03:00
Stinkfist0 97a62f45d0 Fix IfcGeomWrapper.i and IfcParseWrapper.i 2016-08-06 18:19:27 +03:00
Stinkfist0 4ebee68736 Ifc2x3enum.h: fix header inclusion. 2016-08-06 13:44:35 +03:00
Ali Kämäräinen a26253321f Bash on Ubuntu on Windows instructions, readme and cmake improvements (#113)
* README.md: add note about Visual C++ Build Tools and Bash on Ubuntu on Windows. Enhance the Compiling on *nix instructions.

* Fix newline.

* README.md tweak

* CMakeLists.txt: remove CHECK_ADD_OCE_OCC_DEF INCLUDE() for good as these are not needed any more at all (OCE codebase also checked and no signs of these).
2016-08-06 10:45:29 +02:00
Thomas Krijnen 4b90e618b0 Add warning #109 2016-08-04 11:47:14 +02:00
Thomas Krijnen 21b35767ba Fix #109 2016-08-02 15:53:41 +02:00
Thomas Krijnen e6fbfee766 Check for existence of representation identifier in python wrapper create_shape 2016-08-02 15:44:42 +02:00
Stinkfist0 3cba5e6e94 Rename BUILD_SHARED_LIBS project-wide precompiler definition to IFC_SHARED_BUILD 2016-07-20 22:59:19 +03:00
Stinkfist0 6d6e7c2982 Unify IfcParse's dllimport/export macros with IfcGeom. 2016-07-20 22:49:32 +03:00
Thomas Krijnen fd4086aa8d Report errors in string escape sequences more verbosely 2016-07-19 16:41:36 +02:00
Ivano Ras cd2b0c3a05 fix #106. (#107) 2016-07-19 16:31:37 +02:00
Ivano Ras 42067de44c use union to remove warning (issue 105). (#108) 2016-07-19 16:29:01 +02:00
Thomas Krijnen 240133515a Unify usage of spaces in Python library code 2016-07-18 15:53:20 +02:00
Thomas Krijnen b7f23ee701 Implement option to get generic inverses from Python 2016-07-18 14:47:32 +02:00
Ali Kämäräinen 4a85e5e7a5 MSYS build scripts and instructions (#99) and warning fixes
* Preliminary MSYS2 + MinGW build scripts and instructions.

* CMakeLists.txt: MinGW tweaks, enforce C++03, suppress warnings for now.

* Fix some GCC warnings.

* Fix unused parameter warnings coming from Ifc*.h.

* Fix warning regarding unreachable code (++jt) on MSVC.

* Add IfcParse_EXPORT for IfcInvalidTokenException

* Fix potentially uninitialized pointer variables.

* Note about OpenCASCADE cyclic dependencies fix.

* GCC warning fix: don't generate 'current_enum' variable that is only set and not used for anything ever

* Work around -Wmaybe-uninitialized warnings about boost::optional constructs. Also prevent passing of negative values for --bounds.

* Remove unused variable.

* CMakeLists.txt: ENABLE_BUILD_OPTIMIZATIONS for GCC (simply enforce -03)
2016-07-15 05:49:32 +02:00
Stinkfist0 3a507ca061 Code doc tweak 2016-07-11 22:41:18 +03:00
Stinkfist0 6bcabfd567 Dllimport/export for IfcGeom. Closes #77 2016-07-11 22:37:50 +03:00
Thomas Krijnen 435eb7ae10 Update python module install script 2016-06-28 15:48:58 +02:00
Thomas Krijnen 17e153d0c5 Fix rename conflict after merge 2016-06-22 15:52:31 +02:00
Thomas Krijnen aebb9e324b Geometry serialization (#71)
Serialize geometry to IFC instances directly from a TopoDS_Shape
2016-06-22 15:03:18 +02:00
Thomas Krijnen 90ad3a4a93 Merge pull request #97 from aothms/dynamic_lib_fixes_2
Dynamic lib fixes
2016-06-22 14:57:16 +02:00
Thomas Krijnen 478bda30bc Install both libraries. Force IfcGeom to static on Windows. Correct IfcParse linkage. Update IfcMax 2016-06-22 14:54:55 +02:00
Thomas Krijnen 69535800b5 Do no silently drop invalid faces from IfcConnectedFaceSets 2016-06-21 11:27:59 +02:00
Thomas Krijnen ee2303d965 Support for IfcExtrudedAreaSolidTapered 2016-06-21 11:25:10 +02:00
Thomas Krijnen b792aba95f Support for *BrepWithVoids 2016-06-21 11:19:51 +02:00
Thomas Krijnen 8f55aa732d IfcParameterizedProfileDef.Position and IfcSweptAreaSolid.Position optional in IFC4 2016-06-21 11:18:16 +02:00
Thomas Krijnen 2c2be389fb Fix header parsing 2016-06-21 11:11:16 +02:00
Thomas Krijnen 62a0f21a57 Fix #94 2016-06-20 11:34:13 +02:00
Ali Kämäräinen 3c418e8e0a Windows batch script enhancements (#88)
* Make possible to invoke run-cmake.bat, build-ifcopenshell.cmd (now bat), install-ifcopenshell.cmd (now bat) directly from File Explorer or command prompt without VS env vars set, if BuildDepsCache file exists, by utilizing CMake's --build functionality. Do not delete CMakeCache.txt always now in order to keep the build options consistent.

* win/readme.md tweaks + make the line width smaller

* Windows batch files: use the last modified BuildDepsCache. Show an error if GEN_SHORTHAND does not exist.
2016-06-17 22:30:33 +02:00
Johannes Obermayr ea6fbc77dd Bring back logic for BUILD_SHARED_LIBS.
Also remove C++11 code.
2016-06-14 20:30:02 +02:00
Thomas Krijnen be10bc46ca More elaborate error reporting 2016-06-12 11:22:08 +02:00
Thomas Krijnen f4fd3a5ca1 Compiler warnings 2016-06-12 10:43:28 +02:00
Ali Kämäräinen 685717b8b8 Fix build of IfcWrap (#90) 2016-06-09 22:49:00 +02:00
stgatilov 8725c66306 Performance improvement of IfcParse tokenizer (#82)
* Applied MSVC tabify to IfcParse.cpp/h.

* Now Argument base class has throwing implementation for each conversion operator (removed those from derived classes).

* Added NullArgument class for the case when null arguments appear after setting elements.

* Now operator tokens are handled just like any other token.

* Refactoring: Token is now a struct with good fields, not a nameless pair.

* Now end position of token is set at its construction.

* Now type of token is determined on construction, as* function simply check stored type.

* Now int-s, float-s and some etc are parsed when token is created.

* Implemented simple way to remove spaces in parsing.

* Tokens are now created without allocations.

* Call RemoveTokenSeparators once for every token.

* Added temporary std::string object in lexer (for optimization purposes).

* Reimplemented asString without allocations.

* Parsing keywords without allocations.

* Added checks for type to tokenFunc::as*** functions.
2016-06-09 18:25:50 +02:00
Thomas Krijnen cbbdb61a0c Merge pull request #89 from aothms/dynamic_lib_fixes
Dynamic lib fixes (#79)
2016-06-09 10:51:05 +02:00
Thomas Krijnen b3167cf1e6 build script simplification 2016-06-09 10:48:43 +02:00
Thomas Krijnen 44f785cce0 Merge branch 'master' into dynamic_lib_fixes
# Conflicts:
#	cmake/CMakeLists.txt
2016-06-09 10:46:58 +02:00
Thomas Krijnen 8e998ec7db MSYS2 Mingw64 compilation (#84) 2016-06-09 10:39:27 +02:00
Thomas Krijnen fc50e6ac23 Revert change adding additional argument to ColladaSW::Scene constructor 2016-06-05 14:41:17 +02:00
Thomas Krijnen 815ed07192 MinGW fixes and warnings 2016-06-05 14:03:03 +02:00
Thomas Krijnen 009870135f Merge branch 'pr/78' into mingw 2016-06-05 14:01:55 +02:00
Stinkfist0 dbc59fe346 Add .vscode to ignored files 2016-06-03 10:03:58 +03:00
Stinkfist0 08aeb80f58 Make set-python-to-path.bat callable from outside locations 2016-06-02 14:39:29 +03:00
Stinkfist0 7f2729c956 .gitignore: ignore __pycache__ in general 2016-06-02 14:36:55 +03:00
Stinkfist0 4d6e25fb69 Also mark the full URL source for Ifc2x3* files 2016-06-02 14:36:09 +03:00
Stinkfist0 37aadcbfbf Update the source information for Ifc4* files 2016-06-02 14:20:12 +03:00
Stinkfist0 74a3f131be Make IfcException's dtor and what() virtual 2016-05-31 17:08:39 +03:00
Stinkfist0 77b72a9dde IfcException.h: suppress C4275 warnings 2016-05-31 14:45:22 +03:00
Stinkfist0 c644ffbe5e Move wildcard_string_to_regex() from IfcParse to IfcGeom as it's not really related to parsing IFC at all. 2016-05-31 14:04:44 +03:00
Stinkfist0 aa03da20a8 Bump up non-MSVC compiler's warning level to a level somewhat similar to MSVC. 2016-05-30 17:44:36 +03:00
Stinkfist0 42acc7224c Add couple missing IfcParse_EXPORTs + add a missing license information 2016-05-30 17:12:53 +03:00
Stinkfist0 53fadd9808 CMakeLists.txt: document usage of IFCDIRS. 2016-05-30 15:29:45 +03:00
Thomas Krijnen 4afc568a41 Remove unsupported feature from IfcGeomServer 2016-05-30 14:14:45 +02:00
Stinkfist0 906fefaf35 Fix installation of IfcParse DLL. 2016-05-30 15:12:07 +03:00
Stinkfist0 90a2c445ea Fix broken build of the project when BUILD_SHARED_LIBS=1 2016-05-30 13:54:24 +03:00
Stinkfist0 cae24a9492 Fix warnings regarding unused variables. 2016-05-30 13:44:03 +03:00
Stinkfist0 8b3d581131 README: IFC4 -> IFC4 Add1 2016-05-30 13:20:03 +03:00
Stinkfist0 c13eb9e131 The usual way of doing MSVC dllimport/export. Add a warning print if building as DLL against the static VC-runtime. 2016-05-30 01:09:39 +03:00
Fredounet 3b169219af MSYS2 Mingw64 compilation. Compilation successful considering everything but the following:
- IFC4 (only IFC2x3 tried; should work)
- VLD
- IfcMax
- shared libraries
2016-05-29 17:58:03 +01:00
Thomas Krijnen 83243ec514 IFCPARSE_STATIC_DEFINE only when BUILD_SHARED_LIBS is not set 2016-05-29 14:18:18 +02:00
stgatilov b5c4eb3b6f IfcParse dynamic linking, IFCPARSE_NO_REGEX, fixes for three memory leaks (#76)
* CMake: moved setting link directories before all the projects.

* Added IfcParse_Export header for declaring export macro.

* Added IFCPARSE_STATIC_DEFINE macro to all projects.

* Added include for export macro to swig file.

* Added IfcParse_EXPORT macro for all classes in headers generated by express parser.

* Allow removing boost.regex dependency by defining macro IFCPARSE_NO_REGEX.

* Fixed bug in deletion of ICU converter.

* Added export macro to most of the classes across headers

* Fixed memory leak: delete nested IfcAbstractEntity in EntityArgument.

* Fixed memory leak in destructor of IfcWritableEntity (args values).
2016-05-29 14:12:57 +02:00
Thomas Krijnen a298903fdd IfcGeomServer settings 2016-05-28 16:08:31 +02:00
Fredounet ccb24948df Merge pull request #1 from IfcOpenShell/master
Fresh-Upgrade-1
2016-05-28 09:43:59 +01:00
iNEHCi 5bdb4ce668 Add IfcReinforcingBar/IfcSweptDiskSolid generation example 2016-05-27 10:18:39 +02:00
Thomas Krijnen 9909e2f7e2 Don't emit OBJ vertex normal if absent (e.g --weld-vertices) 2016-05-24 15:01:34 +02:00
Thomas Krijnen 38d1ec7a78 #28 2016-05-24 13:50:50 +02:00
Thomas Krijnen 85ddae1228 Do not set wire tolerance prior to creating face 2016-05-24 12:51:00 +02:00
Thomas Krijnen 06c3f8d6a9 Record conversion status on IfcFaceBasedSurfaceModel 2016-05-24 12:50:32 +02:00
Thomas Krijnen b04ca74308 Derive minimal face area from modeling precision 2016-05-24 12:50:05 +02:00
Thomas Krijnen 7c0944e43b Defer pythonOCC imports in order not to break if unavailable 2016-05-19 13:31:54 +02:00
Thomas Krijnen a1c660f4ab Fix static linking 2016-05-19 11:34:04 +02:00
Thomas Krijnen 2a5974fde1 Remove superfluous error message 2016-05-18 17:28:58 +02:00
Thomas Krijnen e2ffd0b6d6 Fix IFC4 compilation 2016-05-18 17:15:44 +02:00
Thomas Krijnen 9bff4876c5 Don't apply rpaths on windows due to possible path separator conflicts 2016-05-15 15:51:12 +02:00
Johannes Obermayr 42188904af Fixes to build on openSUSE/Packman. (#67)
- Support different BINDIR, INCLUDEDIR and LIBDIR on install
- Take right python dir on x86_64 arch
- Fix build against Boost >= 1.58
- Make it possible to build libIfcGeom shared to reduce size of dependent binaries
- Fix INSTALL_RPATH
- Fix some more compiler warnings
2016-05-15 15:47:21 +02:00
Lars Moastuen 414d7bb810 OBJ precision and log messages
* Fixes #68: Increase precision in OBJ files (regression in commit 43f5d44)
* Add some verbose logging of a few geometry errors
2016-05-13 12:59:00 +02:00
Thomas Krijnen 01269e5dd5 Fix missing include for debug build 2016-05-11 14:01:38 +02:00
Ivano Ras 0253c1ddbe Extended error logging
Fixes #33
2016-05-11 10:56:40 +02:00
Thomas Krijnen 3f5d30f497 Merge pull request #65 from iras/nested_argument_list_bug
separated nested argument lists to avoid an error when compiling with…
2016-05-05 11:03:38 +02:00
iras 3d2ab25175 separated nested argument lists to avoid an error when compiling with gcc. 2016-05-05 08:09:45 +01:00
Thomas Krijnen d4dc933b99 Qualify auto keyword 2016-05-04 17:30:31 +02:00
Thomas Krijnen d54c1cdc9c Remove compiler warning 2016-05-03 16:32:36 +02:00
Thomas Krijnen c848a7dbe0 remove redundant type attribute on latebound entity instance 2016-05-03 11:24:26 +02:00
Thomas Krijnen 60cf4ab757 Additional check pertaining to face surfaces 2016-05-03 11:22:15 +02:00
Thomas Krijnen 2c3fa89dd0 Preprocessor consistency 2016-05-03 11:21:39 +02:00
Thomas Krijnen e9c7cf235b Fix compiler warning 2016-05-03 11:19:46 +02:00
Thomas Krijnen fefa8a0563 option to pass settings to pyqt4 app 2016-05-03 11:05:46 +02:00
Thomas Krijnen 04acfe1169 Fix #63 2016-05-03 11:01:47 +02:00
Thomas Krijnen 0e25787df3 Merge pull request #64 from aothms/layerset_slicing
Layerset slicing
2016-05-02 16:14:14 +02:00
Thomas Krijnen 3c3bee71d1 Don't process mapped items in case of material layer associations 2016-05-02 16:11:06 +02:00
Thomas Krijnen 37f0e09947 Fix compiler warnings 2016-05-02 15:56:08 +02:00
Thomas Krijnen 39e26dff46 Merge branch 'master' into layerset_slicing
# Conflicts:
#	src/ifcconvert/IfcConvert.cpp
#	src/ifcgeom/IfcGeom.h
#	src/ifcgeom/IfcGeomFunctions.cpp
#	src/ifcgeom/IfcGeomIteratorSettings.h
2016-05-02 15:13:30 +02:00
Thomas Krijnen 2f129556fd Merge pull request #47 from aothms/performance_improvements
Performance improvements
2016-05-01 20:43:37 +02:00
Thomas Krijnen a1d584796a Set reasonable defaults for caching behavior 2016-05-01 20:38:10 +02:00
Thomas Krijnen c6d5adfa42 Merge branch 'master' into performance_improvements
# Conflicts:
#	src/ifcexpressparser/implementation.py
#	src/ifcgeom/IfcGeomFunctions.cpp
#	src/ifcparse/Ifc4.cpp
2016-04-24 15:22:10 +02:00
Thomas Krijnen 1e262c8768 Update build script to install pyqt app 2016-04-23 11:42:11 +02:00
Thomas Krijnen d8919c50ab Fix serialization of list of list of entity instance 2016-04-19 16:44:08 +02:00
Thomas Krijnen 416b163050 Correct display_shape on TopoDS_Shape 2016-04-19 15:42:59 +02:00
Thomas Krijnen 1d1fb6d27a First steps towards a PyQt4 application 2016-04-17 15:27:05 +02:00
Thomas Krijnen 9fedbbff6d Only convert faces once if sewing shell fails pt.2 2016-04-17 15:12:02 +02:00
Thomas Krijnen 1c1097c8a4 Only convert faces once if sewing shell fails 2016-04-16 14:47:34 +02:00
Thomas Krijnen 884b3fe850 Project wires onto a plane if non-planar. Fixes #57. 2016-04-16 14:47:09 +02:00
Thomas Krijnen 81ee60079e Enable per-item styles in the pythonOCC viewer 2016-04-11 11:50:43 +02:00
Thomas Krijnen 426b1279e3 Implement __hash__ and __eq__ functions on entity_instance 2016-04-09 20:20:08 +02:00
Thomas Krijnen 1142db3265 remove msvc specific leniencies 2016-04-09 17:54:23 +02:00
Thomas Krijnen 191c029546 Correctly allow rule labels to be optional 2016-04-09 13:29:35 +02:00
Thomas Krijnen 9bcfe2f50e Generate code for IFC4_ADD1 2016-04-08 23:24:35 +02:00
Thomas Krijnen fa585e60ee Update EXPRESS code generator to work on ancient IFC schemas 2016-04-08 23:23:45 +02:00
Thomas Krijnen 0ff9de3cd9 Update EXPRESS code generator to work on ancient IFC schemas 2016-04-08 23:23:29 +02:00
Thomas Krijnen 63c3b54762 Merge pull request #56 from Tridify/obj_mtl_fix
Fix temp name usage of .mtl file
2016-03-28 11:17:20 +02:00
Stinkfist0 d7f990d8bd IfcConvert: Do not use temp file for MTL as it's such a small file. Fixes #55. 2016-03-28 11:47:21 +03:00
Stinkfist0 b59e8e22a7 IfcConvert: Show an error msg if renaming from temp to final file fails. 2016-03-28 11:47:02 +03:00
Thomas Krijnen 25a5135e8d Disable geometry re-use with world coords 2016-03-27 21:18:28 +02:00
Thomas Krijnen 4c574df1a4 Immediately emit to serializer and remove option to obtain ownership of objects 2016-03-27 21:17:51 +02:00
Thomas Krijnen f3d5954aee Merge pull request #53 from shsteven/fix_build_script_osx_boost
Fix build script under os x
2016-03-24 10:42:03 +01:00
Steven Zhang 7d145a5f69 fix build script under os x 2016-03-24 15:07:52 +08:00
Thomas Krijnen 5b30dfc580 Set required boost components again after merge 2016-03-23 10:27:34 +01:00
Thomas Krijnen e1bb6c95c3 Merge pull request #51 from shsteven/osx_build_fix
Fix build script under os x
2016-03-23 10:15:56 +01:00
Steven Zhang edc6f8ebd4 fix build script under os x 2016-03-23 15:27:03 +08:00
Thomas Krijnen ee56aad90d Merge branch 'master' into performance_improvements
# Conflicts:
#	src/ifcconvert/ColladaSerializer.cpp
#	src/ifcconvert/ColladaSerializer.h
#	src/ifcgeom/IfcGeomIterator.h
#	src/ifcgeom/IfcGeomRenderStyles.h
2016-03-22 16:15:28 +01:00
Thomas Krijnen 5c1ac39f19 Merge pull request #42 from Tridify/ifcconvert_enhancements
IfcConvert enhancements
2016-03-22 13:28:15 +01:00
Stinkfist0 0fd2f04f08 Utilise Collada stream's double precision feature 2016-03-21 11:42:40 +02:00
Stinkfist0 b171bd4a14 Add note/todo regarding Collada stream's double precision feature. 2016-03-20 13:13:15 +02:00
Stinkfist0 54a9d72e25 IfcConvert: use temp file when writing output. 2016-03-20 12:48:20 +02:00
Stinkfist0 798597d5d9 IfcConvert: check that input file exist early, print filenames in error prints 2016-03-18 22:33:03 +02:00
Stinkfist0 f7453c033a IfcConvert: check if output file already exists and ask user for confirmation for overwriting. Overwriting can be forced with -y/--yes 2016-03-18 22:14:05 +02:00
Stinkfist0 bf76bd17b2 Add large_offset.ifc (wallwindow.ifc, courtesy of @klokoy) as test input case. 2016-03-18 14:45:00 +02:00
Thomas Krijnen 59d2d227d9 Directly re-use IfcMappedItem triangulated elements when not using world coordinates 2016-03-18 11:23:25 +01:00
Thomas Krijnen 4a3a0bff71 Cleanup triangulations after use 2016-03-18 11:21:23 +01:00
Thomas Krijnen 8ecc1269d7 Compile-time options to manipulate caching behaviour 2016-03-18 11:21:04 +01:00
Thomas Krijnen 614148e5e4 Don't iterate past material indices in collada serializer 2016-03-18 11:18:02 +01:00
Thomas Krijnen 74e495cec0 python2.7 compatibility on code generator 2016-03-18 11:17:26 +01:00
Thomas Krijnen 0ceef8fe67 Use constant time parent enumeration lookup 2016-03-18 11:14:14 +01:00
Stinkfist0 562f38756f Calculate and store min. and max. placements IfcGeom::Iterator. Implement --center-model for OBJ. 2016-03-17 23:25:53 +02:00
Stinkfist0 76d3823bd4 Make UVs a property of IfcGeom::Representation::Triangulation. Implement writing of UVs for OBJ output. 2016-03-17 00:25:33 +02:00
Thomas Krijnen 28560d164c Add IfcGeomServer description 2016-03-12 16:54:21 +01:00
Stinkfist0 923f1212f5 Clean up program_options printings 2016-03-11 10:05:33 +02:00
Stinkfist0 e9f551ea71 --names for filtering included or excluded entities by name, e.g. --include --names "Wall Compound*" 2016-03-10 21:15:50 +02:00
Stinkfist0 b9c5b0e6c8 Add IFCCONVERT_DOUBLE_PRECISION build option 2016-03-10 17:00:06 +02:00
Stinkfist0 4953b35849 --generate-uvs, applicable for DAE only currently 2016-03-10 16:46:20 +02:00
Stinkfist0 83e5096570 Support for --deflection-tolerance 2016-03-10 16:09:39 +02:00
Stinkfist0 5008c3503d --center-model for DAE output, fixes #8 (TODO: implement also for OBJ) 2016-03-10 14:39:42 +02:00
Stinkfist0 ce38854cff Add --no-normals 2016-03-10 13:29:22 +02:00
Stinkfist0 24e2aece0b Rename --use-guids and --use-names to --use-element-guids and --use-element-names. Add explicit --use-material-names for controlling material naming. 2016-03-10 12:01:04 +02:00
Stinkfist0 43f5d446ec Implement --use-names and --use-guids for DAE, OBJ, and SVG output. 2016-03-10 11:35:32 +02:00
Stinkfist0 50a467fda5 Fix IfcUtil::wildcard_string_to_regex() 2016-03-07 23:15:29 +02:00
Stinkfist0 0da0e63687 Begin to implement IfcConvert enhancements discussed in #20. Remove C++-specific getters and setters and use the same set() and get() functions in in both C++ and Python. Enhance output of IfcConvert, especially in error situations (spamming a hundred lines of options always hides the original error message), utilize Boost's foreach macro to provide cleaner iteration code. 2016-03-07 22:37:36 +02:00
Stinkfist0 e35cefac52 Fix crash (deleting garbage ptr) when nonexisting file passed to IfcSpfStream ctor. Bug surfaced due to recent memory leak fix. 2016-03-07 22:37:04 +02:00
Stinkfist0 84e7a86e77 XmlSerializer: handle openings. Original author of the commit/idea @otsoa. 2016-03-07 22:37:03 +02:00
Thomas Krijnen 82a1e33386 Merge pull request #39 from Tridify/fixed_opencollada_revision
Use a fixed revision of OpenCOLLADA...
2016-03-05 13:50:41 +01:00
Thomas Krijnen 827c6fd407 Build script fixes and compatibility with OSX / bash 3.2 2016-03-03 20:36:16 +01:00
Stinkfist0 851fadb4ec build-deps.cmd: GitCloneAndCheckoutRevision - always checkout the revision, so that users don't have the nuke their existing clones before running the script. 2016-02-27 17:44:45 +02:00
Thomas Krijnen 90f72c4b2c Merge pull request #35 from Tridify/ifcmax
Create CMake file for building IfcMax
2016-02-27 15:52:10 +01:00
Stinkfist0 7ed219af70 Use a fixed revision of OpenCOLLADA in order to prevent introducing breaking changes. Closes #36, related to #38 2016-02-25 17:34:41 +02:00
Stinkfist0 d1a1759016 Use a fixed revision of OpenCOLLADA in order to prevent introducing breaking changes. Closes #36, related to #38 2016-02-25 17:23:04 +02:00
Thomas Krijnen acc4af87d6 Merge pull request #34 from yilativs/master
Set cmake search paths to ubuntu 16.04 package manager defaults
2016-02-24 09:03:06 +01:00
Stinkfist0 ee75545ecd README tweaks 2016-02-21 16:52:00 +02:00
Stinkfist0 58b5838da9 README.md tweaks 2016-02-20 00:43:35 +02:00
Stinkfist0 e171e308d0 Enable solution folders 2016-02-20 00:13:04 +02:00
Stinkfist0 645315a8f4 remove win/sln as these are not needed anymore 2016-02-19 23:02:09 +02:00
Stinkfist0 5ee9bed590 CMakeLists.txt for IfcMax. Tested with VS 2015 and 3ds Max + SDK 2016 2016-02-19 22:53:09 +02:00
yilativs 0f88520e75 [fix] CmakeLists.txt now works on ubuntu 16.04 without the need to compile oce
instead you can
apt-get install git swig cmake gcc g++ libftgl-dev libtbb2 libtbb-dev libboost-all-dev libgl1-mesa-dev libfreetype6-dev liboce-modeling-dev opencollada-dev liboce-foundation-dev
2016-02-19 20:28:46 +03: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
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 9d730054dd Merge branch 'master' into layerset_slicing 2015-11-24 17:19:05 +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
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
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 c9db70c7c3 Initial implementation of layerset slicing 2015-10-07 17:33:30 +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
322 changed files with 292124 additions and 161831 deletions
+16
View File
@@ -0,0 +1,16 @@
# Dependency and build folders created by the build scripts
/deps*/
/build*/
/install*/
/win/BuildDepsCache*.txt
# IfcExpressParser residue
/src/ifcexpressparser/express_parser.py
# General Python residue
__pycache__
*.py.bak
# Visual Studio Code files
.vscode
# PyCharm files
.idea
# OSX files
.DS_Store
+7
View File
@@ -0,0 +1,7 @@
[submodule "test/input"]
path = test/input
url = https://github.com/IfcOpenShell/files
ignore = dirty
[submodule "src/ifcopenshell-python/ifcopenshell/mvd"]
path = src/ifcopenshell-python/ifcopenshell/mvd
url = https://github.com/opensourceBIM/python-mvdxml/
+66
View File
@@ -0,0 +1,66 @@
language: cpp
compiler: gcc
os: linux
dist: xenial
sudo: required
before_install:
- "sudo add-apt-repository -y ppa:freecad-community/ppa"
- sudo apt-get update -qq
install:
- |
sudo apt-get install -y \
libocct-data-exchange-dev libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev \
libboost-system-dev libboost-program-options-dev libboost-regex-dev libboost-thread-dev libboost-date-time-dev libboost-iostreams-dev libboost-filesystem-dev \
build-essential cmake python2.7 libpython2.7-dev swig zlib1g liblzma5 opencollada-dev wget apt-transport-https
- sudo mkdir -p /usr/include/json/nlohmann/
- sudo wget https://github.com/nlohmann/json/releases/download/v3.6.1/json.hpp -O /usr/include/json/nlohmann/json.hpp
- sudo sh -c 'curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -'
- sudo sh -c 'curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list'
- sudo apt-get update -qq && sudo apt-get install -y dart
- export PATH=$PATH:/usr/lib/dart/bin:$HOME/.pub-cache/bin
- git clone https://github.com/KhronosGroup/glTF-Validator && pushd glTF-Validator && pub get && pub global activate --source path ./ && popd
script:
- pwd
- cd cmake
- mkdir build
- cd build
- |
cmake \
-DOCC_INCLUDE_DIR=/usr/include/opencascade \
-DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
-DPYTHON_LIBRARY=/usr/lib/python2.7/config-x86_64-linux-gnu/libpython2.7.so \
-DPYTHON_INCLUDE_DIR=/usr/include/python2.7 \
-DPYTHON_EXECUTABLE=/usr/bin/python2.7 \
-DLIBXML2_INCLUDE_DIR=/usr/include/libxml2 \
-DLIBXML2_LIBRARIES="/usr/lib/x86_64-linux-gnu/libxml2.a;/lib/x86_64-linux-gnu/libz.so.1;/lib/x86_64-linux-gnu/liblzma.so.5;/usr/lib/x86_64-linux-gnu/libicuuc.so.55;/usr/lib/x86_64-linux-gnu/libicudata.so.55" \
-DGLTF_SUPPORT=On \
-DJSON_INCLUDE_DIR=/usr/include/json \
..
- sudo make -j2 install
- cd ../../test
- /usr/bin/python2.7 tests.py
- cd input
- /usr/local/bin/IfcConvert -yv acad2010_walls.ifc acad2010_walls.glb
- gltf_validator acad2010_walls.glb
- python -c "from __future__ import print_function; from io import open; import ifcopenshell; f = ifcopenshell.open('encoding.ifc'); print(f[1][0], file=open('encoding.txt', 'w', encoding='utf-8'))" && grep "'a' 1m³ ≤ 5m³ ≥ 10m³" encoding.txt
- |
(for i in *.ifc; do \
echo $i | tee -a log; \
timeout 1m /usr/local/bin/IfcConvert -yv "$i" "$i.dae" --validate >> log 2>&1; \
echo $i $? >> statuses; \
done) || true
- echo Failed
- grep -v 0$ statuses
- grep -v 0$ statuses | wc -l
- echo Succeeded
- grep 0$ statuses
- grep 0$ statuses | wc -l
-65
View File
@@ -1,65 +0,0 @@
IfcOpenShell
============
open source (LGPL) software library for working with the IFC file format
http://IfcOpenShell.org
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
If all worked out correctly you can now use IfcOpenShell. For example:
$ wget ftp://ftp.dds.no/pub/ifc/Munkerud/Munkerud_hus6_BE.zip
$ unzip Munkerud_hus6_BE.zip
$ ./IfcObj Munkerud_hus6_BE.ifc
$ less Munkerud_hus6_BE.obj
Or:
$ wget ftp://ftp.dds.no/pub/ifc/Munkerud/Munkerud_hus6_BE.zip
$ unzip Munkerud_hus6_BE.zip
$ python
>>> import IfcImport
>>> IfcImport.Init('Munkerud_hus6_BE.ifc')
>>> geom = IfcImport.Get()
>>> geom.name
>>> for v in geom.mesh.verts: v
+233
View File
@@ -0,0 +1,233 @@
About this branch
=================
This version splits the geometry interpretation process into two steps (a) map IFC to a smaller set of schema-agnostic definitions (`ifcopenshell::geometry::taxonomy`) (b) convert these into explicit breps or polyhedra with Open CASCADE or CGAL.
Three validation options are added to IfcConvert for (a) storey containment (b) wall connectivity (c) space boundaries.
IfcOpenShell
============
IfcOpenShell is an open source ([LGPL]) software library for working with the Industry Foundation Classes ([IFC])
file format. Currently supported IFC releases are [IFC2x3 TC1] and [IFC4 Add2 TC1].
For more information, see
* [http://ifcopenshell.org](http://ifcopenshell.org)
* [http://academy.ifcopenshell.org](http://academy.ifcopenshell.org)
[![Build Status](https://api.travis-ci.org/IfcOpenShell/IfcOpenShell.png)](https://api.travis-ci.org/IfcOpenShell/IfcOpenShell)
Prerequisites
-------------
* Git
* CMake (2.6 or newer)
* Windows: [Visual Studio] 2008 or newer with C++ toolset (or [Visual C++ Build Tools]) or [MSYS2] + MinGW
* *nix: GCC 4.7 or newer, or Clang (any version)
Dependencies
-------------
* [Boost](http://www.boost.org/)
* [Open Cascade](http://opencascade.org) - *optional*, but required for building IfcGeom
([official](http://www.opencascade.org/getocc/download/loadocc/), "OCCT", or [community edition](https://github.com/tpaviot/oce), "OCE")
For converting IFC representation items into BRep solids and tesselated meshes
* [OpenCOLLADA](https://github.com/khronosGroup/OpenCOLLADA/) - *optional*
For IfcConvert to be able to write tessellated Collada (.dae) files
* [SWIG](http://www.swig.org/) and [Python](https://www.python.org/) - *optional*
For building the IfcOpenShell Python interface and the Blender add-on
* [3ds Max SDK](http://www.autodesk.com/products/3ds-max/free-trial) - *optional*
For building the 3ds Max plug-in.
All recent versions of 3ds Max (2014 and newer) are 64-bit only, so a 64-bit installation is assumed.
Building IfcOpenShell
---------------------
**Note:** The path where the source code is cloned to can contain spaces but non-ASCII characters are very likely to cause problems with the build.
### Compiling on Windows
The preferred way to fetch and build this project's dependencies is to use the build scripts
in win/ folder. **See [win/readme.md] for more information**.
#### Using Visual Studio
Instructions in a nutshell (**assuming Visual Studio 2015 x64 environment variables set**):
> cd IfcOpenShell\win
> build-deps.cmd
> run-cmake.bat
You can now open and build the solution file in Visual Studio:
> ..\build-vs2015-x64\IfcOpenShell.sln
As the scripts default to using the `RelWithDebInfo` configuration, and a freshly created solution by CMake defaults
to `Debug`, make sure to switch the used build configuration. Build the `INSTALL` project (right-click -> Project
Only) to deploy the headers and binaries into a single location if wanted/needed.
Alternatively, one can use the utility batch file(s) to build and install the project easily from the command-line
(installing a project will build it also, if required):
> install-ifcopenshell.bat
#### Using MSYS2 + MinGW
Start the MSYS2 Shell and then:
$ cd IfcOpenShell/win
$ ./build-deps.sh
$ ./run-cmake.sh
$ ./install-ifcopenshell.sh
#### Using Bash on Ubuntu on Windows
Start Bash on Ubuntu on Windows and follow the instructions below. Compiling on Ubuntu 14.04.4 LTS using GCC 4.8.4
or Clang 3.5 has been confirmed to work.
### Compiling on *nix
The following instructions are for Ubuntu, modify as required for other operating systems. [nix/build-all.py] script
can be experimented with and studied for pointers for other operating systems, but note that this script is not currently
meant to be used for a typical IfcOpenShell workspace setup.
Note: where `make -j` is written, add a number roughly equal to the amount of CPU cores + 1.
**1)** Install most of the prerequisites and dependencies:
$ sudo apt-get install git cmake gcc g++ libboost-all-dev
**2a)** Either use an OCE package from your operating system's software repository
$ sudo apt-get install liboce-foundation-dev liboce-modeling-dev liboce-ocaf-dev liboce-visualization-dev liboce-ocaf-lite-dev
**2b)** or (if not available, or the latest code is wanted) compile OCE yourself (note that the build takes a long time):
$ sudo apt-get install libftgl-dev libtbb2 libtbb-dev libgl1-mesa-dev libfreetype6-dev
$ git clone https://github.com/tpaviot/oce.git
$ cd oce
$ mkdir build && cd build
$ cmake ..
$ make -j
$ sudo make install
**2c)** or obtain and compile OCCT from http://www.opencascade.org/getocc/download/loadocc/
**3)** For building IfcConvert with COLLADA (.dae) support (on by default), OpenCOLLADA is needed:
$ sudo apt-get install libpcre3-dev libxml2-dev
$ git clone https://github.com/KhronosGroup/OpenCOLLADA.git
$ cd OpenCOLLADA
Using a known good revision, but HEAD should work too:
$ git checkout 064a60b65c2c31b94f013820856bc84fb1937cc6
$ mkdir build && cd build
$ cmake ..
$ make -j
$ sudo make install
**4)** For building the IfcPython wrapper (on by default), SWIG and Python development are needed, if not already available:
$ sudo apt-get install python-all-dev swig
**5)** To build IfcOpenShell please take the following steps. Alternatively use environment variables for setting the
dependencies' paths. `OCC_INCLUDE_DIR` might be needed to set also. `OPENCOLLADA_INCLUDE_DIR` and `OPENCOLLADA_LIBRARY_DIR`
(and potentially `PCRE_LIBRARY_DIR`) are needed if building with COLLADA support. (`-DCOLLADA_SUPPORT=0` disables it).
$ cd /path/to/IfcOpenShell
$ mkdir build && cd build
$ cmake ../cmake -DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu/ \
-DOPENCOLLADA_INCLUDE_DIR="/usr/local/include/opencollada" \
-DOPENCOLLADA_LIBRARY_DIR="/usr/local/lib/opencollada" \
-DPCRE_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu/
$ make -j
If all worked out correctly you can now use IfcOpenShell. See the examples below.
**6)** Install the project if wanted:
$ sudo make install
Installing IfcOpenShell with Conda
----------------------------------
Another option for building and installing IfcOpenShell is to use the popular
[Anaconda Python Distribution](https://www.anaconda.com/download).
The requirements are spread across a number of channels.
You can add these channels to your configuration, or specify them all on the command line:
$ conda install -c conda-forge -c oce -c dlr-sc -c ifcopenshell ifcopenshell
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]
>>> len(wall) # number of EXPRESS attributes
8
>>>
>>> # Accessing EXPRESS attributes by name:
>>> wall.GlobalId
'2O2Fr$t4X7Zf8NOew3FL9r'
>>> wall.Name = "My wall"
>>> wall.NonExistingAttr
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".\ifcopenshell.py", line 14, in __getattr__
except: raise AttributeError("entity instance of type '%s' has no attribute'%s'"%(self.wrapped_data.is_a(), name)) from None
AttributeError: entity instance of type 'IfcWallStandardCase' has no attribute 'NonExistingAttr'
>>> wall.GlobalId = 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".\ifcopenshell.py", line 26, in __setattr__
self[self.wrapped_data.get_argument_index(key)] = value
File ".\ifcopenshell.py", line 30, in __setitem__
self.wrapped_data.set_argument(idx, entity_instance.map_value(value))
File ".\ifc_wrapper.py", line 118, in <lambda>
set_argument = lambda self,x,y: self._set_argument(x) if y is None else self
._set_argument(x,y)
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'
>>> new_guid = _
>>> owner_hist = f.by_type("IfcOwnerHistory")[0]
>>> new_wall = f.createIfcWallStandardCase(new_guid, owner_hist, None, None, Tag='my_tag')
>>> new_wall.ObjectType = ''
>>> new_wall.ObjectPlacement = new_wall.Representation = None
>>>
>>> # Accessing entity instances by instance id or GlobalId:
>>> f[92]
#92=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FLIE',#1,'Basic Wall:Interior - Partition (92mm Stud):143921',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5206,#18805,'143921')
>>> f['2O2Fr$t4X7Zf8NOew3FLIE']
#92=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FLIE',#1,'Basic Wall:Interior - Partition (92mm Stud):143921',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5206,#18805,'143921')
>>>
>>> # Writing IFC-SPF files to disk:
>>> f.write("out.ifc")
[LGPL]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/COPYING "LGPL"
[IFC]: http://www.buildingsmart-tech.org/specifications/ifc-overview "IFC"
[IFC2x3 TC1]: http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc2x3-tc1-release "IFC2x3 TC1"
[IFC4 Add1]: http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc4-add1-release "IFC4 Add1"
[Visual Studio]: https://www.visualstudio.com/ "Visual Studio"
[Visual C++ Build Tools]: http://landinghub.visualstudio.com/visual-cpp-build-tools "Visual C++ Build Tools"
[MSYS2]: https://msys2.github.io/ "MSYS2"
[win/readme.md]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/win/readme.md "win/readme.md"
[nix/build-all.py]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/nix/build-all.py "nix/build-all.py"
+758 -182
View File
@@ -1,235 +1,811 @@
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 3.1.3)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON) # not necessary, but encouraged
project (IfcOpenShell)
FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options)
foreach(max_year RANGE 2014 2030)
set(max_sdk "$ENV{ADSK_3DSMAX_SDK_${max_year}}")
if (NOT "${max_sdk}" STREQUAL "")
MESSAGE(STATUS "Autodesk 3ds Max SDK found at ${max_sdk}")
set(HAS_MAX TRUE)
endif()
endforeach()
OPTION(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON)
OPTION(IFCXML_SUPPORT "Build IfcParse with ifcXML support (requires libxml2)." ON)
OPTION(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF)
OPTION(IFCCONVERT_DOUBLE_PRECISION "IfcConvert: Use double precision floating-point numbers." ON)
OPTION(BUILD_IFCGEOM "Build IfcGeom." ON)
OPTION(BUILD_IFCPYTHON "Build IfcPython." ON)
OPTION(BUILD_EXAMPLES "Build example applications." ON)
OPTION(BUILD_GEOMSERVER "Build IfcGeomServer executable." ON)
OPTION(BUILD_CONVERT "Build IfcConvert executable." ON)
OPTION(USE_VLD "Use Visual Leak Detector for debugging memory leaks, MSVC-only." OFF)
OPTION(USE_MMAP "Adds a command line options to parse IFC files from memory mapped files using Boost.Iostreams" OFF)
OPTION(USE_VOXELS "Use voxelized geometries as a fallback mechanism to calculate quantities in IfcGeomServer" OFF)
OPTION(USE_CGAL "Use CGAL as an alternative geometry kernel implementation" OFF)
OPTION(USE_STATIC_MSVC_RUNTIME "Link to the static runtime on MSVC." OFF)
OPTION(BUILD_SHARED_LIBS "Build IfcParse and IfcGeom as shared libs (SO/DLL)." OFF)
if (${HAS_MAX})
OPTION(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." ON)
endif()
if (${BUILD_CONVERT})
OPTION(GLTF_SUPPORT "Build IfcConvert with glTF support (requires json.hpp)." OFF)
endif()
# 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)
if((BUILD_CONVERT OR BUILD_GEOMSERVER OR BUILD_IFCPYTHON) AND (NOT BUILD_IFCGEOM))
message(STATUS "'IfcGeom' is required with current outputs")
set(BUILD_IFCGEOM ON)
endif()
# Specify where to install files
IF(NOT BINDIR)
set(BINDIR bin)
ENDIF()
IF(NOT IS_ABSOLUTE ${BINDIR})
set(BINDIR ${CMAKE_INSTALL_PREFIX}/${BINDIR})
ENDIF()
MESSAGE(STATUS "BINDIR: ${BINDIR}")
IF(NOT INCLUDEDIR)
set(INCLUDEDIR include)
ENDIF()
IF(NOT IS_ABSOLUTE ${INCLUDEDIR})
set(INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/${INCLUDEDIR})
ENDIF()
MESSAGE(STATUS "INCLUDEDIR: ${INCLUDEDIR}")
IF(NOT LIBDIR)
set(LIBDIR lib)
ENDIF()
IF(NOT IS_ABSOLUTE ${LIBDIR})
set(LIBDIR ${CMAKE_INSTALL_PREFIX}/${LIBDIR})
ENDIF()
MESSAGE(STATUS "LIBDIR: ${LIBDIR}")
set(IFCOPENSHELL_LIBARY_DIR "") # for *nix rpaths
if (BUILD_SHARED_LIBS)
add_definitions(-DIFC_SHARED_BUILD)
if (MSVC)
message(WARNING "Building DLLs against the static VC run-time. This is not recommended if the DLLs are to be redistributed.")
# C4521: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
# There will be couple hundreds of these so suppress them away, https://msdn.microsoft.com/en-us/library/esew7y1w.aspx
add_definitions(-wd4251)
endif()
set(IFCOPENSHELL_LIBARY_DIR "${LIBDIR}")
endif()
# Create cache entries if absent for environment variables
MACRO(UNIFY_ENVVARS_AND_CACHE VAR)
IF ((NOT DEFINED ${VAR}) AND (NOT "$ENV{${VAR}}" STREQUAL ""))
SET(${VAR} "$ENV{${VAR}}" CACHE STRING "${VAR}" FORCE)
ENDIF()
ENDMACRO()
UNIFY_ENVVARS_AND_CACHE(OCC_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(OCC_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(LIBXML2_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(LIBXML2_LIBRARIES)
UNIFY_ENVVARS_AND_CACHE(PCRE_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE)
UNIFY_ENVVARS_AND_CACHE(CGAL_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(CGAL_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(GMP_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(GMP_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(MPFR_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(MPFR_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(VOXEL_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(VOXEL_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(EIGEN_DIR)
if (GLTF_SUPPORT AND BUILD_CONVERT)
UNIFY_ENVVARS_AND_CACHE(JSON_INCLUDE_DIR)
FIND_FILE(json_hpp "json.hpp" ${JSON_INCLUDE_DIR}/nlohmann)
IF(json_hpp)
MESSAGE(STATUS "JSON for Modern C++ header file found")
ELSE()
MESSAGE(FATAL_ERROR "Unable to find JSON for Modern C++ header file, aborting")
ENDIF()
add_definitions(-DWITH_GLTF)
endif()
# Set INSTALL_RPATH for target
MACRO(SET_INSTALL_RPATHS _target _paths)
SET(${_target}_rpaths "")
FOREACH(_path ${_paths})
LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${_path}" isSystemDir)
IF("${isSystemDir}" STREQUAL "-1")
LIST(APPEND ${_target}_rpaths ${_path})
ENDIF()
ENDFOREACH()
MESSAGE(STATUS "Set INSTALL_RPATH for ${_target}: ${${_target}_rpaths}")
SET_TARGET_PROPERTIES(${_target} PROPERTIES INSTALL_RPATH "${${_target}_rpaths}")
ENDMACRO()
# Find Boost: On win32 the (hardcoded) default is to use static libraries and
# runtime, when doing running conda-build we pick what conda prepared for us.
IF(WIN32 AND ("$ENV{CONDA_BUILD}" STREQUAL ""))
SET(Boost_USE_STATIC_LIBS ON)
SET(Boost_USE_MULTITHREADED ON)
if (USE_STATIC_MSVC_RUNTIME)
SET(Boost_USE_STATIC_RUNTIME ON)
endif()
ELSE()
# Disable Boost's autolinking as the libraries to be linked to are supplied
# already by CMake, and it's going to conflict if there are multiple, as is
# the case in conda-forge's libboost feedstock.
ADD_DEFINITIONS(-DBOOST_ALL_NO_LIB)
IF(WIN32)
# Necessary for boost version >= 1.67
SET(BCRYPT_LIBRARIES "bcrypt.lib")
ENDIF()
ENDIF()
set(BOOST_COMPONENTS system program_options regex thread date_time)
if(USE_MMAP OR USE_VOXELS)
if(MSVC)
# filesystem is necessary for the utf-16 wpath
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} iostreams filesystem)
else()
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} iostreams)
endif()
if(USE_MMAP)
add_definitions(-DUSE_MMAP)
endif()
endif()
if (IFCXML_SUPPORT)
add_definitions(-DWITH_IFCXML)
endif()
if (USE_VOXELS)
FIND_LIBRARY(libvoxel NAMES voxel libvoxel PATHS ${VOXEL_LIBRARY_DIR} NO_DEFAULT_PATH)
FIND_LIBRARY(libvoxec NAMES voxec libvoxec PATHS ${VOXEL_LIBRARY_DIR} NO_DEFAULT_PATH)
set(VOXEL_LIBRARIES ${libvoxel} ${libvoxec})
ADD_DEFINITIONS("-DUSE_VOXELS")
endif()
FIND_PACKAGE(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
MESSAGE(STATUS "Boost include files found in ${Boost_INCLUDE_DIRS}")
MESSAGE(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}")
# Find Open CASCADE header files
IF("$ENV{OCC_INCLUDE_DIR}" STREQUAL "")
SET(OCC_INCLUDE_DIR "/usr/include/opencascade/" CACHE FILEPATH "Open CASCADE header files")
MESSAGE(STATUS "Looking for opencascade include files in: ${OCC_INCLUDE_DIR}")
# Usage:
# set(SOME_LIRARIES foo bar)
# add_debug_variants(SOME_LIRARIES "${SOME_LIRARIES}" d)
# "foo bar" -> "optimized foo debug food optimized bar debug bard"
# or
# set(SOME_LIRARIES path/foo.lib)
# add_debug_variants(SOME_LIRARIES "${SOME_LIRARIES}" "d")
# "path/foo.lib" -> "optimized path/foo.lib debug path/food.lib"
# TODO Could be refined: take the library file extension as a parameter and
# make sure the lib variable ends with not just contains it.
function(add_debug_variants NAME LIBRARIES POSTFIX)
set(LIBRARIES_STR "${LIBRARIES}")
set(LIBRARIES "")
# the result, "optimized <lib> debug <lib>", needs to be a list instead of a string
foreach(lib ${LIBRARIES_STR})
list(APPEND LIBRARIES optimized)
if ("${lib}" MATCHES ".lib")
string(REPLACE ".lib" "" lib ${lib})
list(APPEND LIBRARIES ${lib}.lib)
else()
list(APPEND LIBRARIES ${lib})
endif()
list(APPEND LIBRARIES debug)
if ("${lib}" MATCHES ".lib")
string(REPLACE ".lib" "" lib ${lib})
list(APPEND LIBRARIES ${lib}${POSTFIX}.lib)
else()
list(APPEND LIBRARIES ${lib}${POSTFIX})
endif()
endforeach()
set(${NAME} ${LIBRARIES} PARENT_SCOPE)
endfunction()
if(BUILD_IFCGEOM)
# Find Open CASCADE
IF("${OCC_INCLUDE_DIR}" STREQUAL "")
SET(OCC_INCLUDE_DIR "/usr/include/oce/" CACHE FILEPATH "Open CASCADE header files")
MESSAGE(STATUS "Looking for Open CASCADE include files in: ${OCC_INCLUDE_DIR}")
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")
MESSAGE(STATUS "Looking for opencascade include files in: ${OCC_INCLUDE_DIR}")
SET(OCC_INCLUDE_DIR ${OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files")
MESSAGE(STATUS "Looking for Open CASCADE include files in: ${OCC_INCLUDE_DIR}")
ENDIF()
FIND_FILE(gp_Pnt_hxx "gp_Pnt.hxx" ${OCC_INCLUDE_DIR} /usr/inc /usr/local/inc /usr/local/include/oce)
FIND_FILE(gp_Pnt_hxx "gp_Pnt.hxx" ${OCC_INCLUDE_DIR})
IF(gp_Pnt_hxx)
MESSAGE(STATUS "Header files found")
ELSE()
MESSAGE(FATAL_ERROR "Unable to find header files, aborting")
ENDIF()
# Find Open CASCADE library files
IF("$ENV{OCC_LIBRARY_DIR}" STREQUAL "")
SET(OPENCASCADE_LIBRARY_NAMES
TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO
TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset
)
IF("${OCC_LIBRARY_DIR}" STREQUAL "")
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 "Looking for Open CASCADE 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")
MESSAGE(STATUS "Looking for opencascade library files in: ${OCC_LIBRARY_DIR}")
SET(OCC_LIBRARY_DIR ${OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files")
MESSAGE(STATUS "Looking for Open CASCADE library files in: ${OCC_LIBRARY_DIR}")
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} NO_DEFAULT_PATH)
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")
ENDIF()
# Use the found libTKernel as a template for all other OCC libraries
# TODO Extract this into macro/function
foreach(lib ${OPENCASCADE_LIBRARY_NAMES})
# Make sure we'll handle the Windows/MSVC debug postfix convetion too.
string(REPLACE TKerneld "${lib}" lib_path "${libTKernel}")
string(REPLACE TKernel "${lib}" lib_path "${lib_path}")
list(APPEND OPENCASCADE_LIBRARIES "${lib_path}")
endforeach()
IF("$ENV{ICU_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No ICU library directory specified")
ElSE()
SET(ICU_LIBRARY_DIR CACHE FILEPATH "ICU library files")
ENDIF()
list(APPEND GEOMETRY_KERNELS opencascade)
FIND_LIBRARY(icu "icuuc" /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR})
IF(icu)
MESSAGE(STATUS "ICU libraries found")
ADD_DEFINITIONS(-DHAVE_ICU)
if (USE_CGAL)
add_definitions(-DIFOPSH_USE_CGAL)
list(APPEND GEOMETRY_KERNELS cgal)
SET(CGAL_LIBRARY_NAMES libCGAL_Core libCGAL_ImageIO libCGAL)
# Find CGAL
IF("${CGAL_INCLUDE_DIR}" STREQUAL "")
SET(CGAL_INCLUDE_DIR "/usr/include/" CACHE FILEPATH "CGAL header files")
MESSAGE(STATUS "Looking for CGAL include files in: ${CGAL_INCLUDE_DIR}")
MESSAGE(STATUS "Use CGAL_INCLUDE_DIR to specify another directory")
ELSE()
MESSAGE(STATUS "Unable to find ICU library files, continuing")
SET(CGAL_INCLUDE_DIR ${CGAL_INCLUDE_DIR} CACHE FILEPATH "CGAL header files")
MESSAGE(STATUS "Looking for CGAL include files in: ${CGAL_INCLUDE_DIR}")
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
)
IF("${CGAL_LIBRARY_DIR}" STREQUAL "")
SET(CGAL_LIBRARY_DIR "/usr/lib/" CACHE FILEPATH "CGAL library files")
MESSAGE(STATUS "Looking for CGAL library files in: ${CGAL_LIBRARY_DIR}")
MESSAGE(STATUS "Use CGAL_LIBRARY_DIR to specify another directory")
ELSE()
MESSAGE(STATUS "OpenCOLLADA header files not found, continuing without COLLADA support")
SET(CGAL_LIBRARY_DIR ${CGAL_LIBRARY_DIR} CACHE FILEPATH "CGAL library files")
MESSAGE(STATUS "Looking for CGAL library files in: ${CGAL_LIBRARY_DIR}")
ENDIF()
FIND_LIBRARY(libCGAL NAMES CGAL PATHS ${CGAL_LIBRARY_DIR} NO_DEFAULT_PATH)
IF(libCGAL)
MESSAGE(STATUS "CGAL library files found")
foreach(lib ${CGAL_LIBRARY_NAMES})
string(REPLACE libCGAL "${lib}" lib_path "${libCGAL}")
list(APPEND CGAL_LIBRARIES "${lib_path}")
endforeach()
ELSE()
FILE(GLOB CGAL_LIBRARIES ${CGAL_LIBRARY_DIR}/*CGAL*.lib)
message(STATUS CGAL_LIBRARIES ${CGAL_LIBRARIES})
LIST(LENGTH CGAL_LIBRARY_NAMES num_cgal_library_names)
LIST(LENGTH CGAL_LIBRARIES num_cgal_libraries)
message(STATUS ${num_cgal_library_names} ${num_cgal_libraries})
LINK_DIRECTORIES("${CGAL_LIBRARY_DIR}")
if(NOT "${num_cgal_library_names}" STREQUAL "${num_cgal_libraries}")
MESSAGE(FATAL_ERROR "Unable to find CGAL library files, aborting")
endif()
MESSAGE(STATUS "CGAL library files found")
ENDIF()
INCLUDE(CheckIncludeFileCXX)
FIND_LIBRARY(libGMP NAMES gmp mpir PATHS ${GMP_LIBRARY_DIR} NO_DEFAULT_PATH)
FIND_LIBRARY(libMPFR NAMES mpfr PATHS ${MPFR_LIBRARY_DIR} NO_DEFAULT_PATH)
IF(NOT libGMP)
MESSAGE(FATAL_ERROR "Unable to find GMP library files, aborting")
ENDIF()
IF(NOT libMPFR)
MESSAGE(FATAL_ERROR "Unable to find MPFR library files, aborting")
ENDIF()
list(APPEND CGAL_LIBRARIES "${libMPFR}")
list(APPEND CGAL_LIBRARIES "${libGMP}")
endif()
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)
if(MSVC)
add_definitions(-DHAVE_NO_DLL)
add_debug_variants(OPENCASCADE_LIBRARIES "${OPENCASCADE_LIBRARIES}" d)
endif()
if (WIN32)
# OCC might require linking to Winsock depending on the version and build configuration
list(APPEND OPENCASCADE_LIBRARIES ws2_32.lib)
endif()
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)
# 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")
set(OCCT_STATIC ON)
endif()
if(OCCT_STATIC)
find_package(Threads)
# OPENCASCADE_LIBRARIES repeated three times below in order to fix cyclic dependencies - use --start-group ... --end-group instead?
set(OPENCASCADE_LIBRARIES -Wl,--start-group ${OPENCASCADE_LIBRARIES} -Wl,--end-group ${CMAKE_THREAD_LIBS_INIT})
if (NOT APPLE AND NOT WIN32)
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} "rt")
endif()
if (NOT WIN32)
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} "dl")
endif()
endif()
endif(BUILD_IFCGEOM)
IF(COLLADA_SUPPORT AND BUILD_CONVERT)
# Find OpenCOLLADA
IF("${OPENCOLLADA_INCLUDE_DIR}" STREQUAL "")
MESSAGE(STATUS "No OpenCOLLADA include directory specified")
SET(OPENCOLLADA_INCLUDE_DIR "/usr/include/opencollada" CACHE FILEPATH "OpenCOLLADA header files")
ELSE()
SET(OPENCOLLADA_INCLUDE_DIR "${OPENCOLLADA_INCLUDE_DIR}" CACHE FILEPATH "OpenCOLLADA header files")
ENDIF()
IF("${OPENCOLLADA_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No OpenCOLLADA library directory specified")
FIND_LIBRARY(OPENCOLLADA_FRAMEWORK_LIB NAMES OpenCOLLADAFramework
PATHS /usr/lib64/opencollada /usr/lib/opencollada /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib)
GET_FILENAME_COMPONENT(OPENCOLLADA_LIBRARY_DIR ${OPENCOLLADA_FRAMEWORK_LIB} PATH)
ENDIF()
FIND_LIBRARY(OpenCOLLADAFramework NAMES OpenCOLLADAFramework OpenCOLLADAFrameworkd PATHS ${OPENCOLLADA_LIBRARY_DIR} NO_DEFAULT_PATH)
if (OpenCOLLADAFramework)
message(STATUS "OpenCOLLADA library files found")
else()
message(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find OpenCOLLADA libraries. "
"Disable COLLADA_SUPPORT or fix OpenCOLLADA paths to proceed.")
endif()
SET(OPENCOLLADA_LIBRARY_DIR "${OPENCOLLADA_LIBRARY_DIR}" CACHE FILEPATH "OpenCOLLADA library files")
SET(OPENCOLLADA_INCLUDE_DIRS "${OPENCOLLADA_INCLUDE_DIR}/COLLADABaseUtils" "${OPENCOLLADA_INCLUDE_DIR}/COLLADAStreamWriter")
FIND_FILE(COLLADASWStreamWriter_h "COLLADASWStreamWriter.h" ${OPENCOLLADA_INCLUDE_DIRS})
IF(COLLADASWStreamWriter_h)
MESSAGE(STATUS "OpenCOLLADA header files found")
ADD_DEFINITIONS(-DWITH_OPENCOLLADA)
SET(OPENCOLLADA_LIBRARY_NAMES
GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader
OpenCOLLADAStreamWriter UTF buffer ftoa
)
# Use the found OpenCOLLADAFramework as a template for all other OpenCOLLADA libraries
foreach(lib ${OPENCOLLADA_LIBRARY_NAMES})
# Make sure we'll handle the Windows/MSVC debug postfix convetion too.
string(REPLACE OpenCOLLADAFrameworkd "${lib}" lib_path "${OpenCOLLADAFramework}")
string(REPLACE OpenCOLLADAFramework "${lib}" lib_path "${lib_path}")
list(APPEND OPENCOLLADA_LIBRARIES "${lib_path}")
endforeach()
if("${PCRE_LIBRARY_DIR}" STREQUAL "")
if(WIN32)
find_library(pcre_library NAMES pcre pcred PATHS ${OPENCOLLADA_LIBRARY_DIR} NO_DEFAULT_PATH)
else()
find_library(pcre_library NAMES pcre PATHS ${OPENCOLLADA_LIBRARY_DIR})
endif()
GET_FILENAME_COMPONENT(PCRE_LIBRARY_DIR ${pcre_library} PATH)
else()
find_library(pcre_library NAMES pcre pcred PATHS ${PCRE_LIBRARY_DIR} NO_DEFAULT_PATH)
endif()
if (pcre_library)
SET(OPENCOLLADA_LIBRARY_DIR ${OPENCOLLADA_LIBRARY_DIR} ${PCRE_LIBRARY_DIR})
if (MSVC)
# Add release lib regardless whether release or debug found. Debug version will be appended below.
list(APPEND OPENCOLLADA_LIBRARIES "${PCRE_LIBRARY_DIR}/pcre.lib")
else()
list(APPEND OPENCOLLADA_LIBRARIES "${pcre_library}")
endif()
else()
message(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find PCRE. "
"Disable COLLADA_SUPPORT or fix PCRE_LIBRARY_DIR path to proceed.")
endif()
IF(MSVC)
add_debug_variants(OPENCOLLADA_LIBRARIES "${OPENCOLLADA_LIBRARIES}" d)
ENDIF()
ELSE()
message(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find OpenCOLLADA headers. "
"Disable COLLADA_SUPPORT or fix OpenCOLLADA paths to proceed.")
ENDIF()
ENDIF()
IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE "Release")
ENDIF(NOT CMAKE_BUILD_TYPE)
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-latebound.cpp
../src/ifcparse/Ifc2x3.cpp
../src/ifcparse/Ifc4-latebound.cpp
../src/ifcparse/Ifc4.cpp
../src/ifcparse/IfcCharacterDecoder.cpp
../src/ifcparse/IfcGuidHelper.cpp
../src/ifcparse/IfcHierarchyHelper.cpp
../src/ifcparse/IfcLateBoundEntity.cpp
../src/ifcparse/IfcParse.cpp
../src/ifcparse/IfcSIPrefix.cpp
../src/ifcparse/IfcSpfHeader.cpp
../src/ifcparse/IfcUtil.cpp
../src/ifcparse/IfcWrite.cpp
)
ADD_LIBRARY(IfcGeom STATIC
../src/ifcgeom/IfcGeomCurves.cpp
../src/ifcgeom/IfcGeomFaces.cpp
../src/ifcgeom/IfcGeomFunctions.cpp
../src/ifcgeom/IfcGeomHelpers.cpp
../src/ifcgeom/IfcGeomMaterial.cpp
../src/ifcgeom/IfcGeomRenderStyles.cpp
../src/ifcgeom/IfcGeomRepresentation.cpp
../src/ifcgeom/IfcGeomShapes.cpp
../src/ifcgeom/IfcGeomWires.cpp
../src/ifcgeom/IfcRegister.cpp
)
IF(icu)
TARGET_LINK_LIBRARIES(IfcParse icuuc)
SET(CMAKE_BUILD_TYPE "Release")
ENDIF()
TARGET_LINK_LIBRARIES(IfcGeom IfcParse)
if(ENABLE_BUILD_OPTIMIZATIONS)
if(MSVC)
# NOTE: RelWithDebInfo and Release use O2 (= /Ox /Gl /Gy/ = Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy) by default,
# with the exception with RelWithDebInfo has /Ob1 instead. /Ob2 has been observed to improve the performance
# of IfcConvert significantly.
# TODO Setting of /GL and /LTCG don't seem to apply for static libraries (IfcGeom, IfcParse)
# C++
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /GL")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
# Linker
# /OPT:REF enables also /OPT:ICF and disables INCREMENTAL
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
# /OPT:NOICF is recommended when /DEBUG is used (http://msdn.microsoft.com/en-us/library/xe4t6fc1.aspx)
set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
else()
# GCC-like: Release should use O3 but RelWithDebInfo 02 so enforce 03. Anything other useful that could be added here?
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -O3")
endif()
endif()
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})
IF(MSVC)
# Enable solution folders (free VS versions prior to 2012 don't support solution folders)
if (MSVC_VERSION GREATER 1600)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
endif()
ADD_EXECUTABLE(IfcConvert
../src/ifcconvert/ColladaSerializer.cpp
../src/ifcconvert/IfcConvert.cpp
../src/ifcconvert/OpenCascadeBasedSerializer.cpp
../src/ifcconvert/WavefrontObjSerializer.cpp
../src/ifcconvert/XmlSerializer.cpp
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()
# Enforce standards-conformance on VS > 2015, older Boost versions fail to compile with this
if (MSVC_VERSION GREATER 1900 AND (Boost_MAJOR_VERSION GREATER 1 OR Boost_MINOR_VERSION GREATER 66))
# @todo currently fails
# add_definitions(-permissive-)
endif()
if(USE_STATIC_MSVC_RUNTIME)
# Link against the static VC runtime
IF("$ENV{CONDA_BUILD}" STREQUAL "")
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()
ENDIF()
endif()
ElSE()
add_definitions(-Wall -Wextra)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_definitions(-Wno-tautological-constant-out-of-range-compare)
else()
add_definitions(-Wno-maybe-uninitialized)
endif()
# -fPIC is not relevant on Windows and creates pointless warnings
if (UNIX)
add_definitions(-fPIC)
endif()
ENDIF()
if (IFCCONVERT_DOUBLE_PRECISION)
SET(CONVERT_PRECISION "-DIFCCONVERT_DOUBLE_PRECISION")
endif()
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS} ${LIBXML2_INCLUDE_DIR} ${JSON_INCLUDE_DIR}
${CGAL_INCLUDE_DIR} ${GMP_INCLUDE_DIR} ${MPFR_INCLUDE_DIR} ${VOXEL_INCLUDE_DIR} ${EIGEN_DIR}
)
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})
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}.cpp
PARENT_SCOPE
)
endfunction()
ADD_EXECUTABLE(IfcGeomServer
../src/ifcgeomserver/IfcGeomServer.cpp
set(SCHEMA_VERSIONS "2x3" "4" "4x1" "4x2")
if(COMPILE_SCHEMA)
# @todo, this appears to be untested at the moment
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 ${SCHEMA_VERSIONS})
# 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
foreach(s ${SCHEMA_VERSIONS})
if("${COMPILED_SCHEMA_NAME}" STREQUAL "${s}")
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "${s}")
endif()
endforeach()
endif()
# Boost >= 1.58 requires BOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE to build on some Linux distros.
if(NOT Boost_VERSION LESS 105800)
add_definitions(-DBOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE)
endif()
set(IFCOPENSHELL_LIBRARIES IfcParse)
if (BUILD_IFCGEOM)
foreach(s ${SCHEMA_VERSIONS})
set(IFCGEOM_SCHEMA_LIBRARIES ${IFCGEOM_SCHEMA_LIBRARIES} geometry_mapping_ifc${s})
endforeach()
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} IfcGeom geometry_mappings ${IFCGEOM_SCHEMA_LIBRARIES})
endif()
if (BUILD_CONVERT)
foreach(s ${SCHEMA_VERSIONS})
set(SERIALIZER_SCHEMA_LIBRARIES ${SERIALIZER_SCHEMA_LIBRARIES} serializers_ifc${s})
endforeach()
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} serializers ${SERIALIZER_SCHEMA_LIBRARIES})
endif()
# IfcParse
file(GLOB IFCPARSE_H_FILES ../src/ifcparse/*.h)
file(GLOB IFCPARSE_CPP_FILES ../src/ifcparse/*.cpp)
set(IFCPARSE_FILES ${IFCPARSE_CPP_FILES} ${IFCPARSE_H_FILES})
add_library(IfcParse ${IFCPARSE_FILES})
set_target_properties(IfcParse PROPERTIES COMPILE_FLAGS -DIFC_PARSE_EXPORTS)
TARGET_LINK_LIBRARIES(IfcParse ${Boost_LIBRARIES} ${BCRYPT_LIBRARIES} ${LIBXML2_LIBRARIES})
if (BUILD_IFCGEOM)
foreach(kernel ${GEOMETRY_KERNELS})
string(TOUPPER ${kernel} KERNEL_UPPER)
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/kernels/${kernel}/*.h)
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/kernels/${kernel}/*.cpp)
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES})
add_library(geometry_kernel_${kernel} STATIC ${IFCGEOM_FILES})
set_target_properties(geometry_kernel_${kernel} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS")
target_link_libraries(geometry_kernel_${kernel} ${${KERNEL_UPPER}_LIBRARIES})
list(APPEND kernel_libraries geometry_kernel_${kernel})
endforeach()
file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom/kernel_agnostic/*.h)
file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom/kernel_agnostic/*.cpp)
set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES})
add_library(geometry_kernels ${SCHEMA_AGNOSTIC_FILES})
set_target_properties(geometry_kernels PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS)
target_link_libraries(geometry_kernels ${kernel_libraries})
foreach(schema ${SCHEMA_VERSIONS})
file(GLOB IFCGEOM_I_FILES ../src/ifcgeom/schema/*.i)
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/schema/*.h)
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/schema/*.cpp)
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES} ${IFCGEOM_I_FILES})
add_library(geometry_mapping_ifc${schema} STATIC ${IFCGEOM_FILES})
set_target_properties(geometry_mapping_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema}")
target_link_libraries(geometry_mapping_ifc${schema} IfcParse)
list(APPEND mapping_libraries geometry_mapping_ifc${schema})
endforeach()
file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom/*.h)
file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom/*.cpp)
set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES})
add_library(geometry_mappings ${SCHEMA_AGNOSTIC_FILES})
set_target_properties(geometry_mappings PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS)
target_link_libraries(geometry_mappings ${mapping_libraries})
if (UNIX)
find_package(Threads)
endif()
file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom/schema_agnostic/*.h)
file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom/schema_agnostic/*.cpp)
set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES})
add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES})
set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS)
target_link_libraries(IfcGeom geometry_mappings geometry_kernels ${CMAKE_THREAD_LIBS_INIT})
endif(BUILD_IFCGEOM)
if (BUILD_CONVERT)
# serializers
file(GLOB SERIALIZERS_H_FILES ../src/serializers/*.h)
file(GLOB SERIALIZERS_CPP_FILES ../src/serializers/*.cpp)
set(SERIALIZERS_FILES ${SERIALIZERS_H_FILES} ${SERIALIZERS_CPP_FILES})
file(GLOB SERIALIZERS_S_H_FILES ../src/serializers/schema_dependent/*.h)
file(GLOB SERIALIZERS_S_CPP_FILES ../src/serializers/schema_dependent/*.cpp)
set(SERIALIZERS_S_FILES ${SERIALIZERS_S_H_FILES} ${SERIALIZERS_S_CPP_FILES})
foreach(s ${SCHEMA_VERSIONS})
add_library(serializers_ifc${s} STATIC ${SERIALIZERS_S_FILES})
set_target_properties(serializers_ifc${s} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${s} ${CONVERT_PRECISION}")
TARGET_LINK_LIBRARIES(serializers_ifc${s} IfcGeom ${OPENCASCADE_LIBRARIES})
endforeach()
add_library(serializers ${SERIALIZERS_FILES})
set_target_properties(serializers PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS ${CONVERT_PRECISION}")
TARGET_LINK_LIBRARIES(serializers ${SERIALIZER_SCHEMA_LIBRARIES})
# IfcConvert
file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp)
file(GLOB IFCCONVERT_H_FILES ../src/ifcconvert/*.h)
set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES})
ADD_EXECUTABLE(IfcConvert ${IFCCONVERT_FILES})
set_target_properties(IfcConvert PROPERTIES COMPILE_FLAGS "${CONVERT_PRECISION}")
TARGET_LINK_LIBRARIES(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES})
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
# Only set RPATHs when building shared libraries (i.e. IfcParse and
# IfcGeom are dynamically linked). Not necessarily a perfect solution
# but probably a good indication of whether RPATHs are necessary.
SET_INSTALL_RPATHS(IfcConvert "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS};${OPENCOLLADA_LIBRARY_DIR}")
endif()
INSTALL(TARGETS IfcConvert
ARCHIVE DESTINATION ${LIBDIR}
LIBRARY DESTINATION ${LIBDIR}
RUNTIME DESTINATION ${BINDIR}
)
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)
endif(BUILD_CONVERT)
# Build python wrapper using separate CMakeLists.txt
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
# IfcGeomServer
if(BUILD_GEOMSERVER)
# Build IfcParseExamples using separate CMakeLists.txt
ADD_SUBDIRECTORY(../src/examples examples)
file(GLOB CPP_FILES ../src/ifcgeomserver/*.cpp)
file(GLOB H_FILES ../src/ifcgeomserver/*.h)
set(SOURCE_FILES ${CPP_FILES} ${H_FILES})
ADD_EXECUTABLE(IfcGeomServer ${SOURCE_FILES})
TARGET_LINK_LIBRARIES(IfcGeomServer ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${VOXEL_LIBRARIES})
# ADD_SUBDIRECTORY(../src/qtviewer qtviewer)
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
SET_INSTALL_RPATHS(IfcGeomServer "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS}")
endif()
INSTALL(TARGETS IfcGeomServer
ARCHIVE DESTINATION ${LIBDIR}
LIBRARY DESTINATION ${LIBDIR}
RUNTIME DESTINATION ${BINDIR}
)
endif()
IF(BUILD_IFCPYTHON)
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
ENDIF()
IF(BUILD_EXAMPLES)
ADD_SUBDIRECTORY(../src/examples examples)
ENDIF()
IF(BUILD_IFCMAX)
ADD_SUBDIRECTORY(../src/ifcmax ifcmax)
ENDIF()
# CMake installation targets
SET(include_files_geom
../src/ifcgeom/IfcGeom.h
../src/ifcgeom/IfcGeomElement.h
../src/ifcgeom/IfcGeomIterator.h
../src/ifcgeom/IfcGeomIteratorSettings.h
../src/ifcgeom/IfcGeomMaterial.h
../src/ifcgeom/IfcGeomRenderStyles.h
../src/ifcgeom/IfcGeomRepresentation.h
../src/ifcgeom/IfcRegister.h
../src/ifcgeom/IfcRegisterConvertCurve.h
../src/ifcgeom/IfcRegisterConvertFace.h
../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/IfcRepresentationShapeItem.h
INSTALL(FILES ${IFCPARSE_H_FILES}
DESTINATION ${INCLUDEDIR}/ifcparse
)
SET(include_files_parse
../src/ifcparse/Ifc2x3-latebound.h
../src/ifcparse/Ifc2x3.h
../src/ifcparse/Ifc2x3enum.h
../src/ifcparse/Ifc4-latebound.h
../src/ifcparse/Ifc4.h
../src/ifcparse/Ifc4enum.h
../src/ifcparse/IfcCharacterDecoder.h
../src/ifcparse/IfcEntityDescriptor.h
../src/ifcparse/IfcException.h
../src/ifcparse/IfcFile.h
../src/ifcparse/IfcHierarchyHelper.h
../src/ifcparse/IfcLateBoundEntity.h
../src/ifcparse/IfcParse.h
../src/ifcparse/IfcSIPrefix.h
../src/ifcparse/IfcSpfHeader.h
../src/ifcparse/IfcSpfStream.h
../src/ifcparse/IfcUtil.h
../src/ifcparse/IfcWritableEntity.h
../src/ifcparse/IfcWrite.h
../src/ifcparse/SharedPointer.h
INSTALL(TARGETS IfcParse
ARCHIVE DESTINATION ${LIBDIR}
LIBRARY DESTINATION ${LIBDIR}
RUNTIME DESTINATION ${BINDIR}
)
INSTALL(FILES ${include_files_geom} DESTINATION include/ifcgeom)
INSTALL(FILES ${include_files_parse} DESTINATION include/ifcparse)
INSTALL(TARGETS IfcConvert DESTINATION bin)
INSTALL(TARGETS IfcParse IfcGeom DESTINATION lib)
if(BUILD_IFCGEOM)
INSTALL(FILES ${IFCGEOM_H_FILES}
DESTINATION ${INCLUDEDIR}/ifcgeom
)
INSTALL(FILES ${SCHEMA_AGNOSTIC_H_FILES}
DESTINATION ${INCLUDEDIR}/ifcgeom/schema_agnostic
)
INSTALL(TARGETS IfcGeom ${IfcGeom_libraries}
ARCHIVE DESTINATION ${LIBDIR}
LIBRARY DESTINATION ${LIBDIR}
RUNTIME DESTINATION ${BINDIR}
)
endif()
if(BUILD_CONVERT)
INSTALL(TARGETS serializers ${SERIALIZER_SCHEMA_LIBRARIES}
ARCHIVE DESTINATION ${LIBDIR}
LIBRARY DESTINATION ${LIBDIR}
RUNTIME DESTINATION ${BINDIR}
)
INSTALL(FILES ${SERIALIZERS_FILES}
DESTINATION ${INCLUDEDIR}/serializers/
)
INSTALL(FILES ${SERIALIZERS_S_FILES}
DESTINATION ${INCLUDEDIR}/serializers/schema_dependent
)
endif()
+29
View File
@@ -0,0 +1,29 @@
mkdir build && cd build
REM Remove dot from PY_VER for use in library name
REM From https://github.com/tpaviot/pythonocc-core/blob/master/ci/conda/bld.bat
set MY_PY_VER=%PY_VER:.=%
cmake -G "NMake Makefiles" ^
-DCMAKE_INSTALL_PREFIX="%LIBRARY_PREFIX%" ^
-DCMAKE_BUILD_TYPE=Release ^
-DCMAKE_PREFIX_PATH="%LIBRARY_PREFIX%" ^
-DCMAKE_SYSTEM_PREFIX_PATH="%LIBRARY_PREFIX%" ^
-DPYTHON_EXECUTABLE="%PYTHON%" ^
-DPYTHON_INCLUDE_DIR="%PREFIX%"/include ^
-DPYTHON_LIBRARY="%PREFIX%"/libs/python%MY_PY_VER%.lib ^
-DBOOST_LIBRARYDIR="%LIBRARY_PREFIX%\lib" ^
-DBOOST_INCLUDEDIR="%LIBRARY_PREFIX%\include" ^
-DOCC_INCLUDE_DIR="%LIBRARY_PREFIX%\include\oce" ^
-DOCC_LIBRARY_DIR="%LIBRARY_PREFIX%\lib" ^
-DCOLLADA_SUPPORT=Off ^
-DBUILD_EXAMPLES=Off ^
-DBUILD_GEOMSERVER=Off ^
-DBUILD_CONVERT=Off ^
../cmake
if errorlevel 1 exit 1
cmake --build . --target INSTALL --config Release
if errorlevel 1 exit 1
+34
View File
@@ -0,0 +1,34 @@
# From https://github.com/tpaviot/pythonocc-core/blob/master/ci/conda/build.sh
if [ "$PY3K" == "1" ]; then
MY_PY_VER="${PY_VER}m"
else
MY_PY_VER="${PY_VER}"
fi
if [ `uname` == Darwin ]; then
PY_LIB="libpython${MY_PY_VER}.dylib"
export CFLAGS="$CFLAGS -Wl,-flat_namespace,-undefined,suppress"
export CXXFLAGS="$CXXFLAGS -Wl,-flat_namespace,-undefined,suppress"
export LDFLAGS="$LDFLAGS -Wl,-flat_namespace,-undefined,suppress"
else
PY_LIB="libpython${MY_PY_VER}.so"
fi
mkdir build && cd build
cmake \
-DCMAKE_INSTALL_PREFIX=$PREFIX \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH=$PREFIX \
-DCMAKE_SYSTEM_PREFIX_PATH=$PREFIX \
-DOCC_INCLUDE_DIR=$PREFIX/include/oce \
-DOCC_LIBRARY_DIR=$PREFIX/lib \
-DPYTHON_EXECUTABLE:FILEPATH=$PYTHON \
-DPYTHON_INCLUDE_DIR:PATH=$PREFIX/include/python$MY_PY_VER \
-DPYTHON_LIBRARY:FILEPATH=$PREFIX/lib/${PY_LIB} \
-DCOLLADA_SUPPORT=Off \
../cmake
make -j$CPU_COUNT _ifcopenshell_wrapper
cd ifcwrap
make install/local
+36
View File
@@ -0,0 +1,36 @@
package:
name: ifcopenshell
version: "0.6.0a1"
source:
git_rev: "v0.6.0a1"
git_url: https://github.com/IfcOpenShell/IfcOpenShell
build:
number: 0
features:
- vc9 # [win and py27]
- vc10 # [win and py34]
- vc14 # [win and py35]
- vc14 # [win and py36]
requirements:
build:
- gcc # [osx]
- make
- python
- oce ==0.18.3
- cmake
- swig >=3.0.9
- libboost
- icu
run:
- libgcc # [osx]
- python
- oce ==0.18.3
- libboost
- icu
about:
home: http://ifcopenshell.org
license: LGPL
+825
View File
@@ -0,0 +1,825 @@
#!/usr/bin/python
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
###############################################################################
# #
# This script builds IfcOpenShell and its dependencies #
# #
# Prerequisites for this script to function correctly: #
# * git * bzip2 * tar * c(++) compilers * yacc * autoconf #
# #
# if building with USE_OCCT additionally: #
# * freetype * glx.h #
# #
# if building with -shared #
# * libgl1-mesa-dev libxext-dev libxmu-dev libxmu-headers libxi-dev #
# #
# for python37 to install correctly additionally: #
# * libffi(-dev[el]) #
# #
# on debian 7.8 these can be obtained with: #
# $ apt-get install git gcc g++ autoconf bison bzip2 #
# libfreetype6-dev mesa-common-dev libffi-dev #
# #
# on ubuntu 14.04: #
# $ apt-get install git gcc g++ autoconf bison make #
# libfreetype6-dev mesa-common-dev libffi-dev #
# #
# on OS X El Capitan with homebrew: #
# $ brew install git bison autoconf automake freetype libffi #
# #
###############################################################################
from __future__ import print_function
import logging
import os
import sys
import subprocess as sp
import shutil
import time
import tarfile
import multiprocessing
PYTHON_MAJOR = sys.version_info[0]
if PYTHON_MAJOR >= 3:
from urllib.request import urlretrieve
else:
# Not Python 3 - today, it is most likely to be Python 2
# But note that this might need an update when Python 4
# might be around one day
from urllib import urlretrieve
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
logger.addHandler(ch)
PROJECT_NAME="IfcOpenShell"
PYTHON_VERSIONS=["2.7.16", "3.2.6", "3.3.6", "3.4.6", "3.5.3", "3.6.2", "3.7.3"]
JSON_VERSION="v3.6.1"
OCE_VERSION="0.18"
# OCCT_VERSION="7.1.0"
# OCCT_HASH="89aebde"
# OCCT_VERSION="7.2.0"
# OCCT_HASH="88af392"
OCCT_VERSION="7.3.0p3"
BOOST_VERSION="1.69.0"
#PCRE_VERSION="8.39"
PCRE_VERSION="8.41"
#LIBXML2_VERSION="2.9.3"
LIBXML2_VERSION="2.9.9"
CMAKE_VERSION="3.4.1"
#CMAKE_VERSION="3.14.5"
SWIG_VERSION="3.0.12"
#SWIG_VERSION="4.0.0"
#OPENCOLLADA_VERSION="v1.6.63"
OPENCOLLADA_VERSION="v1.6.68"
GMP_VERSION="6.1.2"
MPFR_VERSION="3.1.5"
CGAL_VERSION="4.13"
# binaries
cp="cp"
bash="bash"
uname="uname"
git="git"
bunzip2="bunzip2"
tar="tar"
cc="cc"
cplusplus="c++"
autoconf="autoconf"
automake="automake"
yacc="yacc"
make="make"
date = "date"
curl="curl"
wget="wget"
strip="strip"
# Helper function for coloured printing
NO_COLOR="\033[0m" # <ref>http://stackoverflow.com/questions/5947742/how-to-change-the-output-color-of-echo-in-linux</ref>
BLACK_ON_WHITE="\033[0;30;107m"
RED="\033[31m"
GREEN="\033[32m"
YELLOW="\033[33m"
MAGENTA="\033[35m"
def cecho(message, color=NO_COLOR):
"""Logs message `message` in color `color`."""
logger.info("%s%s\033[0m" % (color, message))
def which(cmd):
for path in os.environ["PATH"].split(":"):
if os.path.exists(path) and cmd in os.listdir(path):
return cmd
return None
def get_os():
ret_value = sp.check_output([uname, "-s"]).strip()
return ret_value
def to_pystring(x):
""" Python 2 & 3 compatibility function for strings handling
(to solve TypeError "Can't mix strings and bytes in path components" for Python 3).
Reference https://github.com/hugsy/gef/issues/382 """
res = str(x, encoding="utf-8") if PYTHON_MAJOR == 3 else x
substs = [("\n","\\n"), ("\r","\\r"), ("\t","\\t"), ("\v","\\v"), ("\b","\\b"), ]
for x,y in substs: res = res.replace(x,y)
return res
# Set defaults for missing empty environment variables
USE_OCCT = os.environ.get("USE_OCCT", "true").lower() == "true"
TOOLSET = None
if get_os() == "Darwin":
# C++11 features used in OCCT 7+ need a more recent stdlib
TOOLSET = "10.9" if USE_OCCT else "10.6"
try:
IFCOS_NUM_BUILD_PROCS = os.environ["IFCOS_NUM_BUILD_PROCS"]
except KeyError:
IFCOS_NUM_BUILD_PROCS=multiprocessing.cpu_count() + 1
try:
TARGET_ARCH = os.environ["TARGET_ARCH"]
except KeyError:
TARGET_ARCH = sp.check_output([uname, "-m"]).strip()
CMAKE_DIR=os.path.realpath(os.path.join("..", "cmake"))
try:
DEPS_DIR = os.environ["DEPS_DIR"]
except KeyError:
path = [b"..", b"build", sp.check_output(uname).strip(), TARGET_ARCH]
if TOOLSET:
path.append(TOOLSET)
DEPS_DIR = to_pystring(os.path.realpath(os.path.join(*path)))
if not os.path.exists(DEPS_DIR):
os.makedirs(DEPS_DIR)
try:
BUILD_CFG=os.environ["BUILD_CFG"]
except KeyError:
BUILD_CFG="RelWithDebInfo"
# Print build configuration information
cecho ("""This script fetches and builds %s and its dependencies
""" % (PROJECT_NAME,), BLACK_ON_WHITE)
cecho("""Script configuration:
""", GREEN)
cecho("""* Target Architecture = %s""" % (TARGET_ARCH,), MAGENTA)
cecho(" - Whether 32-bit (i686) or 64-bit (x86_64) will be built.")
cecho("""* USE_OCCT = %r""" % (USE_OCCT,), MAGENTA)
if USE_OCCT:
cecho(" - Compiling against official Open Cascade")
else:
cecho(" - Compiling against Open Cascade Community Edition")
cecho("* Dependency Directory = %s" % (DEPS_DIR,), MAGENTA)
cecho(" - The directory where %s dependencies are installed." % (PROJECT_NAME,))
cecho("* Build Config Type = %s" % (BUILD_CFG,), MAGENTA)
cecho(""" - The used build configuration type for the dependencies.
Defaults to RelWithDebInfo if not specified.""")
if BUILD_CFG == "MinSizeRel":
cecho(" WARNING: MinSizeRel build can suffer from a significant performance loss.", RED)
cecho("* IFCOS_NUM_BUILD_PROCS = %s" % (IFCOS_NUM_BUILD_PROCS,), MAGENTA)
cecho(""" - How many compiler processes may be run in parallel.
""")
dependency_tree = {
'IfcParse': ('boost', 'libxml2'),
'IfcGeom': ('IfcParse', 'occ', 'cgal', 'voxel'),
'IfcConvert': ('IfcGeom', 'OpenCOLLADA', 'json'),
'OpenCOLLADA': ('libxml2', 'pcre'),
'IfcGeomServer': ('IfcGeom', ),
'IfcOpenShell-Python': ('python', 'swig', 'IfcGeom'),
'voxel': ('occ',),
'swig': ('pcre',),
'boost': (),
'libxml2': (),
'python': (),
'swig': (),
'occ': (),
'cgal': (),
'pcre': (),
'json': ()
}
def v(dep):
yield dep
for d in dependency_tree[dep]:
for x in v(d):
yield x
tgts = [s for s in sys.argv[1:] if not s.startswith("-")]
flags = set(s for s in sys.argv[1:] if s.startswith("-"))
BUILD_STATIC = not "-shared" in flags
ENABLE_FLAG = "--enable-static" if BUILD_STATIC else "--enable-shared"
DISABLE_FLAG = "--disable-shared" if BUILD_STATIC else "--disable-static"
LINK_TYPE = "static" if BUILD_STATIC else "shared"
LINK_TYPE_UCFIRST = LINK_TYPE[0].upper() + LINK_TYPE[1:]
LIBRARY_EXT = "a" if BUILD_STATIC else "so"
PIC = "-fPIC" if BUILD_STATIC else ""
if len(tgts):
targets = set(sum((list(v(target)) for target in tgts), []))
else:
targets = set(dependency_tree.keys())
print("Building:", *sorted(targets, key=lambda t: len(list(v(t)))))
# Check that required tools are in PATH
for cmd in [git, bunzip2, tar, cc, cplusplus, autoconf, automake, yacc, make, "patch", "m4"]:
if which(cmd) is None:
raise ValueError("Required tool '%s' not installed or not added to PATH" % (cmd,))
# identifiers for the download tool (could be less memory consuming as ints, but are more verbose as strings)
download_tool_default = download_tool_py = "py"
download_tool_git = "git"
# Create log directory and file
log_dir = os.path.join(DEPS_DIR, "logs")
if not os.path.exists(log_dir):
os.makedirs(log_dir)
LOG_FILE="%s.log" % (os.path.join(log_dir, to_pystring(sp.check_output([date, "+%Y%m%d"]).strip())),)
if not os.path.exists(LOG_FILE):
open(LOG_FILE, "w").close()
logger.info("using command log file '%s'" % (LOG_FILE,))
def run(cmds, cwd=None):
"""
Wraps `subprocess.Popen.communicate()` and logs the command being executed,
sets up logging `stderr` to `LOG_FILE` (in append mode) and returns stdout
with leading and trailing whitespace removed.
"""
logger.debug("running command %r in directory %r" % (" ".join(cmds), cwd))
log_file_handle = open(LOG_FILE, "ab")
proc = sp.Popen(cmds, cwd=cwd, stdout=sp.PIPE, stderr=sp.PIPE)
stdout, stderr = proc.communicate()
log_file_handle.write(stdout)
log_file_handle.write(stderr)
log_file_handle.close()
logger.debug("command returned %r" % proc.returncode)
if proc.returncode != 0:
print("-" * 70)
print(stderr)
print("-" * 70)
raise Exception("Command `%s` returned exit code %d" % (" ".join(cmds), proc.returncode))
return stdout.strip()
BOOST_VERSION_UNDERSCORE=BOOST_VERSION.replace(".", "_")
CMAKE_VERSION_2=CMAKE_VERSION[:CMAKE_VERSION.rindex('.')]
OCE_LOCATION="https://github.com/tpaviot/oce/archive/OCE-%s.tar.gz" % (OCE_VERSION,)
BOOST_LOCATION="http://downloads.sourceforge.net/project/boost/boost/%s/boost_%s.tar.bz2" % (BOOST_VERSION, BOOST_VERSION_UNDERSCORE)
# Helper functions
def run_autoconf(arg1, configure_args, cwd):
configure_path = os.path.realpath(os.path.join(cwd, "..", "configure"))
install_dir = os.path.realpath("%s/install/%s" % (DEPS_DIR, arg1))
if not os.path.exists(install_dir):
# Some (MPFR) need to have prefix dir manually created
os.makedirs(install_dir)
if not os.path.exists(configure_path):
run([bash, "./autogen.sh"], cwd=os.path.realpath(os.path.join(cwd, ".."))) # only run autogen.sh in the directory it is located and use cwd to achieve that in order to not mess up things
# Using `sh` over `bash` fixes issues with building swig
run(["/bin/sh", "../configure"]+configure_args+["--prefix=%s" % install_dir], cwd=cwd)
def run_cmake(arg1, cmake_args, cmake_dir=None, cwd=None):
if cmake_dir is None:
P=".."
else:
P=cmake_dir
cmake_path= os.path.join(DEPS_DIR, "install", "cmake-%s" % (CMAKE_VERSION,), "bin", "cmake")
run([cmake_path, P]+cmake_args+["-DCMAKE_BUILD_TYPE=%s" % (BUILD_CFG,)], cwd=cwd)
def git_clone_or_pull_repository(clone_url, target_dir, revision=None):
"""Lazily clones the `git` repository denoted by `clone_url` into
the `target_dir` or pulls latest changes if the `target_dir` exists (naively assumes
that a working clone exists there) and optionally checks out a revision
`revision` after cloning or in the existing clone if `revision` is not
`None`."""
if not os.path.exists(target_dir):
logger.info("cloning '%s' into '%s'" % (clone_url, target_dir))
run([git, "clone", clone_url, target_dir])
else:
logger.info("directory '%s' already cloned. Pulling latest changes." % (target_dir,))
# detect whether we are on a branch and pull
if run([git, "rev-parse", "--abbrev-ref", "HEAD"], cwd=target_dir) != "HEAD":
run([git, "pull", clone_url], cwd=target_dir)
if revision != None:
run([git, "checkout", revision], cwd=target_dir)
def build_dependency(name, mode, build_tool_args, download_url, download_name, download_tool=download_tool_default, revision=None, patch=None, additional_files={}, no_append_name=False):
"""Handles building of dependencies with different tools (which are
distinguished with the `mode` argument. `build_tool_args` is expected to be
a list which is necessary in order to not mess up quoting of compiler and
linker flags."""
check_dir = os.path.join(DEPS_DIR, "install", name)
if os.path.exists(check_dir):
logger.info( "Found existing %s, skipping" % (name,))
return
build_dir = os.path.join(DEPS_DIR, "build")
if not os.path.exists(build_dir):
os.makedirs(build_dir)
logger.info("\rFetching %s... " % (name,))
if download_tool == download_tool_py:
if no_append_name:
url = download_url
else:
url = os.path.join(download_url, download_name)
download_path = os.path.join(build_dir, download_name)
if not os.path.exists(download_path):
urlretrieve(url, os.path.join(build_dir, download_path))
else:
logger.info("Download '%s' already exists, assuming it's an undamaged download and that it has been extracted if possible, skipping" % (download_path,))
elif download_tool == download_tool_git:
logger.info("\rChecking %s... " % (name,))
git_clone_or_pull_repository(download_url, target_dir=os.path.join(build_dir, download_name), revision=revision)
else:
raise ValueError("download tool '%s' is not supported" % (download_tool,))
download_dir = os.path.join(build_dir, download_name)
if os.path.isdir(download_dir):
extract_dir_name=download_name
extract_dir = os.path.join(build_dir, extract_dir_name)
else:
download_tarfile_path = os.path.join(build_dir, download_name)
if download_name.endswith(".tar.gz") or download_name.endswith(".tgz"):
compr = "gz"
elif download_name.endswith(".tar.bz2"):
compr = "bz2"
else:
raise RuntimeError("fix source for new download type")
download_tarfile = tarfile.open(name=download_tarfile_path, mode="r:%s" % (compr,))
extract_dir_name= os.path.commonprefix(download_tarfile.getnames()) # tarfile seriously doesn't have a function to retrieve the root directory more easily
#run([tar, "--exclude=\"*/*\"", "-tf", download_name], cwd=build_dir).strip() no longer works
if extract_dir_name is None:
extract_dir_name= run([bash, "-c", "tar -tf %s 2> /dev/null | head -n 1 | cut -f1 -d /" % (download_name,)], cwd=build_dir)
extract_dir = os.path.join(build_dir, extract_dir_name)
if not os.path.exists(extract_dir):
run([tar, "-xf", download_name], cwd=build_dir)
for path, url in additional_files.items():
if not os.path.exists(path):
urlretrieve(url, os.path.join(extract_dir, path))
if patch is not None:
patch_abs = os.path.abspath(os.path.join(os.path.dirname(__file__), patch))
if os.path.exists(patch_abs):
try: run(["patch", "-p1", "--batch", "--forward", "-i", patch_abs], cwd=extract_dir)
except Exception as e:
# Assert that the patch has already been applied
run(["patch", "-p1", "--batch", "--reverse", "--dry-run", "-i", patch_abs], cwd=extract_dir)
if mode != "bjam":
extract_build_dir = os.path.join(extract_dir, "build")
if os.path.exists(extract_build_dir):
shutil.rmtree(extract_build_dir)
os.makedirs(extract_build_dir)
logger.info("\rConfiguring %s..." % (name,))
if mode == "autoconf":
run_autoconf(name, build_tool_args, cwd=extract_build_dir)
elif mode == "cmake":
run_cmake(name, build_tool_args, cwd=extract_build_dir)
else:
raise ValueError()
logger.info("\rBuilding %s... " % (name,))
run([make, "-j%s" % (IFCOS_NUM_BUILD_PROCS,)], cwd=extract_build_dir)
logger.info( "\rInstalling %s... " % (name,))
run([make, "install"], cwd=extract_build_dir)
logger.info( "\rInstalled %s \n" % (name,))
else:
logger.info( "\rConfiguring %s..." % (name,))
run([bash, "./bootstrap.sh"], cwd=extract_dir)
logger.info("\rBuilding %s... " % (name,))
run(["./b2", "-j%s" % (IFCOS_NUM_BUILD_PROCS,)]+build_tool_args, cwd=extract_dir)
logger.info("\rInstalling %s... " % (name,))
shutil.copytree(os.path.join(extract_dir, "boost"), os.path.join(DEPS_DIR, "install", "boost-%s" % BOOST_VERSION, "boost"))
logger.info("\rInstalled %s \n" % (name,))
cecho("Collecting dependencies:", GREEN)
# Set compiler flags for 32bit builds on 64bit system
# TODO: This is untested
ADDITIONAL_ARGS=[]
BOOST_ADDRESS_MODEL=[]
if TARGET_ARCH == "i686" and run([uname, "-m"]).strip() == "x86_64":
ADDITIONAL_ARGS=["-m32", "-arch i386"]
BOOST_ADDRESS_MODEL=["architecture=x86", "address-model=32"]
if get_os() == "Darwin":
ADDITIONAL_ARGS=["-mmacosx-version-min=%s" % TOOLSET]+ADDITIONAL_ARGS
# If the linker supports GC sections, set it up to reduce binary file size
# -fPIC is required for the shared libraries to work
CXXFLAGS=os.environ.get("CXXFLAGS", "")
CFLAGS=os.environ.get("CFLAGS", "")
LDFLAGS=os.environ.get("LDFLAGS", "")
if sp.call([bash, "-c", "ld --gc-sections 2>&1 | grep -- --gc-sections &> /dev/null"]) != 0:
CXXFLAGS_MINIMAL="%s %s %s" % (CXXFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
CFLAGS_MINIMAL="%s %s %s" % (CFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
if BUILD_STATIC:
CXXFLAGS="%s %s -fdata-sections -ffunction-sections -fvisibility=hidden -fvisibility-inlines-hidden %s" % (CXXFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
CFLAGS="%s %s -fdata-sections -ffunction-sections -fvisibility=hidden %s"% (CFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
else:
CXXFLAGS=CXXFLAGS_MINIMAL
CFLAGS=CFLAGS_MINIMAL
LDFLAGS="%s -Wl,--gc-sections %s" % (LDFLAGS, str.join(" ", ADDITIONAL_ARGS))
else:
CXXFLAGS_MINIMAL="%s %s %s" % (CXXFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
CFLAGS_MINIMAL="%s %s %s" % (CFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
if BUILD_STATIC:
CXXFLAGS="%s %s -fvisibility=hidden -fvisibility-inlines-hidden %s" % (CXXFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
CFLAGS="%s %s -fvisibility=hidden -fvisibility-inlines-hidden %s" % (CFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
else:
CXXFLAGS=CXXFLAGS_MINIMAL
CFLAGS=CFLAGS_MINIMAL
LDFLAGS="%s %s" % (LDFLAGS, str.join(" ", ADDITIONAL_ARGS))
os.environ["CXXFLAGS"] = CXXFLAGS
os.environ["CFLAGS"] = CFLAGS
os.environ["LDFLAGS"] = LDFLAGS
# Some dependencies need a more recent CMake version than most distros provide
build_dependency(name="cmake-%s" % (CMAKE_VERSION,), mode="autoconf", build_tool_args=[], download_url="https://cmake.org/files/v%s" % (CMAKE_VERSION_2,), download_name="cmake-%s.tar.gz" % (CMAKE_VERSION,))
# Extract compiler flags from CMake to harmonize settings with other autoconf dependencies
CMAKE_FLAG_EXTRACT_DIR="ifcopenshell_cmake_test_%s" % (time.time(),)
# was sp.check_output([bash, "-c", "cat /dev/urandom | env LC_CTYPE=C tr -dc 'a-zA-Z0-9' | head -c 32"]), in bash script, unclear what the exact required format is and whether it's needed
if os.path.exists(CMAKE_FLAG_EXTRACT_DIR):
shutil.rmtree(CMAKE_FLAG_EXTRACT_DIR)
os.makedirs(CMAKE_FLAG_EXTRACT_DIR)
BUILD_CFG_UPPER=BUILD_CFG.upper()
for FL in ["C", "CXX"]:
run([bash, "-c", """echo "
message(\"\${CMAKE_%s_FLAGS_%s}\")
" > CMakeLists.txt""" % (FL, BUILD_CFG_UPPER)], cwd=CMAKE_FLAG_EXTRACT_DIR)
FL="%sFLAGS" % (FL,)
FLM="%sFLAGS_MINIMAL" % (FL,)
# @TODO: bash code unclear
# exec("%sFLAGS=%s" % (FL, sp.check_output([os.path.join(DEPS_DIR, "install", "cmake-%s" % (CMAKE_VERSION,), "bin", "cmake"), "."
# declare ${FL}FLAGS_MINIMAL="`$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake . 2>&1 >/dev/null` ${!FLM}"
shutil.rmtree(CMAKE_FLAG_EXTRACT_DIR)
if "json" in targets:
json_url = "https://github.com/nlohmann/json/releases/download/{JSON_VERSION}/json.hpp".format(**locals())
json_install_path = "{DEPS_DIR}/install/json/nlohmann/json.hpp".format(**locals())
if not os.path.exists(os.path.dirname(json_install_path)):
os.makedirs(os.path.dirname(json_install_path))
if not os.path.exists(json_install_path):
urlretrieve(json_url, json_install_path)
if "pcre" in targets:
build_dependency(
name="pcre-{PCRE_VERSION}".format(**locals()),
mode="autoconf",
build_tool_args=[DISABLE_FLAG],
download_url="https://downloads.sourceforge.net/project/pcre/pcre/{PCRE_VERSION}/".format(**locals()),
download_name="pcre-{PCRE_VERSION}.tar.bz2".format(**locals())
)
# An issue exists with swig-1.3 and python >= 3.2
# Therefore, build a recent copy from source
if "swig" in targets:
build_dependency(
name="swig",
mode="autoconf",
build_tool_args=["--with-pcre-prefix={DEPS_DIR}/install/pcre-{PCRE_VERSION}".format(**locals())],
download_url="https://github.com/swig/swig.git",
download_name="swig",
download_tool=download_tool_git,
revision="rel-{SWIG_VERSION}".format(**locals())
)
if USE_OCCT and "occ" in targets:
build_dependency(
name="occt-{OCCT_VERSION}".format(**locals()),
mode="cmake",
build_tool_args=[
"-DINSTALL_DIR={DEPS_DIR}/install/occt-{OCCT_VERSION}".format(**locals()),
"-DBUILD_LIBRARY_TYPE={LINK_TYPE_UCFIRST}".format(**locals()),
"-DBUILD_MODULE_Draw=0",
],
download_url = "https://git.dev.opencascade.org/repos/occt.git",
download_name = "occt",
download_tool=download_tool_git,
patch="./patches/occt/enable-exception-handling.patch",
revision="V" + OCCT_VERSION.replace('.', '_')
)
occ_include_dir = "{DEPS_DIR}/install/occt-{OCCT_VERSION}/include/opencascade".format(**locals())
occ_library_dir = "{DEPS_DIR}/install/occt-{OCCT_VERSION}/lib".format(**locals())
elif "occ" in targets:
build_dependency(
name="oce-{OCE_VERSION}".format(**locals()),
mode="cmake",
build_tool_args=[
"-DOCE_DISABLE_TKSERVICE_FONT=ON",
"-DOCE_TESTING=OFF",
"-DOCE_BUILD_SHARED_LIB=OFF",
"-DOCE_DISABLE_X11=ON",
"-DOCE_VISUALISATION=OFF",
"-DOCE_OCAF=OFF",
"-DOCE_INSTALL_PREFIX={DEPS_DIR}/install/oce-{OCE_VERSION}".format(**locals())
],
download_url="https://github.com/tpaviot/oce/archive/",
download_name="OCE-{OCE_VERSION}.tar.gz".format(**locals())
)
occ_include_dir = "{DEPS_DIR}/install/oce-{OCE_VERSION}/include/oce".format(**locals())
occ_library_dir = "{DEPS_DIR}/install/oce-{OCE_VERSION}/lib"
if "libxml2" in targets:
build_dependency(
"libxml2-{LIBXML2_VERSION}".format(**locals()),
"autoconf",
build_tool_args=[
"--without-python",
ENABLE_FLAG,
DISABLE_FLAG,
"--without-zlib",
"--without-iconv",
"--without-lzma"
],
download_url="ftp://xmlsoft.org/libxml2/",
download_name="libxml2-{LIBXML2_VERSION}.tar.gz".format(**locals())
)
if "OpenCOLLADA" in targets:
build_dependency(
"OpenCOLLADA",
"cmake",
build_tool_args=[
"-DLIBXML2_INCLUDE_DIR={DEPS_DIR}/install/libxml2-{LIBXML2_VERSION}/include/libxml2".format(**locals()),
"-DLIBXML2_LIBRARIES={DEPS_DIR}/install/libxml2-{LIBXML2_VERSION}/lib/libxml2.{LIBRARY_EXT}".format(**locals()),
"-DPCRE_INCLUDE_DIR={DEPS_DIR}/install/pcre-{PCRE_VERSION}/include".format(**locals()),
"-DPCRE_PCREPOSIX_LIBRARY={DEPS_DIR}/install/pcre-{PCRE_VERSION}/lib/libpcreposix.{LIBRARY_EXT}".format(**locals()),
"-DPCRE_PCRE_LIBRARY={DEPS_DIR}/install/pcre-{PCRE_VERSION}/lib/libpcre.{LIBRARY_EXT}".format(**locals()),
"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/OpenCOLLADA/".format(**locals())
],
download_url="https://github.com/KhronosGroup/OpenCOLLADA.git",
download_name="OpenCOLLADA",
download_tool=download_tool_git,
revision=OPENCOLLADA_VERSION
)
if "python" in targets:
# Python should not be built with -fvisibility=hidden, from experience that introduces segfaults
OLD_CXX_FLAGS=os.environ["CXXFLAGS"]
OLD_C_FLAGS=os.environ["CFLAGS"]
os.environ["CXXFLAGS"]=CXXFLAGS_MINIMAL
os.environ["CFLAGS"]=CFLAGS_MINIMAL
# On OSX a dynamic python library is built or it would not be compatible
# with the system python because of some threading initialization
PYTHON_CONFIGURE_ARGS=[]
if get_os() == "Darwin":
PYTHON_CONFIGURE_ARGS=["--disable-static", "--enable-shared"]
def get_python_unicode_confs(py_ver):
if py_ver < "3.3":
return [("--enable-unicode=ucs2",""), ("--enable-unicode=ucs4","u")]
else: return [("","")]
def PYTHON_VERSION_CONFS():
for v in PYTHON_VERSIONS:
for unicode_conf, abi_tag in get_python_unicode_confs(v):
yield v, unicode_conf, abi_tag
for PYTHON_VERSION, unicode_conf, abi_tag in PYTHON_VERSION_CONFS():
build_dependency(
"python-{PYTHON_VERSION}{abi_tag}".format(**locals()),
"autoconf",
PYTHON_CONFIGURE_ARGS + [unicode_conf],
"http://www.python.org/ftp/python/{PYTHON_VERSION}/".format(**locals()),
"Python-{PYTHON_VERSION}.tgz".format(**locals())
)
os.environ["CXXFLAGS"]=OLD_CXX_FLAGS
os.environ["CFLAGS"]=OLD_C_FLAGS
if "boost" in targets:
str_concat = lambda prefix: lambda postfix: "" if postfix.strip() == "" else "=".join((prefix, postfix.strip()))
build_dependency(
"boost-{BOOST_VERSION}".format(**locals()),
mode="bjam",
build_tool_args=[
"--stagedir={DEPS_DIR}/install/boost-{BOOST_VERSION}".format(**locals()),
"--with-system",
"--with-program_options",
"--with-regex",
"--with-thread",
"--with-date_time",
"--with-iostreams",
"link={LINK_TYPE}".format(**locals())
] + \
BOOST_ADDRESS_MODEL + \
list(map(str_concat("cxxflags"), CXXFLAGS.strip().split(' '))) + \
list(map(str_concat("linkflags"), LDFLAGS.strip().split(' '))) + \
["stage", "-s", "NO_BZIP2=1"],
download_url="http://downloads.sourceforge.net/project/boost/boost/{BOOST_VERSION}/".format(**locals()),
download_name="boost_{BOOST_VERSION_UNDERSCORE}.tar.bz2".format(**locals())
)
if "cgal" in targets:
build_dependency(name="gmp-%s" % (GMP_VERSION,), mode="autoconf", build_tool_args=["--disable-shared", "--with-pic"], download_url="https://ftp.gnu.org/gnu/gmp/", download_name="gmp-%s.tar.bz2" % (GMP_VERSION,))
build_dependency(name="mpfr-%s" % (MPFR_VERSION,), mode="autoconf", build_tool_args=["--disable-shared", "--with-gmp=%s/install/gmp-%s" % (DEPS_DIR, GMP_VERSION)], download_url="http://www.mpfr.org/mpfr-%s/" % (MPFR_VERSION,), download_name="mpfr-%s.tar.bz2" % (MPFR_VERSION,))
OLD_BUILD_CFG = BUILD_CFG
if BUILD_CFG != "Debug":
# CGAL only supports Debug and Release for CMAKE_BUILD_TYPE
BUILD_CFG = "Release"
build_dependency(name="cgal-{CGAL_VERSION}".format(**locals()), mode="cmake", build_tool_args=["-DGMP_LIBRARIES=%s/install/gmp-%s/lib/libgmp.a" % (DEPS_DIR, GMP_VERSION), "-DGMP_INCLUDE_DIR=%s/install/gmp-%s/include" % (DEPS_DIR, GMP_VERSION), "-DMPFR_LIBRARIES=%s/install/mpfr-%s/lib/libmpfr.a" % (DEPS_DIR, MPFR_VERSION), "-DMPFR_INCLUDE_DIR=%s/install/mpfr-%s/include" % (DEPS_DIR, MPFR_VERSION), "-DBoost_INCLUDE_DIR=%s/install/boost-%s" % (DEPS_DIR, BOOST_VERSION), "-DCMAKE_INSTALL_PREFIX=%s/install/cgal-%s/" % (DEPS_DIR, CGAL_VERSION), "-DBUILD_SHARED_LIBS=Off"], download_url="https://github.com/CGAL/cgal.git", download_name="cgal", download_tool=download_tool_git, revision="releases/CGAL-{CGAL_VERSION}".format(**locals()))
BUILD_CFG = OLD_BUILD_CFG
if "voxel" in targets:
build_dependency(
"voxel",
"cmake",
build_tool_args=[
"-DIFC_SUPPORT=Off",
"-DOCC_INCLUDE_DIR=" +occ_include_dir,
"-DOCC_LIBRARY_DIR=" +occ_library_dir,
"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/voxel".format(**locals()),
"-DBOOST_ROOT=" "{DEPS_DIR}/install/boost-{BOOST_VERSION}".format(**locals())
],
download_url="https://github.com/opensourceBIM/voxel.git",
download_name="voxel",
download_tool=download_tool_git,
revision="master"
)
cecho("Building IfcOpenShell:", GREEN)
IFCOS_DIR=os.path.join(DEPS_DIR, "build", "ifcopenshell")
if os.path.exists(IFCOS_DIR):
shutil.rmtree(IFCOS_DIR)
os.makedirs(IFCOS_DIR)
executables_dir = os.path.join(IFCOS_DIR, "executables")
if not os.path.exists(executables_dir):
os.makedirs(executables_dir)
logger.info("\rConfiguring executables...")
OFF_ON = ["OFF", "ON"]
cmake_args=[
"-DUSE_MMAP=" "OFF",
"-DBUILD_EXAMPLES=" "OFF",
"-DBUILD_IFCPYTHON=" "OFF",
"-DBUILD_SHARED_LIBS=" +OFF_ON[not BUILD_STATIC],
"-DBUILD_IFCGEOM=" +OFF_ON["IfcGeom" in targets],
"-DBUILD_GEOMSERVER=" +OFF_ON["IfcGeomServer" in targets],
"-DBUILD_CONVERT=" +OFF_ON["IfcConvert" in targets],
"-DCMAKE_INSTALL_PREFIX=" "{DEPS_DIR}/install/ifcopenshell".format(**locals()),
"-DBOOST_ROOT=" "{DEPS_DIR}/install/boost-{BOOST_VERSION}".format(**locals()),
"-DGLTF_SUPPORT=" "ON",
"-DJSON_INCLUDE_DIR=" "{DEPS_DIR}/install/json".format(**locals())
]
if "occ" in targets:
cmake_args.extend([
"-DOCC_INCLUDE_DIR=" +occ_include_dir,
"-DOCC_LIBRARY_DIR=" +occ_library_dir
])
elif "occ" in targets:
cmake_args.extend([
"-DOCC_INCLUDE_DIR=" +occ_include_dir,
"-DOCC_LIBRARY_DIR=" +occ_library_dir
])
if "cgal" in targets:
cmake_args.extend([
"-DCGAL_INCLUDE_DIR=" "{DEPS_DIR}/install/cgal-{CGAL_VERSION}/include".format(**locals()),
"-DCGAL_LIBRARY_DIR=" "{DEPS_DIR}/install/cgal-{CGAL_VERSION}/lib".format(**locals()),
"-DGMP_INCLUDE_DIR=" "{DEPS_DIR}/install/gmp-{GMP_VERSION}/include".format(**locals()),
"-DGMP_LIBRARY_DIR=" "{DEPS_DIR}/install/gmp-{GMP_VERSION}/lib".format(**locals()),
"-DMPFR_INCLUDE_DIR=" "{DEPS_DIR}/install/mpfr-{MPFR_VERSION}/include".format(**locals()),
"-DMPFR_LIBRARY_DIR=" "{DEPS_DIR}/install/mpfr-{MPFR_VERSION}/lib".format(**locals())
])
if "OpenCOLLADA" in targets:
cmake_args.extend([
"-DOPENCOLLADA_INCLUDE_DIR=" "{DEPS_DIR}/install/OpenCOLLADA/include/opencollada".format(**locals()),
"-DOPENCOLLADA_LIBRARY_DIR=" "{DEPS_DIR}/install/OpenCOLLADA/lib/opencollada".format(**locals())
])
if "pcre" in targets:
cmake_args.append(
"-DPCRE_LIBRARY_DIR=" "{DEPS_DIR}/install/pcre-{PCRE_VERSION}/lib".format(**locals())
)
if "libxml2" in targets:
cmake_args.extend([
"-DLIBXML2_INCLUDE_DIR=" "{DEPS_DIR}/install/libxml2-{LIBXML2_VERSION}/include/libxml2".format(**locals()),
"-DLIBXML2_LIBRARIES=" "{DEPS_DIR}/install/libxml2-{LIBXML2_VERSION}/lib/libxml2.{LIBRARY_EXT}".format(**locals())
])
run_cmake("", cmake_args, cmake_dir=CMAKE_DIR, cwd=executables_dir)
logger.info("\rBuilding executables... ")
run([make, "-j{IFCOS_NUM_BUILD_PROCS}".format(**locals())], cwd=executables_dir)
run([make, "install/strip" if BUILD_CFG == "Release" else "install"], cwd=executables_dir)
if "IfcOpenShell-Python" in targets:
# On OSX the actual Python library is not linked against.
ADDITIONAL_ARGS=""
if get_os() == "Darwin":
ADDITIONAL_ARGS="-Wl,-flat_namespace,-undefined,suppress"
os.environ["CXXFLAGS"]="%s %s" % (CXXFLAGS_MINIMAL, ADDITIONAL_ARGS)
os.environ["CFLAGS"]="%s %s" % (CFLAGS_MINIMAL, ADDITIONAL_ARGS)
os.environ["LDFLAGS"]="%s %s" % (LDFLAGS, ADDITIONAL_ARGS)
for PYTHON_VERSION, _, TAG in PYTHON_VERSION_CONFS():
logger.info("\rConfiguring python {PYTHON_VERSION}{TAG} wrapper...".format(**locals()))
python_dir = os.path.join(IFCOS_DIR, "python-{PYTHON_VERSION}{TAG}".format(**locals()))
if not os.path.exists(python_dir):
os.makedirs(python_dir)
PYTHON_LIBRARY=run([bash, "-c", "ls {DEPS_DIR}/install/python-{PYTHON_VERSION}{TAG}/lib/libpython*.*".format(**locals())])
PYTHON_INCLUDE=run([bash, "-c", "ls -d {DEPS_DIR}/install/python-{PYTHON_VERSION}{TAG}/include/python*".format(**locals())])
PYTHON_EXECUTABLE=os.path.join(DEPS_DIR, "install", "python-{PYTHON_VERSION}{TAG}".format(**locals()), "bin", "python{PYTHON_VERSION[0]}".format(**locals()))
os.environ["PYTHON_LIBRARY_BASENAME"]=os.path.basename(PYTHON_LIBRARY)
run_cmake("",
cmake_args=[
"-DBUILD_SHARED_LIBS=" "OFF" if BUILD_STATIC else "ON",
"-DBOOST_ROOT=" "{DEPS_DIR}/install/boost-{BOOST_VERSION}".format(**locals()),
"-DOCC_INCLUDE_DIR=" +occ_include_dir,
"-DOCC_LIBRARY_DIR=" +occ_library_dir,
"-DPYTHON_LIBRARY=" +PYTHON_LIBRARY,
"-DPYTHON_EXECUTABLE=" +PYTHON_EXECUTABLE,
"-DPYTHON_INCLUDE_DIR=" +PYTHON_INCLUDE,
"-DSWIG_EXECUTABLE=" "{DEPS_DIR}/install/swig/bin/swig".format(**locals()),
"-DCMAKE_INSTALL_PREFIX=" "{DEPS_DIR}/install/ifcopenshell/tmp".format(**locals()),
"-DLIBXML2_INCLUDE_DIR=" "{DEPS_DIR}/install/libxml2-{LIBXML2_VERSION}/include/libxml2".format(**locals()),
"-DLIBXML2_LIBRARIES=" "{DEPS_DIR}/install/libxml2-{LIBXML2_VERSION}/lib/libxml2.{LIBRARY_EXT}".format(**locals()),
"-DCOLLADA_SUPPORT=OFF"
], cmake_dir=CMAKE_DIR, cwd=python_dir)
logger.info("\rBuilding python %s%s wrapper... " % (PYTHON_VERSION, TAG))
run([make, "-j%s" % (IFCOS_NUM_BUILD_PROCS,), "_ifcopenshell_wrapper"], cwd=python_dir)
run([make, "install/local"], cwd=os.path.join(python_dir, "ifcwrap"))
module_dir = os.path.dirname(run([PYTHON_EXECUTABLE, "-c", "from __future__ import print_function; import inspect, ifcopenshell; print(inspect.getfile(ifcopenshell))"]))
if get_os() != "Darwin":
# TODO: This symbol name depends on the Python version?
run([strip, "-s", "-K", "PyInit__ifcopenshell_wrapper", "_ifcopenshell_wrapper.so"], cwd=module_dir)
run([cp, "-R", module_dir, os.path.join(DEPS_DIR, "install", "ifcopenshell", "python-%s%s" % (PYTHON_VERSION, TAG))])
logger.info("\rBuilt IfcOpenShell...\n\n")
+32
View File
@@ -0,0 +1,32 @@
http://git.dev.opencascade.org/gitweb/?p=occt.git;a=commitdiff;h=0ab4e621833f4eae945a3762c9a29ee12e2eec53#patch1
diff --git a/src/HLRBRep/HLRBRep_InternalAlgo.cxx b/src/HLRBRep/HLRBRep_InternalAlgo.cxx
index ca885ca..c13cb06 100644 (file)
--- a/src/HLRBRep/HLRBRep_InternalAlgo.cxx
+++ b/src/HLRBRep/HLRBRep_InternalAlgo.cxx
@@ -165,7 +165,7 @@ void HLRBRep_InternalAlgo::Update ()
SB.Bounds(v1,v2,e1,e2,f1,f2);
for (Standard_Integer e = e1; e <= e2; e++) {
- HLRBRep_EdgeData ed = aEDataArray.ChangeValue(e);
+ HLRBRep_EdgeData& ed = aEDataArray.ChangeValue(e);
HLRAlgo::DecodeMinMax(ed.MinMax(), TheMin, TheMax);
if (FirstTime) {
FirstTime = Standard_False;
@@ -307,7 +307,7 @@ void HLRBRep_InternalAlgo::InitEdgeStatus ()
Standard_Integer nf = myDS->NbFaces();
for (Standard_Integer e = 1; e <= ne; e++) {
- HLRBRep_EdgeData ed = aEDataArray.ChangeValue(e);
+ HLRBRep_EdgeData& ed = aEDataArray.ChangeValue(e);
if (ed.Selected()) ed.Status().ShowAll();
}
// for (Standard_Integer f = 1; f <= nf; f++) {
@@ -368,7 +368,7 @@ void HLRBRep_InternalAlgo::Select ()
Standard_Integer nf = myDS->NbFaces();
for (Standard_Integer e = 1; e <= ne; e++) {
- HLRBRep_EdgeData ed = aEDataArray.ChangeValue(e);
+ HLRBRep_EdgeData& ed = aEDataArray.ChangeValue(e);
ed.Selected(Standard_True);
}
@@ -0,0 +1,17 @@
Description: Enable exception handling
Upstream defaults to no exception handling for performance reasons,
but in OCCT's role as a shared library it's better for Debian to
enable it.
Author: Kurt Kremitzki <kkremitzki@gmail.com>
Last-Update: 2018-06-10
--- a/adm/cmake/occt_defs_flags.cmake
+++ b/adm/cmake/occt_defs_flags.cmake
@@ -138,5 +138,5 @@
set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s")
endif()
-set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNo_Exception")
-set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNo_Exception")
+#set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNo_Exception")
+#set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNo_Exception")
+27 -2
View File
@@ -1,5 +1,30 @@
################################################################################
# #
# 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)
set_target_properties(IfcParseExamples PROPERTIES FOLDER Examples)
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 ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES})
set_target_properties(IfcOpenHouse PROPERTIES FOLDER Examples)
ADD_EXECUTABLE(IfcAdvancedHouse IfcAdvancedHouse.cpp)
TARGET_LINK_LIBRARIES(IfcAdvancedHouse ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES})
set_target_properties(IfcAdvancedHouse PROPERTIES FOLDER Examples)
+177
View File
@@ -0,0 +1,177 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include <string>
#include <iostream>
#include <fstream>
#include <TColgp_Array2OfPnt.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <Geom_BSplineSurface.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepBuilderAPI_NurbsConvert.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <BRepAlgoAPI_Cut.hxx>
#include <Standard_Version.hxx>
#define IfcSchema Ifc2x3
#include "../ifcparse/macros.h"
#include "../ifcparse/Ifc2x3.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcHierarchyHelper.h"
#include "../ifcgeom/schema_agnostic/Serialization.h"
#if USE_VLD
#include <vld.h>
#endif
// The creation of Nurbs-surface for the IfcSite mesh, to be implemented lateron
void createGroundShape(TopoDS_Shape& shape);
int main() {
// The IfcHierarchyHelper is a subclass of the regular IfcFile that provides several
// convenience functions for working with geometry in IFC files.
IfcHierarchyHelper<IfcSchema> file;
file.header().file_name().name("IfcAdvancedHouse.ifc");
IfcSchema::IfcBuilding* building = file.addBuilding();
// By adding a building, a hierarchy has been automatically created that consists of the following
// structure: IfcProject > IfcSite > IfcBuilding
// Lateron changing the name of the IfcProject can be done by obtaining a reference to the
// project, which has been created automatically.
file.getSingle<IfcSchema::IfcProject>()->setName("IfcOpenHouse");
// To demonstrate the ability to serialize arbitrary opencascade solids a building envelope is
// constructed by applying boolean operations. Naturally, in IFC, building elements should be
// modeled separately, with rich parametric and relational semantics. Creating geometry in this
// way does not preserve any history and is merely a demonstration of technical capabilities.
TopoDS_Shape outer = BRepPrimAPI_MakeBox(gp_Pnt(-5000., -180., -2000.), gp_Pnt(5000., 5180., 3000.)).Shape();
TopoDS_Shape inner = BRepPrimAPI_MakeBox(gp_Pnt(-4640., 180., 0.), gp_Pnt(4640., 4820., 3000.)).Shape();
TopoDS_Shape window1 = BRepPrimAPI_MakeBox(gp_Pnt(-5000., -180., 400.), gp_Pnt( 500., 1180., 2000.)).Shape();
TopoDS_Shape window2 = BRepPrimAPI_MakeBox(gp_Pnt( 2070., -180., 400.), gp_Pnt(3930., 180., 2000.)).Shape();
TopoDS_Shape building_shell = BRepAlgoAPI_Cut(
BRepAlgoAPI_Cut(
BRepAlgoAPI_Cut(outer, inner),
window1
),
window2
);
// Since the solid consists only of planar faces and straight edges it can be serialized as an
// IfcFacetedBRep. If it would not be a polyhedron, serialise() can only be successful when linked
// to the IFC4 model and with `advanced` set to `true` which introduces IfcAdvancedFace. It would
// return `0` otherwise.
IfcSchema::IfcProductDefinitionShape* building_shape = IfcGeom::serialise(STRINGIFY(IfcSchema), building_shell, false)->as<IfcSchema::IfcProductDefinitionShape>();
file.addEntity(building_shape);
IfcSchema::IfcRepresentation* rep = *building_shape->Representations()->begin();
rep->setContextOfItems(file.getRepresentationContext("model"));
building->setRepresentation(building_shape);
// A pale white colour is assigned to the building.
file.setSurfaceColour(
building_shape, 0.75, 0.73, 0.68);
// For the ground mesh of the IfcSite we will use a Nurbs surface created in Open Cascade. Only
// in IFC4 the surface can be directly serialized. In IFC2X3 the it will have to be tesselated.
TopoDS_Shape shape;
createGroundShape(shape);
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::serialise(STRINGIFY(IfcSchema), shape, true)->as<IfcSchema::IfcProductDefinitionShape>();
if (!ground_representation) {
ground_representation = IfcGeom::tesselate(STRINGIFY(IfcSchema), shape, 100.)->as<IfcSchema::IfcProductDefinitionShape>();
}
file.getSingle<IfcSchema::IfcSite>()->setRepresentation(ground_representation);
IfcSchema::IfcRepresentation::list::ptr ground_reps = file.getSingle<IfcSchema::IfcSite>()->Representation()->Representations();
for (IfcSchema::IfcRepresentation::list::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
(*it)->setContextOfItems(file.getRepresentationContext("Model"));
}
file.addEntity(ground_representation);
file.setSurfaceColour(ground_representation, 0.15, 0.25, 0.05);
/*
// Note that IFC lacks elementary surfaces that STEP does have, such as spherical_surface.
// BRepBuilderAPI_NurbsConvert can be used to serialize such surfaces as nurbs surfaces.
TopoDS_Shape sphere = BRepPrimAPI_MakeSphere(gp_Pnt(), 1000.).Shape();
IfcSchema::IfcProductDefinitionShape* sphere_representation = IfcGeom::serialise(sphere, true);
if (S(IfcSchema::Identifier) == "IFC4") {
sphere = BRepBuilderAPI_NurbsConvert(sphere, true).Shape();
sphere_representation = IfcGeom::serialise(sphere, true);
}
*/
// Finally create a file stream for our output and write the IFC file to it.
std::ofstream f("IfcAdvancedHouse.ifc");
f << file;
}
void createGroundShape(TopoDS_Shape& shape) {
TColgp_Array2OfPnt cv (0, 4, 0, 4);
cv.SetValue(0, 0, gp_Pnt(-10000, -10000, -4130));
cv.SetValue(0, 1, gp_Pnt(-10000, -4330, -4130));
cv.SetValue(0, 2, gp_Pnt(-10000, 0, -5130));
cv.SetValue(0, 3, gp_Pnt(-10000, 4330, -7130));
cv.SetValue(0, 4, gp_Pnt(-10000, 10000, -7130));
cv.SetValue(1, 0, gp_Pnt( -3330, -10000, -5130));
cv.SetValue(1, 1, gp_Pnt( -7670, -3670, 5000));
cv.SetValue(1, 2, gp_Pnt( -9000, 0, 1000));
cv.SetValue(1, 3, gp_Pnt( -7670, 7670, 6000));
cv.SetValue(1, 4, gp_Pnt( -3330, 10000, -4130));
cv.SetValue(2, 0, gp_Pnt( 0, -10000, -5530));
cv.SetValue(2, 1, gp_Pnt( 0, -3670, 3000));
cv.SetValue(2, 2, gp_Pnt( 0, 0, -12000));
cv.SetValue(2, 3, gp_Pnt( 0, 7670, 1500));
cv.SetValue(2, 4, gp_Pnt( 0, 10000, -4130));
cv.SetValue(3, 0, gp_Pnt( 3330, -10000, -6130));
cv.SetValue(3, 1, gp_Pnt( 7670, -3670, 6000));
cv.SetValue(3, 2, gp_Pnt( 9000, 0, 5000));
cv.SetValue(3, 3, gp_Pnt( 7670, 9000, 7000));
cv.SetValue(3, 4, gp_Pnt( 3330, 10000, -4130));
cv.SetValue(4, 0, gp_Pnt( 10000, -10000, -6130));
cv.SetValue(4, 1, gp_Pnt( 10000, -4330, -5130));
cv.SetValue(4, 2, gp_Pnt( 10000, 0, -4130));
cv.SetValue(4, 3, gp_Pnt( 10000, 4330, -4130));
cv.SetValue(4, 4, gp_Pnt( 10000, 10000, -8130));
TColStd_Array1OfReal knots(0, 1);
knots(0) = 0;
knots(1) = 1;
TColStd_Array1OfInteger mult(0, 1);
mult(0) = 5;
mult(1) = 5;
Handle(Geom_BSplineSurface) surf = new Geom_BSplineSurface(cv, knots, knots, mult, mult, 4, 4);
#if OCC_VERSION_HEX < 0x60502
shape = BRepBuilderAPI_MakeFace(surf);
#else
shape = BRepBuilderAPI_MakeFace(surf, Precision::Confusion());
#endif
}
+73 -44
View File
@@ -28,33 +28,39 @@
#include <Geom_BSplineSurface.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <Standard_Version.hxx>
#ifdef USE_IFC4
#include "../ifcparse/Ifc4.h"
#else
#include "../ifcparse/Ifc2x3.h"
#endif
#include <BRepGProp.hxx>
#include <GProp_GProps.hxx>
#include "../ifcparse/IfcUtil.h"
#include <Precision.hxx>
#define IfcSchema Ifc2x3
#include "../ifcparse/macros.h"
#include "../ifcparse/Ifc2x3.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcHierarchyHelper.h"
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom/schema_agnostic/Serialization.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;
IfcHierarchyHelper<IfcSchema> file;
file.header().file_name().name("IfcOpenHouse.ifc");
// Start by adding a wall to the file, initially leaving most attributes blank.
@@ -195,45 +201,48 @@ int main(int argc, char** argv) {
file.addBuildingProduct(north_wall);
file.setSurfaceColour(north_wall->Representation(), wall_colour);
IfcSchema::IfcShapeRepresentation* clipped_wall_body_rep = file.addEmptyRepresentation();
file.addBox(clipped_wall_body_rep, 5000, 360, 6000);
// The east wall geometry is clipped using two IfcHalfSpaceSolids, created from an
// 'axis 3d placement' that specifies the plane against which the geometry is clipped.
file.clipRepresentation(clipped_wall_body_rep, file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false);
file.clipRepresentation(clipped_wall_body_rep, file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false);
// Two identical representations are created for the two remaining walls. Mapped items
// are not used, because it is not allowed by the standard for wall body representations.
// MappedItems are not allowed for Axis representations as per CV-2x3-161
IfcSchema::IfcProductDefinitionShape* clipped_wall_body_reps[2];
for (int i = 0; i < 2; ++i) {
IfcSchema::IfcShapeRepresentation* body = file.addEmptyRepresentation();
file.addBox(body, 5000, 360, 6000);
// The wall geometry is clipped using two IfcHalfSpaceSolids, created from an
// 'axis 3d placement' that specifies the plane against which the geometry is clipped.
file.clipRepresentation(body, file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false);
file.clipRepresentation(body, file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false);
file.setSurfaceColour(body, wall_colour);
IfcSchema::IfcShapeRepresentation* axis = file.addEmptyRepresentation("Axis", "Curve2D");
file.addAxis(axis, 5000);
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
reps->push(body);
reps->push(axis);
clipped_wall_body_reps[i] = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
}
// Now create a wall on the east of the building, again starting with just a box shape
IfcSchema::IfcWallStandardCase* east_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
S("East wall"), null, null, file.addLocalPlacement(storey_placement, 4820, 2500, 0, 0, 0, 1, 0, 1, 0), file.addMappedItem(clipped_wall_body_rep), 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);
file.setSurfaceColour(clipped_wall_body_rep, wall_colour);
// The east wall is copied to the west location of the house
IfcSchema::IfcWallStandardCase* west_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
S("West wall"), null, null, file.addLocalPlacement(storey_placement, -4820, 2500, 0, 0, 0, 1, 0, -1, 0), file.addMappedItem(clipped_wall_body_rep), null
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
);
file.addBuildingProduct(west_wall);
for (int i = 0; i < 2; ++i) {
// CV-2x3-161: MappedItems are not allowed for Axis representations
IfcSchema::IfcWallStandardCase* wall = i == 0 ? east_wall : west_wall;
IfcSchema::IfcShapeRepresentation* wall_axis_rep = file.addEmptyRepresentation("Axis", "Curve2D");
file.addAxis(wall_axis_rep, 5000);
IfcSchema::IfcRepresentation::list::ptr reps = wall->Representation()->Representations();
reps->push(wall_axis_rep);
wall->Representation()->setRepresentations(reps);
}
// The west wall is assigned an opening element we created for the south wall, opening elements are
// not shared accross building elements, even if they share the same representation. Hence, the east
// not shared across building elements, even if they share the same representation. Hence, the east
// wall will not feature this opening.
// NB: an Opening Element can only be used to create a single void within a single Element, as per:
// http://www.buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcproductextension/lexical/ifcfeatureelementsubtraction.htm
@@ -255,14 +264,30 @@ int main(int argc, char** argv) {
// will be tesselated using the deflection specified.
TopoDS_Shape shape;
createGroundShape(shape);
IfcEntityList::ptr geometrical_entities(new IfcEntityList);
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::tesselate(shape, 100., geometrical_entities);
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::tesselate(STRINGIFY(IfcSchema), shape, 100.)->as<IfcSchema::IfcProductDefinitionShape>();
file.getSingle<IfcSchema::IfcSite>()->setRepresentation(ground_representation);
file.addEntities(geometrical_entities);
IfcSchema::IfcShapeRepresentation::list::ptr ground_reps = geometrical_entities->as<IfcSchema::IfcShapeRepresentation>();
for (IfcSchema::IfcShapeRepresentation::list::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
GProp_GProps prop;
BRepGProp::SurfaceProperties(shape, prop);
const double site_area = prop.Mass() / 1000 / 1000;
IfcSchema::IfcProperty::list::ptr properties(new IfcSchema::IfcProperty::list);
properties->push(new IfcSchema::IfcPropertySingleValue("TotalArea", null, new IfcSchema::IfcAreaMeasure(site_area), 0));
IfcSchema::IfcPropertySet* pset = new IfcSchema::IfcPropertySet(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("Pset_SiteCommon"), null, properties);
#ifdef USE_IFC4
IfcSchema::IfcObjectDefinition::list::ptr related_objs(new IfcSchema::IfcObjectDefinition::list);
#else
IfcSchema::IfcObject::list::ptr related_objs(new IfcSchema::IfcObject::list);
#endif
related_objs->push(file.getSingle<IfcSchema::IfcSite>());
IfcSchema::IfcRelDefinesByProperties* site_prop = new IfcSchema::IfcRelDefinesByProperties(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, related_objs, pset);
file.addEntity(site_prop);
IfcSchema::IfcRepresentation::list::ptr ground_reps = file.getSingle<IfcSchema::IfcSite>()->Representation()->Representations();
for (IfcSchema::IfcRepresentation::list::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
(*it)->setContextOfItems(file.getRepresentationContext("Model"));
}
file.addEntity(ground_representation);
file.setSurfaceColour(ground_representation, 0.15, 0.25, 0.05);
// According to the Ifc2x3 schema an IfcWallStandardCase needs to have an IfcMaterialLayerSet
@@ -313,9 +338,9 @@ int main(int argc, char** argv) {
null,
null,
#ifdef USE_IFC4
file.entitiesByType<IfcSchema::IfcWallStandardCase>()->generalize(),
file.instances_by_type<IfcSchema::IfcWallStandardCase>()->generalize(),
#else
file.entitiesByType<IfcSchema::IfcWallStandardCase>()->as<IfcSchema::IfcRoot>(),
file.instances_by_type<IfcSchema::IfcWallStandardCase>()->as<IfcSchema::IfcRoot>(),
#endif
layer_usage);
@@ -370,7 +395,7 @@ int main(int argc, char** argv) {
IfcSchema::IfcShapeRepresentation* door_body = 0;
for (IfcSchema::IfcRepresentation::list::it i = door_representations->begin(); i != door_representations->end(); ++i) {
IfcSchema::IfcRepresentation* rep = *i;
if (rep->is(IfcSchema::Type::IfcShapeRepresentation) && rep->RepresentationIdentifier() == "Body") {
if (rep->declaration().is(IfcSchema::IfcShapeRepresentation::Class()) && rep->RepresentationIdentifier() == "Body") {
door_body = (IfcSchema::IfcShapeRepresentation*) rep;
}
}
@@ -381,13 +406,17 @@ int main(int argc, char** argv) {
file.setSurfaceColour(door->Representation(), 0.9, 0.9, 0.9);
file.addEntity(new IfcSchema::IfcRelFillsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, door_opening, door));
IfcSchema::IfcDoorStyle* door_style = new IfcSchema::IfcDoorStyle(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("Door type"), null, null, null, null, null,
IfcSchema::IfcDoorStyleOperationEnum::IfcDoorStyleOperation_SINGLE_SWING_LEFT, IfcSchema::IfcDoorStyleConstructionEnum::IfcDoorStyleConstruction_WOOD, false, false);
file.addRelatedObject<IfcSchema::IfcRelDefinesByType>(door_style, door);
// Surface styles are assigned to representation items, hence there is no real limitation to
// assign different colours within the same representation. However, some viewers have
// difficulties rendering products with representation items with different surface styles.
// Therefore we will construct the window as a decomposition of beams and a plate, in which
// only the plate will have a transparent material assigned.
// The window frame will consists of four seperate beams.
// The window frame will consists of four separate beams.
// AutoCAD Architecture will create an internal window type for the IfcWindow created.
// Therefore the OverallWidth and OverallHeight of the window attributes will need to
// match the bounding box of the representation. Furthermore, the window placement needs
@@ -438,10 +467,10 @@ int main(int argc, char** argv) {
);
file.addBuildingProduct(window);
// Initalize a list of parts for the window to be composed of
// Initialize a list of parts for the window to be composed of
IfcSchema::IfcObjectDefinition::list::ptr window_parts(new IfcTemplatedEntityList<IfcSchema::IfcObjectDefinition>());
// The placements for the beams are not shared accross the different windows because every
// The placements for the beams are not shared across the different windows because every
// beam is placed relative to its parent window entity.
IfcSchema::IfcLocalPlacement::list::ptr frame_placements (new IfcTemplatedEntityList<IfcSchema::IfcLocalPlacement>());
frame_placements->push(file.addLocalPlacement(storey_placement, 930,45));
+17 -12
View File
@@ -17,9 +17,15 @@
* *
********************************************************************************/
#include "../ifcparse/IfcFile.h"
// TODO: Multiple schemas
#define IfcSchema Ifc2x3
using namespace IfcSchema;
#include "../ifcparse/IfcFile.h"
#include "../ifcparse/Ifc2x3.h"
#if USE_VLD
#include <vld.h>
#endif
int main(int argc, char** argv) {
@@ -32,8 +38,8 @@ int main(int argc, char** argv) {
Logger::SetOutput(&std::cout,&std::cout);
// Parse the IFC file provided in argv[1]
IfcParse::IfcFile file;
if ( ! file.Init(argv[1]) ) {
IfcParse::IfcFile file(argv[1]);
if (!file.good()) {
std::cout << "Unable to parse .ifc file" << std::endl;
return 1;
}
@@ -54,19 +60,18 @@ int main(int argc, char** argv) {
// we need to cast them to IfcWindows. Since these properties
// are optional we need to make sure the properties are
// defined for the window in question before accessing them.
IfcBuildingElement::list::ptr elements = file.entitiesByType<IfcBuildingElement>();
IfcSchema::IfcBuildingElement::list::ptr elements = file.instances_by_type<IfcSchema::IfcBuildingElement>();
std::cout << "Found " << elements->size() << " elements in " << argv[1] << ":" << std::endl;
for ( IfcBuildingElement::list::it it = elements->begin(); it != elements->end(); ++ it ) {
for (IfcSchema::IfcBuildingElement::list::it it = elements->begin(); it != elements->end(); ++it) {
const IfcBuildingElement* element = *it;
std::cout << element->entity->toString() << std::endl;
const IfcSchema::IfcBuildingElement* element = *it;
std::cout << element->data().toString() << std::endl;
if ( element->is(IfcWindow::Class()) ) {
const IfcWindow* window = (IfcWindow*)element;
if ( window->hasOverallWidth() && window->hasOverallHeight() ) {
const IfcSchema::IfcWindow* window;
if ((window = element->as<IfcSchema::IfcWindow>()) != 0) {
if (window->hasOverallWidth() && window->hasOverallHeight()) {
const double area = window->OverallWidth()*window->OverallHeight();
std::cout << "The area of this window is " << area << std::endl;
}
+11 -11
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>());
items = IfcSchema::IfcRepresentationItem::list::ptr(new IfcSchema::IfcRepresentationItem::list());
items->push(set);
}
@@ -60,7 +60,7 @@ 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);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
file.addEntity(rep);
file.addEntity(shape);
@@ -109,11 +109,11 @@ 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());
@@ -126,8 +126,8 @@ int main(int argc, char** argv) {
file.addEntity(ellipse);
IfcEntityList::ptr trim1(new IfcEntityList);
IfcEntityList::ptr trim2(new IfcEntityList);
trim1->push(new IfcWrite::IfcSelectHelper( 0., Ifc2x3::Type::IfcParameterValue));
trim2->push(new IfcWrite::IfcSelectHelper(180., Ifc2x3::Type::IfcParameterValue));
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);
+7 -7
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);
@@ -98,15 +98,15 @@ int main(int argc, char** argv) {
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);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
file.addEntity(rep);
file.addEntity(shape);
+6 -6
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:
@@ -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,7 +180,7 @@ 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);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
file.addEntity(rep);
file.addEntity(shape);
+10 -10
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,7 +58,7 @@ 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);
@@ -70,8 +70,8 @@ void create_testcase_for(IfcHierarchyHelper& file, const EllipsePie& pie, Ifc2x3
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);
@@ -79,7 +79,7 @@ void create_testcase_for(IfcHierarchyHelper& file, const EllipsePie& pie, Ifc2x3
Ifc2x3::IfcTrimmedCurve* trim = new Ifc2x3::IfcTrimmedCurve(ellipse, trim1, trim2, true, pref);
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);
@@ -100,22 +100,22 @@ void create_testcase_for(IfcHierarchyHelper& file, const EllipsePie& pie, Ifc2x3
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);
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);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
file.addEntity(rep);
file.addEntity(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;
}
+143
View File
@@ -0,0 +1,143 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* Example of curve rebar. *
* *
********************************************************************************/
#include <iostream>
#include <string>
#include <fstream>
#include "ifcparse\Ifc2x3.h"
#include "ifcparse\IfcUtil.h"
#include "ifcparse\IfcHierarchyHelper.h"
#include "ifcgeom\IfcGeom.h"
typedef std::string S;
typedef IfcParse::IfcGlobalId guid;
boost::none_t const null = boost::none;
void create_curve_rebar(IfcHierarchyHelper& file)
{
int dia = 24;
int R = 3 * dia;
int length = 12 * dia;
double crossSectionarea = M_PI * (dia / 2) * 2;
IfcSchema::IfcReinforcingBar* rebar = new IfcSchema::IfcReinforcingBar(
guid(), 0, S("test"), null,
null, 0, 0,
null, S("SR24"), //SteelGrade
dia, //diameter
crossSectionarea, //crossSectionarea = math.pi*(12.0/2)**2
0,
IfcSchema::IfcReinforcingBarRoleEnum::IfcReinforcingBarRoleEnum::IfcReinforcingBarRole_LIGATURE,
IfcSchema::IfcReinforcingBarSurfaceEnum::IfcReinforcingBarSurfaceEnum::IfcReinforcingBarSurface_PLAIN //PLAIN or TEXTURED
);
file.addBuildingProduct(rebar);
rebar->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
IfcSchema::IfcCompositeCurveSegment::list::ptr segments(new IfcSchema::IfcCompositeCurveSegment::list());
IfcSchema::IfcCartesianPoint* p1 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, 0, 1000.);
IfcSchema::IfcCartesianPoint* p2 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, 0, 0);
IfcSchema::IfcCartesianPoint* p3 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, R, 0);
IfcSchema::IfcCartesianPoint* p4 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, R, -R);
IfcSchema::IfcCartesianPoint* p5 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, R + length, -R);
/*first segment - line */
IfcSchema::IfcCartesianPoint::list::ptr points1(new IfcSchema::IfcCartesianPoint::list());
points1->push(p1);
points1->push(p2);
file.addEntities(points1->generalize());
IfcSchema::IfcPolyline* poly1 = new IfcSchema::IfcPolyline(points1);
file.addEntity(poly1);
IfcSchema::IfcCompositeCurveSegment* segment1 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, poly1);
file.addEntity(segment1);
segments->push(segment1);
/*second segment - arc */
IfcSchema::IfcAxis2Placement3D* axis1 = new IfcSchema::IfcAxis2Placement3D(p3, file.addTriplet<IfcSchema::IfcDirection>(1, 0, 0), file.addTriplet<IfcSchema::IfcDirection>(0, 1, 0));
file.addEntity(axis1);
IfcSchema::IfcCircle* circle = new IfcSchema::IfcCircle(axis1, R);
file.addEntity(circle);
IfcEntityList::ptr trim1(new IfcEntityList);
IfcEntityList::ptr trim2(new IfcEntityList);
trim1->push(new IfcSchema::IfcParameterValue(180));
trim1->push(p2);
trim2->push(new IfcSchema::IfcParameterValue(270));
trim2->push(p4);
IfcSchema::IfcTrimmedCurve* trimmed_curve = new IfcSchema::IfcTrimmedCurve(circle, trim1, trim2, false, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
file.addEntity(trimmed_curve);
IfcSchema::IfcCompositeCurveSegment* segment2 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT, false, trimmed_curve);
file.addEntity(segment2);
segments->push(segment2);
/*third segment - line */
IfcSchema::IfcCartesianPoint::list::ptr points2(new IfcSchema::IfcCartesianPoint::list());
points2->push(p4);
points2->push(p5);
file.addEntities(points2->generalize());
IfcSchema::IfcPolyline* poly2 = new IfcSchema::IfcPolyline(points2);
file.addEntity(poly2);
IfcSchema::IfcCompositeCurveSegment* segment3 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, poly2);
file.addEntity(segment3);
segments->push(segment3);
IfcSchema::IfcCompositeCurve* curve = new IfcSchema::IfcCompositeCurve(segments, false);
file.addEntity(curve);
IfcSchema::IfcSweptDiskSolid* solid = new IfcSchema::IfcSweptDiskSolid(curve, dia / 2, null, 0, 1);
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list());
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list());
items->push(solid);
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("AdvancedSweptSolid"), items);
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
file.addEntity(shape);
rebar->setRepresentation(shape);
IfcSchema::IfcObjectPlacement* storey_placement = file.getSingle<IfcSchema::IfcBuildingStorey>()->ObjectPlacement();
rebar->setObjectPlacement(file.addLocalPlacement(storey_placement, 0, 0, 0));
}
int main()
{
IfcHierarchyHelper file;
file.header().file_name().name("ifc_curve_rebar.ifc");
create_curve_rebar(file);
std::ofstream f("ifc_curve_rebar.ifc");
f << file;
return 0;
}
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;
}
+137 -94
View File
@@ -27,46 +27,51 @@
bl_info = {
"name": "IfcBlender",
"description": "Import files in the "\
"description": "Import files in the "
"Industry Foundation Classes (.ifc) file format",
"author": "Thomas Krijnen, IfcOpenShell",
"blender": (2, 73, 0),
"blender": (2, 80, 0),
"location": "File > Import",
"tracker_url": "https://sourceforge.net/p/ifcopenshell/"\
"tracker_url": "https://sourceforge.net/p/ifcopenshell/"
"_list/tickets?source=navbar",
"category": "Import-Export"}
if "bpy" in locals():
import imp
import importlib
if "ifcopenshell" in locals():
imp.reload(ifcopenshell)
importlib.reload(ifcopenshell)
import bpy
import mathutils
from bpy.props import StringProperty, IntProperty, BoolProperty
from bpy_extras.io_utils import ImportHelper
major,minor = bpy.app.version[0:2]
major, minor = bpy.app.version[0:2]
transpose_matrices = minor >= 62
bpy.types.Object.ifc_id = IntProperty(name="IFC Entity ID",
bpy.types.Object.ifc_id = IntProperty(
name="IFC Entity ID",
description="The STEP entity instance name")
bpy.types.Object.ifc_guid = StringProperty(name="IFC Entity GUID",
bpy.types.Object.ifc_guid = StringProperty(
name="IFC Entity GUID",
description="The IFC Globally Unique Identifier")
bpy.types.Object.ifc_name = StringProperty(name="IFC Entity Name",
bpy.types.Object.ifc_name = StringProperty(
name="IFC Entity Name",
description="The optional name attribute")
bpy.types.Object.ifc_type = StringProperty(name="IFC Entity Type",
bpy.types.Object.ifc_type = StringProperty(
name="IFC Entity Type",
description="The STEP Datatype keyword")
def import_ifc(filename, use_names, process_relations, blender_booleans):
from . import ifcopenshell
from .ifcopenshell import geom as ifcopenshell_geom
print("Reading %s..."%bpy.path.basename(filename))
print(f"Reading {bpy.path.basename(filename)}...")
settings = ifcopenshell_geom.settings()
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, blender_booleans)
iterator = ifcopenshell_geom.iterator(settings, filename)
valid_file = iterator.findContext()
file = ifcopenshell.open(filename)
iterator = ifcopenshell_geom.iterator(settings, file)
valid_file = iterator.initialize()
if not valid_file:
return False
print("Done reading file")
@@ -76,9 +81,14 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
openings = []
old_progress = -1
print("Creating geometry...")
collection = bpy.data.collections.new(f"{bpy.path.basename(filename)}")
bpy.context.scene.collection.children.link(collection)
if process_relations:
rel_collection = bpy.data.collections.new("Relations")
collection.children.link(rel_collection)
while True:
ob = iterator.get()
f = ob.geometry.faces
v = ob.geometry.verts
mats = ob.geometry.materials
@@ -86,52 +96,77 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
m = ob.transformation.matrix.data
t = ob.type[0:21]
nm = ob.name if len(ob.name) and use_names else ob.guid
# MESH CREATION
# Depending on version, geometry.id will be either int or str
mesh_name = 'mesh-%r' % ob.geometry.id
if mesh_name in bpy.data.meshes:
me = bpy.data.meshes[mesh_name]
else:
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)]
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_name)
me.from_pydata(verts, [], faces)
me.validate()
# MATERIAL CREATION
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():
if k == 'transparency':
mat.blend_method = 'HASHED'
mat.use_screen_refraction = True
mat.refraction_depth = 0.1
mat.use_nodes = True
mat.node_tree.nodes["Principled BSDF"].inputs[15].default_value = v
else:
setattr(mat, k, v)
me.materials.append(mat)
me = bpy.data.meshes.new('mesh%d' % ob.geometry.id)
me.from_pydata(verts, [], faces)
def add_material(mname, props):
if mname in bpy.data.materials:
mat = bpy.data.materials[mname]
mat.use_fake_user = True
else:
mat = bpy.data.materials.new(mname)
for k,v in props.items():
setattr(mat, k, v)
me.materials.append(mat)
needs_default = -1 in matids
if needs_default: add_material(t, {})
for mat in mats:
props = {}
if mat.has_diffuse: props['diffuse_color'] = mat.diffuse
if mat.has_specular: props['specular_color'] = mat.specular
if mat.has_transparency and mat.transparency > 0:
props['alpha'] = 1.0 - mat.transparency
props['use_transparency'] = True
if mat.has_specularity: props['specular_hardness'] = mat.specularity
add_material(mat.name, props)
needs_default = -1 in matids
if needs_default:
add_material(t, {})
for mat in mats:
props = {}
if mat.has_diffuse:
alpha = 1.
if mat.has_transparency and mat.transparency > 0:
alpha = 1. - mat.transparency
props['diffuse_color'] = mat.diffuse + (alpha,)
# @todo
# if mat.has_specular:
# props['specular_color'] = mat.specular
# if mat.has_specularity:
# props['specular_intensity'] = mat.specularity
add_material(mat.name, props)
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)
# OBJECT CREATION
bob = bpy.data.objects.new(nm, me)
mat = mathutils.Matrix(([m[0], m[1], m[2], 0],
[m[3], m[4], m[5], 0],
[m[6], m[7], m[8], 0],
[m[9], m[10], m[11], 1]))
if transpose_matrices: mat.transpose()
[m[3], m[4], m[5], 0],
[m[6], m[7], m[8], 0],
[m[9], m[10], m[11], 1]))
if transpose_matrices:
mat.transpose()
if process_relations:
id_to_matrix[ob.id] = mat
else:
bob.matrix_world = mat
bpy.context.scene.objects.link(bob)
collection.objects.link(bob)
bpy.context.scene.objects.active = bob
bpy.context.view_layer.objects.active = bob
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.normals_make_consistent()
bpy.ops.object.mode_set(mode='OBJECT')
@@ -141,23 +176,19 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
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] = []
bob.hide_viewport = bob.hide_render = True
bob.display_type = 'WIRE'
if ob.id not in id_to_object:
id_to_object[ob.id] = []
id_to_object[ob.id].append(bob)
if ob.parent_id > 0:
id_to_parent[ob.id] = ob.parent_id
if blender_booleans and ob.type == 'IfcOpeningElement':
openings.append(ob.id)
faces = me.polygons if hasattr(me, 'polygons') else me.faces
if len(faces) == len(matids):
for face, matid in zip(faces, matids):
face.material_index = matid + (1 if needs_default else 0)
progress = iterator.progress() // 2
if progress > old_progress:
print("\r[" + "#" * progress + " " * (50 - progress) + "]", end="")
@@ -168,13 +199,13 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
print("\rDone creating geometry" + " " * 30)
id_to_parent_temp = dict(id_to_parent)
if process_relations:
print("Processing relations...")
while len(id_to_parent_temp) and process_relations:
id, parent_id = id_to_parent_temp.popitem()
if parent_id in id_to_object:
bob = id_to_object[parent_id][0]
else:
@@ -186,16 +217,17 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
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((
[m[0], m[1], m[2], 0],
[m[3], m[4], m[5], 0],
[m[6], m[7], m[8], 0],
[m[9], m[10], m[11], 1]))
if transpose_matrices: mat.transpose()
if transpose_matrices:
mat.transpose()
id_to_matrix[parent_ob.id] = mat
bpy.context.scene.objects.link(bob)
rel_collection.objects.link(bob)
bob.ifc_id = parent_ob.id
bob.ifc_name, bob.ifc_type, bob.ifc_guid = \
@@ -218,13 +250,13 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
parent_matrix = id_to_matrix.get(parent_id, None)
for ob in id_to_object[id]:
if parent_matrix:
ob.matrix_local = parent_matrix.inverted() * matrix
ob.matrix_local = parent_matrix.inverted() @ matrix
else:
ob.matrix_world = matrix
if process_relations:
print("Done processing relations")
for opening_id in openings:
parent_id = id_to_parent[opening_id]
if parent_id in id_to_object:
@@ -233,9 +265,11 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
mod = parent_ob.modifiers.new("opening", "BOOLEAN")
mod.operation = "DIFFERENCE"
mod.object = opening_ob
txt = bpy.data.texts.new("%s.log"%bpy.path.basename(filename))
txt.from_string(iterator.getLog())
if hasattr(iterator, 'getLog'):
# @todo
txt = bpy.data.texts.new(f"{bpy.path.basename(filename)}.log")
txt.from_string(iterator.getLog())
return True
@@ -245,42 +279,51 @@ class ImportIFC(bpy.types.Operator, ImportHelper):
bl_label = "Import .ifc file"
filename_ext = ".ifc"
filter_glob = StringProperty(default="*.ifc", options={'HIDDEN'})
filter_glob: StringProperty(default="*.ifc", options={'HIDDEN'})
use_names = BoolProperty(name="Use entity names",
description="Use entity names rather than GlobalIds for objects",
default=True)
process_relations = BoolProperty(name="Process relations",
description="Convert containment and aggregation" \
" 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)
use_names: BoolProperty(name="Use entity names",
description="Use entity names rather than "
"GlobalIds for objects",
default=True)
process_relations: BoolProperty(name="Process relations",
description="Convert containment and "
"aggregation relations to parenting"
" (warning: may be slow on large files)",
default=False)
blender_booleans: BoolProperty(name="Use Blender booleans",
description="Use Blender boolean modifiers "
"for opening elements",
default=False)
def execute(self, context):
if not import_ifc(self.filepath, self.use_names, self.process_relations, self.blender_booleans):
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'
)
'Unable to parse .ifc file or no geometrical entities found'
)
return {'FINISHED'}
def menu_func_import(self, context):
self.layout.operator(ImportIFC.bl_idname,
text="Industry Foundation Classes (.ifc)")
text="Industry Foundation Classes (.ifc)")
classes = (
ImportIFC,
)
def register():
bpy.utils.register_module(__name__)
bpy.types.INFO_MT_file_import.append(menu_func_import)
for cls in classes:
bpy.utils.register_class(cls)
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
def unregister():
bpy.utils.unregister_module(__name__)
bpy.types.INFO_MT_file_import.remove(menu_func_import)
for cls in reversed(classes):
bpy.utils.unregister_class(cls)
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
if __name__ == "__main__":
-278
View File
@@ -1,278 +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/>. *
* *
********************************************************************************/
#ifdef WITH_OPENCOLLADA
#include <string>
#include "ColladaSerializer.h"
std::string collada_id(const std::string& s) {
std::string id;
id.reserve(s.size());
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
const std::string::value_type c = *it;
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_')) {
id.push_back(c);
}
}
return id;
}
void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<double>& floats, const char* coords /* = "XYZ" */) {
COLLADASW::FloatSource source(mSW);
source.setId(mesh_id + suffix);
source.setArrayId(mesh_id + suffix + COLLADASW::LibraryGeometries::ARRAY_ID_SUFFIX);
source.setAccessorStride(strlen(coords));
source.setAccessorCount(floats.size() / 3);
for (unsigned int i = 0; i < source.getAccessorStride(); ++i) {
source.getParameterNameList().push_back(std::string(1, coords[i]));
}
source.prepareToAppendValues();
for (std::vector<double>::const_iterator it = floats.begin(); it != floats.end(); ++it) {
source.appendValues(*it);
}
source.finish();
}
void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials) {
// The goal of the IfcGeom::Iterator is to filter out empty geometries, but
// since this function would crash trying to deference the material_ids in
// that case, a hard return statement is added just in case.
if (indices.empty()) return;
openMesh(mesh_id);
// The normals vector can be empty for example when the WELD_VERTICES setting is used.
// IfcOpenShell does not provide them with multiple face normals collapsed into a single vertex.
const bool has_normals = !normals.empty();
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX, positions);
if (has_normals) {
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, normals);
}
COLLADASW::VerticesElement vertices(mSW);
vertices.setId(mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX );
vertices.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::POSITION, "#" + mesh_id + COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX));
vertices.add();
std::vector<int>::const_iterator index_range_start = indices.begin();
std::vector<int>::const_iterator material_it = material_ids.begin();
int previous_material_id = -1;
for (std::vector<int>::const_iterator it = indices.begin(); ; it += 3) {
const int current_material_id = *(material_it++);
const int num_triangles = std::distance(index_range_start, it) / 3;
if ((previous_material_id != current_material_id && num_triangles > 0) || (it == indices.end())) {
COLLADASW::Triangles triangles(mSW);
triangles.setMaterial(materials[previous_material_id].name());
triangles.setCount(num_triangles);
int offset = 0;
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX,"#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++ ) );
if (has_normals) {
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::NORMAL,"#" + mesh_id + COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, offset++ ) );
}
triangles.prepareToAppendValues();
for (std::vector<int>::const_iterator jt = index_range_start; jt != it; ++jt) {
const int idx = *jt;
if (has_normals) {
triangles.appendValues(idx, idx);
} else {
triangles.appendValues(idx);
}
}
triangles.finish();
index_range_start = it;
}
previous_material_id = current_material_id;
if (it == indices.end()) {
break;
}
}
closeMesh();
closeGeometry();
}
void ColladaSerializer::ColladaExporter::ColladaGeometries::close() {
closeLibrary();
}
void ColladaSerializer::ColladaExporter::ColladaScene::add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<double>& matrix) {
if (!scene_opened) {
openVisualScene(scene_id);
scene_opened = true;
}
COLLADASW::Node node(mSW);
node.setNodeId(node_id);
node.setNodeName(node_name);
node.setType(COLLADASW::Node::NODE);
// The matrix attribute of an entity is basically a 4x3 representation of its ObjectPlacement.
// Note that this placement is absolute, ie it is multiplied with all parent placements.
double matrix_array[4][4] = {
{matrix[0], matrix[3], matrix[6], matrix[ 9]},
{matrix[1], matrix[4], matrix[7], matrix[10]},
{matrix[2], matrix[5], matrix[8], matrix[11]},
{ 0, 0, 0, 1}
};
node.start();
node.addMatrix(matrix_array);
COLLADASW::InstanceGeometry instanceGeometry(mSW);
instanceGeometry.setUrl ("#" + geom_name);
for (std::vector<std::string>::const_iterator it = material_ids.begin(); it != material_ids.end(); ++it) {
COLLADASW::InstanceMaterial material (*it, "#" + *it);
instanceGeometry.getBindMaterial().getInstanceMaterialList().push_back(material);
}
instanceGeometry.add();
node.end();
}
void ColladaSerializer::ColladaExporter::ColladaScene::write() {
if (scene_opened) {
closeVisualScene();
closeLibrary();
COLLADASW::Scene scene (mSW, COLLADASW::URI ("#" + scene_id));
scene.add();
}
}
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeom::Material& material) {
openEffect(collada_id(material.name()) + "-fx");
COLLADASW::EffectProfile effect(mSW);
effect.setShaderType(COLLADASW::EffectProfile::LAMBERT);
if (material.hasDiffuse()) {
const double* diffuse = material.diffuse();
effect.setDiffuse(COLLADASW::ColorOrTexture(COLLADASW::Color(diffuse[0],diffuse[1],diffuse[2])));
}
if (material.hasSpecular()) {
const double* specular = material.specular();
effect.setSpecular(COLLADASW::ColorOrTexture(COLLADASW::Color(specular[0],specular[1],specular[2])));
}
if (material.hasSpecularity()) {
effect.setShininess(material.specularity());
}
if (material.hasTransparency()) {
const double transparency = material.transparency();
if (transparency > 0) {
// The default opacity mode for Collada is A_ONE, which apparently indicates a
// transparency value of 1 to be fully opaque. Hence transparency is inverted.
effect.setTransparency(1.0 - transparency);
}
}
addEffectProfile(effect);
closeEffect();
}
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::close() {
closeLibrary();
}
void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const IfcGeom::Material& material) {
if (!contains(material)) {
effects.write(material);
materials.push_back(material);
}
}
bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeom::Material& material) {
return std::find(materials.begin(), materials.end(), material) != materials.end();
}
void ColladaSerializer::ColladaExporter::ColladaMaterials::write() {
effects.close();
for (std::vector<IfcGeom::Material>::const_iterator it = materials.begin(); it != materials.end(); ++it) {
const std::string& material_name = collada_id((*it).name());
openMaterial(material_name);
addInstanceEffect("#" + material_name + "-fx");
closeMaterial();
}
closeLibrary();
}
void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_name, float unit_magnitude) {
stream.startDocument();
COLLADASW::Asset asset(&stream);
asset.getContributor().mAuthoringTool = std::string("IfcOpenShell ") + IFCOPENSHELL_VERSION;
asset.setUnit(unit_name, unit_magnitude);
asset.setUpAxisType(COLLADASW::Asset::Z_UP);
asset.add();
}
void ColladaSerializer::ColladaExporter::write(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& _materials) {
std::vector<std::string> material_references;
for (std::vector<IfcGeom::Material>::const_iterator it = _materials.begin(); it != _materials.end(); ++it) {
const IfcGeom::Material& material = *it;
if (!materials.contains(material)) {
materials.add(material);
}
material_references.push_back(collada_id(material.name()));
}
deferreds.push_back(DeferredObject(guid, name, type, obj_id, matrix, vertices, normals, indices, material_ids, _materials, material_references));
}
const std::string ColladaSerializer::ColladaExporter::DeferredObject::Name() const {
std::stringstream ss;
if (!this->name.empty()) {
ss << this->obj_id << "_" << this->name;
} else {
ss << this->guid;
}
return collada_id(ss.str());
}
void ColladaSerializer::ColladaExporter::endDocument() {
// In fact due the XML based nature of Collada and its dependency on library nodes,
// only at this point all objects are written to the stream.
materials.write();
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
const std::string object_name = it->Name();
geometries.write(object_name, it->type, it->vertices, it->normals, it->indices, it->material_ids, it->materials);
}
geometries.close();
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
const std::string object_name = it->Name();
scene.add(object_name + "-instance", object_name, object_name, it->material_references, it->matrix);
}
scene.write();
stream.endDocument();
}
bool ColladaSerializer::ready() {
return true;
}
void ColladaSerializer::writeHeader() {
exporter.startDocument(unit_name, unit_magnitude);
}
void ColladaSerializer::write(const IfcGeom::TriangulationElement<double>* o) {
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
exporter.write(o->guid(), o->name(), o->type(), o->id(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.material_ids(), mesh.materials());
}
void ColladaSerializer::finalize() {
exporter.endDocument();
}
#endif
-165
View File
@@ -1,165 +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/>. *
* *
********************************************************************************/
#ifdef WITH_OPENCOLLADA
#ifndef COLLADASERIALIZER_H
#define COLLADASERIALIZER_H
#include <COLLADASWStreamWriter.h>
#include <COLLADASWPrimitves.h>
#include <COLLADASWLibraryGeometries.h>
#include <COLLADASWSource.h>
#include <COLLADASWScene.h>
#include <COLLADASWNode.h>
#include <COLLADASWInstanceGeometry.h>
#include <COLLADASWLibraryVisualScenes.h>
#include <COLLADASWLibraryEffects.h>
#include <COLLADASWLibraryMaterials.h>
#include <COLLADASWBaseInputElement.h>
#include <COLLADASWAsset.h>
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcconvert/GeometrySerializer.h"
class ColladaSerializer : public GeometrySerializer
{
private:
class ColladaExporter
{
private:
class ColladaGeometries : public COLLADASW::LibraryGeometries
{
public:
explicit ColladaGeometries(COLLADASW::StreamWriter& stream)
: COLLADASW::LibraryGeometries(&stream)
{}
void addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<double>& floats, const char* coords = "XYZ");
void write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials);
void close();
};
class ColladaScene : public COLLADASW::LibraryVisualScenes
{
private:
const std::string scene_id;
bool scene_opened;
public:
ColladaScene(const std::string& scene_id, COLLADASW::StreamWriter& stream)
: COLLADASW::LibraryVisualScenes(&stream)
, scene_id(scene_id)
, scene_opened(false)
{}
void add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<double>& matrix);
void write();
};
class ColladaMaterials : public COLLADASW::LibraryMaterials
{
private:
class ColladaEffects : public COLLADASW::LibraryEffects
{
public:
explicit ColladaEffects(COLLADASW::StreamWriter& stream)
: COLLADASW::LibraryEffects(&stream)
{}
void write(const IfcGeom::Material& material);
void close();
};
std::vector<IfcGeom::Material> materials;
ColladaEffects effects;
public:
explicit ColladaMaterials(COLLADASW::StreamWriter& stream)
: COLLADASW::LibraryMaterials(&stream)
, effects(stream)
{}
void add(const IfcGeom::Material& material);
bool contains(const IfcGeom::Material& material);
void write();
};
class DeferredObject {
public:
std::string guid, name, type;
int obj_id;
std::vector<double> matrix;
std::vector<double> vertices;
std::vector<double> normals;
std::vector<int> indices;
std::vector<int> material_ids;
std::vector<IfcGeom::Material> materials;
std::vector<std::string> material_references;
DeferredObject(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<double>& matrix, const std::vector<double>& vertices,
const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids,
const std::vector<IfcGeom::Material>& materials, const std::vector<std::string>& material_references)
: guid(guid)
, name(name)
, type(type)
, obj_id(obj_id)
, matrix(matrix)
, vertices(vertices)
, normals(normals)
, indices(indices)
, material_ids(material_ids)
, materials(materials)
, material_references(material_references)
{}
const std::string Name() const;
};
COLLADABU::NativeString filename;
COLLADASW::StreamWriter stream;
ColladaGeometries geometries;
ColladaScene scene;
ColladaMaterials materials;
public:
ColladaExporter(const std::string& scene_name, const std::string& fn)
: filename(fn.c_str())
, stream(filename)
, geometries(stream)
, scene(scene_name, stream)
, materials(stream)
{}
std::vector<DeferredObject> deferreds;
virtual ~ColladaExporter() {}
void startDocument(const std::string& unit_name, float unit_magnitude);
void write(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& materials);
void endDocument();
};
ColladaExporter exporter;
std::string unit_name;
float unit_magnitude;
public:
ColladaSerializer(const std::string& dae_filename)
: GeometrySerializer()
, exporter("IfcOpenShell", dae_filename)
{}
bool ready();
void writeHeader();
void write(const IfcGeom::TriangulationElement<double>* o);
void write(const IfcGeom::BRepElement<double>* o) {}
void finalize();
bool isTesselated() const { return true; }
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
unit_name = name;
unit_magnitude = magnitude;
}
void setFile(IfcParse::IfcFile*) {}
};
#endif
#endif
File diff suppressed because it is too large Load Diff
-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
-116
View File
@@ -1,116 +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 "../ifcgeom/IfcGeomRenderStyles.h"
#include "WavefrontObjSerializer.h"
#include <iomanip>
bool WaveFrontOBJSerializer::ready() {
return obj_stream.is_open() && mtl_stream.is_open();
}
void WaveFrontOBJSerializer::writeHeader() {
obj_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n";
#ifdef WIN32
const char dir_separator = '\\';
#else
const char dir_separator = '/';
#endif
std::string mtl_basename = mtl_filename;
std::string::size_type slash = mtl_basename.find_last_of(dir_separator);
if (slash != std::string::npos) {
mtl_basename = mtl_basename.substr(slash+1);
}
obj_stream << "mtllib " << mtl_basename << "\n";
mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n";
}
void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style) {
mtl_stream << "newmtl " << style.name() << "\n";
if (style.hasDiffuse()) {
const double* diffuse = style.diffuse();
mtl_stream << "Kd " << diffuse[0] << " " << diffuse[1] << " " << diffuse[2] << "\n";
}
if (style.hasSpecular()) {
const double* specular = style.specular();
mtl_stream << "Ks " << specular[0] << " " << specular[1] << " " << specular[2] << "\n";
}
if (style.hasSpecularity()) {
mtl_stream << "Ns " << style.specularity() << "\n";
}
if (style.hasTransparency()) {
const double transparency = 1.0 - style.transparency();
if (transparency < 1) {
mtl_stream << "Tr " << transparency << "\n";
mtl_stream << "d " << transparency << "\n";
mtl_stream << "D " << transparency << "\n";
}
}
}
void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<double>* o) {
std::string tmp = o->name().empty() ? o->guid() : o->name();
std::replace( tmp.begin(), tmp.end(), ' ', '_');
const std::string name = tmp;
obj_stream << "g " << name << "\n";
obj_stream << "s 1" << "\n";
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
const int vcount = mesh.verts().size() / 3;
for ( std::vector<double>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) {
const double x = *(it++);
const double y = *(it++);
const double z = *(it++);
obj_stream << "v " << x << " " << y << " " << z << "\n";
}
for ( std::vector<double>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) {
const double x = *(it++);
const double y = *(it++);
const double z = *(it++);
obj_stream << "vn " << x << " " << y << " " << z << "\n";
}
int previous_material_id = -2;
std::vector<int>::const_iterator material_it = mesh.material_ids().begin();
for ( std::vector<int>::const_iterator it = mesh.faces().begin(); it != mesh.faces().end(); ) {
const int material_id = *(material_it++);
if (material_id != previous_material_id) {
const IfcGeom::Material& material = mesh.materials()[material_id];
const std::string material_name = material.name();
obj_stream << "usemtl " << material_name << "\n";
if (materials.find(material_name) == materials.end()) {
writeMaterial(material);
materials.insert(material_name);
}
previous_material_id = material_id;
}
const int v1 = *(it++)+vcount_total;
const int v2 = *(it++)+vcount_total;
const int v3 = *(it++)+vcount_total;
obj_stream << "f " << v1 << "//" << v1 << " " << v2 << "//" << v2 << " " << v3 << "//" << v3 << "\n";
}
vcount_total += vcount;
}
-257
View File
@@ -1,257 +0,0 @@
#include <map>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/foreach.hpp>
#include <boost/version.hpp>
#include "XmlSerializer.h"
using boost::property_tree::ptree;
using namespace IfcSchema;
static std::map<std::string, std::string> argument_name_map;
// Format an IFC attribute and maybe returns as string. Only literal scalar
// values are converted. Things like entity instances and lists are omitted.
boost::optional<std::string> format_attribute(const Argument* argument, IfcUtil::ArgumentType argument_type) {
boost::optional<std::string> value;
switch(argument_type) {
case IfcUtil::Argument_BOOL: {
const bool b = *argument;
value = b ? "true" : "false";
break; }
case IfcUtil::Argument_DOUBLE: {
const double d = *argument;
std::stringstream stream;
stream << d;
value = stream.str();
break; }
case IfcUtil::Argument_STRING:
case IfcUtil::Argument_ENUMERATION: {
value = static_cast<std::string>(*argument);
break; }
case IfcUtil::Argument_INT: {
const int v = *argument;
std::stringstream stream;
stream << v;
value = stream.str();
break; }
case IfcUtil::Argument_ENTITY: {
IfcUtil::IfcBaseClass* e = *argument;
if (Type::IsSimple(e->type())) {
IfcUtil::IfcBaseType* f = (IfcUtil::IfcBaseType*) e;
value = format_attribute(f->getArgument(0), f->getArgumentType(0));
} else if (e->is(IfcSchema::Type::IfcSIUnit) || e->is(IfcSchema::Type::IfcConversionBasedUnit)) {
// Some string concatenation to have a unit name as a XML attribute.
std::string unit_name;
if (e->is(IfcSchema::Type::IfcSIUnit)) {
IfcSchema::IfcSIUnit* unit = (IfcSchema::IfcSIUnit*) e;
unit_name = IfcSchema::IfcSIUnitName::ToString(unit->Name());
if (unit->hasPrefix()) {
unit_name = IfcSchema::IfcSIPrefix::ToString(unit->Prefix()) + unit_name;
}
} else {
IfcSchema::IfcConversionBasedUnit* unit = (IfcSchema::IfcConversionBasedUnit*) e;
unit_name = unit->Name();
}
for (std::string::iterator c = unit_name.begin(); c != unit_name.end(); ++c) *c = tolower(*c);
value = unit_name;
}
break; }
}
return value;
}
// Formats an entity instances as a ptree node, and insert into the DOM. Recurses
// over the entity attributes and writes them as xml attributes of the node.
ptree& format_entity_instance(IfcUtil::IfcBaseEntity* instance, ptree& tree, bool as_link = false) {
ptree child;
const unsigned n = instance->getArgumentCount();
for (unsigned i = 0; i < n; ++i) {
const Argument* argument = instance->getArgument(i);
if (argument->isNull()) continue;
std::string argument_name = instance->getArgumentName(i);
std::map<std::string, std::string>::const_iterator argument_name_it;
argument_name_it = argument_name_map.find(argument_name);
if (argument_name_it != argument_name_map.end()) {
argument_name = argument_name_it->second;
}
const IfcUtil::ArgumentType argument_type = instance->getArgumentType(i);
boost::optional<std::string> value;
try {
value = format_attribute(argument, argument_type);
} catch (...) {}
if (value) {
if (as_link) {
if (argument_name == "id") {
child.put("<xmlattr>.xlink:href", std::string("#") + *value);
}
} else {
std::stringstream stream;
stream << "<xmlattr>." << argument_name;
child.put(stream.str(), *value);
}
}
}
return tree.add_child(Type::ToString(instance->type()), child);
}
// A function to be called recursively. Template specialization is used
// to descend into decomposition, containment and property relationships.
template <typename A>
void descend(A* instance, ptree& tree) {
format_entity_instance(instance, tree);
}
// Returns related entity instances using IFC's objectified relationship
// model. The second and third argument require a member function pointer.
template <typename T, typename U, typename V, typename F, typename G>
typename V::list::ptr get_related(T* t, F f, G g) {
typename U::list::ptr li = (*t.*f)()->template as<U>();
typename V::list::ptr acc(new typename V::list);
for (typename U::list::it it = li->begin(); it != li->end(); ++it) {
U* u = *it;
acc->push((*u.*g)());
}
return acc;
}
// Descends into the tree by recursing into IfcRelContainedInSpatialStructure,
// IfcRelDecomposes and IfcRelDefinesByProperties relations.
template <>
void descend(IfcProduct* product, ptree& tree) {
ptree& child = format_entity_instance(product, tree);
if (product->is(Type::IfcSpatialStructureElement)) {
IfcSpatialStructureElement* structure = (IfcSpatialStructureElement*) product;
IfcProduct::list::ptr elements = get_related
<IfcSpatialStructureElement, IfcRelContainedInSpatialStructure, IfcProduct>
(structure, &IfcSpatialStructureElement::ContainsElements, &IfcRelContainedInSpatialStructure::RelatedElements);
for (IfcProduct::list::it it = elements->begin(); it != elements->end(); ++it) {
descend(*it, child);
}
}
IfcObjectDefinition::list::ptr structures = get_related
<IfcProduct, IfcRelDecomposes, IfcObjectDefinition>
(product, &IfcProduct::IsDecomposedBy, &IfcRelDecomposes::RelatedObjects);
for (IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
IfcObjectDefinition* ob = *it;
if (ob->is(Type::IfcSpatialStructureElement)) {
descend((IfcProduct*)ob, child);
} else {
descend(ob, child);
}
}
IfcPropertySetDefinition::list::ptr property_sets = get_related
<IfcProduct, IfcRelDefinesByProperties, IfcPropertySetDefinition>
(product, &IfcProduct::IsDefinedBy, &IfcRelDefinesByProperties::RelatingPropertyDefinition);
for (IfcPropertySetDefinition::list::it it = property_sets->begin(); it != property_sets->end(); ++it) {
IfcPropertySetDefinition* pset = *it;
if (pset->is(Type::IfcPropertySet)) {
format_entity_instance(pset, child, true);
}
}
}
// Descends into the tree by recursing into IfcRelDecomposes relations.
template <>
void descend(IfcProject* project, ptree& tree) {
ptree& child = format_entity_instance(project, tree);
IfcObjectDefinition::list::ptr structures = get_related
<IfcProject, IfcRelDecomposes, IfcObjectDefinition>
(project, &IfcProject::IsDecomposedBy, &IfcRelDecomposes::RelatedObjects);
for (IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
IfcObjectDefinition* ob = *it;
if (ob->is(Type::IfcSpatialStructureElement)) {
descend((IfcProduct*)ob, child);
} else {
descend(ob, child);
}
}
}
// Format IfcProperty instances and insert into the DOM. IfcComplexProperties are flattened out.
void format_properties(IfcProperty::list::ptr properties, ptree& node) {
for (IfcProperty::list::it it = properties->begin(); it != properties->end(); ++it) {
IfcProperty* p = *it;
if (p->is(Type::IfcComplexProperty)) {
IfcComplexProperty* complex = (IfcComplexProperty*) p;
format_properties(complex->HasProperties(), node);
} else {
format_entity_instance(p, node);
}
}
}
void XmlSerializer::finalize() {
argument_name_map.insert(std::make_pair("GlobalId", "id"));
IfcProject::list::ptr projects = file->entitiesByType<IfcProject>();
if (projects->size() != 1) {
Logger::Message(Logger::LOG_ERROR, "Expected a single IfcProject");
return;
}
IfcProject* project = *projects->begin();
ptree root, header, decomposition, properties;
// Write the SPF header as XML nodes.
BOOST_FOREACH(const std::string& s, file->header().file_description().description()) {
header.add_child("file_description.description", ptree(s));
}
BOOST_FOREACH(const std::string& s, file->header().file_name().author()) {
header.add_child("file_name.author", ptree(s));
}
BOOST_FOREACH(const std::string& s, file->header().file_name().organization()) {
header.add_child("file_name.organization", ptree(s));
}
BOOST_FOREACH(const std::string& s, file->header().file_schema().schema_identifiers()) {
header.add_child("file_schema.schema_identifiers", ptree(s));
}
header.put("file_description.implementation_level", file->header().file_description().implementation_level());
header.put("file_name.name", file->header().file_name().name());
header.put("file_name.time_stamp", file->header().file_name().time_stamp());
header.put("file_name.preprocessor_version", file->header().file_name().preprocessor_version());
header.put("file_name.originating_system", file->header().file_name().originating_system());
header.put("file_name.authorization", file->header().file_name().authorization());
// Descend into the decomposition structure of the IFC file.
descend(project, decomposition);
// Write all property sets and values as XML nodes.
IfcPropertySet::list::ptr psets = file->entitiesByType<IfcPropertySet>();
for (IfcPropertySet::list::it it = psets->begin(); it != psets->end(); ++it) {
IfcPropertySet* pset = *it;
ptree& node = format_entity_instance(pset, properties);
format_properties(pset->HasProperties(), node);
}
root.add_child("ifc.header", header);
root.add_child("ifc.properties", properties);
root.add_child("ifc.decomposition", decomposition);
root.put("ifc.<xmlattr>.xmlns:xlink", "http://www.w3.org/1999/xlink");
#if BOOST_VERSION >= 105600
boost::property_tree::xml_writer_settings<ptree::key_type> settings = boost::property_tree::xml_writer_make_settings<ptree::key_type>('\t', 1);
#else
boost::property_tree::xml_writer_settings<char> settings('\t', 1);
#endif
boost::property_tree::write_xml(xml_filename, root, std::locale(), settings);
}
@@ -0,0 +1,185 @@
#include "validation_utils.h"
using namespace ifcopenshell::geometry;
#include <CGAL/AABB_tree.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/AABB_face_graph_triangle_primitive.h>
typedef Kernel_::FT FT;
typedef Kernel_::Point_3 Point;
typedef Kernel_::Segment_3 Segment;
typedef CGAL::Polyhedron_3<Kernel_> Polyhedron;
typedef CGAL::AABB_face_graph_triangle_primitive<Polyhedron> Primitive;
typedef CGAL::AABB_traits<Kernel_, Primitive> Traits;
typedef CGAL::AABB_tree<Traits> Tree;
typedef Tree::Point_and_primitive_id Point_and_primitive_id;
void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) {
intersection_validator v(f, { "IfcWall", "IfcSpace", "IfcSlab", "IfcCovering" }, 1.e-5, no_progress, quiet, stderr_progress);
auto rels = f.instances_by_type("IfcRelSpaceBoundary");
std::map<std::pair<const IfcUtil::IfcBaseClass*, const IfcUtil::IfcBaseClass*>, const IfcUtil::IfcBaseClass*> rel_by_space_elem;
if (rels) {
std::for_each(rels->begin(), rels->end(), [&rel_by_space_elem](const IfcUtil::IfcBaseClass* rel) {
auto x = ((IfcUtil::IfcBaseEntity*)rel)->get_value<IfcUtil::IfcBaseClass*>("RelatingSpace");
try {
auto y = ((IfcUtil::IfcBaseEntity*)rel)->get_value<IfcUtil::IfcBaseClass*>("RelatedBuildingElement");
rel_by_space_elem.insert({ { x,y }, rel });
} catch (IfcParse::IfcException&) {
// RelatedBuildingElement can be NULL
}
});
}
std::set<const IfcUtil::IfcBaseClass*> rels_encounted;
IfcParse::IfcFile f2("boundaries-triangulated.ifc");
if (!f2.good()) {
return;
}
ifcopenshell::geometry::settings settings;
settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false);
settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, false);
settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, true);
settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, true);
settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true);
settings.set(ifcopenshell::geometry::settings::DISABLE_OPENING_SUBTRACTIONS, true);
ifcopenshell::geometry::Converter c("cgal", &f2, settings);
std::map<std::set<std::string>, std::vector<Kernel_::Point_3>> elem_to_space_boundary_coords;
for (auto& i : *f2.instances_by_type("IfcProduct")) {
auto n = ((IfcUtil::IfcBaseEntity*)i)->get_value<std::string>("Name");
auto g1 = n.substr(0, 22);
auto g2 = n.substr(23);
auto item = c.mapping()->map(i);
if (((ifcopenshell::geometry::taxonomy::collection*) item)->children[0] == nullptr) {
continue;
}
auto shell = (taxonomy::shell*) ((taxonomy::collection*)((taxonomy::collection*) item)->children[0])->children[0];
for (auto& f : shell->children) {
auto face = (taxonomy::face*) f;
for (auto& w : face->children) {
auto wire = (taxonomy::loop*) w;
for (auto& e : wire->children) {
auto edge = (taxonomy::edge*) e;
auto p3 = boost::get<taxonomy::point3>(edge->start);
auto p4 = ((taxonomy::geom_item*)item)->matrix.components * p3.components.homogeneous();
Kernel_::Point_3 P(p4(0), p4(1), p4(2));
elem_to_space_boundary_coords[{g1, g2}].emplace_back(P);
}
}
}
}
std::set< std::set<std::string> > guid_pairs_visited;
v([&rel_by_space_elem, &elem_to_space_boundary_coords, &guid_pairs_visited](const intersection_validator::Box& a, const intersection_validator::Box& b) {
std::ostringstream ss;
// ss << id_map[a.id()]->first->data().toString() << "x" << id_map[b.id()]->first->data().toString() << std::endl;
// auto x = id_map[a.id()]->second * id_map[b.id()]->second;
auto A = a.handle()->first;
auto B = b.handle()->first;
auto Aguid = A->get_value<std::string>("GlobalId");
auto Bguid = B->get_value<std::string>("GlobalId");
int space_count = 0;
if (A->declaration().name() == "IfcSpace") {
space_count += 1;
}
if (B->declaration().name() == "IfcSpace") {
space_count += 1;
}
if (space_count != 1) {
return;
}
ss << a.handle()->first->data().toString() << "x" << a.handle()->first->data().toString() << std::endl;
auto x = a.handle()->second * b.handle()->second;
if (x.is_empty()) {
return;
}
guid_pairs_visited.insert({ Aguid, Bguid });
cgal_shape_t x_poly;
x.convert_to_polyhedron(x_poly);
{
std::string fn = "computed_boundaries_" + Aguid + "_" + Bguid + ".off";
std::ofstream computed_boundaries(fn.c_str());
computed_boundaries.precision(17);
computed_boundaries << x_poly;
}
Tree tree(faces(x_poly).first, faces(x_poly).second, x_poly);
tree.accelerate_distance_queries();
auto itelem = elem_to_space_boundary_coords.find({ Aguid, Bguid });
if (itelem == elem_to_space_boundary_coords.end()) {
Logger::Error("Missing space boundary relationship " + Aguid + " " + Bguid);
return;
}
const auto& coords = itelem->second;
std::vector<double> distances;
std::transform(coords.begin(), coords.end(), std::back_inserter(distances), [&tree](const auto& p) {
return std::sqrt(CGAL::to_double(tree.squared_distance(p)));
});
bool valid = *std::max_element(distances.begin(), distances.end()) < 0.4;
if (!valid) {
Logger::Error("Wrong connection geometry " + Aguid + " " + Bguid);
}
/*{
remove_thickness r(x_poly);
std::string fn = "thin_computed_boundaries_" + Aguid + "_" + Bguid + ".off";
std::ofstream computed_boundaries(fn.c_str());
computed_boundaries.precision(17);
computed_boundaries << r.flattened;
}*/
/*
{
auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "-sides-sb.off";
std::ofstream os(FN.c_str());
os.precision(17);
os << r.polyhedron2;
}
{
auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "-flat-sb.off";
std::ofstream os(FN.c_str());
os.precision(17);
os << r.flattened;
}
*/
});
auto is_wall_space_or_slab = [&f](const std::string& g) {
auto decl = f.instance_by_guid(g)->declaration();
return decl.is("IfcWall") || decl.is("IfcSpace") || decl.is("IfcSlab");
};
for (auto& i : *f2.instances_by_type("IfcProduct")) {
auto n = ((IfcUtil::IfcBaseEntity*)i)->get_value<std::string>("Name");
auto g1 = n.substr(0, 22);
auto g2 = n.substr(23);
if (is_wall_space_or_slab(g1) && is_wall_space_or_slab(g2) && guid_pairs_visited.find({ g1, g2 }) == guid_pairs_visited.end()) {
Logger::Error("Space boundary for non-bounding geometry " + g1 + " " + g2);
}
}
}
@@ -0,0 +1,233 @@
#include "../ifcgeom/kernels/cgal/CgalKernel.h"
#include "../ifcgeom/schema_agnostic/IfcGeomFilter.h"
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <CGAL/Polygon_mesh_processing/bbox.h>
#include <algorithm>
void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) {
ifcopenshell::geometry::settings settings;
settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false);
settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, false);
settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, true);
settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, true);
settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true);
settings.set(ifcopenshell::geometry::settings::DISABLE_OPENING_SUBTRACTIONS, true);
std::vector<ifcopenshell::geometry::filter_t> no_openings_and_spaces = {
IfcGeom::entity_filter(false, false, {"IfcOpeningElement", "IfcSpace"})
};
ifcopenshell::geometry::Iterator context_iterator("cgal", settings, &f, no_openings_and_spaces);
auto get_elevation = [](IfcUtil::IfcBaseClass* a) {
return ((IfcUtil::IfcBaseEntity*)a)->get_value_or<double>("Elevation", 0.);
};
// latebound inverse attribute lookup not working
auto rels = f.instances_by_type("IfcRelContainedInSpatialStructure");
std::map<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*> elem_to_storey;
std::for_each(rels->begin(), rels->end(), [&elem_to_storey](IfcUtil::IfcBaseClass* r) {
auto elems = ((IfcUtil::IfcBaseEntity*)r)->get_value<IfcEntityList::ptr>("RelatedElements");
auto storey = ((IfcUtil::IfcBaseEntity*)r)->get_value<IfcUtil::IfcBaseClass*>("RelatingStructure");
if (storey->declaration().name() == "IfcBuildingStorey") {
for (auto it = elems->begin(); it != elems->end(); ++it) {
elem_to_storey[*it] = storey;
}
}
});
auto storeys = f.instances_by_type("IfcBuildingStorey");
std::vector<IfcUtil::IfcBaseClass*> storeys_sorted(storeys->begin(), storeys->end());
std::sort(storeys_sorted.begin(), storeys_sorted.end(), [&get_elevation](IfcUtil::IfcBaseClass* a, IfcUtil::IfcBaseClass* b) {
return get_elevation(a) < get_elevation(b);
});
/*
std::wcout << "Storeys ";
for (auto& s : storeys_sorted) {
auto n = ((IfcUtil::IfcBaseEntity*)s)->get_value<std::string>("Name");
std::wcout << n.c_str() << " ";
}
std::wcout << std::endl;
*/
std::vector<double> elevations;
std::transform(storeys_sorted.begin(), storeys_sorted.end(), std::back_inserter(elevations), get_elevation);
double LARGE = 1e4;
std::vector<std::pair<double, double>> elevation_slices;
for (size_t i = 0; i < elevations.size(); ++i) {
elevation_slices.push_back({
i == 0 ? -LARGE : elevations[i],
i + 1 == elevations.size() ? LARGE : elevations[i + 1]
});
}
std::for_each(elevation_slices.begin(), elevation_slices.end(), [](std::pair<double, double>& p) {
p.first -= 0.3;
p.second += 0.3;
});
std::vector<CGAL::Nef_polyhedron_3<Kernel_>> nefs;
std::transform(elevation_slices.begin(), elevation_slices.end(), std::back_inserter(nefs), [&LARGE](const std::pair<double, double>& p) {
// std::wcout << p.first << " - " << p.second << std::endl;
Kernel_::Point_3 p1(-LARGE, -LARGE, p.first);
Kernel_::Point_3 p2(+LARGE, +LARGE, p.second);
auto poly = ifcopenshell::geometry::utils::create_cube(p1, p2);
return ifcopenshell::geometry::utils::create_nef_polyhedron(poly);
});
/*
for (auto& n : nefs) {
auto poly = ifcopenshell::geometry::utils::create_polyhedron(n);
auto bounds = CGAL::Polygon_mesh_processing::bbox_3(poly);
for (int i = 0; i < 3; ++i) {
std::wcout << bounds.min(i) << std::endl;
}
for (int i = 0; i < 3; ++i) {
std::wcout << bounds.max(i) << std::endl;
}
std::wcout << "---" << std::endl;
}
*/
if (!context_iterator.initialize()) {
return;
}
size_t num_created = 0;
int old_progress = quiet ? 0 : -1;
for (;; ++num_created) {
bool has_more = true;
if (num_created) {
has_more = context_iterator.next();
}
ifcopenshell::geometry::NativeElement* geom_object = nullptr;
if (has_more) {
geom_object = context_iterator.get_native();
}
if (!geom_object) {
break;
}
/*
std::stringstream ss;
ss << geom_object->product()->data().toString();
auto sss = ss.str();
std::wcout << sss.c_str() << std::endl;
*/
if (elem_to_storey.find(geom_object->product()) == elem_to_storey.end()) {
// std::wcout << "not associated to storey" << std::endl;
continue;
}
std::vector<double> intersection_volumes(nefs.size());
for (auto& g : geom_object->geometry()) {
auto s = ((ifcopenshell::geometry::CgalShape*) g.Shape())->shape();
const auto& m = g.Placement().components;
const auto& n = geom_object->transformation().data().components;
const cgal_placement_t trsf(
m(0, 0), m(0, 1), m(0, 2), m(0, 3),
m(1, 0), m(1, 1), m(1, 2), m(1, 3),
m(2, 0), m(2, 1), m(2, 2), m(2, 3));
const cgal_placement_t trsf2(
n(0, 0), n(0, 1), n(0, 2), n(0, 3),
n(1, 0), n(1, 1), n(1, 2), n(1, 3),
n(2, 0), n(2, 1), n(2, 2), n(2, 3));
// Apply transformation
for (auto &vertex : vertices(s)) {
vertex->point() = vertex->point().transform(trsf).transform(trsf2);
}
/*
{
auto bounds = CGAL::Polygon_mesh_processing::bbox_3(s);
for (int i = 0; i < 3; ++i) {
std::wcout << bounds.min(i) << std::endl;
}
for (int i = 0; i < 3; ++i) {
std::wcout << bounds.max(i) << std::endl;
}
std::wcout << "---" << std::endl;
}
*/
CGAL::Nef_polyhedron_3<Kernel_> part_nef = ifcopenshell::geometry::utils::create_nef_polyhedron(s);
if (!part_nef.is_simple()) {
// std::wcout << "not simple" << std::endl;
continue;
}
std::vector<double>::iterator accumulator = intersection_volumes.begin();
std::for_each(nefs.begin(), nefs.end(), [&accumulator, &part_nef](const CGAL::Nef_polyhedron_3<Kernel_>& storey_nef) {
auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef * storey_nef);
CGAL::Polygon_mesh_processing::triangulate_faces(poly);
*accumulator += CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly));
accumulator++;
});
}
/*
std::wcout << "volumes: ";
for (auto& v : intersection_volumes) {
std::wcout << v << " ";
}
std::wcout << std::endl;
*/
auto calc_idx = std::max_element(intersection_volumes.begin(), intersection_volumes.end()) - intersection_volumes.begin();
auto calc_overlap = intersection_volumes[calc_idx];
auto assigned_idx = std::distance(storeys_sorted.begin(), std::find(storeys_sorted.begin(), storeys_sorted.end(), elem_to_storey[geom_object->product()]));
auto assigned_overlap = intersection_volumes[assigned_idx];
if (calc_overlap > 0 && assigned_overlap < calc_overlap * 0.9) {
auto s = geom_object->product()->get_value<std::string>("GlobalId");
auto s1 = ((IfcUtil::IfcBaseEntity*)storeys_sorted[calc_idx])->get_value<std::string>("GlobalId");
auto s2 = ((IfcUtil::IfcBaseEntity*)elem_to_storey[geom_object->product()])->get_value<std::string>("GlobalId");
Logger::Error("Element " + s + " contained in " + s2 + " located on " + s1);
}
if (!no_progress) {
if (quiet) {
const int progress = context_iterator.progress();
for (; old_progress < progress; ++old_progress) {
std::cout << ".";
if (stderr_progress)
std::cerr << ".";
}
std::cout << std::flush;
if (stderr_progress)
std::cerr << std::flush;
} else {
const int progress = context_iterator.progress() / 2;
if (old_progress != progress) Logger::ProgressBar(progress);
old_progress = progress;
}
}
}
if (!no_progress && quiet) {
for (; old_progress < 100; ++old_progress) {
std::cout << ".";
if (stderr_progress)
std::cerr << ".";
}
std::cout << std::flush;
if (stderr_progress)
std::cerr << std::flush;
} else {
Logger::Status("\rDone fixing space boundaries for " + boost::lexical_cast<std::string>(num_created) +
" objects ");
}
}
@@ -0,0 +1,198 @@
#include "validation_utils.h"
#include <CGAL/Polygon_mesh_processing/bbox.h>
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <algorithm>
using namespace ifcopenshell::geometry;
void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) {
intersection_validator v(f, { "IfcWall" }, 1.e-3, no_progress, quiet, stderr_progress);
ifcopenshell::geometry::settings settings;
settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false);
settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, false);
settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, true);
settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, true);
settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true);
settings.set(ifcopenshell::geometry::settings::DISABLE_OPENING_SUBTRACTIONS, true);
settings.set(ifcopenshell::geometry::settings::INCLUDE_CURVES, true);
settings.set(ifcopenshell::geometry::settings::EXCLUDE_SOLIDS_AND_SURFACES, true);
ifcopenshell::geometry::Converter c("cgal", &f, settings);
auto rels = f.instances_by_type("IfcRelConnectsPathElements");
std::map<std::set<const IfcUtil::IfcBaseClass*>, const IfcUtil::IfcBaseClass*> rel_by_elem;
std::for_each(rels->begin(), rels->end(), [&rel_by_elem](const IfcUtil::IfcBaseClass* rel) {
auto x = ((IfcUtil::IfcBaseEntity*)rel)->get_value<IfcUtil::IfcBaseClass*>("RelatingElement");
auto y = ((IfcUtil::IfcBaseEntity*)rel)->get_value<IfcUtil::IfcBaseClass*>("RelatedElement");
rel_by_elem.insert({{ x,y }, rel});
});
std::set<const IfcUtil::IfcBaseClass*> rels_encounted;
double total_nef_intersection_time = 0.;
double conversion_to_poly = 0.;
v([&c, &rel_by_elem, &rels_encounted, &total_nef_intersection_time, &conversion_to_poly](const intersection_validator::Box& a, const intersection_validator::Box& b) {
auto A = a.handle()->first;
auto B = b.handle()->first;
const IfcUtil::IfcBaseClass* rel = nullptr;
std::string a_type, b_type;
auto rit = rel_by_elem.find({ A, B });
if (rit != rel_by_elem.end()) {
rel = rit->second;
const bool a_is_relating = A == ((IfcUtil::IfcBaseEntity*)rel)->get_value<IfcUtil::IfcBaseClass*>("RelatingElement");
a_type = ((IfcUtil::IfcBaseEntity*)rel)->get_value<std::string>("RelatingConnectionType");
b_type = ((IfcUtil::IfcBaseEntity*)rel)->get_value<std::string>("RelatedConnectionType");
if (!a_is_relating) {
std::swap(a_type, b_type);
}
}
#if 0
auto a_poly = ifcopenshell::geometry::utils::create_polyhedron(a.handle()->second);
auto b_poly = ifcopenshell::geometry::utils::create_polyhedron(b.handle()->second);
std::wcout << "a" << std::endl;
for (auto& v : vertices(a_poly)) {
for (int i = 0; i < 3; ++i) {
std::wcout << CGAL::to_double(v->point().cartesian(i)) << " ";
}
std::wcout << std::endl;
}
std::wcout << "b" << std::endl;
for (auto& v : vertices(b_poly)) {
for (int i = 0; i < 3; ++i) {
std::wcout << CGAL::to_double(v->point().cartesian(i)) << " ";
}
std::wcout << std::endl;
}
#endif
std::ostringstream ss;
ss << A->data().toString() << "x" << B->data().toString() << std::endl;
std::clock_t intersection_begin = std::clock();
auto x = a.handle()->second * b.handle()->second;
std::clock_t intersection_end = std::clock();
total_nef_intersection_time += (intersection_end - intersection_begin) / (double) CLOCKS_PER_SEC;
if (x.is_empty()) {
return;
}
std::clock_t poly_begin = std::clock();
cgal_shape_t x_poly;
x.convert_to_polyhedron(x_poly);
std::clock_t poly_end = std::clock();
conversion_to_poly += (poly_end - poly_begin) / (double)CLOCKS_PER_SEC;
auto dza = a.bbox().zmax() - a.bbox().zmin();
auto dzb = b.bbox().zmax() - b.bbox().zmin();
auto bb = CGAL::Polygon_mesh_processing::bbox_3(x_poly);
if (bb.zmax() - bb.zmin() < std::min(dza, dzb) / 3.) {
return;
}
CGAL::Polygon_mesh_processing::triangulate_faces(x_poly);
if (CGAL::Polygon_mesh_processing::area(x_poly) > 4.0) {
return;
}
auto get_axis_parameter_min_max = [&c, &x_poly](IfcUtil::IfcBaseEntity* inst) {
auto item = c.mapping()->map(inst);
auto shaperep = ((taxonomy::collection*) item)->children[0];
auto loop = ((taxonomy::collection*) shaperep)->children[0];
if (loop->kind() != taxonomy::LOOP) {
// std::wcout << "no suitable axis" << std::endl;
} else {
auto first_vertex = ((taxonomy::edge*) ((taxonomy::loop*) loop)->children.front())->start;
auto last_vertex = ((taxonomy::edge*) ((taxonomy::loop*) loop)->children.back())->end;
if (first_vertex.which() != 0 || last_vertex.which() != 0) {
// std::wcout << "trims not supported" << std::endl;
} else {
auto p0 = boost::get<taxonomy::point3>(first_vertex);
auto p1 = boost::get<taxonomy::point3>(last_vertex);
auto v0 = ((taxonomy::geom_item*)item)->matrix.components * p0.components.homogeneous();
auto v1 = ((taxonomy::geom_item*)item)->matrix.components * p1.components.homogeneous();
auto P0 = Kernel_::Point_3(v0(0), v0(1), v0(2));
auto P1 = Kernel_::Point_3(v1(0), v1(1), v1(2));
auto D = P1 - P0;
auto len = std::sqrt(CGAL::to_double(D.squared_length()));
D /= len;
std::vector<Kernel_::FT> parameters;
std::transform(vertices(x_poly).begin(), vertices(x_poly).end(), std::back_inserter(parameters), [&P0, D](auto& v) {
return (v->point() - P0) * D;
});
auto pit = std::minmax_element(parameters.begin(), parameters.end());
return std::make_pair(len, std::make_pair(CGAL::to_double(*pit.first), CGAL::to_double(*pit.second)));
}
}
const auto& nan = std::numeric_limits<double>::quiet_NaN();
return std::make_pair(nan, std::make_pair(nan, nan));
};
auto qualify_connection_type = [](double l, const std::pair<double, double>& p) {
if (p.first < 1.e-3) {
return "ATSTART";
} else if (p.second > l - 1.e-3) {
return "ATEND";
} else {
return "ATPATH";
}
};
auto alu0u1 = get_axis_parameter_min_max(A);
auto blu0u1 = get_axis_parameter_min_max(B);
auto atype_computed = qualify_connection_type(alu0u1.first, alu0u1.second);
auto btype_computed = qualify_connection_type(blu0u1.first, blu0u1.second);
rels_encounted.insert(rel);
if (a_type != atype_computed || b_type != btype_computed) {
if (rel) {
Logger::Error(std::string("Connection type ") + atype_computed + " " + btype_computed + " for:", rel);
} else {
auto A_str = A->get_value<std::string>("GlobalId");
auto B_str = B->get_value<std::string>("GlobalId");
Logger::Error("No connection for adjacent " + A_str + " " + B_str);
}
}
});
std::for_each(rels->begin(), rels->end(), [&rels_encounted, &v](const IfcUtil::IfcBaseClass* rel) {
if (rels_encounted.find(rel) == rels_encounted.end()) {
auto x = (IfcUtil::IfcBaseEntity*)((IfcUtil::IfcBaseEntity*)rel)->get_value<IfcUtil::IfcBaseClass*>("RelatingElement");
auto y = (IfcUtil::IfcBaseEntity*)((IfcUtil::IfcBaseEntity*)rel)->get_value<IfcUtil::IfcBaseClass*>("RelatedElement");
if (v.succesfully_processed.find(x) != v.succesfully_processed.end() && v.succesfully_processed.find(y) != v.succesfully_processed.end()) {
Logger::Error("Connection for non-adjacent walls", rel);
}
}
});
std::wcout << std::setprecision(14);
std::wcout << "total_map_time " << v.total_map_time << std::endl;
std::wcout << "total_geom_time " << v.total_geom_time << std::endl;
std::wcout << "total_nef_time " << v.total_nef_time << std::endl;
std::wcout << "total_minkowsky_time " << v.total_minkowsky_time << std::endl;
std::wcout << "total_box_time " << v.total_box_time << std::endl;
std::wcout << "total_nef_intersection_time " << total_nef_intersection_time << std::endl;
std::wcout << "total_conversion_to_poly_time " << conversion_to_poly << std::endl;
}
+28
View File
@@ -0,0 +1,28 @@
#include "validation_utils.h"
double facet_area(const cgal_shape_t::Facet_handle& f) {
auto p0 = f->facet_begin()->vertex()->point();
auto p1 = f->facet_begin()->next()->vertex()->point();
auto p2 = f->facet_begin()->next()->next()->vertex()->point();
return std::sqrt(CGAL::to_double(CGAL::cross_product(p0 - p1, p2 - p1).squared_length()));
}
void dump_facet(const cgal_shape_t::Facet_handle& f) {
auto p0 = f->facet_begin()->vertex()->point();
auto p1 = f->facet_begin()->next()->vertex()->point();
auto p2 = f->facet_begin()->next()->next()->vertex()->point();
auto V = CGAL::cross_product(p0 - p1, p2 - p1);
auto d = std::sqrt(CGAL::to_double(V.squared_length()));
if (d > 1.e-20) {
V /= d;
}
std::ostringstream oss;
oss.precision(8);
oss << "Facet with area " << facet_area(f) << " and normal ("
<< CGAL::to_double(V.cartesian(0)) << " " << CGAL::to_double(V.cartesian(1)) << " "
<< CGAL::to_double(V.cartesian(2)) << ")";
auto osss = oss.str();
std::wcout << osss.c_str() << std::endl;
}
+580
View File
@@ -0,0 +1,580 @@
#include "../ifcgeom/kernels/cgal/CgalKernel.h"
#include "../ifcgeom/schema_agnostic/IfcGeomFilter.h"
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
#include <CGAL/box_intersection_d.h>
#include <CGAL/minkowski_sum_3.h>
#include <CGAL/AABB_tree.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/AABB_face_graph_triangle_primitive.h>
#include <fstream>
#include <iostream>
template <typename T>
T enlarge(const T& t, double d = 1.e-5) {
T::NT min[3];
T::NT max[3];
for (int i = 0; i < t.dimension(); ++i) {
min[i] = t.min_coord(i) - d;
max[i] = t.max_coord(i) + d;
}
return T(min, max, t.handle());
}
template <class HDS>
struct Build_Offset : public CGAL::Modifier_base<HDS> {
std::list<cgal_shape_t::Facet_handle> input;
void operator()(HDS& hds) {
// Postcondition: hds is a valid polyhedral surface.
CGAL::Polyhedron_incremental_builder_3<HDS> B(hds);
int Nv = 0, Nf = 0;
for (auto& f : input) {
Nv += 3;
Nf += 1;
}
B.begin_surface(Nv, Nf);
for (auto& f : input) {
auto p0 = f->facet_begin()->vertex()->point();
auto p1 = f->facet_begin()->next()->vertex()->point();
auto p2 = f->facet_begin()->next()->next()->vertex()->point();
auto O = CGAL::centroid(p0, p1, p2);
Kernel_::Point_3* p012[3] = { &p0, &p1, &p2 };
for (int i = 0; i < 3; ++i) {
*p012[i] = CGAL::ORIGIN + (((*(p012[i])) - CGAL::ORIGIN) + ((*(p012[i])) - O));
B.add_vertex(*p012[i]);
}
}
Nv = 0;
for (int i = 0; i < Nf; ++i) {
B.begin_facet();
B.add_vertex_to_facet(Nv++);
B.add_vertex_to_facet(Nv++);
B.add_vertex_to_facet(Nv++);
B.end_facet();
}
B.end_surface();
}
};
template <typename Ts>
std::list<cgal_shape_t::Facet_handle> connected_faces(cgal_shape_t::Facet_handle& f, const Ts& excluded) {
std::set<cgal_shape_t::Facet_handle> fs = { f };
std::function<void(cgal_shape_t::Facet_handle& f)> process;
process = [&fs, &process, &excluded](cgal_shape_t::Facet_handle& f) {
cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ);
do {
auto ff = circ->opposite()->facet();
if (excluded.find(ff) == excluded.end()) {
auto p = fs.insert(ff);
if (p.second) {
process(ff);
}
}
} while (++circ != end);
};
process(f);
return std::list<cgal_shape_t::Facet_handle>(fs.begin(), fs.end());
}
template <class HDS>
struct Builder_With_Map : public CGAL::Modifier_base<HDS> {
std::list<cgal_shape_t::Facet_handle> input;
std::map<Kernel_::Point_3, Kernel_::Point_3> mapping;
void operator()(HDS& hds) {
// Postcondition: hds is a valid polyhedral surface.
CGAL::Polyhedron_incremental_builder_3<HDS> B(hds);
std::set<Kernel_::Point_3> used_points;
for (auto& f : input) {
cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ);
do {
auto P = circ->vertex()->point();
auto it = mapping.find(P);
if (it == mapping.end()) {
std::wcout << "WARNING unprojected point :(" << std::endl;
} else {
P = it->second;
}
used_points.insert(P);
} while (++circ != end);
}
B.begin_surface(used_points.size(), input.size());
for (auto& p : used_points) {
B.add_vertex(p);
}
for (auto& f : input) {
B.begin_facet();
cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ);
do {
auto P = circ->vertex()->point();
auto it = mapping.find(P);
if (it == mapping.end()) {
std::wcout << "WARNING unprojected point :(" << std::endl;
} else {
P = it->second;
}
auto jt = used_points.find(P);
if (jt == used_points.end()) {
throw std::runtime_error("Unable to map point");
}
size_t idx = std::distance(used_points.begin(), jt);
std::wcout << "idx " << idx << std::endl;
B.add_vertex_to_facet(idx);
} while (++circ != end);
B.end_facet();
}
B.end_surface();
}
};
double facet_area(const cgal_shape_t::Facet_handle& f);
void dump_facet(const cgal_shape_t::Facet_handle& f);
struct remove_thickness {
typedef Kernel_::Point_3 Point;
typedef Kernel_::Plane_3 Plane;
typedef Kernel_::Vector_3 Vector;
typedef Kernel_::Segment_3 Segment;
typedef Kernel_::Ray_3 Ray;
typedef CGAL::Polyhedron_3<Kernel_> Polyhedron;
typedef CGAL::AABB_face_graph_triangle_primitive<Polyhedron> Primitive;
typedef CGAL::AABB_traits<Kernel_, Primitive> Traits;
typedef CGAL::AABB_tree<Traits> Tree;
typedef boost::optional<Tree::Intersection_and_primitive_id<Ray>::Type> Ray_intersection;
cgal_shape_t polyhedron, polyhedron2, flattened;
remove_thickness(const cgal_shape_t& p)
// edge_collapse(p) still does not work :(
: polyhedron(p)
, polyhedron2(p) {
CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron);
CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron2);
std::list<cgal_shape_t::Facet_handle> non_degenerate, degenerate, longitudonal;
std::set<cgal_shape_t::Facet_iterator> thin_sides;
std::wcout << "ALL FACES:" << std::endl;
for (auto& f : faces(polyhedron)) {
dump_facet(f);
if (facet_area(f) > 1.e-20) {
non_degenerate.push_back(f);
} else {
degenerate.push_front(f);
std::wcout << "Degenerate, area: " << facet_area(f) << std::endl;
}
}
std::wcout << "NON DEGENERATE:" << std::endl;
for (auto& f : non_degenerate) {
dump_facet(f);
}
cgal_shape_t enlarged_non_degenerate_triangles;
Build_Offset<cgal_shape_t::HDS> bo;
bo.input = non_degenerate;
enlarged_non_degenerate_triangles.delegate(bo);
// @todo, first on non-enlarged faces, then on enlarged; to fix projection on concave surfaces where the enlarging operation shortens projection distances.
Tree tree(faces(enlarged_non_degenerate_triangles).first, faces(enlarged_non_degenerate_triangles).second, enlarged_non_degenerate_triangles);
std::map<cgal_face_descriptor_t, Kernel_::Vector_3> face_normals;
boost::associative_property_map<std::map<cgal_face_descriptor_t, Kernel_::Vector_3>> face_normals_map(face_normals);
CGAL::Polygon_mesh_processing::compute_face_normals(polyhedron, face_normals_map);
for (auto& f : non_degenerate) {
auto O = CGAL::centroid(
f->facet_begin()->vertex()->point(),
f->facet_begin()->next()->vertex()->point(),
f->facet_begin()->next()->next()->vertex()->point()
);
Ray ray(O, -face_normals_map[f]);
std::list<Ray_intersection> intersections;
tree.all_intersections(ray, std::back_inserter(intersections));
double N = std::numeric_limits<double>::infinity();
Point P;
for (auto& intersection : intersections) {
if (boost::get<Point>(&(intersection->first))) {
const Point* p = boost::get<Point>(&(intersection->first));
const double d = std::sqrt(CGAL::to_double((*p - O).squared_length()));
if (d > 1.e-20 && d < N) {
N = d;
}
}
}
if (N != std::numeric_limits<double>::infinity() && N > 1.e-4) {
thin_sides.insert(f);
}
}
std::wcout << "THIN SIDES:" << std::endl;
for (auto& f : thin_sides) {
dump_facet(f);
}
for (auto& f : non_degenerate) {
if (thin_sides.find(f) == thin_sides.end()) {
longitudonal.push_back(f);
}
}
std::wcout << "LONGITUDONAL:" << std::endl;
for (auto& f : longitudonal) {
dump_facet(f);
}
std::wcout << "faces " << faces(polyhedron).size() << "long " << longitudonal.size() << "thin " << thin_sides.size() << "non-degen " << non_degenerate.size() << std::endl;
cgal_shape_t enlarged_indiv_triangles;
Build_Offset<cgal_shape_t::HDS> bo2;
bo2.input = longitudonal;
enlarged_indiv_triangles.delegate(bo2);
{
std::ofstream ofs("enlarged.off");
ofs.precision(17);
ofs << enlarged_indiv_triangles;
}
Tree tree2(faces(enlarged_indiv_triangles).begin(), faces(enlarged_indiv_triangles).end(), enlarged_indiv_triangles);
std::map<Kernel_::Point_3, Kernel_::Point_3> new_points;
for (Polyhedron::Facet_iterator fit = polyhedron.facets_begin();
fit != polyhedron.facets_end();
++fit) {
if (CGAL::collinear(
fit->halfedge()->vertex()->point(),
fit->halfedge()->next()->vertex()->point(),
fit->halfedge()->opposite()->vertex()->point())) {
std::wcout << "degenerate triangle" << std::endl;
}
}
for (auto& v : vertices(polyhedron)) {
auto O = v->point();
Kernel_::Vector_3 norm;
Kernel_::Vector_3 accum;
int count = 0;
CGAL::Face_around_target_circulator<cgal_shape_t> it(v->halfedge(), polyhedron), end(it);
do {
cgal_shape_t::Facet_handle fh = (*it)->halfedge()->facet();
auto jt = std::find(non_degenerate.begin(), non_degenerate.end(), fh);
std::wcout << "non degen: " << (jt != non_degenerate.end()) << std::endl;
auto kt = std::find(thin_sides.begin(), thin_sides.end(), fh);
std::wcout << "thin side: " << (kt != thin_sides.end()) << std::endl;
if (jt != non_degenerate.end() && kt == thin_sides.end()) {
// else degenerate, prevent div by zero, do not incorporate in vnorm.
// or else part of thin side
auto p0 = (*it)->facet_begin()->vertex()->point();
auto p1 = (*it)->facet_begin()->next()->vertex()->point();
auto p2 = (*it)->facet_begin()->next()->next()->vertex()->point();
{
std::ostringstream oss;
oss.precision(8);
oss << "p0 " << p0.cartesian(0) << " " << p0.cartesian(1) << " " << p0.cartesian(2) << "\n";
oss << "p1 " << p1.cartesian(0) << " " << p1.cartesian(1) << " " << p1.cartesian(2) << "\n";
oss << "p2 " << p2.cartesian(0) << " " << p2.cartesian(1) << " " << p2.cartesian(2) << "\n";
auto osss = oss.str();
std::wcout << osss.c_str() << std::endl;
}
auto fnorm = CGAL::cross_product(p0 - p1, p2 - p1);
fnorm /= std::sqrt(CGAL::to_double(fnorm.squared_length()));
// const auto& fnorm = face_normals_map_2[*it];
std::ostringstream oss;
oss.precision(8);
oss << fnorm.cartesian(0) << " " << fnorm.cartesian(1) << " " << fnorm.cartesian(2);
auto osss = oss.str();
std::wcout << osss.c_str() << std::endl;
accum += fnorm;
++count;
}
++it;
} while (it != end);
norm = accum / count;
std::wcout << "count " << count << std::endl;
if (count == 0) {
// part of only degenerate or only thin sides
continue;
}
// v->vertex_begin();
Ray ray(O, norm);
std::ostringstream oss;
oss.precision(8);
oss << O << " -> " << norm;
auto osss = oss.str();
std::wcout << osss.c_str() << std::endl;
std::list<Ray_intersection> intersections;
tree2.all_intersections(ray, std::back_inserter(intersections));
double N = std::numeric_limits<double>::infinity();
Point P;
bool used_intersection = false;
if (intersections.size()) {
for (auto& intersection : intersections) {
if (boost::get<Point>(&(intersection->first))) {
const Point* p = boost::get<Point>(&(intersection->first));
const double d = std::sqrt(CGAL::to_double((*p - O).squared_length()));
if (d < N && d > 1.e-20) {
N = d;
P = *p;
std::wcout << "intersection @ " << d << std::endl;
}
}
}
std::wcout << "-----------" << std::endl;
// average the new point
new_points[O] = CGAL::ORIGIN + (((O - CGAL::ORIGIN) + (P - CGAL::ORIGIN))) / 2;
used_intersection = true;
}
if (!used_intersection) {
std::wcout << "no intersection :(" << std::endl;
}
}
auto thin_sides_degenerate = thin_sides;
thin_sides_degenerate.insert(degenerate.begin(), degenerate.end());
// @todo choose connected / connected_opposing based on largest combined area of facets?
if (longitudonal.size() == 0) {
std::wcout << "no longitudonal faces detected :(" << std::endl;
return;
}
auto connected = connected_faces(*longitudonal.begin(), thin_sides_degenerate);
decltype(connected) connected_opposing;
for (auto& f : longitudonal) {
if (std::find(connected.begin(), connected.end(), f) == connected.end()) {
connected_opposing = connected_faces(f, thin_sides_degenerate);
std::set<cgal_shape_t::Facet_handle> longi(longitudonal.begin(), longitudonal.end());
std::set<cgal_shape_t::Facet_handle> both_sides(connected.begin(), connected.end());
both_sides.insert(connected_opposing.begin(), connected_opposing.end());
if (longi == both_sides) {
std::wcout << "Facet connection functioning properly" << std::endl;
} else {
std::wcout << "Facet connection functioning incorrectly" << std::endl;
}
break;
}
}
Builder_With_Map<cgal_shape_t::HDS> b2;
b2.input = connected;
b2.mapping = new_points;
flattened.delegate(b2);
}
};
struct intersection_validator {
typedef std::list<std::pair<IfcUtil::IfcBaseEntity*, CGAL::Nef_polyhedron_3<Kernel_>> > nefs_t;
typedef CGAL::Box_intersection_d::Box_with_handle_d<double, 3, nefs_t::value_type*> Box;
std::vector<Box> boxes;
nefs_t nefs;
double total_map_time = 0.;
double total_geom_time = 0.;
double total_nef_time = 0.;
double total_minkowsky_time = 0.;
double total_box_time = 0.;
std::set<IfcUtil::IfcBaseEntity*> succesfully_processed;
intersection_validator(IfcParse::IfcFile& f, std::initializer_list<std::string> entities, double eps, bool no_progress, bool quiet, bool stderr_progress) {
ifcopenshell::geometry::settings settings;
settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false);
settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, false);
settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, true);
settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, true);
settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true);
settings.set(ifcopenshell::geometry::settings::DISABLE_OPENING_SUBTRACTIONS, true);
std::vector<ifcopenshell::geometry::filter_t> spaces_and_walls = {
IfcGeom::entity_filter(true, false, entities)
};
ifcopenshell::geometry::Iterator context_iterator("cgal", settings, &f, spaces_and_walls);
if (!context_iterator.initialize()) {
return;
}
auto cube = ifcopenshell::geometry::utils::create_nef_polyhedron(ifcopenshell::geometry::utils::create_cube(eps));
size_t num_created = 0;
int old_progress = quiet ? 0 : -1;
for (;; ++num_created) {
bool has_more = true;
if (num_created) {
has_more = context_iterator.next();
}
ifcopenshell::geometry::NativeElement* geom_object = nullptr;
if (has_more) {
geom_object = context_iterator.get_native();
}
if (!geom_object) {
break;
}
std::stringstream ss;
ss << geom_object->product()->data().toString();
auto sss = ss.str();
std::wcout << sss.c_str() << std::endl;
for (auto& g : geom_object->geometry()) {
auto s = ((ifcopenshell::geometry::CgalShape*) g.Shape())->shape();
const auto& m = g.Placement().components;
const auto& n = geom_object->transformation().data().components;
const cgal_placement_t trsf(
m(0, 0), m(0, 1), m(0, 2), m(0, 3),
m(1, 0), m(1, 1), m(1, 2), m(1, 3),
m(2, 0), m(2, 1), m(2, 2), m(2, 3));
const cgal_placement_t trsf2(
n(0, 0), n(0, 1), n(0, 2), n(0, 3),
n(1, 0), n(1, 1), n(1, 2), n(1, 3),
n(2, 0), n(2, 1), n(2, 2), n(2, 3));
// Apply transformation
for (auto &vertex : vertices(s)) {
vertex->point() = vertex->point().transform(trsf).transform(trsf2);
}
std::clock_t nef_begin = std::clock();
CGAL::Nef_polyhedron_3<Kernel_> nef = ifcopenshell::geometry::utils::create_nef_polyhedron(s);
std::clock_t nef_end = std::clock();
total_nef_time += (nef_end - nef_begin) / (double) CLOCKS_PER_SEC;
if (nef.is_empty()) {
std::wcout << "Failed to create nef" << std::endl;
continue;
}
succesfully_processed.insert(geom_object->product());
nef = CGAL::minkowski_sum_3(nef, cube);
std::clock_t minkowski_end = std::clock();
total_minkowsky_time += (minkowski_end - nef_end) / (double) CLOCKS_PER_SEC;
std::wcout << "product: " << geom_object->product() << std::endl;
nefs.push_back({ geom_object->product(), nef });
Box b(&*(nefs.rbegin()));
// id_map[b.id()] = ;
for (auto &vertex : vertices(s)) {
double p[3] = {
CGAL::to_double(vertex->point().cartesian(0)),
CGAL::to_double(vertex->point().cartesian(1)),
CGAL::to_double(vertex->point().cartesian(2))
};
b.extend(p);
}
boxes.push_back(enlarge(b));
/*
std::ostringstream ss;
ss << geom_object->product()->data().toString() << std::endl << b.min_coord(0) << " - " << b.max_coord(0) << std::endl;
auto sss = ss.str();
std::wcout << sss.c_str();
*/
}
if (!no_progress) {
if (quiet) {
const int progress = context_iterator.progress();
for (; old_progress < progress; ++old_progress) {
std::cout << ".";
if (stderr_progress)
std::cerr << ".";
}
std::cout << std::flush;
if (stderr_progress)
std::cerr << std::flush;
} else {
const int progress = context_iterator.progress() / 2;
if (old_progress != progress) Logger::ProgressBar(progress);
old_progress = progress;
}
}
}
if (!no_progress && quiet) {
for (; old_progress < 100; ++old_progress) {
std::cout << ".";
if (stderr_progress)
std::cerr << ".";
}
std::cout << std::flush;
if (stderr_progress)
std::cerr << std::flush;
} else {
Logger::Status("\rDone fixing space boundaries for " + boost::lexical_cast<std::string>(num_created) +
" objects ");
}
total_geom_time = context_iterator.converter().total_geom_time;
total_map_time = context_iterator.converter().total_map_time;
}
template <typename Fn>
void operator()(Fn fn) {
std::clock_t box_overlap_begin = std::clock();
CGAL::box_self_intersection_d(boxes.begin(), boxes.end(), [](auto& x, auto& y) {});
std::clock_t box_overlap_end = std::clock();
total_box_time += (box_overlap_end - box_overlap_begin) / (double) CLOCKS_PER_SEC;
CGAL::box_self_intersection_d(boxes.begin(), boxes.end(), fn);
}
};
+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
+56 -30
View File
@@ -19,8 +19,14 @@
import sys
import string
import operator
import itertools
from pyparsing import *
try: from functools import reduce
except: pass
class Expression:
def __init__(self, contents):
self.contents = contents[0]
@@ -56,12 +62,12 @@ class Keyword:
class Terminal:
def __init__(self, contents):
self.contents = contents[0]
def __repr__(self):
s = self.contents
is_keyword = len(s) >= 4 and s[0::len(s)-1] == '""' and \
self.is_keyword = len(s) >= 4 and s[0::len(s)-1] == '""' and \
all(c in alphanums+"_" for c in s[1:-1])
ty = "CaselessKeyword" if is_keyword else "CaselessLiteral"
return "%s(%s)" % (ty, s)
def __repr__(self):
ty = "CaselessKeyword" if self.is_keyword else "CaselessLiteral"
return "%s(%s)" % (ty, self.contents)
LPAREN = Suppress("(")
@@ -94,16 +100,16 @@ grammar.ignore(HASH + restOfLine)
express = grammar.parseFile(sys.argv[1])
def find_keywords(expr, li = None):
def find_bytype(expr, ty, li = None):
if li is None: li = []
if isinstance(expr, Term):
expr = expr.contents
if isinstance(expr, Keyword):
li.append(repr(expr))
return li
if isinstance(expr, ty):
li.append(expr)
return set(li)
elif isinstance(expr, Expression):
for term in expr:
find_keywords(term, li)
find_bytype(term, ty, li)
return set(li)
actions = {
@@ -115,13 +121,16 @@ 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)",
'supertype_constraint' : "lambda t: SuperTypeExpression(t)",
'derive_clause' : "lambda t: AttributeList('derive', t)",
'derived_attr' : "lambda t: DerivedAttribute(t)",
'inverse_clause' : "lambda t: AttributeList('inverse', t)",
'inverse_attr' : "lambda t: InverseAttribute(t)",
'bound_spec' : "lambda t: BoundSpecification(t)",
'explicit_attr' : "lambda t: ExplicitAttribute(t)",
'width_spec' : "lambda t: WidthSpec(t)",
'string_type' : "lambda t: StringType(t)",
}
to_emit = set(id for id, expr in express)
@@ -129,18 +138,22 @@ emitted = set()
to_combine = set(["simple_id"])
to_ignore = set(["where_clause", "supertype_constraint", "unique_clause"])
statements = []
terminals = reduce(lambda x,y: x | y, (find_bytype(e, Terminal) for id, e in express))
keywords = list(filter(operator.attrgetter('is_keyword'), terminals))
negated_keywords = map(lambda s: "~%s" % s, keywords)
while True:
emitted_in_loop = set()
for id, expr in express:
kws = find_keywords(expr)
kws = map(repr, find_bytype(expr, Keyword))
found = [k in emitted for k in kws]
if id in to_emit and all(found):
emitted_in_loop.add(id)
emitted.add(id)
stmt = "(%s)" % expr
if id in to_combine:
stmt = "originalTextFor(Combine%s)" % stmt
stmt = " + ".join(itertools.chain(negated_keywords, ("originalTextFor(Combine%s)" % stmt,)))
if id in actions:
stmt = "%s.setParseAction(%s)" % (stmt, actions[id])
statements.append("%s = %s" % (id, stmt))
@@ -158,29 +171,42 @@ 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)
schema = mapping.schema
else:
from pyparsing import *
from nodes import *
import schema
import mapping
%s
import schema
import mapping
syntax.ignore("--" + restOfLine)
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
ast = syntax.parseFile(sys.argv[1])
schema = schema.Schema(ast)
mapping = mapping.Mapping(schema)
with open(cache_file, "wb") as f:
pickle.dump(mapping, f, protocol=0)
import header
import enum_header
import implementation
import latebound_header
import latebound_implementation
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
ast = syntax.parseFile(sys.argv[1])
schema = schema.Schema(ast)
mapping = mapping.Mapping(schema)
import schema_class
import definitions
header.Header(mapping).emit()
enum_header.EnumHeader(mapping).emit()
implementation.Implementation(mapping).emit()
latebound_header.LateBoundHeader(mapping).emit()
latebound_implementation.LateBoundImplementation(mapping).emit()
"""%('\n'.join(statements)))
schema_class.SchemaClass(mapping).emit()
definitions.Definitions(mapping).emit()
sys.stdout.write(schema.name)
"""%('\n '.join(statements)))
@@ -17,22 +17,19 @@
# #
###############################################################################
import templates
class EnumHeader:
def __init__(self, mapping):
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]))
self.str = templates.enum_header % {
'schema_name_upper' : mapping.schema.name.upper(),
'schema_name' : mapping.schema.name.capitalize(),
'types' : ', '.join(enumerable_types)
}
self.schema_name = mapping.schema.name.capitalize()
def __repr__(self):
return self.str
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):
f = open('%senum.h'%self.schema_name, 'w', encoding='utf-8')
f.write(str(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()
+62
View File
@@ -0,0 +1,62 @@
###############################################################################
# #
# 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
from collections import defaultdict
class Definitions(codegen.Base):
def __init__(self, mapping):
schema_name = mapping.schema.name
self.schema_name = schema_name_title = schema_name.capitalize()
statements = ['']
def write_entity(schema_name, name, type):
attribute_names = list(map(lambda t: (t.name, t.optional), type.attributes))
for attr, is_optional in attribute_names:
statements.append("#define SCHEMA_%(name)s_HAS_%(attr)s" % locals())
if is_optional:
statements.append("#define SCHEMA_%(name)s_%(attr)s_IS_OPTIONAL" % locals())
def write(name):
statements.append("#define SCHEMA_HAS_%(name)s" % locals())
fn = None
if mapping.schema.is_entity(name):
fn = write_entity
if fn is not None:
decl = mapping.schema[name]
if isinstance(decl, nodes.TypeDeclaration):
decl = decl.type.type
fn(schema_name, name, decl) is not False
for name in mapping.schema:
write(name)
self.str = "\n".join(statements) + "\n"
self.file_name = '%s-definitions.h' % self.schema_name
def __repr__(self):
return self.str
+14 -7
View File
@@ -27,34 +27,41 @@
# #
###############################################################################
import re,csv
import re
import os
import csv
from schema import OrderedCaseInsensitiveDict
try: from html.entities import entitydefs
except: from htmlentitydefs import entitydefs
name_to_oid = {}
make_absolute = lambda fn: os.path.join(os.path.dirname(os.path.realpath(__file__)), fn)
name_to_oid = OrderedCaseInsensitiveDict()
oid_to_desc = {}
oid_to_name = {}
oid_to_pid = {}
regices = list(zip([re.compile(s,re.M) for s in [r'<[\w\n=" \-/\.;_\t:%#,\?\(\)]+>',r'(\n[\t ]*){2,}',r'^[\t ]+']],['','\n\n',' ']))
definition_files = ['DocEntity.csv', 'DocEnumeration.csv', 'DocDefined.csv', 'DocSelect.csv']
definition_files = map(make_absolute, definition_files)
for fn in definition_files:
with open(fn) as f:
with open(fn, encoding="utf8", 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')) 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')) 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
name_to_oid[".".join((pname, name))] = oid
oid_to_desc[oid] = desc
def description(item):
@@ -67,4 +74,4 @@ def description(item):
for r,s in regices: desc = r.sub(s,desc)
desc = desc.strip()
return desc.split("\n")
else: return []
else: return []
+2 -4
View File
@@ -1,5 +1,3 @@
# Taken from http://sourceforge.net/p/exp-engine/expresso/ci/master/tree/docs/iso-10303-11--2004.bnf
ABS = "abs" .
ABSTRACT = "abstract" .
ACOS = "acos" .
@@ -202,7 +200,7 @@ constructed_types = enumeration_type | select_type .
declaration = entity_decl | function_decl | procedure_decl | subtype_constraint_decl | type_decl .
derived_attr = attribute_decl ":" parameter_type ":=" expression ";" .
derive_clause = DERIVE derived_attr { derived_attr } .
domain_rule = rule_label_id ":" expression .
domain_rule = [ rule_label_id ":" ] expression .
element = expression [ ":" repetition ] .
entity_body = { explicit_attr } [ derive_clause ] [ inverse_clause ] [ unique_clause ] [ where_clause ] .
entity_constructor = entity_ref "(" [ expression { "," expression } ] ")" .
@@ -334,7 +332,7 @@ type_label_id = simple_id .
unary_op = "+" | "-" | NOT .
underlying_type = constructed_types | concrete_types .
unique_clause = UNIQUE unique_rule ";" { unique_rule ";" } .
unique_rule = rule_label_id ":" referenced_attribute { "," referenced_attribute } .
unique_rule = [ rule_label_id ":" ] referenced_attribute { "," referenced_attribute } .
until_control = UNTIL logical_expression .
use_clause = USE FROM schema_ref [ "(" named_type_or_rename { "," named_type_or_rename } ")" ] ";" .
variable_id = simple_id .
+33 -18
View File
@@ -17,10 +17,13 @@
# #
###############################################################################
import operator
import codegen
import templates
import documentation
class Header:
class Header(codegen.Base):
def __init__(self, mapping):
declarations = []
@@ -40,15 +43,18 @@ class Header:
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
if name.lower() in emitted_simpletypes: continue
type_str = mapping.make_type_string(mapping.flatten_type_string(type))
attr_type = mapping.make_argument_type(type)
superclass = mapping.simple_type_parent(name)
if superclass is None:
superclass = "IfcUtil::IfcBaseType"
elif superclass not in emitted_simpletypes:
elif superclass.lower() not in emitted_simpletypes:
continue
emitted_simpletypes.add(name)
else:
# Case normalize
superclass = [k for k in mapping.schema.simpletypes.keys() if k.lower() == superclass.lower()][0]
emitted_simpletypes.add(name.lower())
write(templates.simpletype, name=name, type=type_str, attr_type=attr_type, superclass=superclass)
class_definitions = []
@@ -59,14 +65,14 @@ class Header:
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:
if name.lower() in emitted_entities: continue
if len(type.supertypes) == 0 or set(map(str.lower, type.supertypes)) <= emitted_entities:
attr_lines = []
def write_method(attr):
if attr.optional:
attr_lines.append(templates.optional_attribute_description % (attr.name, name))
attr_lines.append("bool has%s() const;"%(attr.name))
attr_lines.extend(["/// %s"%d for d in documentation.description((name, attr.name))])
attr_lines.extend(["/// %s"%d for d in documentation.description(".".join((name, attr.name)))])
type_str = mapping.get_parameter_type(attr, allow_optional=False, allow_entities=False)
if mapping.make_argument_type(attr) != "IfcUtil::Argument_UNKNOWN":
attr_lines.append("%s %s() const;"%(type_str, attr.name))
@@ -87,7 +93,11 @@ class Header:
inverse = "\n".join(["%s%s"%(' '*4, a) for a in inv_lines])
if len(inverse): inverse += '\n'
supertypes = type.supertypes if len(type.supertypes) else ['IfcUtil::IfcBaseEntity']
def case_norm(n):
n = n.lower()
return [k for k in mapping.schema.entities.keys() if k.lower() == n][0]
supertypes = map(case_norm, type.supertypes) if len(type.supertypes) else ['IfcUtil::IfcBaseEntity']
superclass = ": %s "%(", ".join(["public %s"%c for c in supertypes]))
argument_count = mapping.argument_count(type)
@@ -95,17 +105,23 @@ 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 ' (void)i; 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"); '
derived = mapping.derived_in_supertype(type)
attribute_names = list(map(operator.attrgetter('name'), mapping.arguments(type)))
derived_in_supertype = set(derived) & set(attribute_names)
derived_in_supertype_indices = sorted(attribute_names.index(nm) for nm in derived_in_supertype)
attribute_type_cases = ['case %d: return IfcUtil::Argument_DERIVED; ' % idx for idx in derived_in_supertype_indices]
attribute_type_cases += ['case %d: return %s; '%(i+argument_start, mapping.make_argument_type(attr)) for i, attr in enumerate(type.attributes)]
argument_type_function_body_switch_stmt = " switch (i) {%s}"%("".join(attribute_type_cases)) if len(type.attributes) else ""
argument_type_function_body_tail = (" return %s::getArgumentType(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' (void)i; throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
argument_type_function_body = argument_type_function_body_switch_stmt + argument_type_function_body_tail
argument_entity_function_body_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return %s; '%(i+argument_start, mapping.make_argument_entity(attr)) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
argument_entity_function_body_tail = (" return %s::getArgumentEntity(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcException("argument out of range"); '
argument_entity_function_body_tail = (" return %s::getArgumentEntity(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' (void)i; throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
argument_entity_function_body = argument_entity_function_body_switch_stmt + argument_entity_function_body_tail
@@ -123,10 +139,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()
+65 -38
View File
@@ -17,15 +17,19 @@
# #
###############################################################################
import codegen
import templates
class Implementation:
from schema import OrderedCaseInsensitiveDict
class Implementation(codegen.Base):
def __init__(self, mapping):
enumeration_functions = []
entity_implementations = []
schema_entity_statements = []
schema_name = mapping.schema.name.capitalize()
schema_name_upper = mapping.schema.name.upper()
stringify = lambda s: '"%s"'%s
cat = lambda vs: "".join(vs)
@@ -43,6 +47,8 @@ class Implementation:
templates.enumeration_function,
max_id = len(enum.values),
name = name,
schema_name = schema_name,
schema_name_upper = schema_name_upper,
values = catc(map(stringify, enum.values)),
from_string_statements = catnl(templates.enum_from_string_stmt%dict(context,**locals()) for value in enum.values)
)
@@ -52,6 +58,7 @@ class Implementation:
for name, type in mapping.schema.entities.items():
parent_type_test = "" if not type.supertypes or len(type.supertypes) != 1 \
else templates.parent_type_test%(type.supertypes[0])
constructor_arguments = mapping.get_assignable_arguments(type, include_derived = True)
constructor_arguments_str = catc("%(full_type)s v%(index)d_%(name)s"%a for a in constructor_arguments if not a['is_derived'])
attributes = []
@@ -63,6 +70,8 @@ class Implementation:
write_attr(
templates.const_function,
class_name = name,
schema_name = schema_name,
schema_name_upper = schema_name_upper,
name = 'has%s'%arg['name'],
arguments = '',
return_type = 'bool',
@@ -72,10 +81,10 @@ class Implementation:
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
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']: return templates.get_attr_stmt_nested_array
elif arg['is_array'] and not (select or simple or express): return templates.get_attr_stmt_array
elif arg['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
@@ -85,9 +94,11 @@ class Implementation:
class_name = name,
name = arg['name'],
arguments = '',
schema_name = schema_name,
schema_name_upper = schema_name_upper,
return_type = arg['non_optional_type'],
body = tmpl % {'index': arg['index']-1,
'type' : arg['non_optional_type'].split('::')[0],
'type' : arg['non_optional_type'].replace('::Value', ''),
'list_instance_type' : arg['list_instance_type']}
)
@@ -96,7 +107,7 @@ class Implementation:
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_array'] and not (select or simple or express): return templates.set_attr_stmt_array
elif arg['is_templated_list'] and not (select or simple or express): return templates.set_attr_stmt_array
else: return templates.set_attr_stmt
tmpl = find_template(arg)
@@ -106,8 +117,10 @@ class Implementation:
name = 'set%s'%arg['name'],
arguments = '%s v'%arg['non_optional_type'],
return_type = 'void',
schema_name = schema_name,
schema_name_upper = schema_name_upper,
body = tmpl % {'index': arg['index']-1,
'type' : arg['non_optional_type'].split('::')[0]}
'type' : arg['non_optional_type'].replace('::Value', '')}
)
if arg['is_derived']:
@@ -122,7 +135,7 @@ class Implementation:
else templates.constructor_stmt
impl = tmpl % {'name' : deref_name,
'index' : arg['index']-1,
'type' : arg['non_optional_type'].split('::')[0]}
'type' : arg['non_optional_type'].replace('::Value', '')}
if is_optional_non_naked_ptr:
impl = templates.constructor_stmt_optional%{'name' : arg_name,
'index' : arg['index']-1,
@@ -131,17 +144,19 @@ class Implementation:
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)
return [a['name'].lower() for a in mapping.get_assignable_arguments(related_entity, include_derived=True)].index(attr_name.lower())
inverse = [templates.const_function % {
'class_name' : name,
'schema_name' : schema_name,
'schema_name_upper' : schema_name_upper,
'name' : i.name,
'arguments' : '',
'return_type' : '%s::list::ptr' % i.entity,
'body' : templates.get_inverse % {'type': i.entity, 'index':get_attribute_index(i.entity, i.attribute)}
'return_type' : '::%s::%s::list::ptr' % (schema_name, i.entity),
'body' : templates.get_inverse % {'type': i.entity, 'index':get_attribute_index(i.entity, i.attribute), 'schema_name' : schema_name, 'schema_name_upper': schema_name_upper}
} for i in (type.inverse.elements if type.inverse else [])]
superclass = "%s((IfcAbstractEntity*)0)" % type.supertypes[0] if len(type.supertypes) == 1 else 'IfcUtil::IfcBaseEntity()'
superclass = "%s((IfcEntityInstanceData*)0)" % type.supertypes[0] if len(type.supertypes) == 1 else 'IfcUtil::IfcBaseEntity()'
write(
templates.entity_implementation,
@@ -151,10 +166,12 @@ class Implementation:
constructor_implementation = cat(constructor_implementations),
attributes = nl(catnl(attributes)),
inverse = nl(catnl(inverse)),
superclass = superclass
superclass = superclass,
schema_name = schema_name,
schema_name_upper = schema_name_upper
)
selectable_simple_types = sorted(set(sum([b.values for a,b in mapping.schema.selects.items()], [])) & set(mapping.schema.types.keys()))
selectable_simple_types = sorted(set(sum([b.values for a,b in mapping.schema.selects.items()], [])) & set(map(str, mapping.schema.types.keys())))
schema_entity_statements += [templates.schema_entity_stmt%locals() for name, type in mapping.schema.simpletypes.items()]
schema_entity_statements += [templates.schema_entity_stmt%locals() for name, type in mapping.schema.entities.items()]
@@ -166,12 +183,15 @@ class Implementation:
'name' : name,
'padding' : ' ' * (max_len - len(name))
} for name in enumerable_types]
enumeration_index_by_str = OrderedCaseInsensitiveDict((j,i) for i,j in enumerate(enumerable_types))
def get_parent_id(s):
e = mapping.schema.entities.get(s)
if e and e.supertypes:
return enumeration_index_by_str[e.supertypes[0]]
else: return -1
parent_type_statements = [templates.parent_type_stmt % {
'name' : name,
'parent' : type.supertypes[0],
'padding' : ' ' * (max_len - len(name))
} for name, type in mapping.schema.entities.items() if type.supertypes and len(type.supertypes) == 1]
parent_type_statements = ",".join(map(str, map(get_parent_id, enumerable_types)))
max_id = len(enumerable_types)
@@ -189,44 +209,51 @@ class Implementation:
constructor = templates.constructor_single_initlist if superclass \
else templates.constructor
def compose(params):
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, schema_name=schema_name, schema_name_upper=schema_name_upper):
class_name, attr_type, superclass, superclass_init, name, tmpl, return_type, args, body = params
underlying_type = mapping.list_instance_type(type)
arguments = ",".join(args)
body = body % locals()
return tmpl % locals()
simple_type_impl.append(templates.simpletype_impl_comment % {'name': class_name})
simple_type_impl.extend(map(compose, map(lambda x: (class_name, attr_type, superclass, "(IfcAbstractEntity*)0")+x, (
('getArgumentType', templates.const_function, 'IfcUtil::ArgumentType', ('unsigned int i',), templates.simpletype_impl_argument_type ),
('getArgument', templates.const_function, 'Argument*', ('unsigned int i',), templates.simpletype_impl_argument ),
('is', templates.const_function, 'bool', ('Type::Enum v',), simpletype_impl_is ),
('type', templates.const_function, 'Type::Enum', (), templates.simpletype_impl_type ),
('Class', templates.function, 'Type::Enum', (), templates.simpletype_impl_class ),
('', constructor, '', ('IfcAbstractEntity* e',), templates.simpletype_impl_explicit_constructor),
('', constructor, '', ("%s v" % type_str,), templates.simpletype_impl_constructor ),
('', templates.cast_function, type_str, (), templates.simpletype_impl_cast )
simple_type_impl.extend(map(compose, map(lambda x: (class_name, attr_type, superclass, "(IfcEntityInstanceData*)0")+x, (
('Class', templates.function, 'const IfcParse::type_declaration&', (), templates.simpletype_impl_class ),
('declaration', templates.const_function, 'const IfcParse::type_declaration&', (), templates.simpletype_impl_declaration ),
('', constructor, '', ('IfcEntityInstanceData* 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_%%s_type;" % schema_name_upper) % n for n in mapping.schema.entities.keys() ] + \
[("extern type_declaration* %s_%%s_type;" % schema_name_upper) % n for n in mapping.schema.simpletypes.keys()]
self.str = templates.implementation % {
'schema_name_upper' : mapping.schema.name.upper(),
'schema_name' : mapping.schema.name.capitalize(),
'schema_name_upper' : schema_name_upper,
'schema_name' : schema_name,
'max_id' : max_id,
'enumeration_functions' : cat(enumeration_functions),
'schema_entity_statements' : catnl(schema_entity_statements),
'type_name_strings' : type_name_strings,
'string_map_statements' : catnl(string_map_statements),
'simple_type_statement' : simple_type_statements,
'parent_type_statements' : catnl(parent_type_statements),
'parent_type_statements' : parent_type_statements,
'entity_implementations' : catnl(entity_implementations),
'simple_type_impl' : catnl(simple_type_impl)
'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()
@@ -1,119 +0,0 @@
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
import templates
class LateBoundImplementation:
def __init__(self, mapping):
schema_name = mapping.schema.name.capitalize()
entity_descriptors = []
enumeration_descriptors = []
derived_field_statements = []
inverse_implementations = []
for name, type in mapping.schema.simpletypes.items():
entity_descriptors.append(templates.entity_descriptor % {
'type' : name,
'parent_statement' : '0',
'entity_descriptor_attributes' : templates.entity_descriptor_attribute_without_entity % {
'name' : 'wrappedValue',
'optional' : 'false',
'type' : mapping.make_argument_type(mapping.schema.types[name].type)
}
})
emitted_entities = set()
entities_to_emit = mapping.schema.entities.keys()
while len(emitted_entities) < len(mapping.schema.entities):
for name, type in mapping.schema.entities.items():
if name in emitted_entities: continue
if len(type.supertypes) == 0 or set(type.supertypes) < emitted_entities:
constructor_arguments = mapping.get_assignable_arguments(type, include_derived = True)
entity_descriptor_attributes = []
for arg in constructor_arguments:
if not arg['is_inherited']:
is_enumeration = arg['argument_type_enum'] == 'IfcUtil::Argument_ENUMERATION'
tmpl = templates.entity_descriptor_attribute_with_entity
entity_name = arg['argument_type'] if is_enumeration else arg['argument_entity'].split('::')[1]
entity_descriptor_attributes.append(tmpl % {
'name' : arg['name'],
'optional' : 'true' if arg['is_optional'] else 'false',
'type' : arg['argument_type_enum'],
'entity_name': entity_name
})
emitted_entities.add(name)
parent_statement = '0' if len(type.supertypes) != 1 else templates.entity_descriptor_parent % {
'type' : type.supertypes[0]
}
entity_descriptors.append(templates.entity_descriptor % {
'type' : name,
'parent_statement' : parent_statement,
'entity_descriptor_attributes' : '\n'.join(entity_descriptor_attributes)
})
for name, enum in mapping.schema.enumerations.items():
enumeration_descriptor_values = '\n'.join([templates.enumeration_descriptor_value % {
'name' : v
} for v in enum.values])
enumeration_descriptors.append(templates.enumeration_descriptor % {
'type' : name,
'enumeration_descriptor_values' : enumeration_descriptor_values
})
for name, type in mapping.schema.entities.items():
constructor_arguments = mapping.get_assignable_arguments(type, include_derived = True)
statements = ''.join(templates.derived_field_statement_attrs % (a['index']-1) for a in constructor_arguments if a['is_derived'])
if len(statements):
derived_field_statements.append(templates.derived_field_statement % {
'type' : name,
'statements' : statements
})
for name, type in mapping.schema.entities.items():
if type.inverse:
for attr in type.inverse.elements:
related_entity = mapping.schema.entities[attr.entity]
related_attrs = [a['name'] for a in mapping.get_assignable_arguments(related_entity, include_derived=True)]
inverse_implementations.append(templates.inverse_implementation % {
'type' : name,
'name' : attr.name,
'related_type' : attr.entity,
'index' : related_attrs.index(attr.attribute)
})
self.str = templates.lb_implementation % {
'schema_name_upper' : mapping.schema.name.upper(),
'schema_name' : mapping.schema.name.capitalize(),
'entity_descriptors' : '\n'.join(entity_descriptors),
'enumeration_descriptors' : '\n'.join(enumeration_descriptors),
'derived_field_statements' : '\n'.join(derived_field_statements),
'inverse_implementations' : '\n'.join(inverse_implementations)
}
self.schema_name = mapping.schema.name.capitalize()
def __repr__(self):
return self.str
def emit(self):
f = open('%s-latebound.cpp'%self.schema_name, 'w', encoding='utf-8')
f.write(str(self))
f.close()
+66 -40
View File
@@ -17,6 +17,9 @@
# #
###############################################################################
from __future__ import print_function
import sys
import nodes
import templates
@@ -28,8 +31,15 @@ class Mapping:
'integer' : 'int',
'real' : 'double',
'number' : 'double',
'string' : 'std::string'
'string' : 'std::string',
'binary' : 'boost::dynamic_bitset<>'
}
supported_argument_types = set([
'INT', 'BOOL', 'DOUBLE', 'STRING', 'BINARY', 'ENUMERATION', 'ENTITY_INSTANCE',
'AGGREGATE_OF_INT', 'AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_STRING', 'AGGREGATE_OF_BINARY', 'AGGREGATE_OF_ENTITY_INSTANCE',
'AGGREGATE_OF_AGGREGATE_OF_INT', 'AGGREGATE_OF_AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE',
])
def __init__(self, schema):
self.schema = schema
@@ -44,17 +54,17 @@ class Mapping:
def simple_type_parent(self, type):
parent = self.schema.types[type].type.type
if isinstance(parent, nodes.AggregationType): parent = None
return None if parent in self.express_to_cpp_typemapping else parent
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, nodes.StringType)):
return self.express_to_cpp_typemapping.get(str(type), "::%s::%s" % (self.schema.name.capitalize(), type))
else:
is_list = self.schema.is_entity(type.type)
is_nested_list = isinstance(type.type, nodes.AggregationType)
tmpl = templates.list_list_type if is_nested_list else templates.list_type if is_list else templates.array_type
return tmpl % {
'instance_type' : self.make_type_string(type.type),
'instance_type' : self.make_type_string(self.flatten_type_string(type.type)),
'lower' : type.bounds.lower,
'upper' : type.bounds.upper,
}
@@ -70,66 +80,71 @@ class Mapping:
def make_argument_entity(self, attr):
type = attr.type if hasattr(attr, 'type') else attr
while isinstance(type, nodes.AggregationType): type = type.type
if type in self.express_to_cpp_typemapping or isinstance(type, nodes.BinaryType): return "Type::UNDEFINED"
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.StringType):
return "STRING"
elif isinstance(type, nodes.EnumerationType):
return "ENUMERATION"
elif isinstance(type, nodes.SelectType):
return "ENTITY"
elif isinstance(type, nodes.AggregationType):
ty = _make_argument_type(type.type)
if ty == "UNKNOWN": return "UNKNOWN"
return "%s_LIST"%ty if ty.startswith("ENTITY") else ("VECTOR_%s"%ty)
else: raise ValueError
supported = {'INT', 'BOOL', 'DOUBLE', 'STRING', 'VECTOR_INT', 'VECTOR_DOUBLE', 'VECTOR_STRING', 'ENTITY', 'ENTITY_LIST', 'ENTITY_LIST_LIST', 'ENUMERATION'}
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 supported: ty = 'UNKNOWN'
if ty not in self.supported_argument_types:
print("Attribute %r mapped as 'unknown'" % (attr), 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):
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)
type_str = '::%s::%s::Value' % (self.schema.name.capitalize(), attr_type)
elif isinstance(type_str, nodes.AggregationType):
is_nested_list = isinstance(attr_type.type, nodes.AggregationType)
ty = self.get_parameter_type(attr_type.type if is_nested_list else attr_type, False, allow_entities, False)
if True and self.schema.is_select(attr_type.type):
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
bounds = (attr_type.bounds.lower, attr_type.bounds.upper) if attr_type.bounds else (-1, -1)
type_str = tmpl % {
'instance_type' : ty,
'lower' : attr_type.bounds.lower,
'upper' : attr_type.bounds.upper
'lower' : bounds[0],
'upper' : bounds[1]
}
else:
tmpl = templates.list_list_type if is_nested_list else templates.list_type
type_str = tmpl % {
'instance_type': ty
}
elif allow_pointer and (self.schema.is_entity(type_str) or self.schema.is_select(type_str)):
type_str += '*'
elif (self.schema.is_entity(type_str) or self.schema.is_select(type_str)):
type_str = '::%s::%s' % (self.schema.name.capitalize(), attr_type)
if allow_pointer:
type_str += "*"
is_ptr = True
elif not allow_pointer and self.schema.is_select(type_str):
type_str = "IfcUtil::IfcBaseClass*"
@@ -151,23 +166,34 @@ 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::IfcBaseClass' if self.schema.is_select(v) else v
if self.is_array(attr.type):
if not isinstance(attr.type, str) and self.is_array(attr.type.type):
if isinstance(attr.type.type, str):
return f(attr.type.type)
else: return f(attr.type.type.type)
attr_type = attr.type if isinstance(attr, nodes.ExplicitAttribute) else attr
if isinstance(attr_type, str): return None
def f(v):
v = self.flatten_type(v)
if self.schema.is_select(v):
return 'IfcUtil::IfcBaseClass'
elif str(v) in self.schema.types or str(v) in self.schema.entities:
return "::%s::%s" % (self.schema.name.capitalize(), v)
else: return 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)
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
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
+37 -10
View File
@@ -21,8 +21,8 @@ import string
import collections
class Node:
def __init__(self, tokens):
self.tokens = tokens
def __init__(self, tokens = None):
self.tokens = tokens or []
self.init()
def tokens_of_type(self, cls):
return [t for t in self.tokens if isinstance(t, cls)]
@@ -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,8 +137,8 @@ class AttributeList(Node):
class InverseAttribute(Node):
name = property(lambda self: self.tokens[0])
type = property(lambda self: self.tokens[2])
bounds = property(lambda self: None if len(self.tokens) == 6 else self.tokens[3])
type = property(lambda self: self.tokens[2] if self.tokens[2] != self.tokens[-4] else None)
bounds = property(lambda self: None if len(self.tokens) != 9 else self.tokens[3])
entity = property(lambda self: self.tokens[-4])
attribute = property(lambda self: self.tokens[-2])
def init(self):
@@ -149,7 +159,7 @@ class BinaryType(Node):
def init(self):
pass
def __repr__(self):
return "BINARY"
return "binary"
class BoundSpecification(Node):
@@ -170,6 +180,23 @@ class ExplicitAttribute(Node):
def init(self):
# NB: This assumes a single name per attribute
# definition, which is not necessarily the case.
if self.tokens[0] == "self":
i = list(self.tokens).index(":")
self.tokens = self.tokens[i-1:]
assert self.tokens[1] == ':'
def __repr__(self):
return "%s : %s%s" % (self.name, self.type, " ?" if self.optional else "")
class WidthSpec(Node):
def init(self):
if self.tokens[-1] == "fixed":
self.tokens[-1:] = []
assert (self.tokens[0], self.tokens[-1]) == ("(", ")")
self.width = int("".join(self.tokens[1:-1]))
class StringType(Node):
def init(self):
pass
def __repr__(self):
return "string"
+48 -10
View File
@@ -18,29 +18,67 @@
###############################################################################
import nodes
import platform
import collections
if tuple(map(int, platform.python_version_tuple())) < (2, 7):
import ordereddict
collections.OrderedDict = ordereddict.OrderedDict
# According to ISO 10303-11 7.1.2: Letters: "... The case of
# letters is significant only within explicit string literals."
class OrderedCaseInsensitiveDict_KeyObject(str):
def __eq__(self, other):
return self.lower() == other.lower()
def __hash__(self):
return hash(self.lower())
class OrderedCaseInsensitiveDict(collections.OrderedDict):
def __init__(self, *args, **kwargs):
collections.OrderedDict.__init__(self)
for key, value in collections.OrderedDict(*args, **kwargs).items():
self[OrderedCaseInsensitiveDict_KeyObject(key)] = value
def __setitem__(self, key, value):
return collections.OrderedDict.__setitem__(self, OrderedCaseInsensitiveDict_KeyObject(key), value)
def __getitem__(self, key):
return collections.OrderedDict.__getitem__(self, OrderedCaseInsensitiveDict_KeyObject(key))
def get(self, key, *args, **kwargs):
return collections.OrderedDict.get(self, OrderedCaseInsensitiveDict_KeyObject(key), *args, **kwargs)
def __contains__(self, key):
return collections.OrderedDict.__contains__(self, OrderedCaseInsensitiveDict_KeyObject(key))
class Schema:
def is_enumeration(self, v):
return 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 __len__(self):
return len(self.types) + len(self.entities)
def __iter__(self):
return iter(self.keys)
def __getitem__(self, key):
return self.types_entities[key]
def __init__(self, parsetree):
self.name = parsetree[1]
sort = lambda d: collections.OrderedDict(sorted(d.items()))
sort = lambda d: OrderedCaseInsensitiveDict(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)])
self.keys = list(self.types.keys()) + list(self.entities.keys())
self.types_entities = {k: v for d in (self.types, self.entities) for k, v in d.items()}
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, nodes.StringType)
+268
View File
@@ -0,0 +1,268 @@
###############################################################################
# #
# 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
from collections import defaultdict
class SchemaClass(codegen.Base):
def __init__(self, mapping):
class UnmetDependenciesException(Exception): pass
schema_name = mapping.schema.name
self.schema_name = schema_name_title = schema_name.capitalize()
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, nodes.StringType):
return "new simple_type(simple_type::string_type)"
elif isinstance(type, str):
if mapping.schema.is_type(type) or mapping.schema.is_entity(type):
if emitted_names is None or type.lower() in emitted_names:
return "new named_type(%s_%s_type)" % (schema_name, 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
else:
raise Exception("No declared type for <%r>" % type)
statements = ['',
'#include "../ifcparse/IfcSchema.h"',
'#include "../ifcparse/%(schema_name_title)s.h"' % locals(),
'',
'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* %(schema_name)s_%(name)s_type = 0;' % locals())
declarations_by_index = []
statements.append("{factory_placeholder}")
statements.append("""
#if defined(__clang__)
__attribute__((optnone))
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC push_options
#pragma GCC optimize ("O0")
#elif defined(_MSC_VER)
#pragma optimize("", off)
#endif
""")
statements.append('IfcParse::schema_definition* %(schema_name)s_populate_schema() {' % locals())
emitted = set()
len_to_emit = len(mapping.schema)
def write_simpletype(schema_name, name, type):
try:
declared_type = get_declared_type(type, emitted)
except UnmetDependenciesException:
# @todo?
# print("Unmet", repr(name))
return False
statements.append(' %(schema_name)s_%(name)s_type = new type_declaration("%(name)s", %%(index_in_schema_%(name)s)d, %(declared_type)s);' % locals())
def write_enumeration(schema_name, name, enum):
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(' %(schema_name)s_%(name)s_type = new enumeration_type("%(name)s", %%(index_in_schema_%(name)s)d, items);' % locals())
statements.append(' }')
def write_entity(schema_name, name, type):
if len(type.supertypes) == 0 or set(map(lambda s: s.lower(), type.supertypes)) < emitted:
supertype = '0' if len(type.supertypes) == 0 else '%s_%s_type' % (schema_name, type.supertypes[0])
is_abstract = "true" if type.abstract else "false"
statements.append(' %(schema_name)s_%(name)s_type = new entity("%(name)s", %(is_abstract)s, %%(index_in_schema_%(name)s)d, %(supertype)s);' % locals())
else: return False
def write_select(schema_name, name, type):
if set(map(lambda s: s.lower(),type.values)) < emitted:
statements.append(' {')
statements.append(' std::vector<const declaration*> items; items.reserve(%d);' % len(type.values))
statements.extend(map(lambda v: ' items.push_back(%s_%s_type);' % (schema_name, v), sorted(type.values)))
statements.append(' %(schema_name)s_%(name)s_type = new select_type("%(name)s", %%(index_in_schema_%(name)s)d, items);' % locals())
statements.append(' }')
else: return False
def write(name):
if mapping.schema.is_simpletype(name):
fn = write_simpletype
elif mapping.schema.is_enumeration(name):
fn = write_enumeration
elif mapping.schema.is_entity(name):
fn = write_entity
elif mapping.schema.is_select(name):
fn = write_select
decl = mapping.schema[name]
if isinstance(decl, nodes.TypeDeclaration):
decl = decl.type.type
return fn(schema_name, name, decl) is not False
while len(emitted) < len_to_emit:
for name in mapping.schema:
if name.lower() in emitted: continue
if write(name):
emitted.add(name.lower())
declarations_by_index.append(name)
declared_types.append('%(schema_name)s_%(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 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 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(' %(schema_name)s_%(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 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 inverse_attribute("%(attr_name)s", inverse_attribute::%(aggr_type)s_type, %(bound1)d, %(bound2)d, %(schema_name)s_%(entity_ref)s_type, %(schema_name)s_%(attribute_entity)s_type->attributes()[%(attribute_entity_index)d]));' % locals())
statements.append(' %(schema_name)s_%(name)s_type->set_inverse_attributes(attributes);' % locals())
statements.append(' }')
subtypes = defaultdict(list)
for name, type in mapping.schema.entities.items():
for ty in type.supertypes:
subtypes[ty].append(name)
for name, tys in subtypes.items():
statements.append(' {')
statements.append(' std::vector<const entity*> defs; defs.reserve(%d);' % len(tys))
statements.append((' ' + "".join(map(lambda t: ("defs.push_back(%%(schema_name)s_%s_type);" % t), tys))) % locals())
statements.append(' %(schema_name)s_%(name)s_type->set_subtypes(defs);' % 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, new %(schema_name)s_instance_factory());' % 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& %s::get_schema() {' % schema_name_title,
'',
' static const schema_definition* s = %(schema_name)s_populate_schema();' % locals(),
' return *s;',
'}','',''))
declarations_by_index.sort(key=str.lower)
declarations_by_index_map = dict(("index_in_schema_%s" % j,i) for i,j in enumerate(declarations_by_index))
def bind(s):
if "%" in s: return s % declarations_by_index_map
else: return s
can_be_instantiated_set = set(list(mapping.schema.entities.keys()) + list(mapping.schema.simpletypes.keys()))
def can_be_instantiated(idx_name):
name = idx_name[1]
return name in can_be_instantiated_set
instance_mapping = """switch(data->type()->index_in_schema()) {
%s
default: throw IfcParse::IfcException(data->type()->name() + " cannot be instantiated");
}
""" % "\n ".join(map(lambda tup: ("case %%d: return new ::%s::%%s(data);" % schema_name_title) % tup, filter(can_be_instantiated, enumerate(declarations_by_index))))
statements[statements.index("{factory_placeholder}")] = """
class %(schema_name)s_instance_factory : public IfcParse::instance_factory {
virtual IfcUtil::IfcBaseClass* operator()(IfcEntityInstanceData* data) const {
%(instance_mapping)s
}
};
""" % locals()
self.str = "\n".join(map(bind, statements))
self.file_name = '%s-schema.cpp'%self.schema_name
def __repr__(self):
return self.str
+78 -290
View File
@@ -23,19 +23,22 @@ header = """
#include <string>
#include <vector>
#include <map>
#include <boost/optional.hpp>
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/ifc_parse_api.h"
#include "../ifcparse/IfcEntityList.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcSchema.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/%(schema_name)senum.h"
#include "../ifcparse/Argument.h"
#define IfcSchema %(schema_name)s
struct %(schema_name)s {
namespace %(schema_name)s {
static const IfcParse::schema_definition& get_schema();
const char* const Identifier = "%(schema_name_upper)s";
static const char* const Identifier;
// Forward definitions
%(forward_definitions)s
@@ -43,9 +46,7 @@ const char* const Identifier = "%(schema_name_upper)s";
%(declarations)s
%(class_definitions)s
void InitStringMap();
IfcUtil::IfcBaseClass* SchemaEntity(IfcAbstractEntity* e = 0);
}
};
#endif
"""
@@ -54,97 +55,31 @@ enum_header = """
#ifndef %(schema_name_upper)sENUM_H
#define %(schema_name_upper)sENUM_H
#define IfcSchema %(schema_name)s
#include "../ifcparse/ifc_parse_api.h"
namespace %(schema_name)s {
namespace Type {
typedef enum {
%(types)s, UNDEFINED
} Enum;
Enum Parent(Enum v);
Enum FromString(const std::string& s);
std::string ToString(Enum v);
bool IsSimple(Enum v);
}
}
#include <string>
#include <boost/optional.hpp>
#endif
"""
lb_header = """
#ifndef %(schema_name_upper)sRT_H
#define %(schema_name_upper)sRT_H
#define IfcSchema %(schema_name)s
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcEntityDescriptor.h"
#include "../ifcparse/IfcWritableEntity.h"
namespace %(schema_name)s {
namespace Type {
int GetAttributeCount(Enum t);
int GetAttributeIndex(Enum t, const std::string& a);
IfcUtil::ArgumentType GetAttributeType(Enum t, unsigned char a);
Enum GetAttributeEntity(Enum t, unsigned char a);
const std::string& GetAttributeName(Enum t, unsigned char a);
bool GetAttributeOptional(Enum t, unsigned char a);
bool GetAttributeDerived(Enum t, unsigned char a);
std::pair<const char*, int> GetEnumerationIndex(Enum t, const std::string& a);
std::pair<Enum, unsigned> GetInverseAttribute(Enum t, const std::string& a);
std::set<std::string> GetInverseAttributeNames(Enum t);
void PopulateDerivedFields(IfcWrite::IfcWritableEntity* e);
}}
#endif
"""
lb_header = """"""
implementation= """
#include "../ifcparse/%(schema_name)s.h"
#include "../ifcparse/IfcSchema.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcWrite.h"
#include "../ifcparse/IfcWritableEntity.h"
using namespace %(schema_name)s;
#include <map>
const char* const %(schema_name)s::Identifier = "%(schema_name_upper)s";
using namespace IfcParse;
using namespace IfcWrite;
IfcUtil::IfcBaseClass* %(schema_name)s::SchemaEntity(IfcAbstractEntity* e) {
switch(e->type()) {
%(schema_entity_statements)s
default: throw IfcException("Unable to find find keyword in schema"); break;
}
}
std::string Type::ToString(Enum v) {
if (v < 0 || v >= %(max_id)d) throw IfcException("Unable to find find keyword in schema");
const char* names[] = { %(type_name_strings)s };
return names[v];
}
static std::map<std::string,Type::Enum> string_map;
void %(schema_name)s::InitStringMap() {
%(string_map_statements)s
}
Type::Enum Type::FromString(const std::string& s) {
if (string_map.empty()) InitStringMap();
std::map<std::string,Type::Enum>::const_iterator it = string_map.find(s);
if ( it == string_map.end() ) throw IfcException("Unable to find find keyword in schema");
else return it->second;
}
Type::Enum Type::Parent(Enum v){
if (v < 0 || v >= %(max_id)d) return (Enum)-1;
%(parent_type_statements)s
return (Enum)-1;
}
bool Type::IsSimple(Enum v) {
return %(simple_type_statement)s;
}
// External definitions
%(external_definitions)s
%(enumeration_functions)s
@@ -153,150 +88,7 @@ bool Type::IsSimple(Enum v) {
%(entity_implementations)s
"""
lb_implementation = """
#include <set>
#include "../ifcparse/%(schema_name)s.h"
#include "../ifcparse/%(schema_name)s-latebound.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcWrite.h"
#include "../ifcparse/IfcWritableEntity.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcEntityDescriptor.h"
using namespace %(schema_name)s;
using namespace IfcParse;
using namespace IfcWrite;
using namespace IfcUtil;
typedef std::map<Type::Enum,IfcEntityDescriptor*> entity_descriptor_map_t;
typedef std::map<Type::Enum,IfcEnumerationDescriptor*> enumeration_descriptor_map_t;
typedef std::map<Type::Enum, std::map<std::string, std::pair<Type::Enum, int> > > inverse_map_t;
typedef std::map<Type::Enum,std::set<int> > derived_map_t;
entity_descriptor_map_t entity_descriptor_map;
enumeration_descriptor_map_t enumeration_descriptor_map;
inverse_map_t inverse_map;
derived_map_t derived_map;
void InitDescriptorMap() {
IfcEntityDescriptor* current;
%(entity_descriptors)s
// Enumerations
IfcEnumerationDescriptor* current_enum;
std::vector<std::string> values;
%(enumeration_descriptors)s
}
void InitInverseMap() {
%(inverse_implementations)s
}
void InitDerivedMap() {
%(derived_field_statements)s
}
int Type::GetAttributeIndex(Enum t, const std::string& a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentIndex(a);
}
int Type::GetAttributeCount(Enum t) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentCount();
}
ArgumentType Type::GetAttributeType(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentType(a);
}
Type::Enum Type::GetAttributeEntity(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentEntity(a);
}
const std::string& Type::GetAttributeName(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentName(a);
}
bool Type::GetAttributeOptional(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentOptional(a);
}
bool Type::GetAttributeDerived(Enum t, unsigned char a) {
if (derived_map.empty()) ::InitDerivedMap();
std::map<Type::Enum,std::set<int> >::const_iterator i = derived_map.find(t);
return i != derived_map.end() && i->second.find(a) != i->second.end();
}
std::pair<const char*, int> Type::GetEnumerationIndex(Enum t, const std::string& a) {
if (enumeration_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEnumerationDescriptor*>::const_iterator i = enumeration_descriptor_map.find(t);
if ( i == enumeration_descriptor_map.end() ) throw IfcException("Value not found");
else return i->second->getIndex(a);
}
std::pair<Type::Enum, unsigned> Type::GetInverseAttribute(Enum t, const std::string& a) {
if (inverse_map.empty()) ::InitInverseMap();
inverse_map_t::const_iterator it;
inverse_map_t::mapped_type::const_iterator jt;
while (true) {
it = inverse_map.find(t);
if (it != inverse_map.end()) {
jt = it->second.find(a);
if (jt != it->second.end()) {
return jt->second;
}
}
if ((t = Parent(t)) == -1) break;
}
throw IfcException("Attribute not found");
}
std::set<std::string> Type::GetInverseAttributeNames(Enum t) {
if (inverse_map.empty()) ::InitInverseMap();
inverse_map_t::const_iterator it;
inverse_map_t::mapped_type::const_iterator jt;
std::set<std::string> return_value;
while (true) {
it = inverse_map.find(t);
if (it != inverse_map.end()) {
for (jt = it->second.begin(); jt != it->second.end(); ++jt) {
return_value.insert(jt->first);
}
}
if ((t = Parent(t)) == -1) break;
}
return return_value;
}
void Type::PopulateDerivedFields(IfcWrite::IfcWritableEntity* e) {
std::map<Type::Enum, std::set<int> >::const_iterator i = derived_map.find(e->type());
if (i != derived_map.end()) {
for (std::set<int>::const_iterator it = i->second.begin(); it != i->second.end(); ++it) {
e->setArgumentDerived(*it);
}
}
}
"""
lb_implementation = """"""
entity_descriptor = """ current = entity_descriptor_map[Type::%(type)s] = new IfcEntityDescriptor(Type::%(type)s,%(parent_statement)s);
%(entity_descriptor_attributes)s"""
@@ -307,7 +99,7 @@ entity_descriptor_attribute_with_entity = ' current->add("%(name)s",%(optiona
enumeration_descriptor = """ values.clear(); values.reserve(128);
%(enumeration_descriptor_values)s
current_enum = enumeration_descriptor_map[Type::%(type)s] = new IfcEnumerationDescriptor(Type::%(type)s, values);"""
enumeration_descriptor_map[Type::%(type)s] = new IfcEnumerationDescriptor(Type::%(type)s, values);"""
enumeration_descriptor_value = ' values.push_back("%(name)s");'
@@ -315,89 +107,85 @@ derived_field_statement = ' {std::set<int> idxs; %(statements)sderived_map[Ty
derived_field_statement_attrs = 'idxs.insert(%d); '
simpletype = """%(documentation)s
class %(name)s : public %(superclass)s {
class IFC_PARSE_API %(name)s : public %(superclass)s {
public:
virtual IfcUtil::ArgumentType getArgumentType(unsigned int i) const;
virtual Argument* getArgument(unsigned int i) const;
bool is(Type::Enum v) const;
Type::Enum type() const;
static Type::Enum Class();
explicit %(name)s (IfcAbstractEntity* e);
virtual const IfcParse::type_declaration& declaration() const;
static const IfcParse::type_declaration& Class();
explicit %(name)s (IfcEntityInstanceData* e);
%(name)s (%(type)s v);
operator %(type)s() const;
};
"""
simpletype_impl_comment = "// Function implementations for %(name)s"
simpletype_impl_argument_type = "if (i == 0) { return %(attr_type)s; } else { throw IfcParse::IfcException(\"argument out of range\"); }"
simpletype_impl_argument = "return entity->getArgument(i);"
simpletype_impl_is_with_supertype = "return v == Type::%(class_name)s || %(superclass)s::is(v);"
simpletype_impl_is_without_supertype = "return v == %(class_name)s::Class();"
simpletype_impl_type = "return Type::%(class_name)s;"
simpletype_impl_class = "return Type::%(class_name)s;"
simpletype_impl_explicit_constructor = "entity = e;"
simpletype_impl_constructor = "IfcWritableEntity* e = new IfcWritableEntity(Type::%(class_name)s); e->setArgument(0, v); entity = e;"
simpletype_impl_cast = "return *entity->getArgument(0);"
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 == %(class_name)s_type || %(superclass)s::is(v);"
simpletype_impl_is_without_supertype = "return v == %(class_name)s_type;"
simpletype_impl_type = "return *%(schema_name_upper)s_%(class_name)s_type;"
simpletype_impl_class = "return *%(schema_name_upper)s_%(class_name)s_type;"
simpletype_impl_explicit_constructor = "data_ = e;"
simpletype_impl_constructor = "data_ = new IfcEntityInstanceData(%(schema_name_upper)s_%(class_name)s_type); {IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument(); attr->set(v" +"); data_->setArgument(0, attr);}"
simpletype_impl_constructor_templated = "data_ = new IfcEntityInstanceData(%(schema_name_upper)s_%(class_name)s_type); {IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument(); attr->set(v->generalize()); data_->setArgument(0, attr);}"
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 *%(schema_name_upper)s_%(class_name)s_type;"
select = """%(documentation)s
typedef IfcUtil::IfcBaseClass %(name)s;
"""
enumeration = """namespace %(name)s {
enumeration = """struct %(name)s {
%(documentation)s
typedef enum {%(values)s} %(name)s;
const char* ToString(%(name)s v);
%(name)s FromString(const std::string& s);
}
typedef enum {%(values)s} Value;
IFC_PARSE_API static const char* ToString(Value v);
IFC_PARSE_API static Value FromString(const std::string& s);
};
"""
entity = """%(documentation)s
class %(name)s %(superclass)s{
class IFC_PARSE_API %(name)s %(superclass)s{
public:
%(attributes)s virtual unsigned int getArgumentCount() const { return %(argument_count)d; }
virtual IfcUtil::ArgumentType getArgumentType(unsigned int i) const {%(argument_type_function_body)s}
virtual Type::Enum getArgumentEntity(unsigned int i) const {%(argument_entity_function_body)s}
virtual const char* getArgumentName(unsigned int i) const {%(argument_name_function_body)s}
virtual Argument* getArgument(unsigned int i) const { return entity->getArgument(i); }
%(inverse)s bool is(Type::Enum v) const;
Type::Enum type() const;
static Type::Enum Class();
%(name)s (IfcAbstractEntity* e);
%(attributes)s %(inverse)s virtual const IfcParse::entity& declaration() const;
static const IfcParse::entity& Class();
%(name)s (IfcEntityInstanceData* e);
%(name)s (%(constructor_arguments)s);
typedef IfcTemplatedEntityList< %(name)s > list;
};
"""
enumeration_function="""
const char* %(name)s::ToString(%(name)s v) {
const char* %(schema_name)s::%(name)s::ToString(Value v) {
if ( v < 0 || v >= %(max_id)d ) throw IfcException("Unable to find find keyword in schema");
const char* names[] = { %(values)s };
return names[v];
}
%(name)s::%(name)s %(name)s::FromString(const std::string& s) {
%(schema_name)s::%(name)s::Value %(schema_name)s::%(name)s::FromString(const std::string& s) {
%(from_string_statements)s
throw IfcException("Unable to find find keyword in schema");
}
"""
entity_implementation = """// Function implementations for %(name)s
%(attributes)s%(inverse)sbool %(name)s::is(Type::Enum v) const { return v == Type::%(name)s%(parent_type_test)s; }
Type::Enum %(name)s::type() const { return Type::%(name)s; }
Type::Enum %(name)s::Class() { return Type::%(name)s; }
%(name)s::%(name)s(IfcAbstractEntity* e) : %(superclass)s { if (!e) return; if (!e->is(Type::%(name)s)) throw IfcException("Unable to find find keyword in schema"); entity = e; }
%(name)s::%(name)s(%(constructor_arguments)s) : %(superclass)s { IfcWritableEntity* e = new IfcWritableEntity(Class());%(constructor_implementation)s entity = e; EntityBuffer::Add(this); }
%(attributes)s
%(inverse)s
const IfcParse::entity& %(schema_name)s::%(name)s::declaration() const { return *%(schema_name_upper)s_%(name)s_type; }
const IfcParse::entity& %(schema_name)s::%(name)s::Class() { return *%(schema_name_upper)s_%(name)s_type; }
%(schema_name)s::%(name)s::%(name)s(IfcEntityInstanceData* e) : %(superclass)s { if (!e) return; if (e->type() != %(schema_name_upper)s_%(name)s_type) throw IfcException("Unable to find find keyword in schema"); data_ = e; }
%(schema_name)s::%(name)s::%(name)s(%(constructor_arguments)s) : %(superclass)s {data_ = new IfcEntityInstanceData(%(schema_name_upper)s_%(name)s_type); %(constructor_implementation)s }
"""
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 }"
function = "%(return_type)s %(schema_name)s::%(class_name)s::%(name)s(%(arguments)s) { %(body)s }"
const_function = "%(return_type)s %(schema_name)s::%(class_name)s::%(name)s(%(arguments)s) const { %(body)s }"
constructor = "%(schema_name)s::%(class_name)s::%(class_name)s(%(arguments)s) { %(body)s }"
constructor_single_initlist = "%(schema_name)s::%(class_name)s::%(class_name)s(%(arguments)s) : %(superclass)s(%(superclass_init)s) { %(body)s }"
cast_function = "%(schema_name)s::%(class_name)s::operator %(return_type)s() const { %(body)s }"
array_type = "std::vector< %(instance_type)s > /*[%(lower)s:%(upper)s]*/"
nested_array_type = "std::vector< std::vector< %(instance_type)s > >"
list_type = "IfcTemplatedEntityList< %(instance_type)s >::ptr"
list_list_type = "IfcTemplatedEntityListList< %(instance_type)s >::ptr"
untyped_list = "IfcEntityList::ptr"
@@ -406,31 +194,31 @@ inverse_attr = "IfcTemplatedEntityList< %(entity)s >::ptr %(name)s() const; // I
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::IfcBaseClass*)(*entity->getArgument(%(index)d)));"
get_attr_stmt_array = "IfcEntityList::ptr es = *entity->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
get_attr_stmt_nested_array = "IfcEntityListList::ptr es = *entity->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
get_attr_stmt = "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 entity->getInverse(Type::%(type)s, %(index)d)->as<%(type)s>();"
get_inverse = "return data_->getInverse(%(schema_name_upper)s_%(type)s_type, %(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 = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set(v" +");data_->setArgument(%(index)d,attr);}"
set_attr_stmt_enum = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set(IfcWrite::IfcWriteArgument::EnumerationReference(v,%(type)s::ToString(v)));data_->setArgument(%(index)d,attr);}"
set_attr_stmt_array = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set(v->generalize()" +");data_->setArgument(%(index)d,attr);}"
constructor_stmt = " e->setArgument(%(index)d,(%(name)s));"
constructor_stmt_enum = " e->setArgument(%(index)d,%(name)s,%(type)s::ToString(%(name)s));"
constructor_stmt_array = " e->setArgument(%(index)d,(%(name)s)->generalize());"
constructor_stmt_optional = " if (%(name)s) {%(stmt)s } else { e->setArgument(%(index)d); }"
constructor_stmt_derived = " e->setArgumentDerived(%(index)d);"
constructor_stmt = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set((%(name)s)" +");data_->setArgument(%(index)d,attr);}"
constructor_stmt_enum = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set((IfcWrite::IfcWriteArgument::EnumerationReference(%(name)s,%(type)s::ToString(%(name)s)))" +");data_->setArgument(%(index)d,attr);}"
constructor_stmt_array = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set((%(name)s)->generalize()" +");data_->setArgument(%(index)d,attr);}"
constructor_stmt_derived = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set(IfcWrite::IfcWriteArgument::Derived()" +");data_->setArgument(%(index)d,attr);}"
constructor_stmt_optional = " if (%(name)s) {%(stmt)s } else { IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument(); attr->set(boost::blank()); data_->setArgument(%(index)d, attr); }"
inverse_implementation = " inverse_map[Type::%(type)s].insert(std::make_pair(\"%(name)s\", std::make_pair(Type::%(related_type)s, %(index)d)));"
-184
View File
@@ -1,184 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef IFCGEOM_H
#define IFCGEOM_H
#define ALMOST_ZERO (1e-9)
#define ALMOST_THE_SAME(a,b) (fabs(a-b) < ALMOST_ZERO)
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#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.hxx>
#include <TopoDS_Wire.hxx>
#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"
#define IN_CACHE(T,E,t,e) std::map<int,t>::const_iterator it = cache.T.find(E->entity->id());\
if ( it != cache.T.end() ) { e = it->second; return true; }
#define CACHE(T,E,e) cache.T[E->entity->id()] = e;
namespace IfcGeom {
class Cache {
public:
#include "IfcRegisterCreateCache.h"
std::map<int, SurfaceStyle> Style;
std::map<int, TopoDS_Shape> Shape;
};
class Kernel {
private:
Cache cache;
public:
// Tolerances and settings for various geometrical operations:
enum GeomValue {
// Specifies the deflection of the mesher
// Default: 0.001m / 1mm
GV_DEFLECTION_TOLERANCE,
// Specifies the tolerance of the wire builder, most notably for trimmed curves
// Defailt: 0.0001m / 0.1mm
GV_WIRE_CREATION_TOLERANCE,
// Specifies the minimal area of a face to be included in an IfcConnectedFaceset
// Default: 0.000001m 0.01cm2
GV_MINIMAL_FACE_AREA,
// Specifies the treshold distance under which cartesian points are deemed equal
// Default: 0.00001m / 0.01mm
GV_POINT_EQUALITY_TOLERANCE,
// Specifies maximum number of faces for a shell to be sewed. Sewing shells
// that consist of many faces is really detrimental for the performance.
// Default: 1000
GV_MAX_FACES_TO_SEW,
// By default singular faces have no explicitly defined orientation, to
// force faces to be defined CounterClockWise, set this value greater than zero.
GV_FORCE_CCW_FACE_ORIENTATION,
// The length unit used the creation of TopoDS_Shapes, primarily affects the
// interpretation of IfcCartesianPoints and IfcVector magnitudes
// DefaultL 1.0
GV_LENGTH_UNIT,
// The plane angle unit used for the creation of TopoDS_Shapes, primarily affects
// the interpretation of IfcParamaterValues of IfcTrimmedCurves
// Default: -1.0 (= not set, fist try degrees, then radians)
GV_PLANEANGLE_UNIT,
// The precision used in boolean operations, setting this value too low results
// in artefacts and potentially modelling failures
// Default: 0.00001 (obtained from IfcGeometricRepresentationContext if available)
GV_PRECISION
};
bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face);
bool convert_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);
bool convert_shape(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
bool flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse);
bool convert_wire(const IfcUtil::IfcBaseClass* L, TopoDS_Wire& result);
bool convert_curve(const IfcUtil::IfcBaseClass* L, Handle(Geom_Curve)& result);
bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
bool convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
IfcSchema::IfcSurfaceStyleShading* get_surface_style(IfcSchema::IfcRepresentationItem* item);
bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid);
bool is_compound(const TopoDS_Shape& shape);
bool is_convex(const TopoDS_Wire& wire);
TopoDS_Shape halfspace_from_plane(const gp_Pln& pln,const gp_Pnt& cent);
gp_Pln plane_from_face(const TopoDS_Face& face);
gp_Pnt point_above_plane(const gp_Pln& pln, bool agree=true);
const TopoDS_Shape& ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid);
bool profile_helper(int numVerts, double* verts, int numFillets, int* filletIndices, double* filletRadii, gp_Trsf2d trsf, TopoDS_Shape& face);
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);
bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape);
void remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
std::pair<std::string, double> initializeUnits(IfcSchema::IfcUnitAssignment*);
IfcSchema::IfcObjectDefinition* get_decomposing_entity(IfcSchema::IfcProduct*);
template <typename P>
IfcGeom::BRepElement<P>* create_brep_for_representation_and_product(const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*);
const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem* representation_item);
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) {
IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem();
for (IfcSchema::IfcStyledItem::list::it jt = styled_items->begin(); jt != styled_items->end(); ++jt) {
#ifdef USE_IFC4
IfcUtil::IfcAbstractSelect::list::ptr style_assignments = (*jt)->Styles();
for (IfcUtil::IfcAbstractSelect::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
if (!(*kt)->is(IfcSchema::Type::IfcPresentationStyleAssignment)) {
continue;
}
IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt;
#else
IfcSchema::IfcPresentationStyleAssignment::list::ptr style_assignments = (*jt)->Styles();
for (IfcSchema::IfcPresentationStyleAssignment::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
IfcSchema::IfcPresentationStyleAssignment* style_assignment = *kt;
#endif
IfcEntityList::ptr styles = style_assignment->Styles();
for (IfcEntityList::it lt = styles->begin(); lt != styles->end(); ++lt) {
IfcUtil::IfcBaseClass* style = *lt;
if (style->is(IfcSchema::Type::IfcSurfaceStyle)) {
IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style;
if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) {
IfcEntityList::ptr styles_elements = surface_style->Styles();
for (IfcEntityList::it mt = styles_elements->begin(); mt != styles_elements->end(); ++mt) {
if ((*mt)->is(T::Class())) {
return std::make_pair(surface_style, (T*) *mt);
}
}
}
}
}
}
// StyledByItem is a SET [0:1] OF IfcStyledItem, so we
// break after encountering the first IfcStyledItem
break;
}
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0,0);
}
#include "IfcRegisterGeomHeader.h"
};
IfcSchema::IfcProductDefinitionShape* tesselate(TopoDS_Shape& shape, double deflection, IfcEntityList::ptr es);
}
#endif
-144
View File
@@ -1,144 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef IFCGEOMELEMENT_H
#define IFCGEOMELEMENT_H
#include "../ifcgeom/IfcGeomRepresentation.h"
#include "../ifcgeom/IfcGeomIteratorSettings.h"
namespace IfcGeom {
template <typename P>
class Matrix {
private:
std::vector<P> _data;
public:
Matrix(const ElementSettings& settings, const gp_Trsf& trsf) {
// Convert the gp_Trsf into a 4x3 Matrix
// Note that in case the CONVERT_BACK_UNITS setting is enabled
// the translation component of the matrix needs to be divided
// by the magnitude of the IFC model length unit because
// internally in IfcOpenShell everything is measured in meters.
for(int i = 1; i < 5; ++i) {
for (int j = 1; j < 4; ++j) {
const double trsf_value = trsf.Value(j,i);
const double matrix_value = i == 4 && settings.convert_back_units()
? trsf_value / settings.unit_magnitude()
: trsf_value;
_data.push_back(static_cast<P>(matrix_value));
}
}
}
const std::vector<P>& data() const { return _data; }
};
template <typename P>
class Transformation {
private:
gp_Trsf trsf;
Matrix<P> _matrix;
public:
Transformation(const ElementSettings& settings, const gp_Trsf& trsf)
: trsf(trsf)
, _matrix(settings, trsf)
{}
const gp_Trsf& data() const { return trsf; }
const Matrix<P>& matrix() const { return _matrix; }
};
template <typename P>
class Element {
private:
int _id;
int _parent_id;
std::string _name;
std::string _type;
std::string _guid;
Transformation<P> _transformation;
public:
int id() const { return _id; }
int parent_id() const { return _parent_id; }
const std::string& name() const { return _name; }
const std::string& type() const { return _type; }
const std::string& guid() const { return _guid; }
const Transformation<P>& transformation() const { return _transformation; }
Element(const ElementSettings& settings, int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf)
: _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _transformation(settings, trsf)
{}
virtual ~Element() {}
};
template <typename P>
class BRepElement : public Element<P> {
private:
Representation::BRep* _geometry;
public:
const Representation::BRep& geometry() const { return *_geometry; }
BRepElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf, Representation::BRep* geometry)
: Element<P>(geometry->settings(),id,parent_id,name,type,guid,trsf)
, _geometry(geometry)
{}
virtual ~BRepElement() {
delete _geometry;
}
private:
BRepElement(const BRepElement& other);
BRepElement& operator=(const BRepElement& other);
};
template <typename P>
class TriangulationElement : public Element<P> {
private:
Representation::Triangulation<P>* _geometry;
public:
const Representation::Triangulation<P>& geometry() const { return *_geometry; }
TriangulationElement(const BRepElement<P>& shape_model)
: Element<P>(shape_model)
, _geometry(new Representation::Triangulation<P>(shape_model.geometry()))
{}
virtual ~TriangulationElement() {
delete _geometry;
}
private:
TriangulationElement(const TriangulationElement& other);
TriangulationElement& operator=(const TriangulationElement& other);
};
template <typename P>
class SerializedElement : public Element<P> {
private:
Representation::Serialization* _geometry;
public:
const Representation::Serialization& geometry() const { return *_geometry; }
SerializedElement(const BRepElement<P>& shape_model)
: Element<P>(shape_model)
, _geometry(new Representation::Serialization(shape_model.geometry()))
{}
virtual ~SerializedElement() {
delete _geometry;
}
private:
SerializedElement(const SerializedElement& other);
SerializedElement& operator=(const SerializedElement& other);
};
}
#endif
File diff suppressed because it is too large Load Diff
-493
View File
@@ -1,493 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) *
* and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). *
* *
* IfcGeom::Representation::Triangulation is a class that represents a *
* triangulated IfcShapeRepresentation. *
* Triangulation.verts is a 1 dimensional vector of float defining the *
* cartesian coordinates of the vertices of the triangulated shape in the *
* format of [x1,y1,z1,..,xn,yn,zn] *
* Triangulation.faces is a 1 dimensional vector of int containing the *
* indices of the triangles referencing positions in Triangulation.verts *
* Triangulation.edges is a 1 dimensional vector of int in {0,1} that dictates*
* the visibility of the edges that span the faces in Triangulation.faces *
* *
* IfcGeom::Element represents the actual IfcBuildingElements. *
* IfcGeomObject.name is the GUID of the element *
* IfcGeomObject.type is the datatype of the element e.g. IfcWindow *
* IfcGeomObject.mesh is a pointer to an IfcMesh *
* IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the *
* orientation and translation of the mesh in relation to the world origin *
* *
* IfcGeom::Iterator::findContext() *
* finds the most suitable representation contexts. Returns true iff *
* at least a single representation will process successfully *
* *
* IfcGeom::Iterator::get() *
* returns a pointer to the current IfcGeom::Element *
* *
* IfcGeom::Iterator::next() *
* returns true iff a following entity is available for a successive call to *
* IfcGeom::Iterator::get() *
* *
* IfcGeom::Iterator::progress() *
* returns an int in [0..100] that indicates the overall progress *
* *
********************************************************************************/
#ifndef IFCGEOMITERATOR_H
#define IFCGEOMITERATOR_H
#include <map>
#include <set>
#include <vector>
#include <limits>
#include <algorithm>
#include <gp_Mat.hxx>
#include <gp_Mat2d.hxx>
#include <gp_GTrsf.hxx>
#include <gp_GTrsf2d.hxx>
#include <gp_Trsf.hxx>
#include <gp_Trsf2d.hxx>
#include "../ifcparse/IfcFile.h"
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom/IfcGeomElement.h"
#include "../ifcgeom/IfcGeomMaterial.h"
#include "../ifcgeom/IfcGeomIteratorSettings.h"
#include "../ifcgeom/IfcRepresentationShapeItem.h"
namespace IfcGeom {
template <typename P>
class Iterator {
private:
Kernel kernel;
IteratorSettings settings;
IfcParse::IfcFile* ifc_file;
// A container and iterator for IfcRepresentations
IfcSchema::IfcRepresentation::list::ptr representations;
IfcSchema::IfcRepresentation::list::it representation_iterator;
// The object is fetched beforehand to be sure that get() returns a valid element
TriangulationElement<P>* current_triangulation;
BRepElement<P>* current_shape_model;
SerializedElement<P>* current_serialization;
// A container and iterator for IfcBuildingElements for the current IfcRepresentation referenced by *representation_iterator
IfcSchema::IfcProduct::list::ptr ifcproducts;
IfcSchema::IfcProduct::list::it ifcproduct_iterator;
int done;
int total;
std::string unit_name;
// double?
P unit_magnitude;
void initUnits() {
IfcSchema::IfcProject::list::ptr projects = ifc_file->entitiesByType<IfcSchema::IfcProject>();
if (projects->size() == 1) {
IfcSchema::IfcProject* project = *projects->begin();
std::pair<std::string, double> length_unit = kernel.initializeUnits(project->UnitsInContext());
unit_name = length_unit.first;
unit_magnitude = static_cast<P>(length_unit.second);
}
}
std::set<IfcSchema::Type::Enum> entities_to_include_or_exclude;
bool include_entities_in_processing;
void populate_set(const std::set<std::string>& include_or_ignore) {
entities_to_include_or_exclude.clear();
for (std::set<std::string>::const_iterator it = include_or_ignore.begin(); it != include_or_ignore.end(); ++it) {
std::string uppercase_type = *it;
for (std::string::iterator c = uppercase_type.begin(); c != uppercase_type.end(); ++c) {
*c = toupper(*c);
}
IfcSchema::Type::Enum ty;
try {
ty = IfcSchema::Type::FromString(uppercase_type);
} catch (const IfcParse::IfcException&) {
std::stringstream ss;
ss << "'" << *it << "' does not name a valid IFC entity";
throw IfcParse::IfcException(ss.str());
}
entities_to_include_or_exclude.insert(ty);
// TODO: Add child classes so that containment in set can be in O(log n)
}
}
public:
bool findContext() {
try {
initUnits();
} catch (...) {}
// Really this should only be 'Model', as per
// the standard 'Design' is deprecated. So,
// just for backwards compatibility:
std::set<std::string> context_types;
context_types.insert("model");
context_types.insert("design");
// DDS likes to output 'model view'
context_types.insert("model view");
double lowest_precision_encountered = std::numeric_limits<double>::infinity();
bool any_precision_encountered = false;
representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
IfcSchema::IfcGeometricRepresentationContext::list::it it;
IfcSchema::IfcGeometricRepresentationSubContext::list::it jt;
IfcSchema::IfcGeometricRepresentationContext::list::ptr contexts =
ifc_file->entitiesByType<IfcSchema::IfcGeometricRepresentationContext>();
IfcSchema::IfcGeometricRepresentationContext::list::ptr filtered_contexts (new IfcSchema::IfcGeometricRepresentationContext::list);
for (it = contexts->begin(); it != contexts->end(); ++it) {
IfcSchema::IfcGeometricRepresentationContext* context = *it;
if (context->is(IfcSchema::Type::IfcGeometricRepresentationSubContext)) {
// Continue, as the list of subcontexts will be considered
// by the parent's context inverse attributes.
continue;
}
if (context->hasContextType()) {
std::string context_type_lc = context->ContextType();
for (std::string::iterator c = context_type_lc.begin(); c != context_type_lc.end(); ++c) {
*c = tolower(*c);
}
if (context_types.find(context_type_lc) != context_types.end()) {
filtered_contexts->push(context);
}
}
}
if (filtered_contexts->size() == 0) {
filtered_contexts = contexts;
}
for (it = filtered_contexts->begin(); it != filtered_contexts->end(); ++it) {
IfcSchema::IfcGeometricRepresentationContext* context = *it;
representations->push(context->RepresentationsInContext());
if (context->hasPrecision() && context->Precision() < lowest_precision_encountered) {
lowest_precision_encountered = context->Precision();
any_precision_encountered = true;
}
IfcSchema::IfcGeometricRepresentationSubContext::list::ptr sub_contexts = context->HasSubContexts();
for (jt = sub_contexts->begin(); jt != sub_contexts->end(); ++jt) {
representations->push((*jt)->RepresentationsInContext());
}
// There is no need for full recursion as the following is governed by the schema:
// WR31: The parent context shall not be another geometric representation sub context.
}
if (any_precision_encountered) {
// Some arbitrary factor that has proven to work better for the models in the set of test files.
lowest_precision_encountered *= 10.;
lowest_precision_encountered *= unit_magnitude;
if (lowest_precision_encountered < 1.e-7) {
Logger::Message(Logger::LOG_WARNING, "Precision lower than 0.0000001 meter not enforced");
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-7);
} else {
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, lowest_precision_encountered);
}
} else {
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-5);
}
if (representations->size() == 0) return false;
representation_iterator = representations->begin();
ifcproducts.reset();
if (!create()) {
return false;
}
done = 0;
total = representations->size();
return true;
}
int progress() {
return 100 * done / total;
}
const std::string& getUnitName() {
return unit_name;
}
const P getUnitMagnitude() {
return unit_magnitude;
}
const std::string getLog() {
return Logger::GetLog();
}
IfcParse::IfcFile* getFile() {
return ifc_file;
}
void includeEntities(const std::set<std::string>& entities) {
populate_set(entities);
include_entities_in_processing = true;
}
void excludeEntities(const std::set<std::string>& entities) {
populate_set(entities);
include_entities_in_processing = false;
}
private:
// Move to the next IfcRepresentation
void _nextShape() {
ifcproducts.reset();
++ representation_iterator;
++ done;
}
BRepElement<P>* create_shape_model_for_next_entity() {
while ( true ) {
IfcSchema::IfcRepresentation* representation;
// Have we reached the end of our list of representations?
if ( representation_iterator == representations->end() ) {
representations.reset();
return 0;
}
representation = *representation_iterator;
// Has the list of IfcProducts for this representation been initialized?
if (!ifcproducts) {
IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation();
ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list);
IfcSchema::IfcProduct::list::ptr unfiltered_products(new IfcSchema::IfcProduct::list);
for ( IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it ) {
if ( (*it)->is(IfcSchema::Type::IfcProductDefinitionShape) ) {
IfcSchema::IfcProductDefinitionShape* pds = (IfcSchema::IfcProductDefinitionShape*)*it;
unfiltered_products->push(pds->ShapeOfProduct());
} else {
// http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm
// IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards.
// It will be changed into an ABSTRACT supertype in future releases of IFC.
// IfcProductRepresentation also lacks the INVERSE relation to IfcProduct
// Let's find the IfcProducts that reference the IfcProductRepresentation anyway
unfiltered_products->push((*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>());
}
// Filter the products based on the set of entities being included or excluded for
// processing. The set is iterated over te able to filter on subtypes.
for ( IfcSchema::IfcProduct::list::it it = unfiltered_products->begin(); it != unfiltered_products->end(); ++it ) {
bool found = false;
for (std::set<IfcSchema::Type::Enum>::const_iterator jt = entities_to_include_or_exclude.begin(); jt != entities_to_include_or_exclude.end(); ++jt) {
if ((*it)->is(*jt)) {
found = true;
break;
}
}
if (found == include_entities_in_processing) {
ifcproducts->push(*it);
}
}
}
// Does this representation have any IfcProducts?
if (!ifcproducts->size()) {
_nextShape();
continue;
}
ifcproduct_iterator = ifcproducts->begin();
}
// Have we reached the end of our list of IfcProducts?
if ( ifcproduct_iterator == ifcproducts->end() ) {
_nextShape();
continue;
}
IfcSchema::IfcProduct* product = *ifcproduct_iterator;
BRepElement<P>* element = kernel.create_brep_for_representation_and_product<P>(settings, representation, product);
if ( !element ) {
_nextShape();
continue;
}
return element;
}
}
public:
bool next() {
// Free all possible representations of the current geometrical entity
delete current_triangulation;
current_triangulation = 0;
delete current_serialization;
current_serialization = 0;
delete current_shape_model;
current_shape_model = 0;
// Increment the iterator over the list of products using the current
// shape representation
if (ifcproducts) {
++ifcproduct_iterator;
}
return create();
}
Element<P>* get() {
// TODO: Test settings and throw
if (current_triangulation) return current_triangulation;
else if (current_serialization) return current_serialization;
else if (current_shape_model) return current_shape_model;
else return 0;
}
const Element<P>* getObject(int id) {
gp_Trsf trsf;
int parent_id = -1;
std::string instance_type, product_name, product_guid;
try {
const IfcUtil::IfcBaseClass* ifc_entity = ifc_file->entityById(id);
instance_type = IfcSchema::Type::ToString(ifc_entity->type());
if ( ifc_entity->is(IfcSchema::Type::IfcProduct) ) {
IfcSchema::IfcProduct* ifc_product = (IfcSchema::IfcProduct*)ifc_entity;
product_guid = ifc_product->GlobalId();
product_name = ifc_product->hasName() ? ifc_product->Name() : "";
parent_id = -1;
try {
IfcSchema::IfcObjectDefinition* parent_object = kernel.get_decomposing_entity(ifc_product);
if (parent_object) {
parent_id = parent_object->entity->id();
}
} catch (...) {}
try {
kernel.convert(ifc_product->ObjectPlacement(), trsf);
} catch (...) {}
}
} catch(...) {}
ElementSettings element_settings(settings, unit_magnitude, instance_type);
Element<P>* ifc_object = new Element<P>(element_settings, id, parent_id, product_name, instance_type, product_guid, trsf);
return ifc_object;
}
bool create() {
try {
current_shape_model = create_shape_model_for_next_entity();
} catch (...) {}
if (!current_shape_model) return false;
if (settings.use_brep_data()) {
try {
current_serialization = new SerializedElement<P>(*current_shape_model);
} catch (...) {}
return !!current_serialization;
} else if (!settings.disable_triangulation()) {
try {
current_triangulation = new TriangulationElement<P>(*current_shape_model);
} catch (...) {}
return !!current_triangulation;
} else {
return true;
}
}
private:
void initialize() {
current_triangulation = 0;
current_shape_model = 0;
current_serialization = 0;
// Upon initialisation, the (empty) set of entity names,
// should be excluded, or no products would be processed.
include_entities_in_processing = false;
unit_name = "METER";
unit_magnitude = 1.f;
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.sew_shells() ? 1000 : -1);
kernel.setValue(IfcGeom::Kernel::GV_FORCE_CCW_FACE_ORIENTATION, settings.force_ccw_face_orientation() ? 1 : -1);
}
public:
Iterator(const IteratorSettings& settings, IfcParse::IfcFile* file)
: settings(settings)
, ifc_file(file)
{
initialize();
}
Iterator(const IteratorSettings& settings, const std::string& filename)
: settings(settings)
, ifc_file(new IfcParse::IfcFile)
{
ifc_file->Init(filename);
initialize();
}
Iterator(const IteratorSettings& settings, void* data, int length)
: settings(settings)
, ifc_file(new IfcParse::IfcFile)
{
ifc_file->Init(data, length);
initialize();
}
Iterator(const IteratorSettings& settings, std::istream& filestream, int length)
: settings(settings)
, ifc_file(new IfcParse::IfcFile)
{
ifc_file->Init(filestream, length);
initialize();
}
~Iterator() {
// TODO: Correctly implement destructor for IfcFile
delete ifc_file;
delete current_triangulation;
current_triangulation = 0;
delete current_serialization;
current_serialization = 0;
delete current_shape_model;
current_shape_model = 0;
}
};
}
#endif
-172
View File
@@ -1,172 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef IFCGEOMITERATORSETTINGS_H
#define IFCGEOMITERATORSETTINGS_H
#include <string>
#include "../ifcparse/IfcException.h"
namespace IfcGeom {
class IteratorSettings {
public:
// Enumeration of setting identifiers. These settings define the
// behaviour of various aspects of IfcOpenShell.
// Specifies whether vertices are welded, meaning that the coordinates
// vector will only contain unique xyz-triplets. This results in a
// manifold mesh which is useful for modelling applications, but might
// result in unwanted shading artifacts in rendering applications.
static const int WELD_VERTICES = 1;
// Specifies whether to apply the local placements of building elements
// directly to the coordinates of the representation mesh rather than
// to represent the local placement in the 4x3 matrix, which will in that
// case be the identity matrix.
static const int USE_WORLD_COORDS = 2;
// Internally IfcOpenShell measures everything in meters. This settings
// specifies whether to convert IfcGeomObjects back to the units in which
// the geometry in the IFC file is specified.
static const int CONVERT_BACK_UNITS = 3;
// Specifies whether to use the Open Cascade BREP format for representation
// items rather than to create triangle meshes. This is useful is IfcOpenShell
// is used as a library in an application that is also built on Open Cascade.
static const int USE_BREP_DATA = 4;
// Specifies whether to sew IfcConnectedFaceSets (open and closed shells) to
// TopoDS_Shells or whether to keep them as a loose collection of faces.
static const int SEW_SHELLS = 5;
// Specifies whether to compose IfcOpeningElements into a single compound
// in order to speed up the processing of opening subtractions.
static const int FASTER_BOOLEANS = 6;
// By default singular faces have no explicitly defined orientation, to
// force faces to be defined CounterClockWise set this to true.
static const int FORCE_CCW_FACE_ORIENTATION = 7;
// Disables the subtraction of IfcOpeningElement representations from
// the related building element representations.
static const int DISABLE_OPENING_SUBTRACTIONS = 8;
// Disables the triangulation of the topological representations. Useful if
// the client application understands Open Cascade's native format.
static const int DISABLE_TRIANGULATION = 9;
// Applies default materials to entity instances without a surface style.
static const int APPLY_DEFAULT_MATERIALS = 10;
// End of settings enumeration.
private:
bool _weld_vertices, _use_world_coords, _convert_back_units, _use_brep_data, _sew_shells, _faster_booleans, _force_ccw_face_orientation, _disable_opening_subtractions, _disable_triangulation, _apply_default_materials;
double _deflection_tolerance;
public:
IteratorSettings()
: _weld_vertices(true)
, _use_world_coords(false)
, _convert_back_units(false)
, _use_brep_data(false)
, _sew_shells(false)
, _faster_booleans(false)
, _force_ccw_face_orientation(false)
, _disable_opening_subtractions(false)
, _disable_triangulation(false)
, _apply_default_materials(false)
// TODO: Make deflection tolerance into a command line argument
// For now, stick to one millimeter. Note that this is independent of the IFC length unit.
, _deflection_tolerance(1.e-3)
{}
const bool& weld_vertices() const { return _weld_vertices; }
bool& weld_vertices() { return _weld_vertices; }
const bool& use_world_coords() const { return _use_world_coords; }
bool& use_world_coords() { return _use_world_coords; }
const bool& convert_back_units() const { return _convert_back_units; }
bool& convert_back_units() { return _convert_back_units; }
const bool& use_brep_data() const { return _use_brep_data; }
bool& use_brep_data() { return _use_brep_data; }
const bool& sew_shells() const { return _sew_shells; }
bool& sew_shells() { return _sew_shells; }
const bool& faster_booleans() const { return _faster_booleans; }
bool& faster_booleans() { return _faster_booleans; }
const bool& force_ccw_face_orientation() const { return _force_ccw_face_orientation; }
bool& force_ccw_face_orientation() { return _force_ccw_face_orientation; }
const bool& disable_opening_subtractions() const { return _disable_opening_subtractions; }
bool& disable_opening_subtractions() { return _disable_opening_subtractions; }
const bool& disable_triangulation() const { return _disable_triangulation; }
bool& disable_triangulation() { return _disable_triangulation; }
const bool& apply_default_materials() const { return _apply_default_materials; }
bool& apply_default_materials() { return _apply_default_materials; }
const double& deflection_tolerance() const { return _deflection_tolerance; }
double& deflection_tolerance() { return _deflection_tolerance; }
void set(int setting, bool value) {
switch (setting) {
case USE_WORLD_COORDS:
_use_world_coords = value;
break;
case WELD_VERTICES:
_weld_vertices = value;
break;
case CONVERT_BACK_UNITS:
_convert_back_units = value;
break;
case USE_BREP_DATA:
_use_brep_data = value;
break;
case FASTER_BOOLEANS:
_faster_booleans = value;
break;
case SEW_SHELLS:
_sew_shells = value;
break;
case FORCE_CCW_FACE_ORIENTATION:
_force_ccw_face_orientation = value;
break;
case DISABLE_OPENING_SUBTRACTIONS:
_disable_opening_subtractions = value;
break;
case DISABLE_TRIANGULATION:
_disable_triangulation = value;
break;
case APPLY_DEFAULT_MATERIALS:
_apply_default_materials = value;
break;
default: throw IfcParse::IfcException("Invalid IteratorSetting");
}
}
};
class ElementSettings : public IteratorSettings {
private:
double _unit_magnitude;
std::string _element_type;
public:
ElementSettings(const IteratorSettings& settings,
double unit_magnitude,
const std::string& element_type)
: IteratorSettings(settings)
, _unit_magnitude(unit_magnitude)
, _element_type(element_type)
{}
const double& unit_magnitude() const { return _unit_magnitude; }
const std::string& element_type() const { return _element_type; }
};
}
#endif
-34
View File
@@ -1,34 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include "IfcGeomMaterial.h"
static double black[3] = {0.,0.,0.};
IfcGeom::Material::Material(const IfcGeom::SurfaceStyle* style) : style(style) {}
bool IfcGeom::Material::hasDiffuse() const { return style->Diffuse() ? true : false; }
bool IfcGeom::Material::hasSpecular() const { return style->Specular() ? true : false; }
bool IfcGeom::Material::hasTransparency() const { return style->Transparency() ? true : false; }
bool IfcGeom::Material::hasSpecularity() const { return style->Specularity() ? true : false; }
const double* IfcGeom::Material::diffuse() const { if (hasDiffuse()) return &((*style->Diffuse()).R()); else return black; }
const double* IfcGeom::Material::specular() const { if (hasSpecular()) return &((*style->Specular()).R()); else return black; }
double IfcGeom::Material::transparency() const { if (hasTransparency()) return *style->Transparency(); else return 0; }
double IfcGeom::Material::specularity() const { if (hasSpecularity()) return *style->Specularity(); else return 0; }
const std::string IfcGeom::Material::name() const { return style->Name(); }
bool IfcGeom::Material::operator==(const IfcGeom::Material& other) const { return style == other.style; }
-162
View File
@@ -1,162 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include <map>
#include "IfcGeom.h"
bool process_colour(IfcSchema::IfcColourRgb* colour, std::tr1::array<double, 3>& rgb) {
if (colour != 0) {
rgb[0] = colour->Red();
rgb[1] = colour->Green();
rgb[2] = colour->Blue();
}
return colour != 0;
}
bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, std::tr1::array<double, 3>& rgb) {
if (factor != 0) {
const double f = *factor;
rgb[0] = rgb[1] = rgb[2] = f;
}
return factor != 0;
}
bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, std::tr1::array<double, 3>& rgb) {
if (colour_or_factor == 0) {
return false;
} else if (colour_or_factor->is(IfcSchema::Type::IfcColourRgb)) {
return process_colour(static_cast<IfcSchema::IfcColourRgb*>(colour_or_factor), rgb);
} else if (colour_or_factor->is(IfcSchema::Type::IfcNormalisedRatioMeasure)) {
return process_colour(static_cast<IfcSchema::IfcNormalisedRatioMeasure*>(colour_or_factor), rgb);
} else {
return false;
}
}
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepresentationItem* item) {
std::pair<IfcSchema::IfcSurfaceStyle*, IfcSchema::IfcSurfaceStyleShading*> shading_styles = get_surface_style<IfcSchema::IfcSurfaceStyleShading>(item);
if (shading_styles.second == 0) {
return 0;
}
int surface_style_id = shading_styles.first->entity->id();
std::map<int,SurfaceStyle>::const_iterator it = cache.Style.find(surface_style_id);
if (it != cache.Style.end()) {
return &(it->second);
}
SurfaceStyle surface_style;
if (shading_styles.first->hasName()) {
surface_style = SurfaceStyle(surface_style_id, shading_styles.first->Name());
} else {
surface_style = SurfaceStyle(surface_style_id);
}
std::tr1::array<double, 3> rgb;
if (process_colour(shading_styles.second->SurfaceColour(), rgb)) {
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
}
if (shading_styles.second->is(IfcSchema::Type::IfcSurfaceStyleRendering)) {
IfcSchema::IfcSurfaceStyleRendering* rendering_style = static_cast<IfcSchema::IfcSurfaceStyleRendering*>(shading_styles.second);
if (rendering_style->hasDiffuseColour() && process_colour(rendering_style->DiffuseColour(), rgb)) {
SurfaceStyle::ColorComponent diffuse = surface_style.Diffuse().get_value_or(SurfaceStyle::ColorComponent(1,1,1));
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(diffuse.R() * rgb[0], diffuse.G() * rgb[1], diffuse.B() * rgb[2]));
}
if (rendering_style->hasDiffuseTransmissionColour()) {
// Not supported
}
if (rendering_style->hasReflectionColour()) {
// Not supported
}
if (rendering_style->hasSpecularColour() && process_colour(rendering_style->SpecularColour(), rgb)) {
surface_style.Specular().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
}
if (rendering_style->hasSpecularHighlight()) {
IfcSchema::IfcSpecularHighlightSelect* highlight = rendering_style->SpecularHighlight();
if (highlight->is(IfcSchema::Type::IfcSpecularRoughness)) {
double roughness = *((IfcSchema::IfcSpecularRoughness*)highlight);
if (roughness >= 1e-9) {
surface_style.Specularity().reset(1.0 / roughness);
}
} else if (highlight->is(IfcSchema::Type::IfcSpecularExponent)) {
surface_style.Specularity().reset(*((IfcSchema::IfcSpecularExponent*)highlight));
}
}
if (rendering_style->hasTransmissionColour()) {
// Not supported
}
if (rendering_style->hasTransparency()) {
const double d = rendering_style->Transparency();
surface_style.Transparency().reset(d);
}
}
return &(cache.Style[surface_style_id] = surface_style);
}
static std::map<std::string, IfcGeom::SurfaceStyle> default_materials;
static IfcGeom::SurfaceStyle default_material;
static bool default_materials_initialized = false;
void InitDefaultMaterials() {
default_materials.insert(std::make_pair("IfcSite", IfcGeom::SurfaceStyle("IfcSite")));
default_materials["IfcSite" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.8, 0.65));
default_materials.insert(std::make_pair("IfcSlab", IfcGeom::SurfaceStyle("IfcSlab")));
default_materials["IfcSlab" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.4 , 0.4, 0.4 ));
default_materials.insert(std::make_pair("IfcWallStandardCase", IfcGeom::SurfaceStyle("IfcWallStandardCase")));
default_materials["IfcWallStandardCase"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.9 , 0.9, 0.9 ));
default_materials.insert(std::make_pair("IfcWall", IfcGeom::SurfaceStyle("IfcWall")));
default_materials["IfcWall" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.9 , 0.9, 0.9 ));
default_materials.insert(std::make_pair("IfcWindow", IfcGeom::SurfaceStyle("IfcWindow")));
default_materials["IfcWindow" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.8, 0.75));
default_materials["IfcWindow" ].Transparency().reset(0.3);
default_materials.insert(std::make_pair("IfcDoor", IfcGeom::SurfaceStyle("IfcDoor")));
default_materials["IfcDoor" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.55, 0.3, 0.15));
default_materials.insert(std::make_pair("IfcBeam", IfcGeom::SurfaceStyle("IfcBeam")));
default_materials["IfcBeam" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.7, 0.7 ));
default_materials.insert(std::make_pair("IfcRailing", IfcGeom::SurfaceStyle("IfcRailing")));
default_materials["IfcRailing" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.65, 0.6, 0.6 ));
default_materials.insert(std::make_pair("IfcMember", IfcGeom::SurfaceStyle("IfcMember")));
default_materials["IfcMember" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.65, 0.6, 0.6 ));
default_materials.insert(std::make_pair("IfcPlate", IfcGeom::SurfaceStyle("IfcPlate")));
default_materials["IfcPlate" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.8 , 0.8, 0.8 ));
default_material = IfcGeom::SurfaceStyle("DefaultMaterial");
default_material.Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.7, 0.7, 0.7));
default_materials_initialized = true;
}
const IfcGeom::SurfaceStyle* IfcGeom::get_default_style(const std::string& s) {
if (!default_materials_initialized) InitDefaultMaterials();
std::map<std::string, IfcGeom::SurfaceStyle>::const_iterator it = default_materials.find(s);
if (it == default_materials.end()) {
default_materials.insert(std::make_pair(s, IfcGeom::SurfaceStyle(s)));
default_materials[s].Diffuse().reset(*default_material.Diffuse());
it = default_materials.find(s);
}
const IfcGeom::SurfaceStyle& surface_style = it->second;
return &surface_style;
}
-103
View File
@@ -1,103 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef IFCGEOMRENDERSTYLES_H
#define IFCGEOMRENDERSTYLES_H
#ifdef __GNUC__
#include <tr1/array>
#else
#include <array>
#endif
#ifdef USE_IFC4
#include "../ifcparse/Ifc4.h"
#else
#include "../ifcparse/Ifc2x3.h"
#endif
namespace IfcGeom {
class SurfaceStyle {
public:
class ColorComponent {
private:
std::tr1::array<double, 3> data;
public:
ColorComponent(double r, double g, double b) {
data[0] = r; data[1] = g; data[2] = b;
}
const double& R() const { return data[0]; }
const double& G() const { return data[1]; }
const double& B() const { return data[2]; }
double& R() { return data[0]; }
double& G() { return data[1]; }
double& B() { return data[2]; }
};
private:
boost::optional<std::string> name;
boost::optional<int> id;
boost::optional<ColorComponent> diffuse, specular;
boost::optional<double> transparency;
boost::optional<double> specularity;
public:
SurfaceStyle() {
this->name = "IfcSurfaceStyleShading";
}
SurfaceStyle(int id) : id(id) {
std::stringstream sstr;
sstr << "IfcSurfaceStyleShading_" << id;
this->name = sstr.str();
}
SurfaceStyle(const std::string& name) : name(name) {}
SurfaceStyle(int id, const std::string& name) : id(id) {
std::stringstream sstr;
sstr << id << "_" << name;
this->name = sstr.str();
}
// Not used at this point. In fact, equality testing in the current
// architecture can just as easily be accomplished by comparing the
// pointer addresses of the styles, as they are always referenced
// from out of a global map of some sort.
bool operator==(const SurfaceStyle& other) {
if (name && other.name) {
return *name == *other.name;
} else if (id && other.id) {
return *id == *other.id;
} else {
return false;
}
}
const std::string& Name() const { return *name; }
const boost::optional<ColorComponent>& Diffuse() const { return diffuse; }
const boost::optional<ColorComponent>& Specular() const { return specular; }
const boost::optional<double>& Transparency() const { return transparency; }
const boost::optional<double>& Specularity() const { return specularity; }
boost::optional<ColorComponent>& Diffuse() { return diffuse; }
boost::optional<ColorComponent>& Specular() { return specular; }
boost::optional<double>& Transparency() { return transparency; }
boost::optional<double>& Specularity() { return specularity; }
};
const SurfaceStyle* get_default_style(const std::string& ifc_type);
}
#endif
-59
View File
@@ -1,59 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include <BRep_Tool.hxx>
#include <BRepTools.hxx>
#include <BRep_Builder.hxx>
#include <TopoDS_Compound.hxx>
#include <BRepBuilderAPI_GTransform.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "IfcGeomRepresentation.h"
IfcGeom::Representation::Serialization::Serialization(const BRep& brep)
: Representation(brep.settings())
, _id(brep.getId())
{
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++ it) {
const TopoDS_Shape& s = it->Shape();
gp_GTrsf trsf = it->Placement();
if (settings().convert_back_units()) {
gp_Trsf scale;
scale.SetScaleFactor(1.0 / settings().unit_magnitude());
trsf.PreMultiply(scale);
}
bool trsf_valid = false;
gp_Trsf _trsf;
try {
_trsf = trsf.Trsf();
trsf_valid = true;
} catch (...) {}
const TopoDS_Shape moved_shape = trsf_valid ? s.Moved(_trsf) :
BRepBuilderAPI_GTransform(s,trsf,true).Shape();
builder.Add(compound,moved_shape);
}
std::stringstream sstream;
BRepTools::Write(compound,sstream);
_brep_data = sstream.str();
}
-272
View File
@@ -1,272 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef IFCGEOMREPRESENTATION_H
#define IFCGEOMREPRESENTATION_H
#include <BRepMesh_IncrementalMesh.hxx>
#include <BRepGProp_Face.hxx>
#include <Poly_Triangulation.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <TopExp_Explorer.hxx>
#include "../ifcgeom/IfcGeomIteratorSettings.h"
#include "../ifcgeom/IfcGeomMaterial.h"
#include "../ifcgeom/IfcRepresentationShapeItem.h"
namespace IfcGeom {
namespace Representation {
class Representation {
protected:
const ElementSettings _settings;
public:
explicit Representation(const ElementSettings& settings)
: _settings(settings)
{}
const ElementSettings& settings() const { return _settings; }
virtual ~Representation() {}
};
class BRep : public Representation {
private:
unsigned int id;
const IfcGeom::IfcRepresentationShapeItems shapes;
BRep(const BRep& other);
BRep& operator=(const BRep& other);
public:
BRep(const ElementSettings& settings, unsigned int id, const IfcGeom::IfcRepresentationShapeItems& shapes)
: Representation(settings)
, id(id)
, shapes(shapes)
{}
virtual ~BRep() {}
IfcGeom::IfcRepresentationShapeItems::const_iterator begin() const { return shapes.begin(); }
IfcGeom::IfcRepresentationShapeItems::const_iterator end() const { return shapes.end(); }
const unsigned int& getId() const { return id; }
};
class Serialization : public Representation {
private:
int _id;
std::string _brep_data;
public:
int id() const { return _id; }
const std::string& brep_data() const { return _brep_data; }
Serialization(const BRep& brep);
virtual ~Serialization() {}
private:
Serialization();
Serialization(const Serialization&);
Serialization& operator=(const Serialization&);
};
template <typename P>
class Triangulation : public Representation {
private:
// A nested pair of floats and a material index to be able to store an XYZ coordinate in a map.
// TODO: Make this a std::tuple when compilers add support for that.
typedef typename std::pair<P, std::pair<P, P> > Coordinate;
typedef typename std::pair<int, Coordinate> VertexKey;
typedef std::map<VertexKey, int> VertexKeyMap;
typedef std::pair<int, int> Edge;
int _id;
std::vector<P> _verts;
std::vector<int> _faces;
std::vector<int> _edges;
std::vector<P> _normals;
std::vector<int> _material_ids;
std::vector<Material> _materials;
VertexKeyMap welds;
public:
int id() const { return _id; }
const std::vector<P>& verts() const { return _verts; }
const std::vector<int>& faces() const { return _faces; }
const std::vector<int>& edges() const { return _edges; }
const std::vector<P>& normals() const { return _normals; }
const std::vector<int>& material_ids() const { return _material_ids; }
const std::vector<Material>& materials() const { return _materials; }
Triangulation(const BRep& shape_model)
: Representation(shape_model.settings())
, _id(shape_model.getId())
{
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it = shape_model.begin(); it != shape_model.end(); ++ it ) {
int surface_style_id = -1;
if (it->hasStyle()) {
Material adapter(&it->Style());
std::vector<Material>::const_iterator jt = std::find(_materials.begin(), _materials.end(), adapter);
if (jt == _materials.end()) {
surface_style_id = _materials.size();
_materials.push_back(adapter);
} else {
surface_style_id = jt - _materials.begin();
}
}
if (settings().apply_default_materials() && surface_style_id == -1) {
Material material(IfcGeom::get_default_style(settings().element_type()));
std::vector<Material>::const_iterator it = std::find(_materials.begin(), _materials.end(), material);
if (it == _materials.end()) {
surface_style_id = _materials.size();
_materials.push_back(material);
} else {
surface_style_id = it - _materials.begin();
}
}
const TopoDS_Shape& s = it->Shape();
const gp_GTrsf& trsf = it->Placement();
// Triangulate the shape
try {
BRepMesh_IncrementalMesh(s, settings().deflection_tolerance());
} catch(...) {
// TODO: Catch outside
// Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape:",ifc_file->entityById(_id)->entity);
Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape");
continue;
}
TopExp_Explorer exp;
// Iterates over the faces of the shape
for ( exp.Init(s,TopAbs_FACE); exp.More(); exp.Next() ) {
TopoDS_Face face = TopoDS::Face(exp.Current());
TopLoc_Location loc;
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face,loc);
if ( ! tri.IsNull() ) {
// A 3x3 matrix to rotate the vertex normals
const gp_Mat rotation_matrix = trsf.VectorialPart();
// Keep track of the number of times an edge is used
// Manifold edges (i.e. edges used twice) are deemed invisible
std::map<std::pair<int,int>,int> edgecount;
std::vector<std::pair<int,int> > edges_temp;
const TColgp_Array1OfPnt& nodes = tri->Nodes();
const TColgp_Array1OfPnt2d& uvs = tri->UVNodes();
std::vector<gp_XYZ> coords;
BRepGProp_Face prop(face);
std::map<int,int> dict;
// Vertex normals are only calculated if vertices are not welded
const bool calculate_normals = !settings().weld_vertices();
for( int i = 1; i <= nodes.Length(); ++ i ) {
coords.push_back(nodes(i).Transformed(loc).XYZ());
trsf.Transforms(*coords.rbegin());
dict[i] = addVertex(surface_style_id, *coords.rbegin());
if ( calculate_normals ) {
const gp_Pnt2d& uv = uvs(i);
gp_Pnt p;
gp_Vec normal_direction;
prop.Normal(uv.X(),uv.Y(),p,normal_direction);
gp_Vec normal(0., 0., 0.);
if (normal_direction.Magnitude() > ALMOST_ZERO) {
normal = gp_Dir(normal_direction.XYZ() * rotation_matrix);
}
_normals.push_back((float)normal.X());
_normals.push_back((float)normal.Y());
_normals.push_back((float)normal.Z());
}
}
const Poly_Array1OfTriangle& triangles = tri->Triangles();
for( int i = 1; i <= triangles.Length(); ++ i ) {
int n1,n2,n3;
if ( face.Orientation() == TopAbs_REVERSED )
triangles(i).Get(n3,n2,n1);
else triangles(i).Get(n1,n2,n3);
/* An alternative would be to calculate normals based
* on the coordinates of the mesh vertices */
/*
const gp_XYZ pt1 = coords[n1-1];
const gp_XYZ pt2 = coords[n2-1];
const gp_XYZ pt3 = coords[n3-1];
const gp_XYZ v1 = pt2-pt1;
const gp_XYZ v2 = pt3-pt2;
gp_Dir normal = gp_Dir(v1^v2);
_normals.push_back((float)normal.X());
_normals.push_back((float)normal.Y());
_normals.push_back((float)normal.Z());
*/
_faces.push_back(dict[n1]);
_faces.push_back(dict[n2]);
_faces.push_back(dict[n3]);
_material_ids.push_back(surface_style_id);
addEdge(n1,n2,edgecount,edges_temp);
addEdge(n2,n3,edgecount,edges_temp);
addEdge(n3,n1,edgecount,edges_temp);
}
for ( std::vector<std::pair<int,int> >::const_iterator it = edges_temp.begin(); it != edges_temp.end(); ++it ) {
_edges.push_back(edgecount[*it]==1);
}
}
}
}
}
virtual ~Triangulation() {}
private:
// Welds vertices that belong to different faces
int addVertex(int material_index, const gp_XYZ& p) {
const P X = static_cast<P>(settings().convert_back_units() ? (p.X() / settings().unit_magnitude()) : p.X());
const P Y = static_cast<P>(settings().convert_back_units() ? (p.Y() / settings().unit_magnitude()) : p.Y());
const P Z = static_cast<P>(settings().convert_back_units() ? (p.Z() / settings().unit_magnitude()) : p.Z());
int i = (int) _verts.size() / 3;
if (settings().weld_vertices()) {
const VertexKey key = std::make_pair(material_index, std::make_pair(X, std::make_pair(Y, Z)));
typename VertexKeyMap::const_iterator it = welds.find(key);
if ( it != welds.end() ) return it->second;
i = (int) welds.size();
welds[key] = i;
}
_verts.push_back(X);
_verts.push_back(Y);
_verts.push_back(Z);
return i;
}
inline void addEdge(int n1, int n2, std::map<std::pair<int,int>,int>& edgecount, std::vector<std::pair<int,int> >& edges_temp) {
const Edge e = Edge( (std::min)(n1,n2),(std::max)(n1,n2) );
if ( edgecount.find(e) == edgecount.end() ) edgecount[e] = 1;
else edgecount[e] ++;
edges_temp.push_back(e);
}
Triangulation();
Triangulation(const Triangulation&);
Triangulation& operator=(const Triangulation&);
};
}
}
#endif
-818
View File
@@ -1,818 +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/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* Implementations of the various conversion functions defined in IfcRegister.h *
* *
********************************************************************************/
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#include <gp_Dir.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Vec2d.hxx>
#include <gp_Dir2d.hxx>
#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 <gp_Ax1.hxx>
#include <gp_Ax3.hxx>
#include <gp_Ax2d.hxx>
#include <gp_Pln.hxx>
#include <gp_Circ.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <Geom_Line.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Ellipse.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <Geom_CylindricalSurface.hxx>
#include <BRepOffsetAPI_Sewing.hxx>
#include <BRepOffsetAPI_MakePipe.hxx>
#include <BRepOffsetAPI_MakePipeShell.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#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 <BRepPrimAPI_MakeRevol.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepPrimAPI_MakeCone.hxx>
#include <BRepPrimAPI_MakeCylinder.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <BRepPrimAPI_MakeWedge.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepBuilderAPI_MakeShell.hxx>
#include <BRepBuilderAPI_MakeSolid.hxx>
#include <BRepPrimAPI_MakeHalfSpace.hxx>
#include <BRepAlgoAPI_Cut.hxx>
#include <BRepAlgoAPI_Fuse.hxx>
#include <BRepAlgoAPI_Common.hxx>
#include <ShapeFix_Shape.hxx>
#include <ShapeFix_ShapeTolerance.hxx>
#include <ShapeFix_Solid.hxx>
#include <TopLoc_Location.hxx>
#include <BRepCheck_Analyzer.hxx>
#include <BRepClass3d_SolidClassifier.hxx>
#include <Standard_Version.hxx>
#include "../ifcgeom/IfcGeom.h"
bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_Shape& shape) {
TopoDS_Shape face;
if ( !convert_face(l->SweptArea(),face) ) return false;
const double height = l->Depth() * getValue(GV_LENGTH_UNIT);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
gp_Dir dir;
convert(l->ExtrudedDirection(),dir);
shape.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::Kernel::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion* l, TopoDS_Shape& shape) {
TopoDS_Wire wire;
if ( !convert_wire(l->SweptCurve(), wire) ) {
TopoDS_Face face;
if ( !convert_face(l->SweptCurve(),face) ) return false;
TopExp_Explorer exp(face, TopAbs_WIRE);
wire = TopoDS::Wire(exp.Current());
}
const double height = l->Depth() * getValue(GV_LENGTH_UNIT);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
gp_Dir dir;
convert(l->ExtrudedDirection(),dir);
shape = BRepPrimAPI_MakePrism(wire, height*dir);
shape.Move(trsf);
return !shape.IsNull();
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfRevolution* l, TopoDS_Shape& shape) {
TopoDS_Wire wire;
if ( !convert_wire(l->SweptCurve(), wire) ) {
TopoDS_Face face;
if ( !convert_face(l->SweptCurve(),face) ) return false;
TopExp_Explorer exp(face, TopAbs_WIRE);
wire = TopoDS::Wire(exp.Current());
}
gp_Ax1 ax1;
IfcGeom::Kernel::convert(l->AxisPosition(), ax1);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
shape = BRepPrimAPI_MakeRevol(wire, ax1);
shape.Move(trsf);
return !shape.IsNull();
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRevolvedAreaSolid* l, TopoDS_Shape& shape) {
const double ang = l->Angle() * getValue(GV_PLANEANGLE_UNIT);
TopoDS_Face face;
if ( ! convert_face(l->SweptArea(),face) ) return false;
gp_Ax1 ax1;
IfcGeom::Kernel::convert(l->Axis(), ax1);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
if (ang >= M_PI * 2. - ALMOST_ZERO) {
shape = BRepPrimAPI_MakeRevol(face, ax1);
} else {
shape = BRepPrimAPI_MakeRevol(face, ax1, ang);
}
shape.Move(trsf);
return !shape.IsNull();
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFacetedBrep* l, IfcRepresentationShapeItems& shape) {
TopoDS_Shape s;
const SurfaceStyle* collective_style = get_style(l);
if (convert_shape(l->Outer(),s) ) {
const SurfaceStyle* indiv_style = get_style(l->Outer());
shape.push_back(IfcRepresentationShapeItem(s, indiv_style ? indiv_style : collective_style));
return true;
}
return false;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFaceBasedSurfaceModel* l, IfcRepresentationShapeItems& shapes) {
IfcSchema::IfcConnectedFaceSet::list::ptr facesets = l->FbsmFaces();
const SurfaceStyle* collective_style = get_style(l);
for( IfcSchema::IfcConnectedFaceSet::list::it it = facesets->begin(); it != facesets->end(); ++ it ) {
TopoDS_Shape s;
const SurfaceStyle* shell_style = get_style(*it);
if (convert_shape(*it,s)) {
shapes.push_back(IfcRepresentationShapeItem(s, shell_style ? shell_style : collective_style));
}
}
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, TopoDS_Shape& shape) {
IfcSchema::IfcSurface* surface = l->BaseSurface();
if ( ! surface->is(IfcSchema::Type::IfcPlane) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface->entity);
return false;
}
gp_Pln pln;
IfcGeom::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::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l, TopoDS_Shape& shape) {
TopoDS_Shape halfspace;
if ( ! IfcGeom::Kernel::convert((IfcSchema::IfcHalfSpaceSolid*)l,halfspace) ) return false;
TopoDS_Wire wire;
if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false;
gp_Trsf trsf;
convert(l->Position(),trsf);
TopoDS_Shape prism = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,200));
gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-100.0));
prism.Move(trsf*down);
shape = BRepAlgoAPI_Common(halfspace,prism);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, IfcRepresentationShapeItems& shapes) {
IfcEntityList::ptr shells = l->SbsmBoundary();
const SurfaceStyle* collective_style = get_style(l);
for( IfcEntityList::it it = shells->begin(); it != shells->end(); ++ it ) {
TopoDS_Shape s;
const SurfaceStyle* shell_style = 0;
if ((*it)->is(IfcSchema::Type::IfcRepresentationItem)) {
shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it);
}
if (convert_shape(*it,s)) {
shapes.push_back(IfcRepresentationShapeItem(s, shell_style ? shell_style : collective_style));
}
}
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) {
TopoDS_Shape s1, s2;
IfcRepresentationShapeItems items1, items2;
TopoDS_Wire boundary_wire;
IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand();
IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand();
bool is_halfspace = operand2->is(IfcSchema::Type::IfcHalfSpaceSolid);
if ( is_shape_collection(operand1) ) {
if (!(convert_shapes(operand1, items1) && flatten_shape_list(items1, s1, true))) {
return false;
}
} else {
if ( ! convert_shape(operand1, s1) ) {
return false;
}
{ TopoDS_Solid temp_solid;
s1 = ensure_fit_for_subtraction(s1, temp_solid); }
}
const double first_operand_volume = shape_volume(s1);
if ( first_operand_volume <= ALMOST_ZERO )
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand()->entity);
bool shape2_processed = false;
if ( is_shape_collection(operand2) ) {
shape2_processed = convert_shapes(operand2, items2) && flatten_shape_list(items2, s2, true);
} else {
shape2_processed = convert_shape(operand2,s2);
if (shape2_processed && !is_halfspace) {
TopoDS_Solid temp_solid;
s2 = ensure_fit_for_subtraction(s2, temp_solid);
}
}
if (!shape2_processed) {
shape = s1;
Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l->entity);
return true;
}
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);
}
const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator();
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
bool valid_cut = false;
BRepAlgoAPI_Cut brep_cut(s1,s2);
if ( brep_cut.IsDone() ) {
TopoDS_Shape result = brep_cut;
ShapeFix_Shape fix(result);
try {
fix.Perform();
result = fix.Shape();
} catch (...) {
Logger::Message(Logger::LOG_WARNING, "Shape healing failed on boolean result", l->entity);
}
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if ( is_valid ) {
shape = result;
valid_cut = true;
}
}
if ( valid_cut ) {
const double volume_after_subtraction = shape_volume(shape);
if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) )
Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",l->entity);
} else {
Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",l->entity);
shape = s1;
}
return true;
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) {
BRepAlgoAPI_Fuse brep_fuse(s1,s2);
if ( brep_fuse.IsDone() ) {
TopoDS_Shape result = brep_fuse;
ShapeFix_Shape fix(result);
fix.Perform();
result = fix.Shape();
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if ( is_valid ) {
shape = result;
return true;
}
}
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) {
BRepAlgoAPI_Common brep_common(s1,s2);
if ( brep_common.IsDone() ) {
TopoDS_Shape result = brep_common;
ShapeFix_Shape fix(result);
fix.Perform();
result = fix.Shape();
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if ( is_valid ) {
shape = result;
return true;
}
}
}
return false;
}
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();
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::list::it it = faces->begin(); it != faces->end(); ++ it ) {
TopoDS_Face face;
bool converted_face = false;
try {
converted_face = convert_face(*it,face);
} catch (...) {}
if ( converted_face && face_area(face) > getValue(GV_MINIMAL_FACE_AREA) ) {
builder.Add(face);
facesAdded = true;
} else {
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
}
}
if ( ! facesAdded ) return false;
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->entity);
}
}
if (!valid_shell) {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
for( IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++ it ) {
TopoDS_Face face;
bool converted_face = false;
try {
converted_face = convert_face(*it,face);
} catch (...) {}
if ( converted_face && face_area(face) > getValue(GV_MINIMAL_FACE_AREA) ) {
builder.Add(compound,face);
facesAdded = true;
} else {
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
}
}
if ( ! facesAdded ) return false;
shape = compound;
}
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentationShapeItems& shapes) {
gp_GTrsf gtrsf;
IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget();
if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf);
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity);
return false;
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) {
gp_Trsf trsf;
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf);
gtrsf = trsf;
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) {
gp_Trsf2d trsf_2d;
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,trsf_2d);
gtrsf = (gp_Trsf) trsf_2d;
}
IfcSchema::IfcRepresentationMap* map = l->MappingSource();
IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin();
gp_Trsf trsf;
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
} else {
gp_Trsf2d trsf_2d;
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf_2d);
trsf = trsf_2d;
}
gtrsf.Multiply(trsf);
const unsigned int previous_size = (const unsigned int) shapes.size();
bool b = convert_shapes(map->MappedRepresentation(),shapes);
for ( unsigned int i = previous_size; i < shapes.size(); ++ i ) {
shapes[i].append(gtrsf);
}
return b;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcShapeRepresentation* l, IfcRepresentationShapeItems& shapes) {
IfcSchema::IfcRepresentationItem::list::ptr items = l->Items();
bool part_succes = false;
if ( items->size() ) {
for ( IfcSchema::IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++ it ) {
IfcSchema::IfcRepresentationItem* representation_item = *it;
if ( is_shape_collection(representation_item) ) {
part_succes |= convert_shapes(*it, shapes);
} else {
TopoDS_Shape s;
if (convert_shape(representation_item,s)) {
shapes.push_back(IfcRepresentationShapeItem(s, get_style(representation_item)));
part_succes |= true;
}
}
}
}
return part_succes;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcGeometricSet* l, IfcRepresentationShapeItems& shapes) {
IfcEntityList::ptr elements = l->Elements();
if ( !elements->size() ) return false;
bool part_succes = false;
const IfcGeom::SurfaceStyle* parent_style = get_style(l);
for ( IfcEntityList::it it = elements->begin(); it != elements->end(); ++ it ) {
IfcSchema::IfcGeometricSetSelect* element = *it;
if (element->is(IfcSchema::Type::IfcSurface)) {
IfcSchema::IfcSurface* surface = (IfcSchema::IfcSurface*) element;
TopoDS_Shape s;
if (convert_shape(surface, s)) {
part_succes = true;
const IfcGeom::SurfaceStyle* style = get_style(surface);
shapes.push_back(IfcRepresentationShapeItem(s, style ? style : parent_style));
}
}
}
return part_succes;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBlock* l, TopoDS_Shape& shape) {
const double dx = l->XLength() * getValue(GV_LENGTH_UNIT);
const double dy = l->YLength() * getValue(GV_LENGTH_UNIT);
const double dz = l->ZLength() * getValue(GV_LENGTH_UNIT);
BRepPrimAPI_MakeBox builder(dx, dy, dz);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
shape = builder.Solid().Moved(trsf);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularPyramid* l, TopoDS_Shape& shape) {
const double dx = l->XLength() * getValue(GV_LENGTH_UNIT);
const double dy = l->YLength() * getValue(GV_LENGTH_UNIT);
const double dz = l->Height() * getValue(GV_LENGTH_UNIT);
BRepPrimAPI_MakeWedge builder(dx, dz, dy, dx / 2., dy / 2., dx / 2., dy / 2.);
gp_Trsf trsf1, trsf2;
trsf2.SetValues(
1, 0, 0, 0,
0, 0, 1, 0,
0, 1, 0, 0
#if OCC_VERSION_HEX < 0x60800
, Precision::Angular(), Precision::Confusion()
#endif
);
IfcGeom::Kernel::convert(l->Position(), trsf1);
shape = BRepBuilderAPI_Transform(builder.Solid(), trsf1 * trsf2);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRightCircularCylinder* l, TopoDS_Shape& shape) {
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
const double h = l->Height() * getValue(GV_LENGTH_UNIT);
BRepPrimAPI_MakeCylinder builder(r, h);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
shape = builder.Solid().Moved(trsf);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRightCircularCone* l, TopoDS_Shape& shape) {
const double r = l->BottomRadius() * getValue(GV_LENGTH_UNIT);
const double h = l->Height() * getValue(GV_LENGTH_UNIT);
BRepPrimAPI_MakeCone builder(r, 0., h);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
shape = builder.Solid().Moved(trsf);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSphere* l, TopoDS_Shape& shape) {
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
BRepPrimAPI_MakeSphere builder(r);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
shape = builder.Solid().Moved(trsf);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCsgSolid* l, TopoDS_Shape& shape) {
return convert_shape(l->TreeRootExpression(), shape);
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_Shape& face) {
gp_Pln pln;
IfcGeom::Kernel::convert(l->BasisSurface(), pln);
gp_Trsf trsf;
trsf.SetTransformation(pln.Position());
TopoDS_Wire outer;
convert_wire(l->OuterBoundary(), outer);
BRepBuilderAPI_MakeFace mf (outer);
mf.Add(outer);
IfcSchema::IfcCurve::list::ptr inner = l->InnerBoundaries();
for (IfcSchema::IfcCurve::list::it it = inner->begin(); it != inner->end(); ++it) {
TopoDS_Wire inner;
convert_wire(*it, inner);
mf.Add(inner);
}
ShapeFix_Shape sfs(mf.Face());
sfs.Perform();
face = TopoDS::Face(sfs.Shape()).Moved(trsf);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularTrimmedSurface* l, TopoDS_Shape& face) {
if (!l->BasisSurface()->is(IfcSchema::Type::IfcPlane)) {
Logger::Message(Logger::LOG_ERROR, "Unsupported BasisSurface:", l->BasisSurface()->entity);
return false;
}
gp_Pln pln;
IfcGeom::Kernel::convert((IfcSchema::IfcPlane*) l->BasisSurface(), pln);
BRepBuilderAPI_MakeFace mf(pln, l->U1(), l->U2(), l->V1(), l->V2());
face = mf.Face();
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, TopoDS_Shape& shape) {
gp_Trsf directrix, position;
TopoDS_Shape face;
TopoDS_Wire wire, section;
if (!l->ReferenceSurface()->is(IfcSchema::Type::IfcPlane)) {
Logger::Message(Logger::LOG_WARNING, "Reference surface not supported", l->ReferenceSurface()->entity);
return false;
}
if (!IfcGeom::Kernel::convert(l->Position(), position) ||
!convert_face(l->SweptArea(), face) ||
!convert_wire(l->Directrix(), wire) ) {
return false;
}
gp_Pln pln;
gp_Pnt directrix_origin;
gp_Vec directrix_tangent;
bool directrix_on_plane = true;
IfcGeom::Kernel::convert((IfcSchema::IfcPlane*) l->ReferenceSurface(), pln);
// As per Informal propositions 2: The Directrix shall lie on the ReferenceSurface.
// This is not always the case with the test files in the repository. I am not sure
// how to deal with this and whether my interpretation of the propositions is
// correct. However, if it has been asserted that the vertices of the directrix do
// not conform to the ReferenceSurface, the ReferenceSurface is ignored.
{
for (TopExp_Explorer exp(wire, TopAbs_VERTEX); exp.More(); exp.Next()) {
if (pln.Distance(BRep_Tool::Pnt(TopoDS::Vertex(exp.Current()))) > ALMOST_ZERO) {
directrix_on_plane = false;
Logger::Message(Logger::LOG_WARNING, "The Directrix does not lie on the ReferenceSurface", l->entity);
break;
}
}
}
{
TopExp_Explorer exp(wire, TopAbs_EDGE);
TopoDS_Edge edge = TopoDS::Edge(exp.Current());
double u0, u1;
Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u0, u1);
crv->D1(u0, directrix_origin, directrix_tangent);
}
if (pln.Axis().Direction().IsNormal(directrix_tangent, Precision::Approximation()) && directrix_on_plane) {
directrix.SetTransformation(gp_Ax3(directrix_origin, directrix_tangent, pln.Axis().Direction()), gp::XOY());
} else {
directrix.SetTransformation(gp_Ax3(directrix_origin, directrix_tangent), gp::XOY());
}
face = BRepBuilderAPI_Transform(face, directrix);
// NB: Note that StartParam and EndParam param are ignored and the assumption is
// made that the parametric range over which to be swept matches the IfcCurve in
// its entirety.
BRepOffsetAPI_MakePipeShell builder(wire);
{ TopExp_Explorer exp(face, TopAbs_WIRE);
section = TopoDS::Wire(exp.Current()); }
builder.Add(section);
builder.SetTransitionMode(BRepBuilderAPI_RightCorner);
if (directrix_on_plane) {
builder.SetMode(pln.Axis().Direction());
}
builder.Build();
builder.MakeSolid();
shape = builder.Shape();
shape.Move(position);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shape& shape) {
TopoDS_Wire wire, section1, section2;
bool hasInnerRadius = l->hasInnerRadius();
if (!convert_wire(l->Directrix(), wire)) {
return false;
}
gp_Ax2 directrix;
{
gp_Pnt directrix_origin;
gp_Vec directrix_tangent;
TopExp_Explorer exp(wire, TopAbs_EDGE);
TopoDS_Edge edge = TopoDS::Edge(exp.Current());
double u0, u1;
Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u0, u1);
crv->D1(u0, directrix_origin, directrix_tangent);
directrix = gp_Ax2(directrix_origin, directrix_tangent);
}
const double r1 = l->Radius() * getValue(GV_LENGTH_UNIT);
Handle(Geom_Circle) circle = new Geom_Circle(directrix, r1);
section1 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle));
if (hasInnerRadius) {
const double r2 = l->InnerRadius() * getValue(GV_LENGTH_UNIT);
if (r2 < getValue(GV_PRECISION)) {
// Subtraction of pipes with small radii is unstable.
hasInnerRadius = false;
} else {
Handle(Geom_Circle) circle = new Geom_Circle(directrix, r2);
section2 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle));
}
}
// NB: Note that StartParam and EndParam param are ignored and the assumption is
// made that the parametric range over which to be swept matches the IfcCurve in
// its entirety.
// NB2: Contrary to IfcSurfaceCurveSweptAreaSolid the transition mode has been
// set to create round corners as this has proven to work better with the types
// of directrices encountered, which do not necessarily conform to a surface.
{ BRepOffsetAPI_MakePipeShell builder(wire);
builder.Add(section1);
builder.SetTransitionMode(BRepBuilderAPI_RoundCorner);
builder.Build();
builder.MakeSolid();
shape = builder.Shape(); }
if (hasInnerRadius) {
BRepOffsetAPI_MakePipeShell builder(wire);
builder.Add(section2);
builder.SetTransitionMode(BRepBuilderAPI_RoundCorner);
builder.Build();
builder.MakeSolid();
TopoDS_Shape inner = builder.Shape();
BRepAlgoAPI_Cut brep_cut(shape, inner);
bool is_valid = false;
if (brep_cut.IsDone()) {
TopoDS_Shape result = brep_cut;
ShapeFix_Shape fix(result);
fix.Perform();
result = fix.Shape();
is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if (is_valid) {
shape = result;
}
}
if (!is_valid) {
Logger::Message(Logger::LOG_WARNING, "Failed to subtract inner radius void for:", l->entity);
}
}
return true;
}
#ifdef USE_IFC4
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCylindricalSurface* l, TopoDS_Shape& face) {
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius()), getValue(GV_PRECISION)).Face().Moved(trsf);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAdvancedBrep* l, TopoDS_Shape& shape) {
return convert(l->Outer(), shape);
}
#endif
-437
View File
@@ -1,437 +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/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* Implementations of the various conversion functions defined in IfcRegister.h *
* *
********************************************************************************/
#define _USE_MATH_DEFINES
#include <cmath>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#include <gp_Dir.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Vec2d.hxx>
#include <gp_Dir2d.hxx>
#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 <gp_Ax3.hxx>
#include <gp_Ax2d.hxx>
#include <gp_Pln.hxx>
#include <gp_Circ.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <Geom_Line.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Ellipse.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
#include <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 <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 "../ifcgeom/IfcGeom.h"
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire& wire) {
if ( getValue(GV_PLANEANGLE_UNIT)<0 ) {
Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l->entity);
// Temporarily pretend we do have unit information
setValue(GV_PLANEANGLE_UNIT,1.0);
bool succes_radians = false;
bool succes_degrees = false;
bool use_radians = false;
bool use_degrees = false;
// First try radians
TopoDS_Wire wire_radians, wire_degrees;
try {
succes_radians = IfcGeom::Kernel::convert(l,wire_radians);
} catch (...) {}
// Now try degrees
setValue(GV_PLANEANGLE_UNIT,0.0174532925199433);
try {
succes_degrees = IfcGeom::Kernel::convert(l,wire_degrees);
} catch (...) {}
// Restore to unknown unit state
setValue(GV_PLANEANGLE_UNIT,-1.0);
if ( succes_degrees && ! succes_radians ) {
use_degrees = true;
} else if ( succes_radians && ! succes_degrees ) {
use_radians = true;
} else if ( succes_radians && succes_degrees ) {
if ( wire_degrees.Closed() && ! wire_radians.Closed() ) {
use_degrees = true;
} else if ( wire_radians.Closed() && ! wire_degrees.Closed() ) {
use_radians = true;
} else {
// No heuristic left to prefer the one over the other,
// apparently both variants are equally succesful.
// The curve might be composed of only straight segments.
// Let's go with the wire created using radians as that
// at least is a SI unit.
use_radians = true;
}
}
if ( use_radians ) {
Logger::Message(Logger::LOG_NOTICE,"Used radians to create composite curve");
wire = wire_radians;
} else if ( use_degrees ) {
Logger::Message(Logger::LOG_NOTICE,"Used degrees to create composite curve");
wire = wire_degrees;
}
return use_radians || use_degrees;
}
IfcSchema::IfcCompositeCurveSegment::list::ptr segments = l->Segments();
BRepBuilderAPI_MakeWire w;
//TopoDS_Vertex last_vertex;
for( IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++ it ) {
IfcSchema::IfcCurve* curve = (*it)->ParentCurve();
TopoDS_Wire wire2;
if ( !convert_wire(curve,wire2) ) {
Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve->entity);
continue;
}
if ( ! (*it)->SameSense() ) wire2.Reverse();
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(wire2, 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());
gp_Pnt first = BRep_Tool::Pnt(first_vertex);
gp_Pnt last = BRep_Tool::Pnt(last_vertex);
Standard_Real distance = first.Distance(last);
if ( distance > ALMOST_ZERO ) {
w.Add( BRepBuilderAPI_MakeEdge( last_vertex, first_vertex ) );
}
}*/
w.Add(wire2);
//last_vertex = w.Vertex();
if ( w.Error() != BRepBuilderAPI_WireDone ) {
Logger::Message(Logger::LOG_ERROR,"Failed to join curve segments:",l->entity);
return false;
}
}
wire = w.Wire();
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& wire) {
IfcSchema::IfcCurve* basis_curve = l->BasisCurve();
bool isConic = basis_curve->is(IfcSchema::Type::IfcConic);
double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT);
Handle(Geom_Curve) curve;
if ( !convert_curve(basis_curve,curve) ) return false;
bool trim_cartesian = l->MasterRepresentation() == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN;
IfcEntityList::ptr trims1 = l->Trim1();
IfcEntityList::ptr trims2 = l->Trim2();
bool trimmed1 = false;
bool trimmed2 = false;
unsigned sense_agreement = l->SenseAgreement() ? 0 : 1;
double flts[2];
gp_Pnt pnts[2];
bool has_flts[2] = {false,false};
bool has_pnts[2] = {false,false};
BRepBuilderAPI_MakeWire w;
for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) {
IfcUtil::IfcBaseClass* i = *it;
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] );
has_pnts[sense_agreement] = true;
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
const double value = *((IfcSchema::IfcParameterValue*)i);
flts[sense_agreement] = value * parameterFactor;
has_flts[sense_agreement] = true;
}
}
for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) {
IfcUtil::IfcBaseClass* i = *it;
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] );
has_pnts[1-sense_agreement] = true;
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
const double value = *((IfcSchema::IfcParameterValue*)i);
flts[1-sense_agreement] = value * parameterFactor;
has_flts[1-sense_agreement] = true;
}
}
trim_cartesian &= has_pnts[0] && has_pnts[1];
bool trim_cartesian_failed = !trim_cartesian;
if ( trim_cartesian ) {
if ( pnts[0].Distance(pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE) ) {
Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l->entity);
return false;
}
ShapeFix_ShapeTolerance FTol;
TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(pnts[0]);
TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(pnts[1]);
FTol.SetTolerance(v1, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
FTol.SetTolerance(v2, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
BRepBuilderAPI_MakeEdge e (curve,v1,v2);
if ( ! e.IsDone() ) {
BRepBuilderAPI_EdgeError err = e.Error();
if ( err == BRepBuilderAPI_PointProjectionFailed ) {
Logger::Message(Logger::LOG_WARNING,"Point projection failed for:",l->entity);
trim_cartesian_failed = true;
}
} else {
w.Add(e.Edge());
}
}
if ( (!trim_cartesian || trim_cartesian_failed) && (has_flts[0] && has_flts[1]) ) {
// The Geom_Line is constructed from a gp_Pnt and gp_Dir, whereas the IfcLine
// is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because
// the vector is normalised when passed to Geom_Line constructor the magnitude
// needs to be factored in with the IfcParameterValue here.
if ( basis_curve->is(IfcSchema::Type::IfcLine) ) {
IfcSchema::IfcLine* line = static_cast<IfcSchema::IfcLine*>(basis_curve);
const double magnitude = line->Dir()->Magnitude();
flts[0] *= magnitude; flts[1] *= magnitude;
}
if ( basis_curve->is(IfcSchema::Type::IfcEllipse) ) {
IfcSchema::IfcEllipse* ellipse = static_cast<IfcSchema::IfcEllipse*>(basis_curve);
double x = ellipse->SemiAxis1() * getValue(GV_LENGTH_UNIT);
double y = ellipse->SemiAxis2() * getValue(GV_LENGTH_UNIT);
const bool rotated = y > x;
if (rotated) {
flts[0] -= M_PI / 2.;
flts[1] -= M_PI / 2.;
}
}
if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],(double)(M_PI*2.0)),0.0f) ) {
w.Add(BRepBuilderAPI_MakeEdge(curve));
} else {
BRepBuilderAPI_MakeEdge e (curve,flts[0],flts[1]);
w.Add(e.Edge());
}
} else if ( trim_cartesian_failed && (has_pnts[0] && has_pnts[1]) ) {
w.Add(BRepBuilderAPI_MakeEdge(pnts[0],pnts[1]));
}
if ( w.IsDone() ) {
wire = w.Wire();
return true;
} else {
return false;
}
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& result) {
IfcSchema::IfcCartesianPoint::list::ptr points = l->Points();
// Parse and store the points in a sequence
TColgp_SequenceOfPnt polygon;
for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) {
gp_Pnt pnt;
IfcGeom::Kernel::convert(*it, pnt);
polygon.Append(pnt);
}
// Remove points that are too close to one another
remove_redundant_points_from_loop(polygon, false);
BRepBuilderAPI_MakePolygon w;
for (int i = 1; i <= polygon.Length(); ++i) {
w.Add(polygon.Value(i));
}
result = w.Wire();
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& result) {
IfcSchema::IfcCartesianPoint::list::ptr points = l->Polygon();
// Parse and store the points in a sequence
TColgp_SequenceOfPnt polygon;
for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) {
gp_Pnt pnt;
IfcGeom::Kernel::convert(*it, pnt);
polygon.Append(pnt);
}
// A loop should consist of at least three vertices
int original_count = polygon.Length();
if (original_count < 3) {
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
return false;
}
// Remove points that are too close to one another
remove_redundant_points_from_loop(polygon, true);
int count = polygon.Length();
if (original_count - count != 0) {
std::stringstream ss; ss << (original_count - count) << " edges removed for:";
Logger::Message(Logger::LOG_WARNING, ss.str(), l->entity);
}
if (count < 3) {
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
return false;
}
BRepBuilderAPI_MakePolygon w;
for (int i = 1; i <= polygon.Length(); ++i) {
w.Add(polygon.Value(i));
}
w.Close();
result = w.Wire();
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryOpenProfileDef* l, TopoDS_Wire& result) {
return convert_wire(l->Curve(), result);
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeCurve* l, TopoDS_Wire& result) {
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry();
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry();
if (!pnt1->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) {
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l->entity);
return false;
}
gp_Pnt p1, p2;
if (!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
{
return false;
}
BRepBuilderAPI_MakeWire mw;
Handle_Geom_Curve crv;
// The lack of a clear separation between topological and geometrical entities
// is starting to get problematic. If the underlying curve is bounded it is
// assumed that a topological wire can be crafted from it. After which an
// attempt is made to reconstruct it from the individual curves and the vertices
// of the IfcEdgeCurve.
const bool is_bounded = l->EdgeGeometry()->is(IfcSchema::Type::IfcBoundedCurve);
if (!is_bounded && convert_curve(l->EdgeGeometry(), crv)) {
mw.Add(BRepBuilderAPI_MakeEdge(crv, p1, p2));
result = mw;
return true;
} else if (is_bounded && convert_wire(l->EdgeGeometry(), result)) {
if (!l->SameSense()) std::swap(pnt1, pnt2);
TopExp_Explorer exp(result, TopAbs_EDGE);
bool first = true;
while (exp.More()) {
const TopoDS_Edge& ed = TopoDS::Edge(exp.Current());
Standard_Real u1, u2;
Handle(Geom_Curve) ecrv = BRep_Tool::Curve(ed, u1, u2);
exp.Next();
const bool last = !exp.More();
first = false;
if (first && last) {
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, p1, p2));
} else if (first) {
gp_Pnt pu;
ecrv->D0(u2, pu);
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, p1, pu));
} else if (last) {
gp_Pnt pu;
ecrv->D0(u1, pu);
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, pu, p2));
} else {
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, u1, u2));
}
}
result = mw;
return true;
} else {
return false;
}
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeLoop* l, TopoDS_Wire& result) {
IfcSchema::IfcOrientedEdge::list::ptr li = l->EdgeList();
BRepBuilderAPI_MakeWire mw;
for (IfcSchema::IfcOrientedEdge::list::it it = li->begin(); it != li->end(); ++it) {
IfcSchema::IfcOrientedEdge* e = *it;
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) e->EdgeStart())->VertexGeometry();
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) e->EdgeEnd())->VertexGeometry();
if (!pnt1->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) {
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l->entity);
return false;
}
gp_Pnt p1, p2;
if (!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
{
return false;
}
mw.Add(BRepBuilderAPI_MakeEdge(p1, p2));
continue;
IfcSchema::IfcEdge* base = e->EdgeElement();
TopoDS_Wire w;
if (convert_wire(e->EdgeElement(), w)) {
if (!e->Orientation()) w.Reverse();
mw.Add(w);
}
}
result = mw;
return true;
}
-73
View File
@@ -1,73 +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 "IfcGeom.h"
using namespace IfcSchema;
using namespace IfcUtil;
bool IfcGeom::Kernel::convert_shapes(const IfcBaseClass* l, IfcRepresentationShapeItems& r) {
#include "IfcRegisterConvertShapes.h"
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
return false;
}
bool IfcGeom::Kernel::is_shape_collection(const IfcBaseClass* l) {
#include "IfcRegisterIsShapeCollection.h"
return false;
}
bool IfcGeom::Kernel::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) {
const unsigned int id = l->entity->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; }
#include "IfcRegisterConvertShape.h"
if ( processed ) {
const double precision = getValue(GV_PRECISION);
apply_tolerance(r, precision);
cache.Shape[id] = r;
} else {
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
}
return success;
}
bool IfcGeom::Kernel::convert_wire(const IfcBaseClass* l, TopoDS_Wire& r) {
#include "IfcRegisterConvertWire.h"
Handle(Geom_Curve) curve;
if (IfcGeom::Kernel::convert_curve(l, curve)) {
return IfcGeom::Kernel::convert_curve_to_wire(curve, r);
}
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
return false;
}
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);
return false;
}
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);
return false;
}
-121
View File
@@ -1,121 +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 registers function prototypes for all supported IFC geometrical *
* entities. For entities of type CLASS an std::map is also created to cache *
* the output of the conversion functions *
* *
********************************************************************************/
#include <TopoDS_Shape.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
#include <gp_Pnt.hxx>
#include <gp_Pln.hxx>
#include <gp_Dir.hxx>
#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/IfcUtil.h"
#include "../ifcparse/IfcParse.h"
SHAPES(IfcShellBasedSurfaceModel);
SHAPES(IfcFaceBasedSurfaceModel);
SHAPES(IfcShapeRepresentation);
SHAPES(IfcMappedItem);
SHAPES(IfcFacetedBrep);
SHAPES(IfcGeometricSet);
#ifdef USE_IFC4
SHAPE(IfcCylindricalSurface);
SHAPE(IfcAdvancedBrep);
#endif
SHAPE(IfcExtrudedAreaSolid);
SHAPE(IfcRevolvedAreaSolid);
SHAPE(IfcConnectedFaceSet);
SHAPE(IfcBooleanResult);
SHAPE(IfcPolygonalBoundedHalfSpace);
SHAPE(IfcHalfSpaceSolid);
SHAPE(IfcSurfaceOfLinearExtrusion);
SHAPE(IfcSurfaceOfRevolution);
SHAPE(IfcBlock);
SHAPE(IfcRectangularPyramid);
SHAPE(IfcRightCircularCylinder);
SHAPE(IfcRightCircularCone);
SHAPE(IfcSphere);
SHAPE(IfcCsgSolid);
SHAPE(IfcCurveBoundedPlane);
SHAPE(IfcRectangularTrimmedSurface);
SHAPE(IfcSurfaceCurveSweptAreaSolid);
SHAPE(IfcSweptDiskSolid);
#ifdef USE_IFC4
FACE(IfcAdvancedFace);
#endif
FACE(IfcArbitraryProfileDefWithVoids);
FACE(IfcArbitraryClosedProfileDef);
FACE(IfcRoundedRectangleProfileDef);
FACE(IfcRectangleHollowProfileDef);
FACE(IfcRectangleProfileDef);
FACE(IfcTrapeziumProfileDef)
FACE(IfcCShapeProfileDef);
// IfcAsymmetricIShapeProfileDef included
FACE(IfcIShapeProfileDef);
FACE(IfcLShapeProfileDef);
FACE(IfcTShapeProfileDef);
FACE(IfcUShapeProfileDef);
FACE(IfcZShapeProfileDef);
FACE(IfcCircleHollowProfileDef);
FACE(IfcCircleProfileDef);
FACE(IfcEllipseProfileDef);
FACE(IfcCenterLineProfileDef);
FACE(IfcCompositeProfileDef);
FACE(IfcDerivedProfileDef);
FACE(IfcFace);
WIRE(IfcEdgeCurve);
WIRE(IfcEdgeLoop);
WIRE(IfcPolyline);
WIRE(IfcPolyLoop);
WIRE(IfcCompositeCurve);
WIRE(IfcTrimmedCurve);
WIRE(IfcArbitraryOpenProfileDef);
CURVE(IfcCircle);
CURVE(IfcEllipse);
CURVE(IfcLine);
CLASS(IfcCartesianPoint,gp_Pnt);
CLASS(IfcDirection,gp_Dir);
CLASS(IfcAxis2Placement2D,gp_Trsf2d);
CLASS(IfcAxis2Placement3D,gp_Trsf);
CLASS(IfcAxis1Placement,gp_Ax1);
CLASS(IfcCartesianTransformationOperator2DnonUniform,gp_GTrsf2d);
CLASS(IfcCartesianTransformationOperator3DnonUniform,gp_GTrsf);
CLASS(IfcCartesianTransformationOperator2D,gp_Trsf2d);
CLASS(IfcCartesianTransformationOperator3D,gp_Trsf);
CLASS(IfcObjectPlacement,gp_Trsf);
CLASS(IfcVector,gp_Vec);
CLASS(IfcPlane,gp_Pln);
-6
View File
@@ -1,6 +0,0 @@
#include "IfcRegisterUndef.h"
#define CURVE(T) \
if ( l->is(T::Class()) ) return convert((T*)l,r);
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
-6
View File
@@ -1,6 +0,0 @@
#include "IfcRegisterUndef.h"
#define FACE(T) \
if ( l->is(T::Class()) ) return convert((T*)l,r);
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
-17
View File
@@ -1,17 +0,0 @@
#include "IfcRegisterUndef.h"
#define SHAPE(T) \
if ( !processed && l->is(T::Class()) ) { \
processed = true; \
try { \
if ( convert((T*)l,r) ) { \
success = true; \
} \
} catch(...) { } \
if ( !success) { \
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
return false; \
} \
}
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
-12
View File
@@ -1,12 +0,0 @@
#include "IfcRegisterUndef.h"
#define SHAPES(T) \
if ( l->is(T::Class()) ) { \
try { \
return convert((T*)l,r); \
} catch (...) { } \
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
return false; \
}
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
-6
View File
@@ -1,6 +0,0 @@
#include "IfcRegisterUndef.h"
#define WIRE(T) \
if ( l->is(T::Class()) ) return convert((T*)l,r);
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
-6
View File
@@ -1,6 +0,0 @@
#include "IfcRegisterUndef.h"
#define CLASS(T,V) \
std::map<int,V> T;
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
-18
View File
@@ -1,18 +0,0 @@
#ifndef SHAPES
#define SHAPES(T)
#endif
#ifndef SHAPE
#define SHAPE(T)
#endif
#ifndef WIRE
#define WIRE(T)
#endif
#ifndef FACE
#define FACE(T)
#endif
#ifndef CURVE
#define CURVE(T)
#endif
#ifndef CLASS
#define CLASS(T,V)
#endif
-10
View File
@@ -1,10 +0,0 @@
#include "IfcRegisterUndef.h"
#define CLASS(T,V) bool convert(const IfcSchema::T* L, V& r);
#define SHAPES(T) CLASS(T,IfcRepresentationShapeItems)
#define SHAPE(T) CLASS(T,TopoDS_Shape)
#define WIRE(T) CLASS(T,TopoDS_Wire)
#define FACE(T) CLASS(T,TopoDS_Shape)
#define CURVE(T) CLASS(T,Handle(Geom_Curve))
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
@@ -1,6 +0,0 @@
#include "IfcRegisterUndef.h"
#define SHAPES(T) \
if ( l->is(T::Class()) ) return true;
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
-6
View File
@@ -1,6 +0,0 @@
#include "IfcRegisterUndef.h"
#define CLASS(T,V) \
T.clear();
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
-18
View File
@@ -1,18 +0,0 @@
#ifdef SHAPES
#undef SHAPES
#endif
#ifdef SHAPE
#undef SHAPE
#endif
#ifdef WIRE
#undef WIRE
#endif
#ifdef FACE
#undef FACE
#endif
#ifdef CURVE
#undef CURVE
#endif
#ifdef CLASS
#undef CLASS
#endif
-52
View File
@@ -1,52 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef IFCSHAPELIST_H
#define IFCSHAPELIST_H
#include <gp_GTrsf.hxx>
#include <TopoDS_Shape.hxx>
#include "../ifcgeom/IfcGeomRenderStyles.h"
namespace IfcGeom {
class IfcRepresentationShapeItem {
private:
gp_GTrsf placement;
TopoDS_Shape shape;
const SurfaceStyle* style;
public:
IfcRepresentationShapeItem(const gp_GTrsf& placement, const TopoDS_Shape& shape, const SurfaceStyle* style)
: placement(placement), shape(shape), style(style) {}
IfcRepresentationShapeItem(const gp_GTrsf& placement, const TopoDS_Shape& shape)
: placement(placement), shape(shape), style(0) {}
IfcRepresentationShapeItem(const TopoDS_Shape& shape, const SurfaceStyle* style)
: shape(shape), style(style) {}
IfcRepresentationShapeItem(const TopoDS_Shape& shape)
: shape(shape), style(0) {}
void append(const gp_GTrsf& trsf) { placement.Multiply(trsf); }
void prepend(const gp_GTrsf& trsf) { placement.PreMultiply(trsf); }
const TopoDS_Shape& Shape() const { return shape; }
const gp_GTrsf& Placement() const { return placement; }
bool hasStyle() const { return style != 0; }
const SurfaceStyle& Style() const { return *style; }
};
typedef std::vector<IfcRepresentationShapeItem> IfcRepresentationShapeItems;
}
#endif
+35
View File
@@ -0,0 +1,35 @@
#include "abstract_mapping.h"
#include "../ifcparse/IfcFile.h"
ifcopenshell::geometry::impl::MappingFactoryImplementation& ifcopenshell::geometry::impl::mapping_implementations() {
static MappingFactoryImplementation impl;
return impl;
}
extern void init_MappingImplementation_Ifc2x3(ifcopenshell::geometry::impl::MappingFactoryImplementation*);
extern void init_MappingImplementation_Ifc4(ifcopenshell::geometry::impl::MappingFactoryImplementation*);
extern void init_MappingImplementation_Ifc4x1(ifcopenshell::geometry::impl::MappingFactoryImplementation*);
extern void init_MappingImplementation_Ifc4x2(ifcopenshell::geometry::impl::MappingFactoryImplementation*);
ifcopenshell::geometry::impl::MappingFactoryImplementation::MappingFactoryImplementation() {
init_MappingImplementation_Ifc2x3(this);
init_MappingImplementation_Ifc4(this);
init_MappingImplementation_Ifc4x1(this);
init_MappingImplementation_Ifc4x2(this);
}
void ifcopenshell::geometry::impl::MappingFactoryImplementation::bind(const std::string& schema_name, ifcopenshell::geometry::impl::mapping_fn fn) {
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
this->insert(std::make_pair(schema_name_lower, fn));
}
ifcopenshell::geometry::abstract_mapping* ifcopenshell::geometry::impl::MappingFactoryImplementation::construct(IfcParse::IfcFile* file, settings& s) {
const std::string schema_name_lower = boost::to_lower_copy(file->schema()->name());
std::map<std::string, ifcopenshell::geometry::impl::mapping_fn>::const_iterator it;
it = this->find(schema_name_lower);
if (it == end()) {
throw IfcParse::IfcException("No geometry mapping registered for " + schema_name_lower);
}
return it->second(file, s);
}
+60
View File
@@ -0,0 +1,60 @@
#ifndef ABSTRACT_MAPPING_H
#define ABSTRACT_MAPPING_H
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcEntityList.h"
#include "../ifcgeom/taxonomy.h"
#include "../ifcgeom/settings.h"
#include <boost/function.hpp>
#include <map>
#include <string>
namespace ifcopenshell {
namespace geometry {
class Element;
class NativeElement;
struct geometry_conversion_task {
int index;
IfcUtil::IfcBaseEntity* representation;
IfcEntityList::ptr products;
std::vector<ifcopenshell::geometry::NativeElement*> breps;
std::vector<ifcopenshell::geometry::Element*> elements;
};
typedef boost::function<bool(IfcUtil::IfcBaseEntity*)> filter_t;
class abstract_mapping {
protected:
settings settings_;
public:
abstract_mapping(settings& s) : settings_(s) {}
virtual ifcopenshell::geometry::taxonomy::item* map(const IfcUtil::IfcBaseClass*) = 0;
virtual void get_representations(std::vector<geometry_conversion_task>& tasks, std::vector<filter_t>& filters, settings& s) = 0;
virtual IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity* product, bool include_openings = true) = 0;
virtual std::map<std::string, IfcUtil::IfcBaseEntity*> get_layers(IfcUtil::IfcBaseEntity*) = 0;
};
namespace impl {
typedef boost::function2<abstract_mapping*, IfcParse::IfcFile*, settings&> mapping_fn;
class MappingFactoryImplementation : public std::map<std::string, mapping_fn> {
public:
MappingFactoryImplementation();
void bind(const std::string& schema_name, mapping_fn);
abstract_mapping* construct(IfcParse::IfcFile*, settings&);
};
MappingFactoryImplementation& mapping_implementations();
}
}
}
#endif
@@ -0,0 +1,135 @@
#include "AbstractKernel.h"
#include "../../ifcgeom/schema_agnostic/IfcGeomElement.h"
#include "../../ifcgeom/kernels/opencascade/OpenCascadeKernel.h"
#undef Handle
#include "../../ifcgeom/kernels/cgal/CgalKernel.h"
namespace {
/* A compile-time for loop over the taxonomy kinds */
template <size_t N>
struct dispatch_conversion {
static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel* kernel, const ifcopenshell::geometry::taxonomy::item* item, ifcopenshell::geometry::ConversionResults& results) {
if (N == item->kind()) {
auto concrete_item = static_cast<const ifcopenshell::geometry::taxonomy::type_by_kind::type<N>*>(item);
return kernel->convert_impl(concrete_item, results);
} else {
return dispatch_conversion<N + 1>::dispatch(kernel, item, results);
}
}
};
template <>
struct dispatch_conversion<ifcopenshell::geometry::taxonomy::type_by_kind::max> {
static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel*, const ifcopenshell::geometry::taxonomy::item* item, ifcopenshell::geometry::ConversionResults&) {
Logger::Error("No conversion for " + std::to_string(item->kind()));
return false;
}
};
}
bool ifcopenshell::geometry::kernels::AbstractKernel::convert(const taxonomy::item* item, ifcopenshell::geometry::ConversionResults& results) {
try {
return dispatch_conversion<0>::dispatch(this, item, results);
} catch (std::exception& e) {
Logger::Error(e, item->instance);
return false;
}
}
ifcopenshell::geometry::kernels::AbstractKernel* ifcopenshell::geometry::kernels::construct(const std::string& geometry_library, IfcParse::IfcFile* file) {
const std::string geometry_library_lower = boost::to_lower_copy(geometry_library);
if (geometry_library_lower == "opencascade") {
return new OpenCascadeKernel;
} else if (geometry_library_lower == "cgal") {
return new CgalKernel;
} else {
throw IfcParse::IfcException("No geometry kernel registered for " + geometry_library);
}
}
bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::collection* collection, ifcopenshell::geometry::ConversionResults& r) {
auto s = r.size();
for (auto& c : collection->children) {
convert(c, r);
}
for (auto i = s; i < r.size(); ++i) {
r[i].prepend(collection->matrix);
}
return r.size() > s;
}
//void ifcopenshell::geometry::kernels::AbstractKernel::set_conversion_placement_rel_to(const IfcParse::declaration* type) {
// placement_rel_to = type;
//}
//
//void ifcopenshell::geometry::kernels::AbstractKernel::setValue(GeomValue var, double value) {
// switch (var) {
// case GV_DEFLECTION_TOLERANCE:
// deflection_tolerance = value;
// break;
// case GV_POINT_EQUALITY_TOLERANCE:
// point_equality_tolerance = value;
// break;
// case GV_LENGTH_UNIT:
// ifc_length_unit = value;
// break;
// case GV_PLANEANGLE_UNIT:
// ifc_planeangle_unit = value;
// break;
// case GV_PRECISION:
// modelling_precision = value;
// break;
// case GV_DIMENSIONALITY:
// dimensionality = value;
// break;
// default:
// assert(!"never reach here");
// }
//}
//
//double ifcopenshell::geometry::kernels::AbstractKernel::getValue(GeomValue var) const {
// switch (var) {
// case GV_DEFLECTION_TOLERANCE:
// return deflection_tolerance;
// case GV_MINIMAL_FACE_AREA:
// // Considering a right-angled triangle, this about the smallest
// // area you can obtain without the vertices being confused.
// return modelling_precision * modelling_precision / 2.;
// case GV_POINT_EQUALITY_TOLERANCE:
// return point_equality_tolerance;
// case GV_LENGTH_UNIT:
// return ifc_length_unit;
// break;
// case GV_PLANEANGLE_UNIT:
// return ifc_planeangle_unit;
// break;
// case GV_PRECISION:
// return modelling_precision;
// break;
// case GV_DIMENSIONALITY:
// return dimensionality;
// break;
// }
// assert(!"never reach here");
// return 0;
//}
//
//
//
//
//template IFC_GEOM_API ifcopenshell::geometry::kernels::NativeElement<float, float>* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_representation_and_product<float, float>(
// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product);
//template IFC_GEOM_API ifcopenshell::geometry::kernels::NativeElement<float, double>* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_representation_and_product<float, double>(
// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product);
//template IFC_GEOM_API ifcopenshell::geometry::kernels::NativeElement<double, double>* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_representation_and_product<double, double>(
// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product);
//
//template IFC_GEOM_API ifcopenshell::geometry::kernels::NativeElement<float, float>* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_processed_representation<float, float>(
// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, ifcopenshell::geometry::kernels::NativeElement<float, float>* brep);
//template IFC_GEOM_API ifcopenshell::geometry::kernels::NativeElement<float, double>* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_processed_representation<float, double>(
// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, ifcopenshell::geometry::kernels::NativeElement<float, double>* brep);
//template IFC_GEOM_API ifcopenshell::geometry::kernels::NativeElement<double, double>* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_processed_representation<double, double>(
// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, ifcopenshell::geometry::kernels::NativeElement<double, double>* brep);
@@ -0,0 +1,74 @@
#ifndef ABSTRACT_KERNEL_H
#define ABSTRACT_KERNEL_H
#include "../../ifcparse/macros.h"
#include "../../ifcgeom/schema_agnostic/ifc_geom_api.h"
#include "../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
#include "../../ifcgeom/taxonomy.h"
static const double ALMOST_ZERO = 1.e-9;
template <typename T>
inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance = ALMOST_ZERO) {
return fabs(a - b) < tolerance;
}
namespace ifcopenshell { namespace geometry { namespace kernels {
class IFC_GEOM_API AbstractKernel {
protected:
// For stopping PlacementRelTo recursion in convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf)
const IfcParse::declaration* placement_rel_to;
double deflection_tolerance;
double wire_creation_tolerance;
double point_equality_tolerance;
double max_faces_to_sew;
double ifc_length_unit;
double ifc_planeangle_unit;
double modelling_precision;
double dimensionality;
std::string geometry_library;
public:
AbstractKernel(const std::string& geometry_library)
: geometry_library(geometry_library)
, deflection_tolerance(0.001)
, wire_creation_tolerance(0.0001)
, point_equality_tolerance(0.00001)
, max_faces_to_sew(-1.0)
, ifc_length_unit(1.0)
, ifc_planeangle_unit(-1.0)
, modelling_precision(0.00001)
, dimensionality(1.)
, placement_rel_to(0) {}
bool convert(const taxonomy::item*, ifcopenshell::geometry::ConversionResults&);
virtual bool convert_impl(const taxonomy::matrix4*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
virtual bool convert_impl(const taxonomy::point3*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
virtual bool convert_impl(const taxonomy::direction3*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
virtual bool convert_impl(const taxonomy::line*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
virtual bool convert_impl(const taxonomy::circle*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
virtual bool convert_impl(const taxonomy::ellipse*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
virtual bool convert_impl(const taxonomy::bspline_curve*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
virtual bool convert_impl(const taxonomy::edge*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
virtual bool convert_impl(const taxonomy::loop*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
virtual bool convert_impl(const taxonomy::shell*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
virtual bool convert_impl(const taxonomy::face*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
virtual bool convert_impl(const taxonomy::node*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
virtual bool convert_impl(const taxonomy::colour*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
virtual bool convert_impl(const taxonomy::boolean_result*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
virtual bool convert_impl(const taxonomy::plane*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); }
virtual bool convert_impl(const taxonomy::collection*, ifcopenshell::geometry::ConversionResults&);
};
AbstractKernel* construct(const std::string& geometry_library, IfcParse::IfcFile*);
}
}
}
#endif
@@ -0,0 +1,118 @@
#include "CgalKernel.h"
#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h"
#define CgalKernel MAKE_TYPE_NAME(CgalKernel)
bool IfcGeom::CgalKernel::convert_wire_to_face(const cgal_wire_t& wire, cgal_face_t& face) {
face.outer = wire;
return true;
}
void IfcGeom::CgalKernel::remove_duplicate_points_from_loop(cgal_wire_t& polygon) {
std::set<cgal_point_t> points;
for (int i = 0; i < polygon.size(); ++i) {
if (points.count(polygon[i])) {
polygon.erase(polygon.begin()+i);
--i;
} else points.insert(polygon[i]);
}
}
CGAL::Polyhedron_3<Kernel_> IfcGeom::CgalKernel::create_polyhedron(std::list<cgal_face_t> &face_list) {
// Naive creation
CGAL::Polyhedron_3<Kernel_> polyhedron;
PolyhedronBuilder builder(&face_list);
polyhedron.delegate(builder);
// Stitch edges
// std::cout << "Before: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl;
CGAL::Polygon_mesh_processing::stitch_borders(polyhedron);
if (!polyhedron.is_valid()) {
Logger::Message(Logger::LOG_ERROR, "create_polyhedron: Polyhedron not valid!");
// std::ofstream fresult;
// fresult.open("/Users/ken/Desktop/invalid.off");
// fresult << polyhedron << std::endl;
// fresult.close();
return CGAL::Polyhedron_3<Kernel_>();
} if (polyhedron.is_closed()) {
if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) {
CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron);
}
}
// std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl;
return polyhedron;
}
CGAL::Polyhedron_3<Kernel_> IfcGeom::CgalKernel::create_polyhedron(CGAL::Nef_polyhedron_3<Kernel_> &nef_polyhedron) {
if (nef_polyhedron.is_simple()) {
try {
CGAL::Polyhedron_3<Kernel_> polyhedron;
nef_polyhedron.convert_to_polyhedron(polyhedron);
return polyhedron;
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Conversion from Nef to polyhedron failed!");
return CGAL::Polyhedron_3<Kernel_>();
}
} else {
Logger::Message(Logger::LOG_ERROR, "Nef polyhedron not simple: cannot create polyhedron!");
return CGAL::Polyhedron_3<Kernel_>();
}
}
CGAL::Nef_polyhedron_3<Kernel_> IfcGeom::CgalKernel::create_nef_polyhedron(std::list<cgal_face_t> &face_list) {
CGAL::Polyhedron_3<Kernel_> polyhedron = create_polyhedron(face_list);
CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron);
CGAL::Nef_polyhedron_3<Kernel_> nef_polyhedron;
try {
nef_polyhedron = CGAL::Nef_polyhedron_3<Kernel_>(polyhedron);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef polyhedron failed!");
return nef_polyhedron;
} return nef_polyhedron;
}
CGAL::Nef_polyhedron_3<Kernel_> IfcGeom::CgalKernel::create_nef_polyhedron(CGAL::Polyhedron_3<Kernel_> &polyhedron) {
if (polyhedron.is_valid()) {
CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron);
CGAL::Nef_polyhedron_3<Kernel_> nef_polyhedron;
try {
nef_polyhedron = CGAL::Nef_polyhedron_3<Kernel_>(polyhedron);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef polyhedron failed!");
return nef_polyhedron;
} return nef_polyhedron;
} else {
Logger::Message(Logger::LOG_ERROR, "Polyhedron not valid: cannot create Nef polyhedron!");
return CGAL::Nef_polyhedron_3<Kernel_>();
}
}
//CGAL::Polyhedron_3<Kernel_> IfcGeom::CgalKernel::triangulate_faces(CGAL::Polyhedron_3<Kernel_> &polyhedron) {
// std::list<cgal_face_t> face_list;
//
// for (CGAL::Polyhedron_3<Kernel_>::Facet_const_iterator current_facet = polyhedron.facets_begin();
// current_facet != polyhedron.facets_end();
// ++current_facet) {
//
// // Triangle
// if (current_facet->is_triangle()) {
// face_list.push_back(cgal_face_t());
// CGAL::Polyhedron_3<Kernel_>::Halfedge_around_facet_const_circulator current_halfedge = current_facet->facet_begin();
// do {
// face_list.back().outer.push_back(current_halfedge->vertex()->point());
// ++current_halfedge;
// } while (current_halfedge != current_facet->facet_begin());
// }
//
// // Polygon
// else {
// std::list<Kernel_::Point_3> points_in_polygon;
//
// }
// }
//
// return create_polyhedron(face_list);
//}
@@ -0,0 +1,102 @@
#include "CgalConversionResult.h"
#include "../../../ifcparse/IfcLogger.h"
#include "../../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
void ifcopenshell::geometry::CgalShape::Triangulate(const settings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, Representation::Triangulation* t, int surface_style_id) const {
// Copy is made because triangulate_faces() does not accept a const argument
cgal_shape_t s = shape_;
if (!place.components.isIdentity()) {
const auto& m = place.components;
// @todo check
const cgal_placement_t trsf(
m(0, 0), m(0, 1), m(0, 2), m(0, 3),
m(1, 0), m(1, 1), m(1, 2), m(1, 3),
m(2, 0), m(2, 1), m(2, 2), m(2, 3));
// Apply transformation
for (auto &vertex : vertices(s)) {
vertex->point() = vertex->point().transform(trsf);
}
}
if (!s.is_valid()) {
Logger::Message(Logger::LOG_ERROR, "Invalid Polyhedron_3 in object (before triangulation)");
return;
}
// Triangulate the shape and compute the normals
// std::map<cgal_vertex_descriptor_t, Kernel_::Vector_3> vertex_normals;
// boost::associative_property_map<std::map<cgal_vertex_descriptor_t, Kernel_::Vector_3>> vertex_normals_map(vertex_normals);
std::map<cgal_face_descriptor_t, Kernel_::Vector_3> face_normals;
boost::associative_property_map<std::map<cgal_face_descriptor_t, Kernel_::Vector_3>> face_normals_map(face_normals);
bool success = false;
try {
success = CGAL::Polygon_mesh_processing::triangulate_faces(s);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Triangulation crashed");
return;
}
if (!success) {
Logger::Message(Logger::LOG_ERROR, "Triangulation failed");
return;
}
// std::cout << "Triangulated model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl;
if (!s.is_valid()) {
Logger::Message(Logger::LOG_ERROR, "Invalid Polyhedron_3 in object (after triangulation)");
return;
}
// CGAL::Polygon_mesh_processing::compute_normals(s, vertex_normals_map, face_normals_map);
try {
CGAL::Polygon_mesh_processing::compute_face_normals(s, face_normals_map);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Face normal calculation failed");
return;
}
int num_faces = 0, num_vertices = 0;
for (auto &face: faces(s)) {
if (!face->is_triangle()) {
std::cout << "Warning: non-triangular face!" << std::endl;
continue;
}
CGAL::Polyhedron_3<Kernel_>::Halfedge_around_facet_const_circulator current_halfedge = face->facet_begin();
int vertexidx[3];
int i = 0;
do {
vertexidx[i++] = t->addVertex(surface_style_id,
CGAL::to_double(current_halfedge->vertex()->point().cartesian(0)),
CGAL::to_double(current_halfedge->vertex()->point().cartesian(1)),
CGAL::to_double(current_halfedge->vertex()->point().cartesian(2)));
double nx = 0.;
double ny = 0.;
double nz = 1.;
// @todo normal calculation throws divide by zero?
// try {
if (false) {
nx = CGAL::to_double(face_normals_map[face].cartesian(0));
ny = CGAL::to_double(face_normals_map[face].cartesian(1));
nz = CGAL::to_double(face_normals_map[face].cartesian(2));
}
// catch (...) {
// Logger::Error("Error during normal calculation");
// }
t->addNormal(nx, ny, nz);
++num_vertices;
++current_halfedge;
} while (current_halfedge != face->facet_begin());
t->addFace(surface_style_id, vertexidx[0], vertexidx[1], vertexidx[2]);
++num_faces;
}
}
@@ -0,0 +1,91 @@
/********************************************************************************
* *
* 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 CGALCONVERSIONRESULT_H
#define CGALCONVERSIONRESULT_H
#include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h"
#include <boost/property_map/property_map.hpp>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
#include <CGAL/Polygon_mesh_processing/stitch_borders.h>
#include <CGAL/Polygon_mesh_processing/orientation.h>
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
#include <CGAL/Nef_polyhedron_3.h>
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel_;
typedef Kernel_::Aff_transformation_3 cgal_placement_t;
typedef Kernel_::Point_3 cgal_point_t;
typedef Kernel_::Vector_3 cgal_direction_t;
typedef Kernel_::Vector_3 cgal_vector_t;
typedef Kernel_::Plane_3 cgal_plane_t;
typedef std::vector<Kernel_::Point_3> cgal_curve_t;
typedef std::vector<Kernel_::Point_3> cgal_wire_t;
struct cgal_face_t {
cgal_wire_t outer;
std::vector<cgal_wire_t> inner;
};
typedef CGAL::Polyhedron_3<Kernel_> cgal_shape_t;
typedef boost::graph_traits<CGAL::Polyhedron_3<Kernel_>>::vertex_descriptor cgal_vertex_descriptor_t;
typedef boost::graph_traits<CGAL::Polyhedron_3<Kernel_>>::face_descriptor cgal_face_descriptor_t;
#include "../../../ifcgeom/schema_agnostic/ConversionResult.h"
namespace ifcopenshell { namespace geometry {
class CgalShape : public ConversionResultShape {
public:
CgalShape(const cgal_shape_t& shape)
: shape_(shape)
{}
const cgal_shape_t& shape() const { return shape_; }
operator const cgal_shape_t& () { return shape_; }
virtual void Triangulate(const settings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, Representation::Triangulation* t, int surface_style_id) const;
virtual void Serialize(std::string&) const {
throw std::runtime_error("Not implemented");
}
virtual ConversionResultShape* clone() const {
return new CgalShape(shape_);
}
virtual bool is_manifold() const {
throw std::runtime_error("Not implemented");
}
virtual int surface_genus() const {
throw std::runtime_error("Not implemented");
}
private:
cgal_shape_t shape_;
};
}}
#endif
@@ -0,0 +1,78 @@
#include "CgalKernel.h"
#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h"
#define CgalKernel MAKE_TYPE_NAME(CgalKernel)
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCircle* l, cgal_curve_t& 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);
return false;
}
cgal_placement_t trsf;
IfcSchema::IfcAxis2Placement* placement = l->Position();
if (placement->as<IfcSchema::IfcAxis2Placement3D>()) {
IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
} else {
cgal_placement_t trsf2d;
IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d);
trsf = trsf2d;
}
const int segments = 12;
curve = cgal_curve_t();
for (int current_segment = 0; current_segment < segments; ++current_segment) {
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
curve.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0));
}
for (auto &vertex: curve) {
vertex = vertex.transform(trsf);
}
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEllipse* l, cgal_curve_t& 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);
return false;
}
cgal_placement_t trsf;
IfcSchema::IfcAxis2Placement* placement = l->Position();
if (placement->as<IfcSchema::IfcAxis2Placement3D>()) {
convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
} else {
cgal_placement_t trsf2d;
convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d);
trsf = trsf2d;
}
const int segments = 12;
curve = cgal_curve_t();
for (int current_segment = 0; current_segment < segments; ++current_segment) {
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
curve.push_back(Kernel_::Point_3(x*cos(current_angle), y*sin(current_angle), 0));
}
for (auto &vertex: curve) {
vertex = vertex.transform(trsf);
}
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcLine* l, cgal_curve_t& curve) {
cgal_point_t pnt;
cgal_direction_t vec;
convert(l->Pnt(),pnt);
convert(l->Dir(),vec);
curve = cgal_curve_t();
curve.push_back(pnt);
curve.push_back(pnt+vec);
return true;
}
@@ -0,0 +1,991 @@
#include "CgalKernel.h"
#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h"
#define CgalKernel MAKE_TYPE_NAME(CgalKernel)
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, cgal_face_t& face) {
cgal_wire_t wire;
if ( ! convert_wire(l->OuterCurve(),wire) ) return false;
cgal_face_t f;
bool success = convert_wire_to_face(wire, f);
if (success) face = f;
return success;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids* l, cgal_face_t& face) {
cgal_wire_t profile;
if ( ! convert_wire(l->OuterCurve(),profile) ) return false;
cgal_face_t mf;
mf.outer = profile;
IfcSchema::IfcCurve::list::ptr voids = l->InnerCurves();
for( IfcSchema::IfcCurve::list::it it = voids->begin(); it != voids->end(); ++ it ) {
cgal_wire_t hole;
if ( convert_wire(*it,hole) ) {
mf.inner.push_back(hole);
}
} face = mf;
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cgal_face_t& 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);
return false;
}
cgal_placement_t trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
face = cgal_face_t();
face.outer.push_back(Kernel_::Point_3(-x, -y, 0.0));
face.outer.push_back(Kernel_::Point_3( x, -y, 0.0));
face.outer.push_back(Kernel_::Point_3( x, y, 0.0));
face.outer.push_back(Kernel_::Point_3(-x, y, 0.0));
if (has_position) {
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
for (auto &vertex: face.outer) {
vertex = vertex.transform(trsf2d);
}
}
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef* l, cgal_face_t& 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);
return false;
}
cgal_placement_t trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
const int segments = 3;
if (r == 0.0) {
face = cgal_face_t();
face.outer.push_back(Kernel_::Point_3(-x, -y, 0.0));
face.outer.push_back(Kernel_::Point_3( x, -y, 0.0));
face.outer.push_back(Kernel_::Point_3( x, y, 0.0));
face.outer.push_back(Kernel_::Point_3(-x, y, 0.0));
}
else {
face = cgal_face_t();
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(x-r+r*cos(current_angle), y-r+r*sin(current_angle), 0));
}
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(-x+r+r*cos(current_angle), y-r+r*sin(current_angle), 0));
}
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(-x+r+r*cos(current_angle), -y+r+r*sin(current_angle), 0));
}
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(x-r+r*cos(current_angle), -y+r+r*sin(current_angle), 0));
}
}
if (has_position) {
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
for (auto &vertex: face.outer) {
vertex = vertex.transform(trsf2d);
}
}
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l, cgal_face_t& 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->hasOuterFilletRadius();
const bool fr2 = l->hasInnerFilletRadius();
const double r1 = fr1 ? l->OuterFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.;
const double r2 = fr2 ? l->InnerFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.;
if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
cgal_placement_t trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
const int segments = 3;
if (!fr1 || r1 == 0.0) {
face = cgal_face_t();
face.outer.push_back(Kernel_::Point_3(-x, -y, 0.0));
face.outer.push_back(Kernel_::Point_3( x, -y, 0.0));
face.outer.push_back(Kernel_::Point_3( x, y, 0.0));
face.outer.push_back(Kernel_::Point_3(-x, y, 0.0));
}
else {
face = cgal_face_t();
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(x-r1+r1*cos(current_angle), y-r1+r1*sin(current_angle), 0));
}
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(-x+r1+r1*cos(current_angle), y-r1+r1*sin(current_angle), 0));
}
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(-x+r1+r1*cos(current_angle), -y+r1+r1*sin(current_angle), 0));
}
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(x-r1+r1*cos(current_angle), -y+r1+r1*sin(current_angle), 0));
}
}
if (!fr2 || r2 == 0.0) {
face.inner.push_back(cgal_wire_t());
face.inner.back().push_back(Kernel_::Point_3(-x+d, -y+d, 0.0));
face.inner.back().push_back(Kernel_::Point_3( x-d, -y+d, 0.0));
face.inner.back().push_back(Kernel_::Point_3( x-d, y-d, 0.0));
face.inner.back().push_back(Kernel_::Point_3(-x+d, y-d, 0.0));
}
else {
face.inner.push_back(cgal_wire_t());
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
face.inner.back().push_back(Kernel_::Point_3(x-d-r1+r1*cos(current_angle), y-d-r1+r1*sin(current_angle), 0));
}
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.inner.back().push_back(Kernel_::Point_3(-x+d+r1+r1*cos(current_angle), y-d-r1+r1*sin(current_angle), 0));
}
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.inner.back().push_back(Kernel_::Point_3(-x+d+r1+r1*cos(current_angle), -y+d+r1+r1*sin(current_angle), 0));
}
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.inner.back().push_back(Kernel_::Point_3(x-d-r1+r1*cos(current_angle), -y+d+r1+r1*sin(current_angle), 0));
}
}
if (has_position) {
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
for (auto &vertex: face.outer) {
vertex = vertex.transform(trsf2d);
} for (auto &inner: face.inner) {
for (auto &vertex: inner) {
vertex = vertex.transform(trsf2d);
}
}
}
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrapeziumProfileDef* l, cgal_face_t& 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);
return false;
}
cgal_placement_t trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
face = cgal_face_t();
face.outer.push_back(Kernel_::Point_3(-x1, -y, 0.0));
face.outer.push_back(Kernel_::Point_3(x1, -y, 0.0));
face.outer.push_back(Kernel_::Point_3(dx+w-x1, y, 0.0));
face.outer.push_back(Kernel_::Point_3(dx-x1, y, 0.0));
if (has_position) {
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
for (auto &vertex: face.outer) {
vertex = vertex.transform(trsf2d);
}
}
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCircleProfileDef* l, cgal_face_t& face) {
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
if ( r == 0.0f ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
cgal_placement_t trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
const int segments = 12;
face = cgal_face_t();
for (int current_segment = 0; current_segment < segments; ++current_segment) {
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0));
}
if (has_position) {
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
for (auto &vertex: face.outer) {
vertex = vertex.transform(trsf2d);
}
}
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, cgal_face_t& 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);
return false;
}
cgal_placement_t trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
const int segments = 12;
face = cgal_face_t();
for (int current_segment = 0; current_segment < segments; ++current_segment) {
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0));
}
face.inner.push_back(cgal_wire_t());
for (int current_segment = 0; current_segment < segments; ++current_segment) {
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
face.inner.back().push_back(Kernel_::Point_3((r-t)*cos(current_angle), (r-t)*sin(current_angle), 0));
}
if (has_position) {
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
for (auto &vertex: face.outer) {
vertex = vertex.transform(trsf2d);
} for (auto &inner: face.inner) {
for (auto &vertex: inner) {
vertex = vertex.transform(trsf2d);
}
}
}
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEllipseProfileDef* l, cgal_face_t& 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);
return false;
}
cgal_placement_t trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
const int segments = 12;
face = cgal_face_t();
for (int current_segment = 0; current_segment < segments; ++current_segment) {
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(rx*cos(current_angle), ry*sin(current_angle), 0));
}
if (has_position) {
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
for (auto &vertex: face.outer) {
vertex = vertex.transform(trsf2d);
}
}
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face) {
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
int num_outer_bounds = 0;
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
IfcSchema::IfcFaceBound* bound = *it;
if (bound->as<IfcSchema::IfcFaceOuterBound>()) num_outer_bounds ++;
}
if (num_outer_bounds != 1) {
Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l);
return false;
}
cgal_face_t mf;
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
IfcSchema::IfcFaceBound* bound = *it;
IfcSchema::IfcLoop* loop = bound->Bound();
const bool is_interior = !bound->as<IfcSchema::IfcFaceOuterBound>();
cgal_wire_t wire;
if (!convert_wire(loop, wire)) {
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop);
return false;
}
if (!is_interior) {
mf.outer = wire;
} else {
mf.inner.push_back(wire);
}
}
face = mf;
// std::cout << "Face: " << std::endl;
// for (auto &point: face.outer) {
// std::cout << "\tPoint(" << point << ")" << std::endl;
// }
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCShapeProfileDef* l, cgal_face_t& 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() * 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);
return false;
}
cgal_placement_t trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
const int segments = 3;
if (!doFillet || f1 == 0.0) {
face = cgal_face_t();
face.outer.push_back(Kernel_::Point_3(-x, -y, 0.0));
face.outer.push_back(Kernel_::Point_3(x, -y, 0.0));
face.outer.push_back(Kernel_::Point_3(x, -y+d2, 0.0));
face.outer.push_back(Kernel_::Point_3(x-d1, -y+d2, 0.0));
face.outer.push_back(Kernel_::Point_3(x-d1, -y+d1, 0.0));
face.outer.push_back(Kernel_::Point_3(-x+d1, -y+d1, 0.0));
face.outer.push_back(Kernel_::Point_3(-x+d1, y-d1, 0.0));
face.outer.push_back(Kernel_::Point_3(x-d1, y-d1, 0.0));
face.outer.push_back(Kernel_::Point_3(x-d1, y-d2, 0.0));
face.outer.push_back(Kernel_::Point_3(x, y-d2, 0.0));
face.outer.push_back(Kernel_::Point_3(x, y, 0.0));
face.outer.push_back(Kernel_::Point_3(-x, y, 0.0));
}
else {
face = cgal_face_t();
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(-x+f2+f2*cos(current_angle), -y+f2+f2*sin(current_angle), 0));
}
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(x-f2+f2*cos(current_angle), -y+f2+f2*sin(current_angle), 0));
}
face.outer.push_back(Kernel_::Point_3(x, -y+d2, 0.0));
face.outer.push_back(Kernel_::Point_3(x-d1, -y+d2, 0.0));
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(x-f2+f1*cos(current_angle), -y+f2+f1*sin(current_angle), 0));
}
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(-x+f2+f1*cos(current_angle), -y+f2+f1*sin(current_angle), 0));
}
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(-x+f2+f1*cos(current_angle), y-f2+f1*sin(current_angle), 0));
}
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(x-f2+f1*cos(current_angle), y-f2+f1*sin(current_angle), 0));
}
face.outer.push_back(Kernel_::Point_3(x-d1, y-d2, 0.0));
face.outer.push_back(Kernel_::Point_3(x, y-d2, 0.0));
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(x-f2+f2*cos(current_angle), y-f2+f2*sin(current_angle), 0));
}
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(-x+f2+f2*cos(current_angle), y-f2+f2*sin(current_angle), 0));
}
}
if (has_position) {
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
for (auto &vertex: face.outer) {
vertex = vertex.transform(trsf2d);
}
}
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcLShapeProfileDef* l, cgal_face_t& face) {
const bool hasSlope = l->hasLegSlope();
const bool doEdgeFillet = l->hasEdgeRadius();
const bool doFillet = l->hasFilletRadius();
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double x = (l->hasWidth() ? l->Width() : l->Depth()) / 2.0f * getValue(GV_LENGTH_UNIT);
const double d = l->Thickness() * getValue(GV_LENGTH_UNIT);
const double slope = hasSlope ? (l->LegSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
double f1 = 0.0f;
double f2 = 0.0f;
if (doFillet) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
}
if ( doEdgeFillet) {
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
}
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
double xx = -x+d;
double xy = -y+d;
double dy1 = 0.;
double dy2 = 0.;
double dx1 = 0.;
double dx2 = 0.;
if (hasSlope) {
dy1 = tan(slope) * x;
dy2 = tan(slope) * (x - d);
dx1 = tan(slope) * y;
dx2 = tan(slope) * (y - d);
const double x1s = x; const double y1s = -y + d - dy1;
const double x1e = -x + d; const double y1e = -y + d + dy2;
const double x2s = -x + d - dx1; const double y2s = y;
const double x2e = -x + d + dx2; const double y2e = -y + d;
const double a1 = y1e - y1s;
const double b1 = x1s - x1e;
const double c1 = a1*x1s + b1*y1s;
const double a2 = y2e - y2s;
const double b2 = x2s - x2e;
const double c2 = a2*x2s + b2*y2s;
const double det = a1*b2 - a2*b1;
if (ALMOST_THE_SAME(det, 0.)) {
Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:",l);
return false;
}
xx = (b2*c1 - b1*c2) / det;
xy = (a1*c2 - a2*c1) / det;
}
cgal_placement_t trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
const int segments = 3;
face = cgal_face_t();
face.outer.push_back(Kernel_::Point_3(-x, -y, 0.0));
face.outer.push_back(Kernel_::Point_3(x, -y, 0.0));
if (f2 == 0.0) {
face.outer.push_back(Kernel_::Point_3(x, -y+d-dy1, 0.0));
} else {
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(x-f2+f2*cos(current_angle), -y+d-dy1-f2+f2*sin(current_angle), 0));
}
} if (f1 == 0.0) {
face.outer.push_back(Kernel_::Point_3(xx, xy, 0.0));
} else {
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(xx+f1+f1*cos(current_angle), xy+f1+f1*sin(current_angle), 0));
}
} if (f2 == 0.0) {
face.outer.push_back(Kernel_::Point_3(-x+d-dx1, y, 0.0));
} else {
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(-x+d-dx1-f2+f2*cos(current_angle), y-f2+f2*sin(current_angle), 0));
}
} face.outer.push_back(Kernel_::Point_3(-x, y, 0.0));
if (has_position) {
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
for (auto &vertex: face.outer) {
vertex = vertex.transform(trsf2d);
}
}
return true;
}
// TODO: Untested
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcIShapeProfileDef* l, cgal_face_t& face) {
const double x1 = l->OverallWidth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double y = l->OverallDepth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() / 2.0f * getValue(GV_LENGTH_UNIT);
const double dy1 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
bool doFillet1 = l->hasFilletRadius();
double f1 = 0.;
if ( doFillet1 ) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
}
bool doFillet2 = doFillet1;
double x2 = x1, dy2 = dy1, f2 = f1;
if (l->as<IfcSchema::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;
}
cgal_placement_t trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
const int segments = 3;
face = cgal_face_t();
face.outer.push_back(Kernel_::Point_3(-x1, -y, 0.0));
face.outer.push_back(Kernel_::Point_3(x1, -y, 0.0));
face.outer.push_back(Kernel_::Point_3(x1, -y+dy1, 0.0));
if (f1 == 0.0) {
face.outer.push_back(Kernel_::Point_3(d1, -y+dy1, 0.0));
face.outer.push_back(Kernel_::Point_3(d1, y-dy2, 0.0));
} else {
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(d1+f1+f1*cos(current_angle), -y+dy1+f1+f1*sin(current_angle), 0));
} for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(d1+f1+f1*cos(current_angle), y-dy2-f1+f1*sin(current_angle), 0));
}
} face.outer.push_back(Kernel_::Point_3(x2, y-dy2, 0.0));
face.outer.push_back(Kernel_::Point_3(x2, y, 0.0));
face.outer.push_back(Kernel_::Point_3(-x2, y, 0.0));
face.outer.push_back(Kernel_::Point_3(-x2, y-dy2, 0.0));
if (f2 == 0.0) {
face.outer.push_back(Kernel_::Point_3(-d1, y-dy2, 0.0));
face.outer.push_back(Kernel_::Point_3(-d1, -y+dy1, 0.0));
} else {
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(-d1-f2+f2*cos(current_angle), y-dy2-f2+f2*sin(current_angle), 0));
} for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(-d1-f2+f2*cos(current_angle), -y+dy1+f2+f2*sin(current_angle), 0));
}
} face.outer.push_back(Kernel_::Point_3(-x1, -y+dy1, 0.0));
if (has_position) {
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
for (auto &vertex: face.outer) {
vertex = vertex.transform(trsf2d);
}
}
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTShapeProfileDef* l, cgal_face_t& face) {
const bool doFlangeEdgeFillet = l->hasFlangeEdgeRadius();
const bool doWebEdgeFillet = l->hasWebEdgeRadius();
const bool doFillet = l->hasFilletRadius();
const bool hasFlangeSlope = l->hasFlangeSlope();
const bool hasWebSlope = l->hasWebSlope();
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double x = l->FlangeWidth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() * getValue(GV_LENGTH_UNIT);
const double d2 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
const double flangeSlope = hasFlangeSlope ? (l->FlangeSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
const double webSlope = hasWebSlope ? (l->WebSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
double dy1 = 0.0f;
double dy2 = 0.0f;
double dx1 = 0.0f;
double dx2 = 0.0f;
double f1 = 0.0f;
double f2 = 0.0f;
double f3 = 0.0f;
if (doFillet) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
}
if (doWebEdgeFillet) {
f2 = l->WebEdgeRadius() * getValue(GV_LENGTH_UNIT);
}
if (doFlangeEdgeFillet) {
f3 = l->FlangeEdgeRadius() * getValue(GV_LENGTH_UNIT);
}
double xx, xy;
if (hasFlangeSlope) {
dy1 = (x / 2. - d1) * tan(flangeSlope);
dy2 = x / 2. * tan(flangeSlope);
}
if (hasWebSlope) {
dx1 = (y - d2) * tan(webSlope);
dx2 = y * tan(webSlope);
}
if (hasWebSlope || hasFlangeSlope) {
const double x1s = d1/2. - dx2; const double y1s = -y;
const double x1e = d1/2. + dx1; const double y1e = y - d2;
const double x2s = x; const double y2s = y - d2 + dy2;
const double x2e = d1/2.; const double y2e = y - d2 - dy1;
const double a1 = y1e - y1s;
const double b1 = x1s - x1e;
const double c1 = a1*x1s + b1*y1s;
const double a2 = y2e - y2s;
const double b2 = x2s - x2e;
const double c2 = a2*x2s + b2*y2s;
const double det = a1*b2 - a2*b1;
if (ALMOST_THE_SAME(det, 0.)) {
Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:",l);
return false;
}
xx = (b2*c1 - b1*c2) / det;
xy = (a1*c2 - a2*c1) / det;
} else {
xx = d1 / 2;
xy = y - d2;
}
cgal_placement_t trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
const int segments = 3;
face = cgal_face_t();
if (f2 == 0.0) {
face.outer.push_back(Kernel_::Point_3(d1/2.-dx2, -y, 0.0));
} else {
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(d1/2.-dx2-f2+f2*cos(current_angle), -y+f2+f2*sin(current_angle), 0));
}
} if (f1 == 0.0) {
face.outer.push_back(Kernel_::Point_3(xx, xy, 0.0));
} else {
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(xx+f1+f1*cos(current_angle), xy-f1+f1*sin(current_angle), 0));
}
} if (f3 == 0.0) {
face.outer.push_back(Kernel_::Point_3(x, y-d2+dy2, 0.0));
} else {
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(x-f3+f3*cos(current_angle), y-d2+dy2+f3+f3*sin(current_angle), 0));
}
} face.outer.push_back(Kernel_::Point_3(x, y, 0.0));
face.outer.push_back(Kernel_::Point_3(-x, y, 0.0));
if (f3 == 0.0) {
face.outer.push_back(Kernel_::Point_3(-x, y-d2+dy2, 0.0));
} else {
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(-x+f3+f3*cos(current_angle), y-d2+dy2+f3+f3*sin(current_angle), 0));
}
} if (f1 == 0.0) {
face.outer.push_back(Kernel_::Point_3(-xx, xy, 0.0));
} else {
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(-xx-f1+f1*cos(current_angle), xy-f1+f1*sin(current_angle), 0));
}
} if (f2 == 0.0) {
face.outer.push_back(Kernel_::Point_3(-d1/2.+dx2, -y, 0.0));
} else {
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(-d1/2.+dx2+f2+f2*cos(current_angle), -y+f2+f2*sin(current_angle), 0));
}
}
if (has_position) {
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
for (auto &vertex: face.outer) {
vertex = vertex.transform(trsf2d);
}
}
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcUShapeProfileDef* l, cgal_face_t& face) {
const bool doEdgeFillet = l->hasEdgeRadius();
const bool doFillet = l->hasFilletRadius();
const bool hasSlope = l->hasFlangeSlope();
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double x = l->FlangeWidth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() * getValue(GV_LENGTH_UNIT);
const double d2 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
const double slope = hasSlope ? (l->FlangeSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
double dy1 = 0.0f;
double dy2 = 0.0f;
double f1 = 0.0f;
double f2 = 0.0f;
if (doFillet) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
}
if (doEdgeFillet) {
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
}
if (hasSlope) {
dy1 = (x - d1) * tan(slope);
dy2 = x * tan(slope);
}
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
cgal_placement_t trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
const int segments = 3;
face = cgal_face_t();
face.outer.push_back(Kernel_::Point_3(-x, -y, 0.0));
face.outer.push_back(Kernel_::Point_3(x, -y, 0.0));
if (f2 == 0.0) {
face.outer.push_back(Kernel_::Point_3(x, -y+d2-dy2, 0.0));
} else {
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(x-f2+f2*cos(current_angle), -y+d2-dy2-f2+f2*sin(current_angle), 0));
}
} if (f1 == 0.0) {
face.outer.push_back(Kernel_::Point_3(-x+d1, -y+d2+dy1, 0.0));
} else {
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(-x+d1+f1+f1*cos(current_angle), -y+d2+dy1+f1+f1*sin(current_angle), 0));
}
} if (f1 == 0.0) {
face.outer.push_back(Kernel_::Point_3(-x+d1, y-d2-dy1, 0.0));
} else {
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(-x+d1+f1+f1*cos(current_angle), y-d2-dy1-f1+f1*sin(current_angle), 0));
}
} if (f2 == 0.0) {
face.outer.push_back(Kernel_::Point_3(x,y-d2+dy2, 0.0));
} else {
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(x-f2+f2*cos(current_angle), y-d2+dy2+f2+f2*sin(current_angle), 0));
}
} face.outer.push_back(Kernel_::Point_3(x,y, 0.0));
face.outer.push_back(Kernel_::Point_3(-x,y, 0.0));
if (has_position) {
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
for (auto &vertex: face.outer) {
vertex = vertex.transform(trsf2d);
}
}
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcZShapeProfileDef* l, cgal_face_t& 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();
double f1 = 0.;
double f2 = 0.;
if ( doFillet ) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
}
if ( doEdgeFillet ) {
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
}
if ( x == 0.0f || y == 0.0f || dx == 0.0f || dy == 0.0f ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
cgal_placement_t trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
const int segments = 3;
face = cgal_face_t();
face.outer.push_back(Kernel_::Point_3(-dx, -y, 0.0));
face.outer.push_back(Kernel_::Point_3(x, -y, 0.0));
if (f2 == 0.0) {
face.outer.push_back(Kernel_::Point_3(x, -y+dy, 0.0));
} else {
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(x-f2+f2*cos(current_angle), -y+dy-f2+f2*sin(current_angle), 0));
}
} if (f1 == 0.0) {
face.outer.push_back(Kernel_::Point_3(dx, -y+dy, 0.0));
} else {
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(dx+f1+f1*cos(current_angle), -y+dy+f1+f1*sin(current_angle), 0));
}
} face.outer.push_back(Kernel_::Point_3(dx, y, 0.0));
face.outer.push_back(Kernel_::Point_3(-x, y, 0.0));
if (f2 == 0.0) {
face.outer.push_back(Kernel_::Point_3(-x, y-dy, 0.0));
} else {
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(-x+f2+f2*cos(current_angle), y-dy+f2+f2*sin(current_angle), 0));
}
} if (f1 == 0.0) {
face.outer.push_back(Kernel_::Point_3(-dx, y-dy, 0.0));
} else {
for (int current_segment = segments; current_segment >= 0; --current_segment) {
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
face.outer.push_back(Kernel_::Point_3(-dx-f1+f1*cos(current_angle), y-dy-f1+f1*sin(current_angle), 0));
}
}
if (has_position) {
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
for (auto &vertex: face.outer) {
vertex = vertex.transform(trsf2d);
}
}
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDerivedProfileDef* l, cgal_face_t& face) {
cgal_face_t f;
cgal_placement_t trsf2d;
if (convert_face(l->ParentProfile(), f) && IfcGeom::CgalKernel::convert(l->Operator(), trsf2d)) {
cgal_placement_t trsf = trsf2d;
for (auto &vertex: f.outer) vertex = vertex.transform(trsf);
for (auto &ring: f.inner) {
for (auto &vertex: ring) vertex = vertex.transform(trsf);
} face = f;
return true;
} else {
return false;
}
}
@@ -0,0 +1,323 @@
#include "CgalKernel.h"
#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h"
#define CgalKernel MAKE_TYPE_NAME(CgalKernel)
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) {
std::vector<double> xyz = l->Coordinates();
point = Kernel_::Point_3(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);
// std::cout << "Converted Point(" << point << ")" << std::endl;
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDirection* l, cgal_direction_t& dir) {
// IN_CACHE(IfcDirection,l,cgal_direction_t,dir)
std::vector<double> xyz = l->DirectionRatios();
dir = Kernel_::Vector_3(xyz.size() ? xyz[0] : 0.0f,
xyz.size() > 1 ? xyz[1] : 0.0f,
xyz.size() > 2 ? xyz[2] : 0.0f);
// CACHE(IfcDirection,l,dir)
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcVector* l, cgal_vector_t& v) {
// IN_CACHE(IfcVector,l,cgal_vector_t,v)
cgal_direction_t d;
IfcGeom::CgalKernel::convert(l->Orientation(),d);
v = l->Magnitude() * getValue(GV_LENGTH_UNIT) * d;
// CACHE(IfcVector,l,v)
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPlane* pln, cgal_plane_t& plane) {
// IN_CACHE(IfcPlane,pln,gp_Pln,plane)
IfcSchema::IfcAxis2Placement3D* l = pln->Position();
cgal_point_t o;
cgal_direction_t axis = Kernel_::Vector_3(0,0,1);
cgal_direction_t refDirection = Kernel_::Vector_3(1,0,0);
IfcGeom::CgalKernel::convert(l->Location(),o);
bool hasRef = l->hasRefDirection();
if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(),axis);
if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection);
Kernel_::Vector_3 y = CGAL::cross_product(axis, refDirection);
Kernel_::Vector_3 x = CGAL::cross_product(y, axis);
cgal_plane_t ax3;
if ( hasRef ) ax3 = Kernel_::Plane_3(o,o+x,o+y);
else ax3 = Kernel_::Plane_3(o,axis);
plane = ax3;
// std::cout << "IfcPlane C = " << o << std::endl;
// std::cout << "IfcPlane z (axis, exact) = " << axis << std::endl;
// std::cout << "IfcPlane x (refDirection, approximate) = " << refDirection << std::endl;
// std::cout << "IfcPlane y (computed, exact) = " << y << std::endl;
// std::cout << "IfcPlane x (computed, exact) = " << x << std::endl;
//
// std::cout << "Plane_3 o = " << o << std::endl;
// std::cout << "Plane_3 o+x = " << o+x << std::endl;
// std::cout << "Plane_3 o+y = " << o+y << std::endl;
// ax + by + cz + d = 0
// std::cout << "Plane: a = " << plane.a() << ", b = " << plane.b() << ", c = " << plane.c() << ", d = " << plane.d() << std::endl;
// std::ofstream fresult;
// fresult.open("/Users/ken/Desktop/plane.obj");
// // x = -5, y = -5, z = (5a +5b -d)/c
// fresult << "v -5 -5 " << (5.0*CGAL::to_double(plane.a())+5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl;
// // x = -5, y = +5, z = (5a -5b -d)/c
// fresult << "v -5 5 " << (5.0*CGAL::to_double(plane.a())-5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl;
// // x = 5, y = -5, z = (-5a +5b -d)/c
// fresult << "v 5 -5 " << (-5.0*CGAL::to_double(plane.a())+5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl;
// // x = 5, y = +5, z = (-5a -5b -d)/c
// fresult << "v 5 5 " << (-5.0*CGAL::to_double(plane.a())-5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl;
// fresult << "f 1 2 3" << std::endl;
// fresult << "f 4 3 2" << std::endl;
// fresult.close();
// CACHE(IfcPlane,pln,plane)
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, cgal_placement_t& trsf) {
// IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf)
cgal_point_t o;
cgal_direction_t refDirection = Kernel_::Vector_3(1,0,0);
IfcGeom::CgalKernel::convert(l->Location(),o);
bool hasRef = l->hasRefDirection();
if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection);
cgal_direction_t y = Kernel_::Vector_3(-refDirection.y(), refDirection.x(), 0.0);
const double tolerance = 0.01;
if (refDirection.squared_length() < 1.0-tolerance || refDirection.squared_length() > 1.0+tolerance ||
y.squared_length() < 1.0-tolerance || y.squared_length() > 1.0+tolerance) {
std::cout << "Ref direction (x): " << refDirection << " squared length: " << refDirection.squared_length() << std::endl;
std::cout << "y: " << y << " squared length: " << y.squared_length() << std::endl;
std::cout << "Origin: " << o << std::endl;
}
// TODO: Should be checked.
trsf = Kernel_::Aff_transformation_3(refDirection.cartesian(0), y.cartesian(0), 0.0, o.cartesian(0),
refDirection.cartesian(1), y.cartesian(1), 0.0, o.cartesian(1),
0.0, 0.0, 1.0, 0.0);
// CACHE(IfcAxis2Placement3D,l,trsf)
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_placement_t& trsf) {
// IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf)
cgal_point_t o;
cgal_direction_t axis = Kernel_::Vector_3(0,0,1);
cgal_direction_t refDirection = Kernel_::Vector_3(1,0,0);
IfcGeom::CgalKernel::convert(l->Location(),o);
bool hasRef = l->hasRefDirection();
if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(),axis);
if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection);
Kernel_::Vector_3 y = CGAL::cross_product(axis, refDirection);
Kernel_::Vector_3 x = CGAL::cross_product(y, axis);
const double tolerance = 0.01;
if (x.squared_length() < 1.0-tolerance || x.squared_length() > 1.0+tolerance ||
y.squared_length() < 1.0-tolerance || y.squared_length() > 1.0+tolerance ||
axis.squared_length() < 1.0-tolerance || axis.squared_length() > 1.0+tolerance) {
std::cout << "Ref direction: " << refDirection << " squared length: " << refDirection.squared_length() << std::endl;
std::cout << "Axis (z): " << axis << " squared length: " << axis.squared_length() << std::endl;
std::cout << "y: " << y << " squared length: " << y.squared_length() << std::endl;
std::cout << "x: " << x << " squared length: " << x.squared_length() << std::endl;
std::cout << "Origin: " << o << std::endl;
}
// TODO: Should be checked.
trsf = Kernel_::Aff_transformation_3(x.cartesian(0), y.cartesian(0), axis.cartesian(0), o.cartesian(0),
x.cartesian(1), y.cartesian(1), axis.cartesian(1), o.cartesian(1),
x.cartesian(2), y.cartesian(2), axis.cartesian(2), o.cartesian(2));
// for (int i = 0; i < 3; ++i) {
// for (int j = 0; j < 4; ++j) {
// std::cout << trsf.cartesian(i, j) << " ";
// } std::cout << std::endl;
// }
// CACHE(IfcAxis2Placement3D,l,trsf)
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis1Placement* l, cgal_placement_t& ax) {
// IN_CACHE(IfcAxis1Placement,l,gp_Ax1,ax)
cgal_point_t o;
cgal_direction_t axis = Kernel_::Vector_3(0,0,1);
IfcGeom::CgalKernel::convert(l->Location(),o);
if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(), axis);
const double tolerance = 0.01;
if (axis.squared_length() < 1.0-tolerance || axis.squared_length() > 1.0+tolerance) {
std::cout << "Axis (z): " << axis << " squared length: " << axis.squared_length() << std::endl;
std::cout << "Origin: " << o << std::endl;
}
// TODO: Should be checked.
ax = Kernel_::Aff_transformation_3(1.0, 0.0, axis.cartesian(0), o.cartesian(0),
0.0, 1.0, axis.cartesian(1), o.cartesian(1),
0.0, 0.0, axis.cartesian(2), o.cartesian(2));
// CACHE(IfcAxis1Placement,l,ax)
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_placement_t& trsf) {
// IN_CACHE(IfcObjectPlacement,l,cgal_placement_t,trsf)
if ( ! l->as<IfcSchema::IfcLocalPlacement>() ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l);
return false;
}
// std::cout << "initial trsf (identity?)" << std::endl;
// for (int i = 0; i < 3; ++i) {
// for (int j = 0; j < 4; ++j) {
// std::cout << trsf.cartesian(i, j) << " ";
// } std::cout << std::endl;
// }
IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l;
for (;;) {
cgal_placement_t trsf2;
IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement();
if ( relplacement->as<IfcSchema::IfcAxis2Placement3D>() ) {
IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2);
// std::cout << "trsf2" << std::endl;
// for (int i = 0; i < 3; ++i) {
// for (int j = 0; j < 4; ++j) {
// std::cout << trsf2.cartesian(i, j) << " ";
// } std::cout << std::endl;
// }
trsf = trsf2 * trsf;
// std::cout << "trsf (after multiplication)" << std::endl;
// for (int i = 0; i < 3; ++i) {
// for (int j = 0; j < 4; ++j) {
// std::cout << trsf.cartesian(i, j) << " ";
// } std::cout << std::endl;
// }
}
if ( current->hasPlacementRelTo() ) {
IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo();
if ( relto->as<IfcSchema::IfcLocalPlacement>() )
current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo();
else break;
} else break;
}
// CACHE(IfcObjectPlacement,l,trsf)
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOperator2D* l, cgal_placement_t& trsf) {
// IN_CACHE(IfcCartesianTransformationOperator2D,l,cgal_placement_t,trsf)
cgal_point_t origin;
cgal_direction_t axis1 (1.,0.,0.);
cgal_direction_t axis2 (0.,1.,0.);
IfcGeom::CgalKernel::convert(l->LocalOrigin(),origin);
if ( l->hasAxis1() ) IfcGeom::CgalKernel::convert(l->Axis1(),axis1);
if ( l->hasAxis2() ) IfcGeom::CgalKernel::convert(l->Axis2(),axis2);
double scale = 1.0;
if (l->hasScale()) {
scale = l->Scale();
}
// TODO: Untested
trsf = Kernel_::Aff_transformation_3(scale*axis1.cartesian(0), axis2.cartesian(0), 0.0, origin.cartesian(0),
axis1.cartesian(1), scale*axis2.cartesian(1), 0.0, origin.cartesian(1),
0.0, 0.0, 1.0, 0.0);
// CACHE(IfcCartesianTransformationOperator2D,l,trsf)
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* l, cgal_placement_t& trsf) {
// IN_CACHE(IfcCartesianTransformationOperator2DnonUniform,l,cgal_placement_t,gtrsf)
cgal_point_t origin;
cgal_direction_t axis1 (1.,0.,0.);
cgal_direction_t axis2 (0.,1.,0.);
IfcGeom::CgalKernel::convert(l->LocalOrigin(),origin);
if ( l->hasAxis1() ) IfcGeom::CgalKernel::convert(l->Axis1(),axis1);
if ( l->hasAxis2() ) IfcGeom::CgalKernel::convert(l->Axis2(),axis2);
const double scale1 = l->hasScale() ? l->Scale() : 1.0f;
const double scale2 = l->hasScale2() ? l->Scale2() : scale1;
// TODO: Untested
trsf = Kernel_::Aff_transformation_3(scale1*axis1.cartesian(0), axis2.cartesian(0), 0.0, origin.cartesian(0),
axis1.cartesian(1), scale2*axis2.cartesian(1), 0.0, origin.cartesian(1),
0.0, 0.0, 1.0, 0.0);
// CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gtrsf)
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOperator3D* l, cgal_placement_t& trsf) {
// IN_CACHE(IfcCartesianTransformationOperator3D,l,gp_Trsf,trsf)
cgal_point_t origin;
IfcGeom::CgalKernel::convert(l->LocalOrigin(),origin);
cgal_direction_t axis1 (1.,0.,0.);
cgal_direction_t axis2 (0.,1.,0.);
cgal_direction_t axis3 (0.,0.,1.);
if ( l->hasAxis1() ) IfcGeom::CgalKernel::convert(l->Axis1(),axis1);
if ( l->hasAxis2() ) IfcGeom::CgalKernel::convert(l->Axis2(),axis2);
if ( l->hasAxis3() ) IfcGeom::CgalKernel::convert(l->Axis3(),axis3);
double scale = 1.0;
if (l->hasScale()) {
scale = l->Scale();
}
// TODO: Untested
trsf = Kernel_::Aff_transformation_3(scale*axis1.cartesian(0), axis2.cartesian(0), axis3.cartesian(0), origin.cartesian(0),
axis1.cartesian(1), scale*axis2.cartesian(1), axis3.cartesian(1), origin.cartesian(1),
axis1.cartesian(2), axis2.cartesian(2), scale*axis3.cartesian(2), origin.cartesian(2));
// std::cout << std::endl;
// for (int i = 0; i < 3; ++i) {
// for (int j = 0; j < 4; ++j) {
// std::cout << trsf.cartesian(i, j) << " ";
// } std::cout << std::endl;
// }
// CACHE(IfcCartesianTransformationOperator3D,l,trsf)
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* l, cgal_placement_t& gtrsf) {
// IN_CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gp_GTrsf,gtrsf)
cgal_point_t origin;
IfcGeom::CgalKernel::convert(l->LocalOrigin(),origin);
cgal_direction_t axis1 (1.,0.,0.);
cgal_direction_t axis2 (0.,1.,0.);
cgal_direction_t axis3 (0.,0.,1.);
if ( l->hasAxis1() ) IfcGeom::CgalKernel::convert(l->Axis1(),axis1);
if ( l->hasAxis2() ) IfcGeom::CgalKernel::convert(l->Axis2(),axis2);
if ( l->hasAxis3() ) IfcGeom::CgalKernel::convert(l->Axis3(),axis3);
const double scale1 = l->hasScale() ? l->Scale() : 1.0f;
const double scale2 = l->hasScale2() ? l->Scale2() : scale1;
const double scale3 = l->hasScale3() ? l->Scale3() : scale1;
// TODO: Untested
gtrsf = Kernel_::Aff_transformation_3(scale1*axis1.cartesian(0), axis2.cartesian(0), axis3.cartesian(0), origin.cartesian(0),
axis1.cartesian(1), scale2*axis2.cartesian(1), axis3.cartesian(1), origin.cartesian(1),
axis1.cartesian(2), axis2.cartesian(2), scale3*axis3.cartesian(2), origin.cartesian(2));
// for (int i = 0; i < 3; ++i) {
// for (int j = 0; j < 4; ++j) {
// std::cout << gtrsf.cartesian(i, j) << " ";
// } std::cout << std::endl;
// }
// CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gtrsf)
return true;
}
@@ -0,0 +1,919 @@
#include "CgalKernel.h"
#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h"
#define CgalKernel MAKE_TYPE_NAME(CgalKernel)
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal_shape_t &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;
}
// Outer
cgal_face_t bottom_face;
if ( !convert_face(l->SweptArea(),bottom_face) ) return false;
// std::cout << "Face vertices: " << face.outer.size() << std::endl;
cgal_placement_t trsf;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::CgalKernel::convert(l->Position(), trsf);
}
cgal_direction_t dir;
convert(l->ExtrudedDirection(),dir);
// std::cout << "Direction: " << dir << std::endl;
std::list<cgal_face_t> face_list;
face_list.push_back(bottom_face);
for (std::vector<Kernel_::Point_3>::const_iterator current_vertex = bottom_face.outer.begin();
current_vertex != bottom_face.outer.end();
++current_vertex) {
std::vector<Kernel_::Point_3>::const_iterator next_vertex = current_vertex;
++next_vertex;
if (next_vertex == bottom_face.outer.end()) {
next_vertex = bottom_face.outer.begin();
} cgal_face_t side_face;
side_face.outer.push_back(*next_vertex);
side_face.outer.push_back(*current_vertex);
side_face.outer.push_back(*current_vertex+height*dir);
side_face.outer.push_back(*next_vertex+height*dir);
face_list.push_back(side_face);
}
cgal_face_t top_face;
for (std::vector<Kernel_::Point_3>::const_reverse_iterator vertex = bottom_face.outer.rbegin();
vertex != bottom_face.outer.rend();
++vertex) {
top_face.outer.push_back(*vertex+height*dir);
} face_list.push_back(top_face);
if (bottom_face.inner.empty()) {
shape = create_polyhedron(face_list);
if (has_position) for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf);
return true;
}
CGAL::Nef_polyhedron_3<Kernel_> nef_shape = create_nef_polyhedron(face_list);
// Inner
// TODO: Would be faster to triangulate top/bottom face template rather than use Nef polyhedra for subtraction
for (auto &inner: bottom_face.inner) {
// std::cout << "Inner wire" << std::endl;
face_list.clear();
cgal_face_t hole_bottom_face;
hole_bottom_face.outer = inner;
remove_duplicate_points_from_loop(hole_bottom_face.outer);
face_list.push_back(hole_bottom_face);
for (std::vector<Kernel_::Point_3>::const_iterator current_vertex = inner.begin();
current_vertex != inner.end();
++current_vertex) {
std::vector<Kernel_::Point_3>::const_iterator next_vertex = current_vertex;
++next_vertex;
if (next_vertex == inner.end()) {
next_vertex = inner.begin();
} cgal_face_t hole_side_face;
hole_side_face.outer.push_back(*next_vertex);
hole_side_face.outer.push_back(*current_vertex);
hole_side_face.outer.push_back(*current_vertex+height*dir);
hole_side_face.outer.push_back(*next_vertex+height*dir);
face_list.push_back(hole_side_face);
}
cgal_face_t hole_top_face;
for (std::vector<Kernel_::Point_3>::const_reverse_iterator vertex = inner.rbegin();
vertex != inner.rend();
++vertex) {
hole_top_face.outer.push_back(*vertex+height*dir);
} face_list.push_back(hole_top_face);
try {
nef_shape -= create_nef_polyhedron(face_list);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot subtract opening for:", l);
return false;
}
}
if (has_position) {
// IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D
// and therefore has a unit scale factor
nef_shape.transform(trsf);
}
try {
nef_shape.convert_to_polyhedron(shape);
return true;
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot convert Nef to polyhedron for:", l);
return false;
}
}
#ifdef USE_IFC4
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* l, cgal_shape_t& 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;
}
cgal_face_t face1, face2;
if (!convert_face(l->SweptArea(), face1)) return false;
if (!convert_face(l->EndSweptArea(), face2)) return false;
cgal_placement_t trsf;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::CgalKernel::convert(l->Position(), trsf);
}
cgal_direction_t dir;
convert(l->ExtrudedDirection(), dir);
for (auto &vertex: face2.outer) vertex = vertex + height*dir;
for (auto &ring: face2.inner) {
for (auto &vertex: ring) vertex = vertex + height*dir;
}
// Outer
std::list<cgal_face_t> face_list;
face_list.push_back(face1);
std::vector<Kernel_::Point_3>::const_iterator current_face1_vertex = face1.outer.begin();
std::vector<Kernel_::Point_3>::const_iterator current_face2_vertex = face2.outer.begin();
while (current_face1_vertex != face1.outer.end() &&
current_face2_vertex != face2.outer.end()) {
std::vector<Kernel_::Point_3>::const_iterator next_face1_vertex = current_face1_vertex;
std::vector<Kernel_::Point_3>::const_iterator next_face2_vertex = current_face2_vertex;
++next_face1_vertex;
++next_face2_vertex;
if (next_face1_vertex == face1.outer.end()) next_face1_vertex = face1.outer.begin();
if (next_face2_vertex == face2.outer.end()) next_face2_vertex = face2.outer.begin();
cgal_face_t side_face;
side_face.outer.push_back(*next_face1_vertex);
side_face.outer.push_back(*current_face1_vertex);
side_face.outer.push_back(*current_face2_vertex);
side_face.outer.push_back(*next_face2_vertex);
face_list.push_back(side_face);
++current_face1_vertex;
++current_face2_vertex;
}
cgal_face_t top_face;
for (std::vector<Kernel_::Point_3>::const_reverse_iterator vertex = face2.outer.rbegin();
vertex != face2.outer.rend();
++vertex) {
top_face.outer.push_back(*vertex);
} face_list.push_back(top_face);
if (face1.inner.empty() || face2.inner.empty()) {
shape = create_polyhedron(face_list);
if (has_position) for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf);
return true;
}
// std::ofstream f1;
// CGAL::Polyhedron_3<Kernel_> outer_polyhedron;
// PolyhedronBuilder builder(&face_list);
// outer_polyhedron.delegate(builder);
// f1.open("/Users/ken/Desktop/outer.off");
// f1 << outer_polyhedron << std::endl;
// f1.close();
CGAL::Nef_polyhedron_3<Kernel_> nef_shape = create_nef_polyhedron(face_list);
// Inner
// TODO: Would be faster to triangulate top/bottom face template rather than use Nef polyhedra for subtraction
std::vector<cgal_wire_t>::iterator inner_face1 = face1.inner.begin();
std::vector<cgal_wire_t>::iterator inner_face2 = face2.inner.begin();
while (inner_face1 != face1.inner.end() &&
inner_face2 != face2.inner.end()) {
face_list.clear();
cgal_face_t hole_face1;
hole_face1.outer = *inner_face1;
remove_duplicate_points_from_loop(hole_face1.outer);
face_list.push_back(hole_face1);
cgal_face_t hole_face2;
hole_face2.outer = *inner_face2;
remove_duplicate_points_from_loop(hole_face2.outer);
current_face1_vertex = hole_face1.outer.begin();
current_face2_vertex = hole_face2.outer.begin();
while (current_face1_vertex != hole_face1.outer.end() &&
current_face2_vertex != hole_face2.outer.end()) {
std::vector<Kernel_::Point_3>::const_iterator next_face1_vertex = current_face1_vertex;
std::vector<Kernel_::Point_3>::const_iterator next_face2_vertex = current_face2_vertex;
++next_face1_vertex;
++next_face2_vertex;
if (next_face1_vertex == hole_face1.outer.end()) next_face1_vertex = hole_face1.outer.begin();
if (next_face2_vertex == hole_face2.outer.end()) next_face2_vertex = hole_face2.outer.begin();
cgal_face_t side_face;
side_face.outer.push_back(*next_face1_vertex);
side_face.outer.push_back(*current_face1_vertex);
side_face.outer.push_back(*current_face2_vertex);
side_face.outer.push_back(*next_face2_vertex);
face_list.push_back(side_face);
++current_face1_vertex;
++current_face2_vertex;
}
cgal_face_t top_hole_face;
for (std::vector<Kernel_::Point_3>::const_reverse_iterator vertex = hole_face2.outer.rbegin();
vertex != hole_face2.outer.rend();
++vertex) {
top_hole_face.outer.push_back(*vertex);
} face_list.push_back(top_hole_face);
// std::ofstream f2;
// CGAL::Polyhedron_3<Kernel_> inner_polyhedron;
// PolyhedronBuilder builder(&face_list);
// inner_polyhedron.delegate(builder);
// f2.open("/Users/ken/Desktop/inner.off");
// f2 << inner_polyhedron << std::endl;
// f2.close();
try {
nef_shape -= create_nef_polyhedron(face_list);
} catch (...) {
std::cout << "IfcExtrudedAreaSolidTapered: cannot subtract opening for:" << std::endl;
return false;
}
++inner_face1;
++inner_face2;
}
if (has_position) {
// IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D
// and therefore has a unit scale factor
nef_shape.transform(trsf);
}
try {
nef_shape.convert_to_polyhedron(shape);
return true;
} catch (...) {
std::cout << "IfcExtrudedAreaSolidTapered: cannot convert Nef to polyhedron!" << std::endl;
return false;
}
}
#endif
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_shape_t& shape) {
IfcSchema::IfcFace::list::ptr faces = l->CfsFaces();
std::list<cgal_face_t> face_list;
for (IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++it) {
bool success = false;
cgal_face_t face;
try {
success = convert_face(*it, face);
} catch (...) {}
if (!success) {
Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", (*it));
continue;
}
// std::cout << "Face in ConnectedFaceSet: " << std::endl;
// for (auto &point: face.outer) {
// std::cout << "\tPoint(" << point << ")" << std::endl;
// }
face_list.push_back(face);
}
shape = create_polyhedron(face_list);
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCsgSolid* l, cgal_shape_t& shape) {
return convert_shape(l->TreeRootExpression(), shape);
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& 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);
std::list<cgal_face_t> face_list;
// x = 0
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, 0));
face_list.back().outer.push_back(Kernel_::Point_3(0, dy, 0));
face_list.back().outer.push_back(Kernel_::Point_3(0, dy, dz));
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, dz));
// x = dx
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(Kernel_::Point_3(dx, 0, 0));
face_list.back().outer.push_back(Kernel_::Point_3(dx, 0, dz));
face_list.back().outer.push_back(Kernel_::Point_3(dx, dy, dz));
face_list.back().outer.push_back(Kernel_::Point_3(dx, dy, 0));
// y = 0
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, 0));
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, dz));
face_list.back().outer.push_back(Kernel_::Point_3(dx, 0, dz));
face_list.back().outer.push_back(Kernel_::Point_3(dx, 0, 0));
// y = dy
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(Kernel_::Point_3(0, dy, 0));
face_list.back().outer.push_back(Kernel_::Point_3(dx, dy, 0));
face_list.back().outer.push_back(Kernel_::Point_3(dx, dy, dz));
face_list.back().outer.push_back(Kernel_::Point_3(0, dy, dz));
// z = 0
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, 0));
face_list.back().outer.push_back(Kernel_::Point_3(dx, 0, 0));
face_list.back().outer.push_back(Kernel_::Point_3(dx, dy, 0));
face_list.back().outer.push_back(Kernel_::Point_3(0, dy, 0));
// z = dz
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, dz));
face_list.back().outer.push_back(Kernel_::Point_3(0, dy, dz));
face_list.back().outer.push_back(Kernel_::Point_3(dx, dy, dz));
face_list.back().outer.push_back(Kernel_::Point_3(dx, 0, dz));
cgal_placement_t trsf;
IfcGeom::CgalKernel::convert(l->Position(),trsf);
shape = create_polyhedron(face_list);
for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf);
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_shape_t& shape) {
cgal_shape_t s1, s2;
ConversionResults items1, items2;
cgal_wire_t boundary_wire;
IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand();
IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand();
bool is_halfspace = operand2->as<IfcSchema::IfcHalfSpaceSolid>();
if ( shape_type(operand1) == ST_SHAPELIST ) {
Logger::Message(Logger::LOG_ERROR, "s1: ST_SHAPELIST Unsupported", operand1);
// 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;
}
} else {
Logger::Message(Logger::LOG_ERROR, "s1: 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());
bool shape2_processed = false;
if ( shape_type(operand2) == ST_SHAPELIST ) {
Logger::Message(Logger::LOG_ERROR, "s2: ST_SHAPELIST Unsupported", operand1);
// 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);
} else {
Logger::Message(Logger::LOG_ERROR, "s2: Invalid representation item for boolean operation", operand2);
}
if (!shape2_processed) {
shape = s1;
Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l);
return true;
}
// 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);
// }
const IfcSchema::IfcBooleanOperator::Value op = l->Operator();
if (!s1.is_valid()) {
Logger::Message(Logger::LOG_ERROR, "s1: Not valid?", operand1);
return false;
} else {
// std::ofstream f1;
// CGAL::Polyhedron_3<Kernel_> p1;
// s1.convert_to_Polyhedron(p1);
// f1.open("/Users/ken/Desktop/s1.off");
// f1 << p1 << std::endl;
// f1.close();
}
bool is_plane = false;
cgal_plane_t plane;
if (!s2.is_valid()) {
Logger::Message(Logger::LOG_ERROR, "s2: Not valid?", operand2);
return false;
} else if (is_halfspace) {
// std::cout << "s2: halfspace" << std::endl;
IfcSchema::IfcHalfSpaceSolid *hss = static_cast<IfcSchema::IfcHalfSpaceSolid *>(operand2);
IfcSchema::IfcSurface* surface = hss->BaseSurface();
if (surface->as<IfcSchema::IfcPlane>() ) {
is_plane = true;
IfcGeom::CgalKernel::convert((IfcSchema::IfcPlane *)surface, plane);
if (hss->AgreementFlag()) plane = plane.opposite();
// std::ofstream fresult;
// fresult.open("/Users/ken/Desktop/s2.off");
// fresult << "OFF" << std::endl << "4 2 4" << std::endl;
// // x = -5, y = -5, z = (5a +5b -d)/c
// fresult << "-5 -5 " << (5.0*CGAL::to_double(plane.a())+5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl;
// // x = -5, y = +5, z = (5a -5b -d)/c
// fresult << "-5 5 " << (5.0*CGAL::to_double(plane.a())-5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl;
// // x = 5, y = -5, z = (-5a +5b -d)/c
// fresult << "5 -5 " << (-5.0*CGAL::to_double(plane.a())+5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl;
// // x = 5, y = +5, z = (-5a -5b -d)/c
// fresult << "5 5 " << (-5.0*CGAL::to_double(plane.a())-5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl;
// fresult << "3 0 1 2" << std::endl;
// fresult << "3 3 2 1" << std::endl;
// fresult.close();
}
} else {
// std::ofstream f2;
// CGAL::Polyhedron_3<Kernel_> p2;
// s2.convert_to_Polyhedron(p2);
// f2.open("/Users/ken/Desktop/s2.off");
// f2 << p2 << std::endl;
// f2.close();
}
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
// std::cout << "Difference" << std::endl;
CGAL::Nef_polyhedron_3<Kernel_> nef_result;
try {
nef_result = CGAL::Nef_polyhedron_3<Kernel_>(s1);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "s1: cannot convert to Nef?", operand1);
return false;
} if (is_halfspace) {
if (is_plane) nef_result = nef_result.intersection(plane, CGAL::Nef_polyhedron_3<Kernel_>::Intersection_mode::CLOSED_HALFSPACE);
} else {
CGAL::Nef_polyhedron_3<Kernel_> nef_s2;
try {
nef_s2 = CGAL::Nef_polyhedron_3<Kernel_>(s2);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "s2: cannot convert to Nef?", operand2);
} nef_result -= nef_s2;
}
if (!nef_result.is_simple()) {
Logger::Message(Logger::LOG_ERROR, "s2: not simple?", operand2);
return false;
} else {
// CGAL::Polyhedron_3<Kernel_> result;
// nef_result.convert_to_polyhedron(result);
// std::ofstream fresult;
// fresult.open("/Users/ken/Desktop/result.off");
// fresult << result << std::endl;
// fresult.close();
} try {
nef_result.convert_to_polyhedron(shape);
return true;
} catch (...) {
std::cout << "IfcBooleanResult: cannot convert Nef to polyhedron!" << std::endl;
return false;
}
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) {
// std::cout << "Union" << std::endl;
CGAL::Nef_polyhedron_3<Kernel_> nef_result = CGAL::Nef_polyhedron_3<Kernel_>(s1)+CGAL::Nef_polyhedron_3<Kernel_>(s2);
if (!nef_result.is_simple()) {
std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl;
return false;
} else {
// CGAL::Polyhedron_3<Kernel_> result;
// nef_result.convert_to_polyhedron(result);
// std::ofstream fresult;
// fresult.open("/Users/ken/Desktop/result.off");
// fresult << result << std::endl;
// fresult.close();
} try {
nef_result.convert_to_polyhedron(shape);
return true;
} catch (...) {
std::cout << "IfcBooleanResult: cannot convert Nef to polyhedron!" << std::endl;
return false;
}
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) {
// std::cout << "Intersection" << std::endl;
CGAL::Nef_polyhedron_3<Kernel_> nef_result = CGAL::Nef_polyhedron_3<Kernel_>(s1)*CGAL::Nef_polyhedron_3<Kernel_>(s2);
if (!nef_result.is_simple()) {
std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl;
return false;
} else {
// CGAL::Polyhedron_3<Kernel_> result;
// nef_result.convert_to_polyhedron(result);
// std::ofstream fresult;
// fresult.open("/Users/ken/Desktop/result.off");
// fresult << result << std::endl;
// fresult.close();
} try {
nef_result.convert_to_polyhedron(shape);
return true;
} catch (...) {
std::cout << "IfcBooleanResult: cannot convert Nef to polyhedron!" << std::endl;
return false;
}
} return false;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& shape) {
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
// Make icosahedron
float golden_ratio = (1.0+sqrtf(5.0))/2.0;
float normalising_factor = sqrtf(golden_ratio*golden_ratio+1.0);
std::vector<Kernel_::Point_3> icosahedron_vertices;
icosahedron_vertices.push_back(Kernel_::Point_3(-1.0/normalising_factor, golden_ratio/normalising_factor, 0.0));
icosahedron_vertices.push_back(Kernel_::Point_3( 1.0/normalising_factor, golden_ratio/normalising_factor, 0.0));
icosahedron_vertices.push_back(Kernel_::Point_3(-1.0/normalising_factor, -golden_ratio/normalising_factor, 0.0));
icosahedron_vertices.push_back(Kernel_::Point_3( 1.0/normalising_factor, -golden_ratio/normalising_factor, 0.0));
icosahedron_vertices.push_back(Kernel_::Point_3(0.0, -1.0/normalising_factor, golden_ratio/normalising_factor));
icosahedron_vertices.push_back(Kernel_::Point_3(0.0, 1.0/normalising_factor, golden_ratio/normalising_factor));
icosahedron_vertices.push_back(Kernel_::Point_3(0.0, -1.0/normalising_factor, -golden_ratio/normalising_factor));
icosahedron_vertices.push_back(Kernel_::Point_3(0.0, 1.0/normalising_factor, -golden_ratio/normalising_factor));
icosahedron_vertices.push_back(Kernel_::Point_3( golden_ratio/normalising_factor, 0.0, -1.0/normalising_factor));
icosahedron_vertices.push_back(Kernel_::Point_3( golden_ratio/normalising_factor, 0.0, 1.0/normalising_factor));
icosahedron_vertices.push_back(Kernel_::Point_3(-golden_ratio/normalising_factor, 0.0, -1.0/normalising_factor));
icosahedron_vertices.push_back(Kernel_::Point_3(-golden_ratio/normalising_factor, 0.0, 1.0/normalising_factor));
std::list<cgal_face_t> face_list;
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[0]);
face_list.back().outer.push_back(icosahedron_vertices[11]);
face_list.back().outer.push_back(icosahedron_vertices[5]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[0]);
face_list.back().outer.push_back(icosahedron_vertices[5]);
face_list.back().outer.push_back(icosahedron_vertices[1]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[0]);
face_list.back().outer.push_back(icosahedron_vertices[1]);
face_list.back().outer.push_back(icosahedron_vertices[7]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[0]);
face_list.back().outer.push_back(icosahedron_vertices[7]);
face_list.back().outer.push_back(icosahedron_vertices[10]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[0]);
face_list.back().outer.push_back(icosahedron_vertices[10]);
face_list.back().outer.push_back(icosahedron_vertices[11]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[1]);
face_list.back().outer.push_back(icosahedron_vertices[5]);
face_list.back().outer.push_back(icosahedron_vertices[9]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[5]);
face_list.back().outer.push_back(icosahedron_vertices[11]);
face_list.back().outer.push_back(icosahedron_vertices[4]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[11]);
face_list.back().outer.push_back(icosahedron_vertices[10]);
face_list.back().outer.push_back(icosahedron_vertices[2]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[10]);
face_list.back().outer.push_back(icosahedron_vertices[7]);
face_list.back().outer.push_back(icosahedron_vertices[6]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[7]);
face_list.back().outer.push_back(icosahedron_vertices[1]);
face_list.back().outer.push_back(icosahedron_vertices[8]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[3]);
face_list.back().outer.push_back(icosahedron_vertices[9]);
face_list.back().outer.push_back(icosahedron_vertices[4]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[3]);
face_list.back().outer.push_back(icosahedron_vertices[4]);
face_list.back().outer.push_back(icosahedron_vertices[2]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[3]);
face_list.back().outer.push_back(icosahedron_vertices[2]);
face_list.back().outer.push_back(icosahedron_vertices[6]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[3]);
face_list.back().outer.push_back(icosahedron_vertices[6]);
face_list.back().outer.push_back(icosahedron_vertices[8]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[3]);
face_list.back().outer.push_back(icosahedron_vertices[8]);
face_list.back().outer.push_back(icosahedron_vertices[9]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[4]);
face_list.back().outer.push_back(icosahedron_vertices[9]);
face_list.back().outer.push_back(icosahedron_vertices[5]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[2]);
face_list.back().outer.push_back(icosahedron_vertices[4]);
face_list.back().outer.push_back(icosahedron_vertices[11]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[6]);
face_list.back().outer.push_back(icosahedron_vertices[2]);
face_list.back().outer.push_back(icosahedron_vertices[10]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[8]);
face_list.back().outer.push_back(icosahedron_vertices[6]);
face_list.back().outer.push_back(icosahedron_vertices[7]);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(icosahedron_vertices[9]);
face_list.back().outer.push_back(icosahedron_vertices[8]);
face_list.back().outer.push_back(icosahedron_vertices[1]);
const unsigned int refinements = 2;
for (unsigned int current_refinement = 0; current_refinement < refinements; ++current_refinement) {
std::list<cgal_face_t> refined_face_list;
for (auto &face: face_list) {
Kernel_::Point_3 vertex0 = face.outer[0];
Kernel_::Point_3 vertex1 = face.outer[1];
Kernel_::Point_3 vertex2 = face.outer[2];
Kernel_::Point_3 midpoint01 = CGAL::midpoint(vertex0, vertex1);
Kernel_::Point_3 midpoint12 = CGAL::midpoint(vertex1, vertex2);
Kernel_::Point_3 midpoint20 = CGAL::midpoint(vertex2, vertex0);
double midpoint01_distance_to_origin = sqrt(CGAL::to_double(CGAL::squared_distance(midpoint01, Kernel_::Point_3(0, 0, 0))));
midpoint01 = Kernel_::Point_3(midpoint01.x()/midpoint01_distance_to_origin,
midpoint01.y()/midpoint01_distance_to_origin,
midpoint01.z()/midpoint01_distance_to_origin);
double midpoint12_distance_to_origin = sqrt(CGAL::to_double(CGAL::squared_distance(midpoint12, Kernel_::Point_3(0, 0, 0))));
midpoint12 = Kernel_::Point_3(midpoint12.x()/midpoint12_distance_to_origin,
midpoint12.y()/midpoint12_distance_to_origin,
midpoint12.z()/midpoint12_distance_to_origin);
double midpoint20_distance_to_origin = sqrt(CGAL::to_double(CGAL::squared_distance(midpoint20, Kernel_::Point_3(0, 0, 0))));
midpoint20 = Kernel_::Point_3(midpoint20.x()/midpoint20_distance_to_origin,
midpoint20.y()/midpoint20_distance_to_origin,
midpoint20.z()/midpoint20_distance_to_origin);
refined_face_list.push_back(cgal_face_t());
refined_face_list.back().outer.push_back(vertex0);
refined_face_list.back().outer.push_back(midpoint01);
refined_face_list.back().outer.push_back(midpoint20);
refined_face_list.push_back(cgal_face_t());
refined_face_list.back().outer.push_back(vertex1);
refined_face_list.back().outer.push_back(midpoint12);
refined_face_list.back().outer.push_back(midpoint01);
refined_face_list.push_back(cgal_face_t());
refined_face_list.back().outer.push_back(vertex2);
refined_face_list.back().outer.push_back(midpoint20);
refined_face_list.back().outer.push_back(midpoint12);
refined_face_list.push_back(cgal_face_t());
refined_face_list.back().outer.push_back(midpoint01);
refined_face_list.back().outer.push_back(midpoint12);
refined_face_list.back().outer.push_back(midpoint20);
} face_list = refined_face_list;
}
cgal_placement_t trsf;
IfcGeom::CgalKernel::convert(l->Position(),trsf);
shape = create_polyhedron(face_list);
for (auto &vertex: vertices(shape)) {
vertex->point() = Kernel_::Point_3(r*vertex->point().x(),
r*vertex->point().y(),
r*vertex->point().z());
vertex->point() = vertex->point().transform(trsf);
}
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangularPyramid* l, cgal_shape_t& 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);
std::list<cgal_face_t> face_list;
// Base
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, 0));
face_list.back().outer.push_back(Kernel_::Point_3(dx, 0, 0));
face_list.back().outer.push_back(Kernel_::Point_3(dx, dy, 0));
face_list.back().outer.push_back(Kernel_::Point_3(0, dy, 0));
// Lateral faces
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, 0));
face_list.back().outer.push_back(Kernel_::Point_3(0, dy, 0));
face_list.back().outer.push_back(Kernel_::Point_3(0.5*dx, 0.5*dy, dz));
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(Kernel_::Point_3(0, dy, 0));
face_list.back().outer.push_back(Kernel_::Point_3(dx, dy, 0));
face_list.back().outer.push_back(Kernel_::Point_3(0.5*dx, 0.5*dy, dz));
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(Kernel_::Point_3(dx, dy, 0));
face_list.back().outer.push_back(Kernel_::Point_3(dx, 0, 0));
face_list.back().outer.push_back(Kernel_::Point_3(0.5*dx, 0.5*dy, dz));
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(Kernel_::Point_3(dx, 0, 0));
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, 0));
face_list.back().outer.push_back(Kernel_::Point_3(0.5*dx, 0.5*dy, dz));
cgal_placement_t trsf;
IfcGeom::CgalKernel::convert(l->Position(),trsf);
shape = create_polyhedron(face_list);
for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf);
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, cgal_shape_t& shape) {
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
const double h = l->Height() * getValue(GV_LENGTH_UNIT);
std::list<cgal_face_t> face_list;
const int segments = 12;
// Base
face_list.push_back(cgal_face_t());
for (int current_segment = 0; current_segment < segments; ++current_segment) {
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
face_list.back().outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0));
}
// Side faces
for (int current_segment = 0; current_segment < segments; ++current_segment) {
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
int next_segment = (current_segment+1)%segments;
double next_angle = next_segment*2.0*3.141592653589793/((double)segments);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(Kernel_::Point_3(r*cos(next_angle), r*sin(next_angle), 0));
face_list.back().outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0));
face_list.back().outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), h));
face_list.back().outer.push_back(Kernel_::Point_3(r*cos(next_angle), r*sin(next_angle), h));
}
// Top
face_list.push_back(cgal_face_t());
for (int current_segment = segments-1; current_segment >= 0; --current_segment) {
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
face_list.back().outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), h));
}
cgal_placement_t trsf;
IfcGeom::CgalKernel::convert(l->Position(),trsf);
shape = create_polyhedron(face_list);
for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf);
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal_shape_t& shape) {
const double r = l->BottomRadius() * getValue(GV_LENGTH_UNIT);
const double h = l->Height() * getValue(GV_LENGTH_UNIT);
std::list<cgal_face_t> face_list;
const int segments = 12;
// Base
face_list.push_back(cgal_face_t());
for (int current_segment = 0; current_segment < segments; ++current_segment) {
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
face_list.back().outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0));
}
// Side faces
for (int current_segment = 0; current_segment < segments; ++current_segment) {
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
int next_segment = (current_segment+1)%segments;
double next_angle = next_segment*2.0*3.141592653589793/((double)segments);
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(Kernel_::Point_3(r*cos(next_angle), r*sin(next_angle), 0));
face_list.back().outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0));
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, h));
}
cgal_placement_t trsf;
IfcGeom::CgalKernel::convert(l->Position(),trsf);
shape = create_polyhedron(face_list);
for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf);
return true;
}
#ifdef USE_IFC4
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, cgal_shape_t& shape) {
IfcSchema::IfcCartesianPointList3D* point_list = l->Coordinates();
const std::vector< std::vector<double> > coordinates = point_list->CoordList();
std::vector<cgal_point_t> 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(Kernel_::Point_3(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::list<cgal_face_t> face_list;
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 > (int) points.size()) {
Logger::Message(Logger::LOG_ERROR, "Contents of CoordIndex out of bounds", l);
return false;
}
const Kernel_::Point_3& a = points[tri[0] - 1]; // account for zero- vs
const Kernel_::Point_3& b = points[tri[1] - 1]; // one-based indices in
const Kernel_::Point_3& c = points[tri[2] - 1]; // c++ and express
face_list.push_back(cgal_face_t());
face_list.back().outer.push_back(a);
face_list.back().outer.push_back(b);
face_list.back().outer.push_back(c);
}
shape = create_polyhedron(face_list);
return true;
}
#endif
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, cgal_shape_t& shape) {
IfcSchema::IfcSurface* surface = l->BaseSurface();
if ( ! surface->as<IfcSchema::IfcPlane>() ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface);
return false;
}
cgal_plane_t pln;
IfcGeom::CgalKernel::convert((IfcSchema::IfcPlane*)surface,pln);
// TODO: Don't fully understand the logic here. Might be incorrect.
if (l->AgreementFlag()) pln = pln.opposite();
// const gp_Pnt pnt = pln.Location().Translated( l->AgreementFlag() ? -pln.Axis().Direction() : pln.Axis().Direction());
// shape = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln),pnt).Solid();
// TODO: For now we do nothing and process halfspaces in IfcBooleanResult, which likely doesn't capture all cases.
// Find a better solution later (with an abstract shape class?)
shape = CGAL::Polyhedron_3<Kernel_>();
return true;
}
@@ -0,0 +1,166 @@
#include "CgalKernel.h"
#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h"
#define CgalKernel MAKE_TYPE_NAME(CgalKernel)
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, ConversionResults& 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 {
cgal_shape_t s;
if (convert_shape(representation_item, s)) {
shapes.push_back(ConversionResult(representation_item->data().id(), new CgalShape(s), get_style(representation_item)));
part_succes |= true;
}
}
}
}
return part_succes;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcGeometricSet* l, ConversionResults& shapes) {
IfcEntityList::ptr elements = l->Elements();
if ( !elements->size() ) return false;
bool part_succes = false;
const IfcGeom::SurfaceStyle* parent_style = get_style(l);
for ( IfcEntityList::it it = elements->begin(); it != elements->end(); ++ it ) {
IfcSchema::IfcGeometricSetSelect* element = *it;
cgal_shape_t s;
if (convert_shape(element, s)) {
part_succes = true;
const IfcGeom::SurfaceStyle* style = 0;
if (element->as<IfcSchema::IfcPoint>()) {
style = get_style((IfcSchema::IfcPoint*) element);
} else if (element->as<IfcSchema::IfcCurve>()) {
style = get_style((IfcSchema::IfcCurve*) element);
} else if (element->as<IfcSchema::IfcSurface>()) {
style = get_style((IfcSchema::IfcSurface*) element);
}
shapes.push_back(ConversionResult(element->data().id(), new CgalShape(s), style ? style : parent_style));
}
}
return part_succes;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, ConversionResults& shapes) {
IfcEntityList::ptr shells = l->SbsmBoundary();
const SurfaceStyle* collective_style = get_style(l);
for( IfcEntityList::it it = shells->begin(); it != shells->end(); ++ it ) {
cgal_shape_t s;
const SurfaceStyle* shell_style = 0;
if ((*it)->as<IfcSchema::IfcRepresentationItem>()) {
shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it);
}
if (convert_shape(*it,s)) {
shapes.push_back(ConversionResult((*it)->data().id(), new CgalShape(s), shell_style ? shell_style : collective_style));
}
}
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, ConversionResults& shape) {
cgal_shape_t s;
const SurfaceStyle* collective_style = get_style(l);
const SurfaceStyle* indiv_style = get_style(l->Outer());
if (convert_shape(l->Outer(),s) ) {
IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list);
if (l->as<IfcSchema::IfcFacetedBrepWithVoids>()) {
voids = l->as<IfcSchema::IfcFacetedBrepWithVoids>()->Voids();
}
#ifdef USE_IFC4
if (l->as<IfcSchema::IfcAdvancedBrepWithVoids>()) {
voids = l->as<IfcSchema::IfcAdvancedBrepWithVoids>()->Voids();
}
#endif
if (voids->size()) {
CGAL::Nef_polyhedron_3<Kernel_> nef_s = create_nef_polyhedron(s);
for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) {
cgal_shape_t s2;
if (convert_shape(*it, s2)) {
nef_s -= CGAL::Nef_polyhedron_3<Kernel_>(s2);
}
}
s = create_polyhedron(nef_s);
}
shape.push_back(ConversionResult(l->data().id(), new CgalShape(s), indiv_style ? indiv_style : collective_style));
return true;
}
return false;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionResults& shapes) {
cgal_placement_t gtrsf;
IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget();
if ( transform->as<IfcSchema::IfcCartesianTransformationOperator3DnonUniform>() ) {
IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf);
} else if ( transform->as<IfcSchema::IfcCartesianTransformationOperator2DnonUniform>() ) {
IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator2DnonUniform*)transform,gtrsf);
} else if ( transform->as<IfcSchema::IfcCartesianTransformationOperator3D>() ) {
IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,gtrsf);
} else if ( transform->as<IfcSchema::IfcCartesianTransformationOperator2D>() ) {
IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,gtrsf);
}
IfcSchema::IfcRepresentationMap* map = l->MappingSource();
IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin();
cgal_placement_t trsf;
if (placement->as<IfcSchema::IfcAxis2Placement3D>()) {
IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
} else {
cgal_placement_t trsf_2d;
IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf_2d);
trsf = trsf_2d;
}
// TODO: Check
gtrsf = trsf * gtrsf;
// std::cout << std::endl;
// for (int i = 0; i < 3; ++i) {
// for (int j = 0; j < 4; ++j) {
// std::cout << gtrsf.cartesian(i, j) << " ";
// } std::cout << std::endl;
// }
const IfcGeom::SurfaceStyle* mapped_item_style = get_style(l);
const size_t previous_size = shapes.size();
bool b = convert_shapes(map->MappedRepresentation(), shapes);
for (size_t i = previous_size; i < shapes.size(); ++ i ) {
IfcGeom::CgalPlacement place(gtrsf);
shapes[i].prepend(&place);
// 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::CgalKernel::convert(const IfcSchema::IfcFaceBasedSurfaceModel* l, ConversionResults& shapes) {
bool part_success = false;
IfcSchema::IfcConnectedFaceSet::list::ptr facesets = l->FbsmFaces();
const SurfaceStyle* collective_style = get_style(l);
for( IfcSchema::IfcConnectedFaceSet::list::it it = facesets->begin(); it != facesets->end(); ++ it ) {
cgal_shape_t s;
const SurfaceStyle* shell_style = get_style(*it);
if (convert_shape(*it,s)) {
shapes.push_back(ConversionResult((*it)->data().id(), new CgalShape(s), shell_style ? shell_style : collective_style));
part_success |= true;
}
}
return part_success;
}
@@ -0,0 +1,336 @@
// For MSVC to have M_PI
#define _USE_MATH_DEFINES
#include <cmath>
#include "CgalKernel.h"
#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h"
#define CgalKernel MAKE_TYPE_NAME(CgalKernel)
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& result) {
IfcSchema::IfcCartesianPoint::list::ptr points = l->Polygon();
// Parse and store the points in a sequence
cgal_wire_t polygon = std::vector<Kernel_::Point_3>();
for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) {
cgal_point_t pnt;
IfcGeom::CgalKernel::convert(*it, pnt);
polygon.push_back(pnt);
}
// A loop should consist of at least three vertices
std::size_t original_count = polygon.size();
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);
std::size_t count = polygon.size();
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;
}
result = polygon;
// std::cout << "PolyLoop: " << std::endl;
// for (auto &point: polygon) {
// std::cout << "\tPoint(" << point << ")" << std::endl;
// }
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyline* l, cgal_wire_t& result) {
IfcSchema::IfcCartesianPoint::list::ptr points = l->Points();
// Parse and store the points in a sequence
cgal_wire_t polygon = std::vector<Kernel_::Point_3>();
for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) {
cgal_point_t pnt;
IfcGeom::CgalKernel::convert(*it, pnt);
polygon.push_back(pnt);
}
// Remove points that are too close to one another
remove_duplicate_points_from_loop(polygon);
result = polygon;
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEdgeLoop* l, cgal_wire_t& result) {
IfcSchema::IfcOrientedEdge::list::ptr li = l->EdgeList();
cgal_wire_t mw;
for (IfcSchema::IfcOrientedEdge::list::it it = li->begin(); it != li->end(); ++it) {
cgal_wire_t w;
if (convert_wire(*it, w)) {
// TODO: What to do here? Add some points only?
// mw.Add(TopoDS::Edge(TopoDS_Iterator(w).Value()));
return false;
}
}
result = mw;
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcOrientedEdge* l, cgal_wire_t& result) {
if (convert_wire(l->EdgeElement(), result)) {
if (!l->Orientation()) {
std::reverse(result.begin(),result.end());
}
return true;
} else {
return false;
}
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEdge* l, cgal_wire_t& result) {
if (!l->EdgeStart()->as<IfcSchema::IfcVertexPoint>() || !l->EdgeEnd()->as<IfcSchema::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->as<IfcSchema::IfcCartesianPoint>() || !pnt2->as<IfcSchema::IfcCartesianPoint>()) {
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l);
return false;
}
cgal_point_t p1, p2;
if (!convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
!convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
{
return false;
}
cgal_wire_t mw;
mw.push_back(p1);
mw.push_back(p2);
result = mw;
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCompositeCurve* l, cgal_wire_t& 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
setValue(GV_PLANEANGLE_UNIT,1.0);
bool succes_radians = false;
bool succes_degrees = false;
bool use_radians = false;
bool use_degrees = false;
// First try radians
cgal_wire_t wire_radians, wire_degrees;
try {
succes_radians = IfcGeom::CgalKernel::convert(l,wire_radians);
} catch (...) {}
// Now try degrees
setValue(GV_PLANEANGLE_UNIT,0.0174532925199433);
try {
succes_degrees = IfcGeom::CgalKernel::convert(l,wire_degrees);
} catch (...) {}
// Restore to unknown unit state
setValue(GV_PLANEANGLE_UNIT,-1.0);
if ( succes_degrees && ! succes_radians ) {
use_degrees = true;
} else if ( succes_radians && ! succes_degrees ) {
use_radians = true;
} else if ( succes_radians && succes_degrees ) {
if ( wire_degrees.back() == wire_degrees.front() && wire_radians.back() != wire_radians.front() ) {
use_degrees = true;
} else if ( wire_radians.back() == wire_radians.front() && wire_degrees.back() != wire_degrees.front() ) {
use_radians = true;
} else {
// No heuristic left to prefer the one over the other,
// apparently both variants are equally succesful.
// The curve might be composed of only straight segments.
// Let's go with the wire created using radians as that
// at least is a SI unit.
use_radians = true;
}
}
if ( use_radians ) {
Logger::Message(Logger::LOG_NOTICE,"Used radians to create composite curve");
wire = wire_radians;
} else if ( use_degrees ) {
Logger::Message(Logger::LOG_NOTICE,"Used degrees to create composite curve");
wire = wire_degrees;
}
return use_radians || use_degrees;
}
IfcSchema::IfcCompositeCurveSegment::list::ptr segments = l->Segments();
cgal_wire_t w;
//TopoDS_Vertex last_vertex;
for( IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++ it ) {
IfcSchema::IfcCurve* curve = (*it)->ParentCurve();
cgal_wire_t wire2;
if ( !convert_wire(curve,wire2) ) {
Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve);
continue;
}
if ( ! (*it)->SameSense() ) std::reverse(wire2.begin(),wire2.end());
if (wire2.empty()) {
continue;
} else if (w.empty()) {
w = wire2;
} else if (w.back() == w.front()) {
std::vector<Kernel_::Point_3>::const_iterator vertex = wire2.begin();
++vertex;
while (vertex != wire2.end()) {
w.push_back(*vertex);
++vertex;
}
} else {
for (auto &vertex: wire2) w.push_back(vertex);
}
}
remove_duplicate_points_from_loop(w);
wire = w;
return true;
}
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrimmedCurve* l, cgal_wire_t& wire) {
IfcSchema::IfcCurve* basis_curve = l->BasisCurve();
bool isConic = basis_curve->as<IfcSchema::IfcConic>();
double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT);
cgal_curve_t curve;
if ( !convert_curve(basis_curve,curve) ) return false;
bool trim_cartesian = l->MasterRepresentation() == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN;
IfcEntityList::ptr trims1 = l->Trim1();
IfcEntityList::ptr trims2 = l->Trim2();
unsigned sense_agreement = l->SenseAgreement() ? 0 : 1;
double flts[2];
cgal_point_t pnts[2];
bool has_flts[2] = {false,false};
bool has_pnts[2] = {false,false};
cgal_wire_t w;
for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) {
IfcUtil::IfcBaseClass* i = *it;
if ( i->as<IfcSchema::IfcCartesianPoint>() ) {
IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] );
has_pnts[sense_agreement] = true;
} else if ( i->as<IfcSchema::IfcParameterValue>() ) {
const double value = *((IfcSchema::IfcParameterValue*)i);
flts[sense_agreement] = value * parameterFactor;
has_flts[sense_agreement] = true;
}
}
for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) {
IfcUtil::IfcBaseClass* i = *it;
if ( i->as<IfcSchema::IfcCartesianPoint>() ) {
IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] );
has_pnts[1-sense_agreement] = true;
} else if ( i->as<IfcSchema::IfcParameterValue>() ) {
const double value = *((IfcSchema::IfcParameterValue*)i);
flts[1-sense_agreement] = value * parameterFactor;
has_flts[1-sense_agreement] = true;
}
}
trim_cartesian &= has_pnts[0] && has_pnts[1];
bool trim_cartesian_failed = !trim_cartesian;
if ( trim_cartesian ) {
// TODO: Project points to closest point in curve?
if ( CGAL::squared_distance(pnts[0], pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE) ) {
Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l);
return false;
}
if (l->SenseAgreement()) {
bool found = false;
int loops_to_go = 2;
std::vector<Kernel_::Point_3>::const_iterator point = curve.begin();
do {
if (!found) {
if (CGAL::squared_distance(*point, pnts[0]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) {
found = true;
w.push_back(*point);
}
} else {
w.push_back(*point);
if (CGAL::squared_distance(*point, pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) {
break;
}
} ++point;
if (point == curve.end()) {
point = curve.begin();
--loops_to_go;
}
} while (point != curve.begin() && loops_to_go > 0);
} else {
bool found = false;
int loops_to_go = 2;
std::vector<Kernel_::Point_3>::const_reverse_iterator point = curve.rbegin();
do {
if (!found) {
if (CGAL::squared_distance(*point, pnts[0]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) {
found = true;
w.push_back(*point);
}
} else {
w.push_back(*point);
if (CGAL::squared_distance(*point, pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) {
break;
}
} ++point;
if (point == curve.rend() && loops_to_go > 0) point = curve.rbegin();
} while (point != curve.rbegin());
}
}
if ( (!trim_cartesian || trim_cartesian_failed) && (has_flts[0] && has_flts[1]) ) {
// The Geom_Line is constructed from a gp_Pnt and gp_Dir, whereas the IfcLine
// is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because
// the vector is normalised when passed to Geom_Line constructor the magnitude
// needs to be factored in with the IfcParameterValue here.
if ( basis_curve->as<IfcSchema::IfcLine>() ) {
IfcSchema::IfcLine* line = static_cast<IfcSchema::IfcLine*>(basis_curve);
const double magnitude = line->Dir()->Magnitude();
flts[0] *= magnitude; flts[1] *= magnitude;
}
if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],M_PI*2.),0.) ) {
for (auto &point: curve) w.push_back(point);
} else {
const int segments_of_full_curve = 12;
double segment_angle = 2.0*3.141592653589793/segments_of_full_curve;
if ( basis_curve->as<IfcSchema::IfcEllipse>() ) {
IfcSchema::IfcEllipse* ellipse = static_cast<IfcSchema::IfcEllipse*>(basis_curve);
double x = ellipse->SemiAxis1() * getValue(GV_LENGTH_UNIT);
double y = ellipse->SemiAxis2() * getValue(GV_LENGTH_UNIT);
for (double current_angle = flts[0]; current_angle < flts[1]; current_angle += segment_angle) {
w.push_back(Kernel_::Point_3(x*cos(current_angle), y*sin(current_angle), 0));
} w.push_back(Kernel_::Point_3(x*cos(flts[1]), y*sin(flts[1]), 0));
} if ( basis_curve->as<IfcSchema::IfcCircle>() ) {
IfcSchema::IfcCircle* circle = static_cast<IfcSchema::IfcCircle*>(basis_curve);
double r = circle->Radius() * getValue(GV_LENGTH_UNIT);
for (double current_angle = flts[0]; current_angle < flts[1]; current_angle += segment_angle) {
w.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0));
} w.push_back(Kernel_::Point_3(r*cos(flts[1]), r*sin(flts[1]), 0));
}
}
} else if ( trim_cartesian_failed && (has_pnts[0] && has_pnts[1]) ) {
w.push_back(pnts[0]);
w.push_back(pnts[1]);
}
wire = w;
return true;
}
+686
View File
@@ -0,0 +1,686 @@
/********************************************************************************
* *
* 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 "CgalKernel.h"
#include "../../../ifcparse/IfcLogger.h"
#include "../../../ifcgeom/kernels/cgal/CgalConversionResult.h"
#include <CGAL/minkowski_sum_3.h>
using namespace ifcopenshell::geometry;
using namespace ifcopenshell::geometry::kernels;
void CgalKernel::remove_duplicate_points_from_loop(cgal_wire_t& polygon) {
std::set<cgal_point_t> points;
for (int i = 0; i < polygon.size(); ++i) {
if (points.count(polygon[i])) {
polygon.erase(polygon.begin() + i);
--i;
} else points.insert(polygon[i]);
}
}
CGAL::Polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_polyhedron(std::list<cgal_face_t> &face_list) {
// Naive creation
CGAL::Polyhedron_3<Kernel_> polyhedron;
PolyhedronBuilder builder(&face_list);
polyhedron.delegate(builder);
// Stitch edges
// std::cout << "Before: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl;
CGAL::Polygon_mesh_processing::stitch_borders(polyhedron);
if (!polyhedron.is_valid()) {
Logger::Message(Logger::LOG_ERROR, "create_polyhedron: Polyhedron not valid!");
// std::ofstream fresult;
// fresult.open("/Users/ken/Desktop/invalid.off");
// fresult << polyhedron << std::endl;
// fresult.close();
return CGAL::Polyhedron_3<Kernel_>();
} if (polyhedron.is_closed()) {
if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) {
CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron);
}
}
// std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl;
return polyhedron;
}
CGAL::Polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_polyhedron(const CGAL::Nef_polyhedron_3<Kernel_>& nef_polyhedron) {
if (nef_polyhedron.is_simple()) {
try {
CGAL::Polyhedron_3<Kernel_> polyhedron;
nef_polyhedron.convert_to_polyhedron(polyhedron);
return polyhedron;
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Conversion from Nef to polyhedron failed!");
return CGAL::Polyhedron_3<Kernel_>();
}
} else {
Logger::Message(Logger::LOG_ERROR, "Nef polyhedron not simple: cannot create polyhedron!");
return CGAL::Polyhedron_3<Kernel_>();
}
}
CGAL::Nef_polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_nef_polyhedron(std::list<cgal_face_t> &face_list) {
CGAL::Polyhedron_3<Kernel_> polyhedron = create_polyhedron(face_list);
CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron);
CGAL::Nef_polyhedron_3<Kernel_> nef_polyhedron;
try {
nef_polyhedron = CGAL::Nef_polyhedron_3<Kernel_>(polyhedron);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef polyhedron failed!");
}
return nef_polyhedron;
}
CGAL::Nef_polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_nef_polyhedron(CGAL::Polyhedron_3<Kernel_> &polyhedron) {
if (polyhedron.is_valid() && polyhedron.is_closed()) {
// @todo is it necessary to triangulat?
CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron);
CGAL::Nef_polyhedron_3<Kernel_> nef_polyhedron;
try {
nef_polyhedron = CGAL::Nef_polyhedron_3<Kernel_>(polyhedron);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef polyhedron failed!");
}
return nef_polyhedron;
} else {
Logger::Message(Logger::LOG_ERROR, "Polyhedron not valid: cannot create Nef polyhedron!");
return CGAL::Nef_polyhedron_3<Kernel_>();
}
}
bool CgalKernel::convert(const taxonomy::shell* l, cgal_shape_t& shape) {
auto faces = l->children_as<taxonomy::face>();
std::list<cgal_face_t> face_list;
for (auto& f : faces) {
bool success = false;
cgal_face_t face;
try {
success = convert(f, face);
} catch (...) {}
if (!success) {
Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", f->instance);
continue;
}
// std::cout << "Face in ConnectedFaceSet: " << std::endl;
// for (auto &point: face.outer) {
// std::cout << "\tPoint(" << point << ")" << std::endl;
// }
face_list.push_back(face);
}
shape = utils::create_polyhedron(face_list);
return true;
}
bool CgalKernel::convert(const taxonomy::face* face, cgal_face_t& result) {
auto bounds = face->children_as<taxonomy::loop>();
int num_outer_bounds = 0;
for (auto& bound : bounds) {
if (bound->external.get_value_or(false)) num_outer_bounds++;
}
if (num_outer_bounds != 1) {
Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", face->instance);
return false;
}
cgal_face_t mf;
for (auto& bound : bounds) {
const bool is_interior = !bound->external.get_value_or(false);
cgal_wire_t wire;
if (!convert(bound, wire)) {
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", bound->instance);
return false;
}
if (!is_interior) {
mf.outer = wire;
} else {
mf.inner.push_back(wire);
}
}
result = mf;
// std::cout << "Face: " << std::endl;
// for (auto &point: face.outer) {
// std::cout << "\tPoint(" << point << ")" << std::endl;
// }
return true;
}
namespace {
bool convert_curve(CgalKernel* kernel, const taxonomy::item* curve, cgal_wire_t& builder) {
if (curve->kind() == taxonomy::EDGE) {
auto e = (taxonomy::edge*) curve;
if (true || e->basis == nullptr) {
if (builder.empty()) {
const auto& p = boost::get<taxonomy::point3>(e->start);
cgal_point_t pnt(p.components(0), p.components(1), p.components(2));
builder.push_back(pnt);
}
const auto& p = boost::get<taxonomy::point3>(e->end);
cgal_point_t pnt(p.components(0), p.components(1), p.components(2));
builder.push_back(pnt);
} else if (e->basis->kind() == taxonomy::CIRCLE) {
// @todo
} else if (e->basis->kind() == taxonomy::ELLIPSE) {
} else {
throw std::runtime_error("Not implemented basis kind");
}
} else if (curve->kind() == taxonomy::LOOP) {
const auto& edges = ((taxonomy::loop*) curve)->children;
for (auto& c : edges) {
convert_curve(kernel, c, builder);
}
} else {
throw std::runtime_error("Not implemented curve");
}
}
}
bool CgalKernel::convert(const taxonomy::loop* loop, cgal_wire_t& result) {
// @todo only implement polygonal loops
auto edges = loop->children_as<taxonomy::edge>();
std::vector<taxonomy::point3> points;
for (auto& e : edges) {
if (e->basis) {
Logger::Error("Only polyhedra supported :(");
return false;
}
points.push_back(boost::get<taxonomy::point3>(e->start));
}
// Parse and store the points in a sequence
cgal_wire_t polygon = std::vector<Kernel_::Point_3>();
for (auto& p : points) {
cgal_point_t pnt(p.components(0), p.components(1), p.components(2));
polygon.push_back(pnt);
}
// A loop should consist of at least three vertices
std::size_t original_count = polygon.size();
if (original_count < 3) {
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", loop->instance);
return false;
}
// Remove points that are too close to one another
remove_duplicate_points_from_loop(polygon);
std::size_t count = polygon.size();
if (original_count - count != 0) {
std::stringstream ss; ss << (original_count - count) << " edges removed for:";
Logger::Message(Logger::LOG_WARNING, ss.str(), loop->instance);
}
if (count < 3) {
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", loop->instance);
return false;
}
result = polygon;
// std::cout << "PolyLoop: " << std::endl;
// for (auto &point: polygon) {
// std::cout << "\tPoint(" << point << ")" << std::endl;
// }
return true;
}
bool CgalKernel::convert_impl(const taxonomy::shell *shell, ifcopenshell::geometry::ConversionResults& results) {
cgal_shape_t shape;
if (!convert(shell, shape)) {
return false;
}
results.emplace_back(ConversionResult(
shell->instance->data().id(),
shell->matrix,
new CgalShape(shape),
shell->surface_style
));
return true;
}
bool CgalKernel::convert_impl(const taxonomy::extrusion* extrusion, ifcopenshell::geometry::ConversionResults& results) {
cgal_shape_t shape;
if (!convert(extrusion, shape)) {
return false;
}
results.emplace_back(ConversionResult(
extrusion->instance->data().id(),
extrusion->matrix,
new CgalShape(shape),
extrusion->surface_style
));
return true;
}
bool CgalKernel::convert(const taxonomy::extrusion* extrusion, cgal_shape_t &shape) {
const double& height = extrusion->depth;
if (height < precision_) {
Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", extrusion->instance);
return false;
}
// Outer
cgal_face_t bottom_face;
if (!convert(&extrusion->basis, bottom_face)) {
return false;
}
// std::cout << "Face vertices: " << face.outer.size() << std::endl;
auto fs = extrusion->direction.components;
cgal_direction_t dir(fs(0), fs(1), fs(2));
// std::cout << "Direction: " << dir << std::endl;
std::list<cgal_face_t> face_list;
face_list.push_back(bottom_face);
for (std::vector<Kernel_::Point_3>::const_iterator current_vertex = bottom_face.outer.begin();
current_vertex != bottom_face.outer.end();
++current_vertex) {
std::vector<Kernel_::Point_3>::const_iterator next_vertex = current_vertex;
++next_vertex;
if (next_vertex == bottom_face.outer.end()) {
next_vertex = bottom_face.outer.begin();
} cgal_face_t side_face;
side_face.outer.push_back(*next_vertex);
side_face.outer.push_back(*current_vertex);
side_face.outer.push_back(*current_vertex + height * dir);
side_face.outer.push_back(*next_vertex + height * dir);
face_list.push_back(side_face);
}
cgal_face_t top_face;
for (std::vector<Kernel_::Point_3>::const_reverse_iterator vertex = bottom_face.outer.rbegin();
vertex != bottom_face.outer.rend();
++vertex) {
top_face.outer.push_back(*vertex + height * dir);
} face_list.push_back(top_face);
if (bottom_face.inner.empty()) {
shape = utils::create_polyhedron(face_list);
// if (has_position) for (auto &vertex : vertices(shape)) vertex->point() = vertex->point().transform(trsf);
return true;
}
CGAL::Nef_polyhedron_3<Kernel_> nef_shape = utils::create_nef_polyhedron(face_list);
// Inner
// TODO: Would be faster to triangulate top/bottom face template rather than use Nef polyhedra for subtraction
for (auto &inner : bottom_face.inner) {
// std::cout << "Inner wire" << std::endl;
face_list.clear();
cgal_face_t hole_bottom_face;
hole_bottom_face.outer = inner;
remove_duplicate_points_from_loop(hole_bottom_face.outer);
face_list.push_back(hole_bottom_face);
for (std::vector<Kernel_::Point_3>::const_iterator current_vertex = inner.begin();
current_vertex != inner.end();
++current_vertex) {
std::vector<Kernel_::Point_3>::const_iterator next_vertex = current_vertex;
++next_vertex;
if (next_vertex == inner.end()) {
next_vertex = inner.begin();
} cgal_face_t hole_side_face;
hole_side_face.outer.push_back(*next_vertex);
hole_side_face.outer.push_back(*current_vertex);
hole_side_face.outer.push_back(*current_vertex + height * dir);
hole_side_face.outer.push_back(*next_vertex + height * dir);
face_list.push_back(hole_side_face);
}
cgal_face_t hole_top_face;
for (std::vector<Kernel_::Point_3>::const_reverse_iterator vertex = inner.rbegin();
vertex != inner.rend();
++vertex) {
hole_top_face.outer.push_back(*vertex + height * dir);
} face_list.push_back(hole_top_face);
try {
nef_shape -= utils::create_nef_polyhedron(face_list);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot subtract opening for:", extrusion->instance);
return false;
}
}
/*if (has_position) {
// IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D
// and therefore has a unit scale factor
nef_shape.transform(trsf);
}*/
try {
nef_shape.convert_to_polyhedron(shape);
return true;
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot convert Nef to polyhedron for:", extrusion->instance);
return false;
}
}
CGAL::Polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_cube(double d) {
cgal_face_t bottom_face;
bottom_face.outer.push_back(Kernel_::Point_3(-d, -d, -d));
bottom_face.outer.push_back(Kernel_::Point_3(+d, -d, -d));
bottom_face.outer.push_back(Kernel_::Point_3(+d, +d, -d));
bottom_face.outer.push_back(Kernel_::Point_3(-d, +d, -d));
cgal_direction_t dir(0, 0, 2 * d);
std::list<cgal_face_t> face_list = { bottom_face };
for (std::vector<Kernel_::Point_3>::const_iterator current_vertex = bottom_face.outer.begin();
current_vertex != bottom_face.outer.end();
++current_vertex)
{
std::vector<Kernel_::Point_3>::const_iterator next_vertex = current_vertex;
++next_vertex;
if (next_vertex == bottom_face.outer.end()) {
next_vertex = bottom_face.outer.begin();
}
cgal_face_t side_face;
side_face.outer.push_back(*next_vertex);
side_face.outer.push_back(*current_vertex);
side_face.outer.push_back(*current_vertex + dir);
side_face.outer.push_back(*next_vertex + dir);
face_list.push_back(side_face);
}
cgal_face_t top_face;
for (std::vector<Kernel_::Point_3>::const_reverse_iterator vertex = bottom_face.outer.rbegin();
vertex != bottom_face.outer.rend();
++vertex)
{
top_face.outer.push_back(*vertex + dir);
}
face_list.push_back(top_face);
return create_polyhedron(face_list);
}
CGAL::Polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_cube(const Kernel_::Point_3& lower, const Kernel_::Point_3& upper) {
cgal_face_t bottom_face;
auto& a0 = lower.cartesian(0);
auto& a1 = lower.cartesian(1);
auto& a2 = lower.cartesian(2);
auto& b0 = upper.cartesian(0);
auto& b1 = upper.cartesian(1);
auto& b2 = upper.cartesian(2);
bottom_face.outer.push_back(Kernel_::Point_3(a0, a1, a2));
bottom_face.outer.push_back(Kernel_::Point_3(b0, a1, a2));
bottom_face.outer.push_back(Kernel_::Point_3(b0, b1, a2));
bottom_face.outer.push_back(Kernel_::Point_3(a0, b1, a2));
cgal_direction_t dir(0, 0, b2 - a2);
std::list<cgal_face_t> face_list = { bottom_face };
for (std::vector<Kernel_::Point_3>::const_iterator current_vertex = bottom_face.outer.begin();
current_vertex != bottom_face.outer.end();
++current_vertex)
{
std::vector<Kernel_::Point_3>::const_iterator next_vertex = current_vertex;
++next_vertex;
if (next_vertex == bottom_face.outer.end()) {
next_vertex = bottom_face.outer.begin();
}
cgal_face_t side_face;
side_face.outer.push_back(*next_vertex);
side_face.outer.push_back(*current_vertex);
side_face.outer.push_back(*current_vertex + dir);
side_face.outer.push_back(*next_vertex + dir);
face_list.push_back(side_face);
}
cgal_face_t top_face;
for (std::vector<Kernel_::Point_3>::const_reverse_iterator vertex = bottom_face.outer.rbegin();
vertex != bottom_face.outer.rend();
++vertex)
{
top_face.outer.push_back(*vertex + dir);
}
face_list.push_back(top_face);
return create_polyhedron(face_list);
}
bool CgalKernel::thin_solid(const CGAL::Nef_polyhedron_3<Kernel_>& a, CGAL::Nef_polyhedron_3<Kernel_>& result) {
// @todo this should be possible as a minkowski sum of facet & cube. rather than a set of boolean ops.
auto a_nonconst = a;
auto ax = CGAL::minkowski_sum_3(a_nonconst, precision_cube_);
auto x = ax - a;
result = x;
return true;
auto yxy = CGAL::minkowski_sum_3(x, precision_cube_);
auto y = yxy * a;
auto zyz = CGAL::minkowski_sum_3(y, precision_cube_);
result = yxy * zyz;
return true;
}
bool CgalKernel::preprocess_boolean_operand(const IfcUtil::IfcBaseClass* log_reference, const cgal_shape_t& shape_const, CGAL::Nef_polyhedron_3<Kernel_>& result, bool dilate) {
cgal_shape_t shape = shape_const;
if (!shape.is_valid()) {
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Invalid geometry:", log_reference);
return false;
}
if (!shape.is_closed()) {
// TODO: There can be substractions to remove parts of non-volumetric objects. Maybe iterate over all faces of an entity and put them in a Nef_polyhedron_3 through Boolean union? Highly inefficient but maybe desirable...
Logger::Message(Logger::LOG_ERROR, "Subtraction of openings not supported for non-closed geometry:", log_reference);
return false;
}
bool success = false;
try {
success = CGAL::Polygon_mesh_processing::triangulate_faces(shape);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Triangulation of geometry crashed:", log_reference);
return false;
}
if (!success) {
Logger::Message(Logger::LOG_ERROR, "Triangulation of geometry failed:", log_reference);
return false;
}
if (CGAL::Polygon_mesh_processing::does_self_intersect(shape)) {
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Self-intersecting geometry:", log_reference);
return false;
}
try {
result = CGAL::Nef_polyhedron_3<Kernel_>(shape);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Could not convert geometry to Nef:", log_reference);
return false;
}
if (dilate) {
try {
// @todo don't dilate in 3 dimensions but only in the XY plane, orthogonal to wall axis.
result = CGAL::minkowski_sum_3(result, precision_cube_);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Could not dilate boolean operand", log_reference);
return false;
}
}
try {
cgal_shape_t convert_back;
result.convert_to_polyhedron(convert_back);
} catch (...) {
Logger::Message(Logger::LOG_WARNING, "Final conversion will likely fail. Could not convert geometry from Nef:", log_reference);
}
return true;
}
namespace {
bool convert_placement(const ifcopenshell::geometry::taxonomy::matrix4& place, cgal_placement_t& trsf) {
const auto& m = place.components;
// @todo check
trsf = cgal_placement_t(
m(0, 0), m(0, 1), m(0, 2), m(0, 3),
m(1, 0), m(1, 1), m(1, 2), m(1, 3),
m(2, 0), m(2, 1), m(2, 2), m(2, 3));
return true;
}
}
bool CgalKernel::convert_impl(const taxonomy::boolean_result* br, ifcopenshell::geometry::ConversionResults& results) {
bool first = true;
CGAL::Nef_polyhedron_3<Kernel_> a;
taxonomy::style first_item_style;
for (auto& c : br->children) {
// AbstractKernel::convert(c, results);
// continue;
ifcopenshell::geometry::ConversionResults cr;
// @todo half-space detection
AbstractKernel::convert(c, cr);
if (first && br->operation == taxonomy::boolean_result::SUBTRACTION) {
first_item_style = ((taxonomy::geom_item*)c)->surface_style;
if (!first_item_style.diffuse && c->kind() == taxonomy::COLLECTION) {
first_item_style = ((taxonomy::geom_item*) ((taxonomy::collection*)c)->children[0])->surface_style;
}
}
for (auto it = cr.begin(); it != cr.end(); ++it) {
const cgal_shape_t& entity_shape_unlocated(((CgalShape*)it->Shape())->shape());
cgal_shape_t entity_shape(entity_shape_unlocated);
if (!it->Placement().components.isIdentity()) {
cgal_placement_t trsf;
convert_placement(it->Placement(), trsf);
for (auto &vertex : vertices(entity_shape)) {
if (false) {
auto x = CGAL::to_double(vertex->point().x());
auto y = CGAL::to_double(vertex->point().y());
auto z = CGAL::to_double(vertex->point().z());
std::wcout << x << " " << y << " " << z << std::endl;
}
vertex->point() = vertex->point().transform(trsf);
if (false) {
auto x = CGAL::to_double(vertex->point().x());
auto y = CGAL::to_double(vertex->point().y());
auto z = CGAL::to_double(vertex->point().z());
std::wcout << x << " " << y << " " << z << std::endl;
}
}
}
CGAL::Nef_polyhedron_3<Kernel_> nef;
preprocess_boolean_operand(c->instance, entity_shape, nef,
// Dilate boolean subtraction operands
(!first && br->operation == taxonomy::boolean_result::SUBTRACTION));
if (first) {
a = nef;
} else {
if (br->operation == taxonomy::boolean_result::SUBTRACTION) {
a -= nef;
} else if (br->operation == taxonomy::boolean_result::INTERSECTION) {
a *= nef;
} else if (br->operation == taxonomy::boolean_result::UNION) {
a += nef;
}
}
}
first = false;
}
cgal_shape_t a_poly, b_poly;
// CGAL::Nef_polyhedron_3<Kernel_> b;
// thin_solid(a, b);
try {
a.convert_to_polyhedron(a_poly);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Could not convert geometry with openings from Nef:", br->instance);
return false;
}
results.emplace_back(ConversionResult(
br->instance->data().id(),
br->matrix,
new CgalShape(a_poly),
br->surface_style.diffuse ? br->surface_style : first_item_style
));
return true;
}
+267
View File
@@ -0,0 +1,267 @@
/********************************************************************************
* *
* 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 "CgalKernel.h"
namespace {
struct MAKE_TYPE_NAME(factory_t) {
IfcGeom::Kernel* operator()(IfcParse::IfcFile* file) const {
IfcGeom::MAKE_TYPE_NAME(CgalKernel)* k = new IfcGeom::MAKE_TYPE_NAME(CgalKernel);
return k;
}
};
}
void MAKE_INIT_FN(KernelImplementation_cgal_)(IfcGeom::impl::KernelFactoryImplementation* mapping) {
static const std::string schema_name = STRINGIFY(IfcSchema);
MAKE_TYPE_NAME(factory_t) factory;
mapping->bind(schema_name, "cgal", factory);
}
#define CgalKernel MAKE_TYPE_NAME(CgalKernel)
bool IfcGeom::CgalKernel::is_identity_transform(const IfcUtil::IfcBaseClass* l) {
Logger::Message(Logger::LOG_ERROR, "Not implemented is_identity_transform()");
return false;
/*
// OpenCascade kernel code below
IfcSchema::IfcAxis2Placement2D* ax2d;
IfcSchema::IfcAxis2Placement3D* ax3d;
IfcSchema::IfcCartesianTransformationOperator2D* op2d;
IfcSchema::IfcCartesianTransformationOperator3D* op3d;
IfcSchema::IfcCartesianTransformationOperator2DnonUniform* op2dnonu;
IfcSchema::IfcCartesianTransformationOperator3DnonUniform* op3dnonu;
if ((op2dnonu = l->as<IfcSchema::IfcCartesianTransformationOperator2DnonUniform>()) != 0) {
gp_GTrsf2d gtrsf2d;
convert(op2dnonu, gtrsf2d);
return gtrsf2d.Form() == gp_Identity;
} else if ((op2d = l->as<IfcSchema::IfcCartesianTransformationOperator2D>()) != 0) {
gp_Trsf2d trsf2d;
convert(op2d, trsf2d);
return trsf2d.Form() == gp_Identity;
} else if ((op3dnonu = l->as<IfcSchema::IfcCartesianTransformationOperator3DnonUniform>()) != 0) {
gp_GTrsf gtrsf;
convert(op3dnonu, gtrsf);
return gtrsf.Form() == gp_Identity;
} else if ((op3d = l->as<IfcSchema::IfcCartesianTransformationOperator3D>()) != 0) {
gp_Trsf trsf;
convert(op3d, trsf);
return trsf.Form() == gp_Identity;
} else if ((ax2d = l->as<IfcSchema::IfcAxis2Placement2D>()) != 0) {
gp_Trsf2d trsf2d;
convert(ax2d, trsf2d);
return trsf2d.Form() == gp_Identity;
} else if ((ax3d = l->as<IfcSchema::IfcAxis2Placement3D>()) != 0) {
gp_Trsf trsf;
convert(ax3d, trsf);
return trsf.Form() == gp_Identity;
} else {
throw IfcParse::IfcException("Invalid valuation for IfcAxis2Placement / IfcCartesianTransformationOperator");
}
*/
}
bool IfcGeom::CgalKernel::apply_layerset(const IfcSchema::IfcProduct* product, IfcGeom::ConversionResults& shapes) {
throw std::runtime_error("not implemented");
}
bool IfcGeom::CgalKernel::validate_quantities(const IfcSchema::IfcProduct* product, const IfcGeom::Representation::BRep& brep) {
throw std::runtime_error("not implemented");
}
bool IfcGeom::CgalKernel::convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf) {
if (item->as<IfcSchema::IfcObjectPlacement>()) {
cgal_placement_t cgal_trsf;
if (convert(item->as<IfcSchema::IfcObjectPlacement>(), cgal_trsf)) {
trsf = new CgalPlacement(cgal_trsf);
return true;
}
}
return false;
}
bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* product, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcGeom::ConversionResults& entity_shapes, const IfcGeom::ConversionResultPlacement* trsf, IfcGeom::ConversionResults& opened_shapes) {
const cgal_placement_t& entity_trsf = ((CgalPlacement*) trsf)->trsf();
std::list<cgal_shape_t> opening_shapelist;
for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) {
IfcSchema::IfcRelVoidsElement* v = *it;
IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement();
if ( fes->as<IfcSchema::IfcOpeningElement>() ) {
if (!fes->hasRepresentation()) continue;
// Convert the IfcRepresentation of the IfcOpeningElement
cgal_placement_t opening_trsf;
if (fes->hasObjectPlacement()) {
try {
convert(fes->ObjectPlacement(),opening_trsf);
} catch (...) {}
}
// Move the opening into the coordinate system of the IfcProduct
opening_trsf = entity_trsf.inverse() * opening_trsf;
IfcSchema::IfcProductRepresentation* prodrep = fes->Representation();
IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations();
IfcGeom::ConversionResults opening_shapes;
for ( IfcSchema::IfcRepresentation::list::it it2 = reps->begin(); it2 != reps->end(); ++ it2 ) {
convert_shapes(*it2,opening_shapes);
}
for ( unsigned int i = 0; i < opening_shapes.size(); ++ i ) {
cgal_placement_t gtrsf;
if (opening_shapes[i].Placement()) {
gtrsf = *(CgalPlacement*)opening_shapes[i].Placement();
}
gtrsf = opening_trsf * gtrsf;
cgal_shape_t opening_shape(((CgalShape*)opening_shapes[i].Shape())->shape());
for (auto &vertex: vertices(opening_shape)) vertex->point() = vertex->point().transform(gtrsf);
opening_shapelist.push_back(opening_shape);
}
}
}
// Iterate over the shapes of the IfcProduct
for ( IfcGeom::ConversionResults::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) {
const cgal_shape_t& entity_shape_unlocated(((CgalShape*)it3->Shape())->shape());
cgal_shape_t entity_shape(entity_shape_unlocated);
if (it3->Placement()) {
const cgal_placement_t& entity_shape_gtrsf = *(CgalPlacement*)it3->Placement();
for (auto &vertex: vertices(entity_shape)) vertex->point() = vertex->point().transform(entity_shape_gtrsf);
}
cgal_shape_t original_entity_shape(entity_shape);
if (!entity_shape.is_valid()) {
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Invalid geometry:", product);
return false;
}
if (!entity_shape.is_closed()) {
// TODO: There can be substractions to remove parts of non-volumetric objects. Maybe iterate over all faces of an entity and put them in a Nef_polyhedron_3 through Boolean union? Highly inefficient but maybe desirable...
Logger::Message(Logger::LOG_ERROR, "Subtraction of openings not supported for non-closed geometry:", product);
return false;
}
bool success = false;
try {
success = CGAL::Polygon_mesh_processing::triangulate_faces(entity_shape);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Triangulation of geometry crashed:", product);
return false;
}
if (!success) {
Logger::Message(Logger::LOG_ERROR, "Triangulation of geometry failed:", product);
return false;
}
if (CGAL::Polygon_mesh_processing::does_self_intersect(entity_shape)) {
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Self-intersecting geometry:", product);
return false;
}
CGAL::Nef_polyhedron_3<Kernel_> nef_brep_cut_result;
try {
nef_brep_cut_result = CGAL::Nef_polyhedron_3<Kernel_>(entity_shape);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Could not convert geometry to Nef:", product);
return false;
}
try {
cgal_shape_t brep_cut_result;
nef_brep_cut_result.convert_to_polyhedron(brep_cut_result);
} catch (...) {
Logger::Message(Logger::LOG_WARNING, "Final conversion will likely fail. Could not convert geometry from Nef:", product);
}
for (auto &opening: opening_shapelist) {
cgal_shape_t original_opening_shape(opening);
if (!opening.is_valid()) {
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Invalid opening in geometry:", product);
return false;
} if (!opening.is_closed()) {
Logger::Message(Logger::LOG_ERROR, "Subtraction of opening makes no sense. Not closed opening in geometry:", product);
return false;
}
success = false;
try {
success = CGAL::Polygon_mesh_processing::triangulate_faces(opening);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Triangulation of opening of geometry crashed:", product);
return false;
}
if (!success) {
Logger::Message(Logger::LOG_ERROR, "Triangulation of opening of geometry failed:", product);
return false;
}
if (CGAL::Polygon_mesh_processing::does_self_intersect(entity_shape)) {
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Self-intersecting opening of geometry:", product);
}
CGAL::Nef_polyhedron_3<Kernel_> nef_opening;
try {
nef_opening = CGAL::Nef_polyhedron_3<Kernel_>(opening);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Could not convert opening of geometry to Nef:", product);
return false;
}
try {
cgal_shape_t opening_shape;
nef_opening.convert_to_polyhedron(opening_shape);
} catch (...) {
Logger::Message(Logger::LOG_WARNING, "Final conversion will likely fail. Could not convert opening of geometry from Nef:", product);
// return false;
}
try {
nef_brep_cut_result -= nef_opening;
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Could not subtract Nef opening of geometry:", product);
return false;
}
}
try {
nef_brep_cut_result.convert_to_polyhedron(entity_shape);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Could not convert geometry with openings from Nef:", product);
return false;
}
opened_shapes.push_back(IfcGeom::ConversionResult(it3->ItemId(), new CgalShape(entity_shape), &it3->Style()));
} return true;
}
+142
View File
@@ -0,0 +1,142 @@
/********************************************************************************
* *
* 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 CGAL_KERNEL_H
#define CGAL_KERNEL_H
/*
#ifdef NO_CACHE
#define IN_CACHE(T,E,t,e)
#define CACHE(T,E,e)
#else
#define IN_CACHE(T,E,t,e) std::map<int,t>::const_iterator it = cache.T.find(E->entity->id());\
if ( it != cache.T.end() ) { e = it->second; return true; }
#define CACHE(T,E,e) cache.T[E->entity->id()] = e;
#endif
*/
#include <cmath>
#include "../../../ifcparse/macros.h"
#include "../../../ifcgeom/kernel_agnostic/AbstractKernel.h"
#include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h"
#include "../../../ifcgeom/kernels/cgal/CgalConversionResult.h"
struct PolyhedronBuilder : public CGAL::Modifier_base<CGAL::Polyhedron_3<Kernel_>::HalfedgeDS> {
private:
std::list<cgal_face_t> *face_list;
public:
PolyhedronBuilder(std::list<cgal_face_t> *face_list) {
this->face_list = face_list;
}
void operator()(CGAL::Polyhedron_3<Kernel_>::HalfedgeDS &hds) {
std::list<Kernel_::Point_3> points;
std::list<std::list<std::size_t>> facet_vertices;
CGAL::Polyhedron_incremental_builder_3<CGAL::Polyhedron_3<Kernel_>::HalfedgeDS> builder(hds, true);
for (auto &face: *face_list) {
facet_vertices.push_back(std::list<std::size_t>());
for (auto &point: face.outer) {
facet_vertices.back().push_back(points.size());
points.push_back(point);
}
}
builder.begin_surface(points.size(), facet_vertices.size());
for (auto &point: points) {
// std::cout << "Adding point " << point << std::endl;
builder.add_vertex(point);
}
for (auto &facet: facet_vertices) {
builder.begin_facet();
// std::cout << "Adding facet ";
for (auto &vertex: facet) {
// std::cout << vertex << " ";
builder.add_vertex_to_facet(vertex);
}
// std::cout << std::endl;
builder.end_facet();
}
builder.end_surface();
}
};
namespace ifcopenshell {
namespace geometry {
namespace utils {
IFC_GEOM_API CGAL::Polyhedron_3<Kernel_> create_cube(double d);
IFC_GEOM_API CGAL::Polyhedron_3<Kernel_> create_cube(const Kernel_::Point_3& lower, const Kernel_::Point_3& upper);
IFC_GEOM_API CGAL::Polyhedron_3<Kernel_> create_polyhedron(std::list<cgal_face_t> &face_list);
IFC_GEOM_API CGAL::Polyhedron_3<Kernel_> create_polyhedron(const CGAL::Nef_polyhedron_3<Kernel_> &nef_polyhedron);
IFC_GEOM_API CGAL::Nef_polyhedron_3<Kernel_> create_nef_polyhedron(std::list<cgal_face_t> &face_list);
IFC_GEOM_API CGAL::Nef_polyhedron_3<Kernel_> create_nef_polyhedron(CGAL::Polyhedron_3<Kernel_> &polyhedron);
}
namespace kernels {
class IFC_GEOM_API CgalKernel : public AbstractKernel {
private:
double precision_;
size_t circle_segments_;
CGAL::Nef_polyhedron_3<Kernel_> precision_cube_;
bool preprocess_boolean_operand(const IfcUtil::IfcBaseClass* log_reference, const cgal_shape_t& shape_const, CGAL::Nef_polyhedron_3<Kernel_>& result, bool dilate);
bool thin_solid(const CGAL::Nef_polyhedron_3<Kernel_>& a, CGAL::Nef_polyhedron_3<Kernel_>& result);
public:
CgalKernel()
: AbstractKernel("cgal")
// @todo
, precision_(1.e-5)
, circle_segments_(16)
{
auto cc = utils::create_cube(precision_);
precision_cube_ = CGAL::Nef_polyhedron_3<Kernel_>(cc);
}
void remove_duplicate_points_from_loop(cgal_wire_t& polygon);
bool convert(const taxonomy::extrusion*, cgal_shape_t&);
bool convert(const taxonomy::face*, cgal_face_t&);
bool convert(const taxonomy::loop*, cgal_wire_t&);
// bool convert(const taxonomy::matrix4*, cgal_placement_t&);
bool convert(const taxonomy::shell*, cgal_shape_t&);
// virtual bool convert_impl(const taxonomy::face*, ifcopenshell::geometry::ConversionResults&);
virtual bool convert_impl(const taxonomy::shell*, ifcopenshell::geometry::ConversionResults&);
virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&);
virtual bool convert_impl(const taxonomy::boolean_result*, ifcopenshell::geometry::ConversionResults&);
const CGAL::Nef_polyhedron_3<Kernel_>& precision_cube() const { return precision_cube_; }
};
}
}
}
#endif
@@ -77,17 +77,23 @@
#include <TopLoc_Location.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h"
#ifdef SCHEMA_HAS_IfcBSplineCurveWithKnots
#include <Geom_BSplineCurve.hxx>
#endif
#define Kernel POSTFIX_SCHEMA(Kernel)
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)) {
if (placement->declaration().is(IfcSchema::IfcAxis2Placement3D::Class())) {
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
} else {
gp_Trsf2d trsf2d;
@@ -102,7 +108,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipse* l, Handle(Geom_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
@@ -112,7 +118,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipse* l, Handle(Geom_Curve)
const bool rotated = y > x;
gp_Trsf trsf;
IfcSchema::IfcAxis2Placement* placement = l->Position();
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
if (placement->declaration().is(IfcSchema::IfcAxis2Placement3D::Class())) {
convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
} else {
gp_Trsf2d trsf2d;
@@ -135,4 +141,58 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLine* l, Handle(Geom_Curve)& c
// See note at IfcGeomWires.cpp:237
curve = new Geom_Line(pnt,vec);
return true;
}
}
#ifdef SCHEMA_HAS_IfcBSplineCurveWithKnots
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineCurveWithKnots* l, Handle(Geom_Curve)& curve) {
const bool is_rational = l->declaration().is(IfcSchema::IfcRationalBSplineCurveWithKnots::Class());
const IfcSchema::IfcCartesianPoint::list::ptr cps = l->ControlPointsList();
const std::vector<int> mults = l->KnotMultiplicities();
const std::vector<double> knots = l->Knots();
TColgp_Array1OfPnt Poles(0, cps->size() - 1);
TColStd_Array1OfReal Weights(0, cps->size() - 1);
TColStd_Array1OfReal Knots(0, (int)knots.size() - 1);
TColStd_Array1OfInteger Mults(0, (int)mults.size() - 1);
Standard_Integer Degree = l->Degree();
Standard_Boolean Periodic = l->ClosedCurve();
int i;
if (is_rational) {
IfcSchema::IfcRationalBSplineCurveWithKnots* rl = (IfcSchema::IfcRationalBSplineCurveWithKnots*)l;
std::vector<double> weights = rl->WeightsData();
i = 0;
for (std::vector<double>::const_iterator it = weights.begin(); it != weights.end(); ++it, ++i) {
Weights(i) = *it;
}
}
i = 0;
for (IfcSchema::IfcCartesianPoint::list::it it = cps->begin(); it != cps->end(); ++it, ++i) {
gp_Pnt pnt;
if (!convert(*it, pnt)) return false;
Poles(i) = pnt;
}
i = 0;
for (std::vector<int>::const_iterator it = mults.begin(); it != mults.end(); ++it, ++i) {
Mults(i) = *it;
}
i = 0;
for (std::vector<double>::const_iterator it = knots.begin(); it != knots.end(); ++it, ++i) {
Knots(i) = *it;
}
if (is_rational) {
curve = new Geom_BSplineCurve(Poles, Weights, Knots, Mults, Degree, Periodic);
} else {
curve = new Geom_BSplineCurve(Poles, Knots, Mults, Degree, Periodic);
}
return true;
}
#endif
@@ -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>
@@ -66,13 +67,16 @@
#include <BRepBuilderAPI_MakeShell.hxx>
#include <BRepBuilderAPI_MakeSolid.hxx>
#include <TopExp.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS_Iterator.hxx>
#include <BRepAlgoAPI_Cut.hxx>
#include <ShapeFix_Edge.hxx>
#include <ShapeFix_Shape.hxx>
#include <ShapeFix_ShapeTolerance.hxx>
#include <ShapeFix_Solid.hxx>
@@ -83,167 +87,398 @@
#include <Standard_Failure.hxx>
#include <BRep_Tool.hxx>
#include <BRepCheck_Face.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#ifdef USE_IFC4
#include <Standard_Version.hxx>
#include <TopTools_DataMapOfShapeInteger.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <BRepLib_FindSurface.hxx>
#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h"
#ifdef SCHEMA_HAS_IfcBSplineSurfaceWithKnots
#include <Geom_BSplineSurface.hxx>
#include <TColgp_Array2OfPnt.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <Geom_Plane.hxx>
#include <BRepCheck_Face.hxx>
#endif
#include "../ifcgeom/IfcGeom.h"
#define Kernel POSTFIX_SCHEMA(Kernel)
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
IfcSchema::IfcFaceBound::list::it it = bounds->begin();
IfcSchema::IfcLoop* loop = (*it)->Bound();
TopoDS_Wire outer_wire;
if ( ! convert_wire(loop,outer_wire) ) return false;
BRepBuilderAPI_MakeFace mf (outer_wire);
BRepBuilderAPI_FaceError er = mf.Error();
if ( er == BRepBuilderAPI_NotPlanar ) {
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(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* loop = (*it)->Bound();
TopoDS_Wire wire;
if ( ! 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 {
namespace {
/* Returns whether wire conforms to a polyhedron, i.e. only edges with linear curves*/
bool is_polyhedron(const TopoDS_Wire& wire) {
double a, b;
TopLoc_Location l;
TopoDS_Iterator it(wire, false, false);
for (; it.More(); it.Next()) {
auto crv = BRep_Tool::Curve(TopoDS::Edge(it.Value()), l, a, b);
if (!crv || crv->DynamicType() != STANDARD_TYPE(Geom_Line)) {
return false;
}
} else {
return false;
}
return true;
}
if ( getValue(GV_FORCE_CCW_FACE_ORIENTATION)>0 ) {
// Check the orientation of the face by comparing the
// normal of the topological surface to the Newell's Method's
// normal. Newell's Method is used for the normal calculation
// as a simple edge cross product can give opposite results
// for a concave face boundary.
// Reference: Graphics Gems III p. 231
BRepGProp_Face prop(TopoDS::Face(face));
gp_Vec normal_direction;
gp_Pnt center;
double u1,u2,v1,v2;
prop.Bounds(u1,u2,v1,v2);
prop.Normal((u1+u2)/2.0,(v1+v2)/2.0,center,normal_direction);
gp_Dir face_normal1 = gp_Dir(normal_direction.XYZ());
/* A temporary structure to store the intermediate data for the face conversion */
class face_definition {
private:
Handle(Geom_Surface) surface_;
std::vector<TopoDS_Wire> wires_;
bool all_outer_;
public:
face_definition() : surface_(), all_outer_(false) {}
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;
typedef std::vector<TopoDS_Wire>::const_iterator wire_it;
bool& all_outer() {
return all_outer_;
}
if ( n ) {
const double& xn = previous.X();
const double& yn = previous.Y();
const double& zn = previous.Z();
const double& xn1 = current.X();
const double& yn1 = current.Y();
const double& zn1 = current.Z();
x += (yn-yn1)*(zn+zn1);
y += (xn+xn1)*(zn-zn1);
z += (xn-xn1)*(yn+yn1);
} else {
first = current;
}
if ( !has_more ) {
break;
}
previous = current;
++n;
}
// If Newell's normal does not point in the same direction
// as the topological face normal the face orientation is
// reversed
gp_Vec face_normal2(x,y,z);
if (face_normal2.Magnitude() > ALMOST_ZERO) {
if ( face_normal1.Dot(face_normal2) < 0 ) {
TopAbs_Orientation o = face.Orientation();
face.Orientation(o == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD);
bool all_outer() const {
return all_outer_;
}
}
Handle(Geom_Surface)& surface() {
return surface_;
}
const Handle(Geom_Surface)& surface() const {
return surface_;
}
std::vector<TopoDS_Wire>& wires() {
return wires_;
}
const TopoDS_Wire& outer_wire() const {
return wires_.front();
}
std::pair<wire_it, wire_it> inner_wires() const {
return { wires_.begin() + 1, wires_.end() };
}
};
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& result) {
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
face_definition fd;
const bool is_face_surface = l->declaration().is(IfcSchema::IfcFaceSurface::Class());
if (is_face_surface) {
IfcSchema::IfcFaceSurface* fs = (IfcSchema::IfcFaceSurface*) l;
fs->FaceSurface();
// FIXME: Surfaces are interpreted as a TopoDS_Shape
TopoDS_Shape surface_shape;
if (!convert_shape(fs->FaceSurface(), surface_shape)) return false;
// FIXME: Assert this obtaines the only face
TopExp_Explorer exp(surface_shape, TopAbs_FACE);
if (!exp.More()) return false;
TopoDS_Face surface = TopoDS::Face(exp.Current());
fd.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;
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::IfcFaceOuterBound::Class())) 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;
}
if (num_outer_bounds > 1) {
Logger::Message(Logger::LOG_WARNING, "Multiple outer boundaries for:", l);
fd.all_outer() = true;
}
TopTools_DataMapOfShapeInteger wire_senses;
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::IfcFaceOuterBound::Class()) &&
(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 (faceset_helper_ && loop->as<IfcSchema::IfcPolyLoop>()) {
if (!faceset_helper_->wire(loop->as<IfcSchema::IfcPolyLoop>(), wire)) {
Logger::Message(Logger::LOG_WARNING, "Face boundary loop not included", loop);
continue;
}
} else if (!convert_wire(loop, wire)) {
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop);
return false;
}
if (!same_sense) {
wire.Reverse();
}
wire_senses.Bind(wire.Oriented(TopAbs_FORWARD), same_sense ? TopAbs_FORWARD : TopAbs_REVERSED);
fd.wires().emplace_back(wire);
}
}
if (fd.wires().empty()) {
Logger::Warning("Face with no boundaries", l);
return false;
}
if (fd.surface().IsNull()) {
// Use the first wire to find a plane manually for polygonal wires
const TopoDS_Wire& wire = fd.wires().front();
if (is_polyhedron(wire)) {
TopExp_Explorer exp(wire, TopAbs_EDGE);
int count = 0;
TopoDS_Edge edges[2];
for (; exp.More(); exp.Next(), count++) {
if (count < 2) {
edges[count] = TopoDS::Edge(exp.Current());
}
}
if (count == 3) {
// Help Open Cascade by finding the plane more efficiently
double _, __;
Handle(Geom_Line) c1 = Handle(Geom_Line)::DownCast(BRep_Tool::Curve(edges[0], _, __));
Handle(Geom_Line) c2 = Handle(Geom_Line)::DownCast(BRep_Tool::Curve(edges[1], _, __));
const gp_Vec ab = c1->Position().Direction();
const gp_Vec ac = c2->Position().Direction();
const gp_Vec cross = ab.Crossed(ac);
if (cross.SquareMagnitude() > ALMOST_ZERO) {
const gp_Dir n = cross;
fd.surface() = new Geom_Plane(c1->Position().Location(), n);
}
} else {
gp_Pln pln;
if (approximate_plane_through_wire(wire, pln)) {
fd.surface() = new Geom_Plane(pln);
}
}
}
}
if (fd.surface().IsNull()) {
// BRepLib_FindSurface is used in case no surface is found or provided
const TopoDS_Wire& wire = fd.wires().front();
BRepLib_FindSurface fs(wire, getValue(GV_PRECISION), true, true);
if (fs.Found()) {
fd.surface() = fs.Surface();
ShapeFix_ShapeTolerance ftol;
ftol.SetTolerance(wire, fs.ToleranceReached(), TopAbs_WIRE);
}
}
TopTools_ListOfShape face_list;
if (fd.surface().IsNull()) {
// The set of wires is triangulated in case no surface can be found
Logger::Message(Logger::LOG_WARNING, "Triangulating face boundaries for face", l);
if (fd.all_outer()) {
for (const auto& w : fd.wires()) {
TopTools_ListOfShape fl;
triangulate_wire({ w }, fl);
face_list.Append(fl);
}
} else {
triangulate_wire(fd.wires(), face_list);
}
} else if (!fd.all_outer()) {
BRepBuilderAPI_MakeFace mf(fd.surface(), fd.outer_wire());
if (mf.IsDone()) {
// Is this necessary
TopoDS_Face f = mf.Face();
mf.Init(f);
for (auto it = fd.inner_wires().first; it != fd.inner_wires().second; ++it) {
mf.Add(*it);
}
face_list.Append(mf.Face());
}
} else {
for (const auto& w : fd.wires()) {
BRepBuilderAPI_MakeFace mf(fd.surface(), w);
if (mf.IsDone()) {
face_list.Append(mf.Face());
}
}
}
if (!fd.surface().IsNull()) {
// Some fixes for orientation and p-curves. If we have no surface, it
// means the face has been triangulated in which case none of these
// fixes are necessary.
if (fd.surface()->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
// In case of (non-planar) face surface, p-curves need to be computed.
// For planar faces, Open Cascade generates p-curves on the fly.
for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) {
// Small chance there are multiple faces
const TopoDS_Face& face = TopoDS::Face(it.Value());
for (TopExp_Explorer exp2(face, TopAbs_EDGE); exp2.More(); exp2.Next()) {
const TopoDS_Edge& edge = TopoDS::Edge(exp2.Current());
ShapeFix_Edge fix_edge;
fix_edge.FixAddPCurve(edge, face, false, getValue(GV_PRECISION));
}
}
}
for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) {
const TopoDS_Face& face = TopoDS::Face(it.Value());
ShapeFix_Face sfs(TopoDS::Face(face));
TopTools_DataMapOfShapeListOfShape wire_map;
sfs.FixOrientation(wire_map);
TopoDS_Iterator jt(face, false);
for (; jt.More(); jt.Next()) {
const TopoDS_Wire& w = TopoDS::Wire(jt.Value());
// tfk: @todo if wire_map contains w, I would assume wire_senses also contains w,
// this is not the case in github issue #405.
if (wire_map.IsBound(w) && wire_senses.IsBound(w)) {
const TopTools_ListOfShape& shapes = wire_map.Find(w);
TopTools_ListIteratorOfListOfShape kt(shapes);
for (; kt.More(); kt.Next()) {
// Apparently the wire got reversed, so register it with opposite orientation in the map
wire_senses.Bind(kt.Value(), wire_senses.Find(w) == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD);
}
}
}
it.Value() = sfs.Face();
}
for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) {
TopoDS_Face& face = TopoDS::Face(it.Value());
bool all_reversed = true;
TopoDS_Iterator jt(face, false);
for (; jt.More(); jt.Next()) {
const TopoDS_Wire& w = TopoDS::Wire(jt.Value());
if (!wire_senses.IsBound(w.Oriented(TopAbs_FORWARD)) || (w.Orientation() == wire_senses.Find(w.Oriented(TopAbs_FORWARD)))) {
all_reversed = false;
}
}
if (all_reversed) {
face.Reverse();
}
}
}
if (face_list.Extent() > 1) {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) {
TopoDS_Face& face = TopoDS::Face(it.Value());
builder.Add(compound, face);
}
result = compound;
} else {
result = face_list.First();
}
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, TopoDS_Shape& face) {
TopoDS_Wire wire;
if ( ! convert_wire(l->OuterCurve(),wire) ) return false;
if (!convert_wire(l->OuterCurve(), wire)) {
return false;
}
assert_closed_wire(wire);
TopoDS_Face f;
bool success = convert_wire_to_face(wire, f);
if (success) face = f;
if (success) {
face = f;
}
return success;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids* l, TopoDS_Shape& face) {
TopoDS_Wire profile;
if ( ! convert_wire(l->OuterCurve(),profile) ) return false;
if (!convert_wire(l->OuterCurve(), profile)) {
return false;
}
assert_closed_wire(profile);
BRepBuilderAPI_MakeFace mf(profile);
IfcSchema::IfcCurve::list::ptr voids = l->InnerCurves();
for( IfcSchema::IfcCurve::list::it it = voids->begin(); it != voids->end(); ++ it ) {
for(IfcSchema::IfcCurve::list::it it = voids->begin(); it != voids->end(); ++it) {
TopoDS_Wire hole;
if ( convert_wire(*it,hole) ) {
if (convert_wire(*it, hole)) {
assert_closed_wire(hole);
mf.Add(hole);
}
}
ShapeFix_Shape sfs(mf.Face());
sfs.Perform();
face = TopoDS::Face(sfs.Shape());
face = sfs.Shape();
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleProfileDef* l, TopoDS_Shape& face) {
const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
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::Kernel::convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
double coords[8] = {-x,-y,x,-y,x,y,-x,y};
return profile_helper(4,coords,0,0,0,trsf2d,face);
}
@@ -254,12 +489,19 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef* l,
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::Kernel::convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
has_position = l->hasPosition();
#endif
if (has_position) {
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};
@@ -278,7 +520,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l,
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;
}
@@ -286,7 +528,14 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l,
TopoDS_Face f2;
gp_Trsf2d trsf2d;
IfcGeom::Kernel::convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
has_position = l->hasPosition();
#endif
if (has_position) {
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};
@@ -320,12 +569,19 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrapeziumProfileDef* l, TopoDS
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::Kernel::convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
double coords[8] = {-x1,-y, x1,-y, dx+w-x1,y, dx-x1,y};
return profile_helper(4,coords,0,0,0,trsf2d,face);
}
@@ -345,7 +601,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcIShapeProfileDef* l, TopoDS_Sh
bool doFillet2 = doFillet1;
double x2 = x1, dy2 = dy1, f2 = f1;
if (l->is(IfcSchema::Type::IfcAsymmetricIShapeProfileDef)) {
if (l->declaration().is(IfcSchema::IfcAsymmetricIShapeProfileDef::Class())) {
IfcSchema::IfcAsymmetricIShapeProfileDef* assym = (IfcSchema::IfcAsymmetricIShapeProfileDef*) l;
x2 = assym->TopFlangeWidth() / 2. * getValue(GV_LENGTH_UNIT);
doFillet2 = assym->hasTopFlangeFilletRadius();
@@ -358,12 +614,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcIShapeProfileDef* l, TopoDS_Sh
}
if ( x1 < ALMOST_ZERO || x2 < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || dy1 < ALMOST_ZERO || dy2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
gp_Trsf2d trsf2d;
convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
double coords[24] = {-x1,-y, x1,-y, x1,-y+dy1, d1,-y+dy1, d1,y-dy2, x2,y-dy2, x2,y, -x2,y, -x2,y-dy2, -d1,y-dy2, -d1,-y+dy1, -x1,-y+dy1};
int fillets[4] = {3,4,9,10};
@@ -391,12 +653,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcZShapeProfileDef* l, TopoDS_Sh
}
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::Kernel::convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
has_position = l->hasPosition();
#endif
if (has_position) {
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};
@@ -418,12 +686,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCShapeProfileDef* l, TopoDS_Sh
}
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
gp_Trsf2d trsf2d;
IfcGeom::Kernel::convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
has_position = l->hasPosition();
#endif
if (has_position) {
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};
@@ -451,7 +725,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Sh
}
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;
}
@@ -483,7 +757,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Sh
const double det = a1*b2 - a2*b1;
if (ALMOST_THE_SAME(det, 0.)) {
Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:",l->entity);
Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:",l);
return false;
}
@@ -492,7 +766,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Sh
}
gp_Trsf2d trsf2d;
convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::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};
@@ -529,12 +809,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcUShapeProfileDef* l, TopoDS_Sh
}
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
gp_Trsf2d trsf2d;
convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::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};
@@ -557,7 +843,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
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;
}
@@ -605,7 +891,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
const double det = a1*b2 - a2*b1;
if (ALMOST_THE_SAME(det, 0.)) {
Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:",l->entity);
Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:",l);
return false;
}
@@ -617,7 +903,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
}
gp_Trsf2d trsf2d;
convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::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};
@@ -628,17 +920,25 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
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;
convert(l->Position(),trsf);
gp_Trsf2d trsf2d;
bool has_position = true;
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
gp_Ax2 ax = gp_Ax2().Transformed(trsf2d);
BRepBuilderAPI_MakeWire w;
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
Handle(Geom_Circle) circle = new Geom_Circle(ax, r);
TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(circle);
BRepBuilderAPI_MakeWire w;
w.Add(edge);
TopoDS_Face f;
@@ -652,13 +952,20 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, Top
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;
convert(l->Position(),trsf);
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
gp_Trsf2d trsf2d;
bool has_position = true;
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
gp_Ax2 ax = gp_Ax2().Transformed(trsf2d);
BRepBuilderAPI_MakeWire outer;
Handle(Geom_Circle) outerCircle = new Geom_Circle(ax, r);
@@ -681,20 +988,27 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipseProfileDef* l, TopoDS_S
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;
convert(l->Position(),trsf);
gp_Trsf2d trsf2d;
bool has_position = true;
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
gp_Ax2 ax = gp_Ax2();
if (rotated) {
ax.Rotate(ax.Axis(), M_PI / 2.);
std::swap(rx, ry);
}
ax.Transform(trsf);
ax.Transform(trsf2d);
BRepBuilderAPI_MakeWire w;
Handle(Geom_Ellipse) ellipse = new Geom_Ellipse(ax, rx, ry);
@@ -764,7 +1078,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeProfileDef* l, TopoDS
builder.MakeCompound(compound);
IfcSchema::IfcProfileDef::list::ptr profiles = l->Profiles();
bool first = true;
//bool first = true;
for (IfcSchema::IfcProfileDef::list::it it = profiles->begin(); it != profiles->end(); ++it) {
TopoDS_Face f;
if (convert_face(*it, f)) {
@@ -798,20 +1112,32 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcDerivedProfileDef* l, TopoDS_S
}
}
#ifdef USE_IFC4
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;
}
bool convert_surf(IfcSchema::IfcBSplineSurfaceWithKnots* l, Handle_Geom_Surface& surf) {
SHARED_PTR< IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint> > cps = l->ControlPointsList();
#ifdef SCHEMA_HAS_IfcBSplineSurfaceWithKnots
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, cps->size() - 1, 0, (*cps->begin()).size() - 1);
TColStd_Array1OfReal UKnots(0, uknots.size() - 1);
TColStd_Array1OfReal VKnots(0, vknots.size() - 1);
TColStd_Array1OfInteger UMults(0, umults.size() - 1);
TColStd_Array1OfInteger VMults(0, vmults.size() - 1);
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();
@@ -841,51 +1167,13 @@ bool convert_surf(IfcSchema::IfcBSplineSurfaceWithKnots* l, Handle_Geom_Surface&
for (std::vector<int>::const_iterator it = vmults.begin(); it != vmults.end(); ++it, ++i) {
VMults(i) = *it;
}
surf = new Geom_BSplineSurface(Poles, UKnots, VKnots, UMults, VMults, UDegree, VDegree);
return true;
}
Handle_Geom_Surface surf = new Geom_BSplineSurface(Poles, UKnots, VKnots, UMults, VMults, UDegree, VDegree);
bool convert_surf(IfcSchema::IfcPlane* l, Handle_Geom_Surface& surf) {
gp_Pln pln;
convert(l, pln);
surf = new Geom_Plane(pln);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAdvancedFace* l, TopoDS_Shape& face) {
IfcSchema::IfcSurface* s = l->FaceSurface();
Handle_Geom_Surface surf(0);
if (s->is(IfcSchema::Type::IfcBSplineSurfaceWithKnots)) {
convert_surf((IfcSchema::IfcBSplineSurfaceWithKnots*)s, surf);
} else if (s->is(IfcSchema::Type::IfcPlane)) {
convert_surf((IfcSchema::IfcPlane*)s, surf);
} else {
return false;
}
BRepBuilderAPI_MakeFace mf(surf, Precision::Confusion());
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
IfcSchema::IfcLoop* loop = (*it)->Bound();
TopoDS_Wire outer_wire;
if (!convert_wire(loop, outer_wire)) return false;
TopoDS_Face temp = BRepBuilderAPI_MakeFace(surf, outer_wire);
if (BRepCheck_Face(temp).OrientationOfWires() == BRepCheck_BadOrientationOfSubshape) {
outer_wire.Reverse();
ShapeFix_Face fix(BRepBuilderAPI_MakeFace(surf, outer_wire).Face());
fix.FixOrientation();
fix.Perform();
TopoDS_Face temp = fix.Face();
TopExp_Explorer exp(temp, TopAbs_WIRE);
outer_wire = TopoDS::Wire(exp.Current());
}
mf.Add(outer_wire);
}
face = mf.Face();
#if OCC_VERSION_HEX < 0x60502
face = BRepBuilderAPI_MakeFace(surf);
#else
face = BRepBuilderAPI_MakeFace(surf, getValue(GV_PRECISION));
#endif
return true;
}
File diff suppressed because it is too large Load Diff
@@ -75,7 +75,59 @@
#include <TopLoc_Location.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h"
#define Kernel POSTFIX_SCHEMA(Kernel)
namespace {
// Helper functions (re)set gp_(G)Trsf(2d) forms explicitly to 'Identity'
// so that it can be easily identified in the IfcMappedItem processing
// For axis placements detect equality early in order for the
// relatively computionaly expensive gp_Trsf calculation to be skipped
template <typename T>
bool axis_equal(const T& a, const T& b, double tolerance);
template <>
bool axis_equal(const gp_Ax3& a, const gp_Ax3& b, double tolerance) {
if (!a.Location().IsEqual(b.Location(), tolerance)) return false;
// Note that the tolerance below is angular, above is linear. Since architectural
// objects are about 1m'ish in scale, it should be somewhat equivalent. Besides,
// this is mostly a filter for NULL or default values in the placements.
if (!a.Direction().IsEqual(b.Direction(), tolerance)) return false;
if (!a.XDirection().IsEqual(b.XDirection(), tolerance)) return false;
if (!a.YDirection().IsEqual(b.YDirection(), tolerance)) return false;
return true;
}
bool axis_equal(const gp_Ax2d& a, const gp_Ax2d& b, double tolerance) {
if (!a.Location().IsEqual(b.Location(), tolerance)) return false;
if (!a.Direction().IsEqual(b.Direction(), tolerance)) return false;
return true;
}
template <typename T> struct dimension_count {};
template <> struct dimension_count <gp_Trsf2d > { static const int n = 2; };
template <> struct dimension_count <gp_GTrsf2d> { static const int n = 2; };
template <> struct dimension_count < gp_Trsf > { static const int n = 3; };
template <> struct dimension_count < gp_GTrsf > { static const int n = 3; };
template <typename T>
bool is_identity(const T& t, double tolerance) {
// Note the {1, n+1} range due to Open Cascade's 1-based indexing
// Note the {1, n+2} range due to the translation part of the matrix
for (int i = 1; i < dimension_count<T>::n + 2; ++i) {
for (int j = 1; j < dimension_count<T>::n + 1; ++j) {
const double iden_value = i == j ? 1. : 0.;
const double trsf_value = t.Value(j, i);
if (fabs(trsf_value - iden_value) > tolerance) {
return false;
}
}
}
return true;
}
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianPoint* l, gp_Pnt& point) {
IN_CACHE(IfcCartesianPoint,l,gp_Pnt,point)
@@ -111,16 +163,43 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcVector* l, gp_Vec& v) {
}
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::Kernel::convert(l->Location(),o);
bool hasRef = l->hasRefDirection();
if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(),axis);
if ( hasRef ) IfcGeom::Kernel::convert(l->RefDirection(),refDirection);
gp_Ax3 ax3;
if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection);
else ax3 = gp_Ax3(o,axis);
trsf.SetTransformation(ax3, gp_Ax3(gp_Pnt(),gp_Dir(0,0,1),gp_Dir(1,0,0)));
IN_CACHE(IfcAxis2Placement3D, l, gp_Trsf, trsf)
gp_Pnt o;
gp_Dir axis(0, 0, 1);
gp_Dir refDirection;
IfcGeom::Kernel::convert(l->Location(), o);
const bool hasAxis = l->hasAxis();
const bool hasRef = l->hasRefDirection();
if (hasAxis != hasRef) {
Logger::Warning("Axis and RefDirection should be specified together", l);
}
if (hasAxis) {
IfcGeom::Kernel::convert(l->Axis(), axis);
}
if (hasRef) {
IfcGeom::Kernel::convert(l->RefDirection(), refDirection);
} else {
if (!axis.IsParallel(gp::DX(), 1.e-5)) {
refDirection = gp::DX();
} else {
refDirection = gp::DZ();
}
gp_Vec Xvec = axis.Dot(refDirection) * axis;
gp_Vec Xaxis = refDirection.XYZ() - Xvec.XYZ();
refDirection = Xaxis;
}
gp_Ax3 ax3(o, axis, refDirection);
if (!axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) {
trsf.SetTransformation(ax3, gp::XOY());
}
CACHE(IfcAxis2Placement3D,l,trsf)
return true;
}
@@ -147,9 +226,16 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
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);
trsf.Invert();
if ( l->hasScale() ) trsf.SetScaleFactor(l->Scale());
if (!axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) {
trsf.SetTransformation(ax3);
trsf.Invert();
}
if (l->hasScale() && !ALMOST_THE_SAME(l->Scale(), 1.)) {
trsf.SetScaleFactor(l->Scale());
}
CACHE(IfcCartesianTransformationOperator3D,l,trsf)
return true;
}
@@ -183,7 +269,12 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
}
trsf.Invert();
if ( l->hasScale() ) trsf.SetScaleFactor(l->Scale());
if ( l->hasScale() && !ALMOST_THE_SAME(l->Scale(), 1.) ) trsf.SetScaleFactor(l->Scale());
if (is_identity(trsf, getValue(GV_PRECISION))) {
trsf = gp_Trsf2d();
}
CACHE(IfcCartesianTransformationOperator2D,l,trsf)
return true;
}
@@ -211,6 +302,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
gtrsf.SetValue(2,2,scale2);
gtrsf.SetValue(3,3,scale3);
gtrsf.PreMultiply(trsf);
if (is_identity(gtrsf, getValue(GV_PRECISION))) {
gtrsf = gp_GTrsf();
}
CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gtrsf)
return true;
}
@@ -247,6 +343,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
gtrsf.SetValue(1,1,scale1);
gtrsf.SetValue(2,2,scale2);
gtrsf.Multiply(trsf);
if (is_identity(gtrsf, getValue(GV_PRECISION))) {
gtrsf = gp_GTrsf2d();
}
CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gtrsf)
return true;
}
@@ -274,33 +375,45 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d
if ( l->hasRefDirection() )
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());
gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()), gp_Dir2d(V.X(),V.Y()));
if (!axis_equal(axis, gp_Ax2d(), getValue(GV_PRECISION))) {
trsf.SetTransformation(axis, gp_Ax2d());
}
CACHE(IfcAxis2Placement2D,l,trsf)
return true;
}
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::IfcLocalPlacement::Class()) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l);
return false;
}
IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l;
while (1) {
for (;;) {
gp_Trsf trsf2;
IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement();
if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) {
if ( relplacement->declaration().is(IfcSchema::IfcAxis2Placement3D::Class()) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2);
trsf.PreMultiply(trsf2);
}
if ( current->hasPlacementRelTo() ) {
IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo();
if ( relto->is(IfcSchema::Type::IfcLocalPlacement) )
IfcSchema::IfcObjectPlacement* parent = current->PlacementRelTo();
IfcSchema::IfcProduct::list::ptr parentPlaces = parent->PlacesObject();
bool parentPlacesType = false;
for ( IfcSchema::IfcProduct::list::it iter = parentPlaces->begin();
iter != parentPlaces->end(); ++iter) {
if ( (*iter)->declaration().is(*placement_rel_to) ) parentPlacesType = true;
}
if ( parentPlacesType ) break;
else if ( parent->declaration().is(IfcSchema::IfcLocalPlacement::Class()) )
current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo();
else break;
else break;
} else break;
}
CACHE(IfcObjectPlacement,l,trsf)
return true;
}
}
@@ -0,0 +1,660 @@
#include <Geom_Line.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Ellipse.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Geom_Plane.hxx>
#include <Geom_BSplineSurface.hxx>
#include <Geom_CylindricalSurface.hxx>
#include <BRepTools_WireExplorer.hxx>
#include <TColgp_Array2OfPnt.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array2OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include "IfcGeom.h"
template <typename T, typename U>
int convert_to_ifc(const T& t, U*& u, bool /*advanced*/) {
std::vector<double> coords(3);
coords[0] = t.X(); coords[1] = t.Y(); coords[2] = t.Z();
u = new U(coords);
return 1;
}
template <>
int convert_to_ifc(const TopoDS_Vertex& v, IfcSchema::IfcCartesianPoint*& p, bool advanced) {
gp_Pnt pnt = BRep_Tool::Pnt(v);
return convert_to_ifc(pnt, p, advanced);
}
template <>
int convert_to_ifc(const TopoDS_Vertex& v, IfcSchema::IfcVertex*& vertex, bool advanced) {
IfcSchema::IfcCartesianPoint* p;
convert_to_ifc(v, p, advanced);
vertex = new IfcSchema::IfcVertexPoint(p);
return 1;
}
template <>
int convert_to_ifc(const gp_Ax2& a, IfcSchema::IfcAxis2Placement3D*& ax, bool advanced) {
IfcSchema::IfcCartesianPoint* p;
IfcSchema::IfcDirection *x, *z;
if (!(convert_to_ifc(a.Location(), p, advanced) && convert_to_ifc(a.Direction(), z, advanced) && convert_to_ifc(a.XDirection(), x, advanced))) {
ax = 0;
return 0;
}
ax = new IfcSchema::IfcAxis2Placement3D(p, z, x);
return 1;
}
template <typename T, typename U>
void opencascade_array_to_vector(T& t, std::vector<U>& u) {
u.reserve(t.Length());
for (int i = t.Lower(); i <= t.Upper(); ++i) {
u.push_back(t.Value(i));
}
}
template <typename T, typename U>
void opencascade_array_to_vector2(T& t, std::vector< std::vector<U> >& u) {
u.reserve(t.RowLength());
for (int j = t.LowerRow(); j <= t.UpperRow(); ++j) {
std::vector<U> v;
v.reserve(t.ColLength());
for (int i = t.LowerCol(); i <= t.UpperCol(); ++i) {
v.push_back(t.Value(j, i));
}
u.push_back(v);
}
}
#ifdef USE_IFC4
IfcSchema::IfcKnotType::Value opencascade_knotspec_to_ifc(GeomAbs_BSplKnotDistribution bspline_knot_spec) {
IfcSchema::IfcKnotType::Value knot_spec = IfcSchema::IfcKnotType::IfcKnotType_UNSPECIFIED;
if (bspline_knot_spec == GeomAbs_Uniform) {
knot_spec = IfcSchema::IfcKnotType::IfcKnotType_UNIFORM_KNOTS;
} else if (bspline_knot_spec == GeomAbs_QuasiUniform) {
knot_spec = IfcSchema::IfcKnotType::IfcKnotType_QUASI_UNIFORM_KNOTS;
} else if (bspline_knot_spec == GeomAbs_PiecewiseBezier) {
knot_spec = IfcSchema::IfcKnotType::IfcKnotType_PIECEWISE_BEZIER_KNOTS;
}
return knot_spec;
}
#endif
template <>
int convert_to_ifc(const Handle_Geom_Curve& c, IfcSchema::IfcCurve*& curve, bool advanced) {
if (c->DynamicType() == STANDARD_TYPE(Geom_Line)) {
IfcSchema::IfcDirection* d;
IfcSchema::IfcCartesianPoint* p;
Handle_Geom_Line line = Handle_Geom_Line::DownCast(c);
if (!convert_to_ifc(line->Position().Location(), p, advanced)) {
return 0;
}
if (!convert_to_ifc(line->Position().Direction(), d, advanced)) {
return 0;
}
IfcSchema::IfcVector* v = new IfcSchema::IfcVector(d, 1.);
curve = new IfcSchema::IfcLine(p, v);
return 1;
} else if (c->DynamicType() == STANDARD_TYPE(Geom_Circle)) {
IfcSchema::IfcAxis2Placement3D* ax;
Handle_Geom_Circle circle = Handle_Geom_Circle::DownCast(c);
convert_to_ifc(circle->Position(), ax, advanced);
curve = new IfcSchema::IfcCircle(ax, circle->Radius());
return 1;
} else if (c->DynamicType() == STANDARD_TYPE(Geom_Ellipse)) {
IfcSchema::IfcAxis2Placement3D* ax;
Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(c);
convert_to_ifc(ellipse->Position(), ax, advanced);
curve = new IfcSchema::IfcEllipse(ax, ellipse->MajorRadius(), ellipse->MinorRadius());
return 1;
}
#ifdef USE_IFC4
else if (c->DynamicType() == STANDARD_TYPE(Geom_BSplineCurve)) {
Handle_Geom_BSplineCurve bspline = Handle_Geom_BSplineCurve::DownCast(c);
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
TColgp_Array1OfPnt poles(1, bspline->NbPoles());
bspline->Poles(poles);
for (int i = 1; i <= bspline->NbPoles(); ++i) {
IfcSchema::IfcCartesianPoint* p;
if (!convert_to_ifc(poles.Value(i), p, advanced)) {
return 0;
}
points->push(p);
}
IfcSchema::IfcKnotType::Value knot_spec = opencascade_knotspec_to_ifc(bspline->KnotDistribution());
std::vector<int> mults;
std::vector<double> knots;
std::vector<double> weights;
TColStd_Array1OfInteger bspline_mults(1, bspline->NbKnots());
TColStd_Array1OfReal bspline_knots(1, bspline->NbKnots());
TColStd_Array1OfReal bspline_weights(1, bspline->NbPoles());
bspline->Multiplicities(bspline_mults);
bspline->Knots(bspline_knots);
bspline->Weights(bspline_weights);
opencascade_array_to_vector(bspline_mults, mults);
opencascade_array_to_vector(bspline_knots, knots);
opencascade_array_to_vector(bspline_weights, weights);
bool rational = false;
for (std::vector<double>::const_iterator it = weights.begin(); it != weights.end(); ++it) {
if ((*it) != 1.) {
rational = true;
break;
}
}
if (rational) {
curve = new IfcSchema::IfcRationalBSplineCurveWithKnots(
bspline->Degree(),
points,
IfcSchema::IfcBSplineCurveForm::IfcBSplineCurveForm_UNSPECIFIED,
bspline->IsClosed() != 0,
false,
mults,
knots,
knot_spec,
weights
);
} else {
curve = new IfcSchema::IfcBSplineCurveWithKnots(
bspline->Degree(),
points,
IfcSchema::IfcBSplineCurveForm::IfcBSplineCurveForm_UNSPECIFIED,
bspline->IsClosed() != 0,
false,
mults,
knots,
knot_spec
);
}
return 1;
}
#endif
return 0;
}
template <>
int convert_to_ifc(const Handle_Geom_Surface& s, IfcSchema::IfcSurface*& surface, bool advanced) {
if (s->DynamicType() == STANDARD_TYPE(Geom_Plane)) {
Handle_Geom_Plane plane = Handle_Geom_Plane::DownCast(s);
IfcSchema::IfcAxis2Placement3D* place;
/// @todo: Note that the Ax3 is converted to an Ax2 here
if (!convert_to_ifc(plane->Position().Ax2(), place, advanced)) {
return 0;
}
surface = new IfcSchema::IfcPlane(place);
return 1;
}
#ifdef USE_IFC4
else if (s->DynamicType() == STANDARD_TYPE(Geom_CylindricalSurface)) {
Handle_Geom_CylindricalSurface cyl = Handle_Geom_CylindricalSurface::DownCast(s);
IfcSchema::IfcAxis2Placement3D* place;
/// @todo: Note that the Ax3 is converted to an Ax2 here
if (!convert_to_ifc(cyl->Position().Ax2(), place, advanced)) {
return 0;
}
surface = new IfcSchema::IfcCylindricalSurface(place, cyl->Radius());
return 1;
} else if (s->DynamicType() == STANDARD_TYPE(Geom_BSplineSurface)) {
typedef IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint> points_t;
Handle_Geom_BSplineSurface bspline = Handle_Geom_BSplineSurface::DownCast(s);
points_t::ptr points(new points_t);
TColgp_Array2OfPnt poles(1, bspline->NbUPoles(), 1, bspline->NbVPoles());
bspline->Poles(poles);
for (int i = 1; i <= bspline->NbUPoles(); ++i) {
std::vector<IfcSchema::IfcCartesianPoint*> ps;
ps.reserve(bspline->NbVPoles());
for (int j = 1; j <= bspline->NbVPoles(); ++j) {
IfcSchema::IfcCartesianPoint* p;
if (!convert_to_ifc(poles.Value(i, j), p, advanced)) {
return 0;
}
ps.push_back(p);
}
points->push(ps);
}
IfcSchema::IfcKnotType::Value knot_spec_u = opencascade_knotspec_to_ifc(bspline->UKnotDistribution());
IfcSchema::IfcKnotType::Value knot_spec_v = opencascade_knotspec_to_ifc(bspline->VKnotDistribution());
if (knot_spec_u != knot_spec_v) {
knot_spec_u = IfcSchema::IfcKnotType::IfcKnotType_UNSPECIFIED;
}
std::vector<int> umults;
std::vector<int> vmults;
std::vector<double> uknots;
std::vector<double> vknots;
std::vector< std::vector<double> > weights;
TColStd_Array1OfInteger bspline_umults(1, bspline->NbUKnots());
TColStd_Array1OfInteger bspline_vmults(1, bspline->NbVKnots());
TColStd_Array1OfReal bspline_uknots(1, bspline->NbUKnots());
TColStd_Array1OfReal bspline_vknots(1, bspline->NbVKnots());
TColStd_Array2OfReal bspline_weights(1, bspline->NbUPoles(), 1, bspline->NbVPoles());
bspline->UMultiplicities(bspline_umults);
bspline->VMultiplicities(bspline_vmults);
bspline->UKnots(bspline_uknots);
bspline->VKnots(bspline_vknots);
bspline->Weights(bspline_weights);
opencascade_array_to_vector(bspline_umults, umults);
opencascade_array_to_vector(bspline_vmults, vmults);
opencascade_array_to_vector(bspline_uknots, uknots);
opencascade_array_to_vector(bspline_vknots, vknots);
opencascade_array_to_vector2(bspline_weights, weights);
bool rational = false;
for (std::vector< std::vector<double> >::const_iterator it = weights.begin(); it != weights.end(); ++it) {
for (std::vector<double>::const_iterator jt = it->begin(); jt != it->end(); ++jt) {
if ((*jt) != 1.) {
rational = true;
break;
}
}
}
if (rational) {
surface = new IfcSchema::IfcRationalBSplineSurfaceWithKnots(
bspline->UDegree(),
bspline->VDegree(),
points,
IfcSchema::IfcBSplineSurfaceForm::IfcBSplineSurfaceForm_UNSPECIFIED,
bspline->IsUClosed() != 0,
bspline->IsVClosed() != 0,
false,
umults,
vmults,
uknots,
vknots,
knot_spec_u,
weights
);
} else {
surface = new IfcSchema::IfcBSplineSurfaceWithKnots(
bspline->UDegree(),
bspline->VDegree(),
points,
IfcSchema::IfcBSplineSurfaceForm::IfcBSplineSurfaceForm_UNSPECIFIED,
bspline->IsUClosed() != 0,
bspline->IsVClosed() != 0,
false,
umults,
vmults,
uknots,
vknots,
knot_spec_u
);
}
return 1;
}
#endif
return 0;
}
template <>
int convert_to_ifc(const TopoDS_Edge& e, IfcSchema::IfcCurve*& c, bool advanced) {
double a, b;
IfcSchema::IfcCurve* base;
Handle_Geom_Curve crv = BRep_Tool::Curve(e, a, b);
if (!convert_to_ifc(crv, base, advanced)) {
return 0;
}
IfcEntityList::ptr trim1(new IfcEntityList);
IfcEntityList::ptr trim2(new IfcEntityList);
trim1->push(new IfcSchema::IfcParameterValue(a));
trim2->push(new IfcSchema::IfcParameterValue(b));
c = new IfcSchema::IfcTrimmedCurve(base, trim1, trim2, true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
return 1;
}
template <>
int convert_to_ifc(const TopoDS_Edge& e, IfcSchema::IfcEdge*& edge, bool advanced) {
double a, b;
TopExp_Explorer exp(e, TopAbs_VERTEX);
if (!exp.More()) return 0;
TopoDS_Vertex v1 = TopoDS::Vertex(exp.Current());
exp.Next();
if (!exp.More()) return 0;
TopoDS_Vertex v2 = TopoDS::Vertex(exp.Current());
IfcSchema::IfcVertex *vertex1, *vertex2;
if (!(convert_to_ifc(v1, vertex1, advanced) && convert_to_ifc(v2, vertex2, advanced))) {
return 0;
}
Handle_Geom_Curve crv = BRep_Tool::Curve(e, a, b);
if (crv.IsNull()) {
return 0;
}
if (crv->DynamicType() == STANDARD_TYPE(Geom_Line) && !advanced) {
IfcSchema::IfcEdge* edge2 = new IfcSchema::IfcEdge(vertex1, vertex2);
edge = new IfcSchema::IfcOrientedEdge(edge2, true);
return 1;
} else {
IfcSchema::IfcCurve* curve;
if (!convert_to_ifc(crv, curve, advanced)) {
return 0;
}
/// @todo probably not correct
const bool sense = e.Orientation() == TopAbs_FORWARD;
IfcSchema::IfcEdge* edge2 = new IfcSchema::IfcEdgeCurve(vertex1, vertex2, curve, true);
edge = new IfcSchema::IfcOrientedEdge(edge2, sense);
return 1;
}
}
template <>
int convert_to_ifc(const TopoDS_Wire& wire, IfcSchema::IfcLoop*& loop, bool advanced) {
bool polygonal = true;
for (TopExp_Explorer exp(wire, TopAbs_EDGE); exp.More(); exp.Next()) {
double a, b;
Handle_Geom_Curve crv = BRep_Tool::Curve(TopoDS::Edge(exp.Current()), a, b);
if (crv.IsNull()) {
continue;
}
if (crv->DynamicType() != STANDARD_TYPE(Geom_Line)) {
polygonal = false;
break;
}
}
if (!polygonal && !advanced) {
return 0;
} else if (polygonal && !advanced) {
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
BRepTools_WireExplorer exp(wire);
IfcSchema::IfcCartesianPoint* p;
for (; exp.More(); exp.Next()) {
if (convert_to_ifc(exp.CurrentVertex(), p, advanced)) {
points->push(p);
} else {
return 0;
}
}
loop = new IfcSchema::IfcPolyLoop(points);
return 1;
} else {
IfcSchema::IfcOrientedEdge::list::ptr edges(new IfcSchema::IfcOrientedEdge::list);
BRepTools_WireExplorer exp(wire);
for (; exp.More(); exp.Next()) {
IfcSchema::IfcEdge* edge;
// With advanced set to true convert_to_ifc(TopoDS_Edge&) will always create an IfcOrientedEdge
if (!convert_to_ifc(exp.Current(), edge, true)) {
double a, b;
if (BRep_Tool::Curve(TopoDS::Edge(exp.Current()), a, b).IsNull()) {
continue;
} else {
return 0;
}
}
edges->push(edge->as<IfcSchema::IfcOrientedEdge>());
}
loop = new IfcSchema::IfcEdgeLoop(edges);
return 1;
}
}
template <>
int convert_to_ifc(const TopoDS_Face& f, IfcSchema::IfcFace*& face, bool advanced) {
Handle_Geom_Surface surf = BRep_Tool::Surface(f);
TopExp_Explorer exp(f, TopAbs_WIRE);
IfcSchema::IfcFaceBound::list::ptr bounds(new IfcSchema::IfcFaceBound::list);
int index = 0;
for (; exp.More(); exp.Next(), ++index) {
IfcSchema::IfcLoop* loop;
if (!convert_to_ifc(TopoDS::Wire(exp.Current()), loop, advanced)) {
return 0;
}
IfcSchema::IfcFaceBound* bnd;
if (index == 0) {
bnd = new IfcSchema::IfcFaceOuterBound(loop, true);
} else {
bnd = new IfcSchema::IfcFaceBound(loop, true);
}
bounds->push(bnd);
}
const bool is_planar = surf->DynamicType() == STANDARD_TYPE(Geom_Plane);
if (!is_planar && !advanced) {
return 0;
}
if (is_planar && !advanced) {
face = new IfcSchema::IfcFace(bounds);
return 1;
} else {
#ifdef USE_IFC4
IfcSchema::IfcSurface* surface;
if (!convert_to_ifc(surf, surface, advanced)) {
return 0;
}
face = new IfcSchema::IfcAdvancedFace(bounds, surface, f.Orientation() == TopAbs_FORWARD);
return 1;
#else
// No IfcAdvancedFace in Ifc2x3
return 0;
#endif
}
}
template <typename U>
int convert_to_ifc(const TopoDS_Shape& s, U*& item, bool advanced) {
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
IfcSchema::IfcFace* f;
for (TopExp_Explorer exp(s, TopAbs_FACE); exp.More(); exp.Next()) {
if (convert_to_ifc(TopoDS::Face(exp.Current()), f, advanced)) {
faces->push(f);
} else {
/// Cleanup:
for (IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++it) {
IfcEntityList::ptr data = IfcParse::traverse(*it)->unique();
for (IfcEntityList::it jt = data->begin(); jt != data->end(); ++jt) {
delete *jt;
}
}
return 0;
}
}
item = new U(faces);
return faces->size();
}
IfcUtil::IfcBaseClass* IfcGeom::POSTFIX_SCHEMA(serialise_)(const TopoDS_Shape& shape, bool advanced) {
#ifndef USE_IFC4
advanced = false;
#endif
for (TopExp_Explorer exp(shape, TopAbs_COMPSOLID); exp.More();) {
/// @todo CompSolids are not supported
return 0;
}
IfcSchema::IfcRepresentation* rep = 0;
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
// First check if there is a solid with one or more shells
for (TopExp_Explorer exp(shape, TopAbs_SOLID); exp.More(); exp.Next()) {
IfcSchema::IfcClosedShell* outer = 0;
IfcSchema::IfcClosedShell::list::ptr inner(new IfcSchema::IfcClosedShell::list);
for (TopExp_Explorer exp2(exp.Current(), TopAbs_SHELL); exp2.More(); exp2.Next()) {
IfcSchema::IfcClosedShell* shell;
if (!convert_to_ifc(exp2.Current(), shell, advanced)) {
return 0;
}
/// @todo Are shells always in this order or does Orientation() needs to be checked?
if (outer) {
inner->push(shell);
} else {
outer = shell;
}
}
#ifdef USE_IFC4
if (advanced) {
if (inner->size()) {
items->push(new IfcSchema::IfcAdvancedBrepWithVoids(outer, inner));
} else {
items->push(new IfcSchema::IfcAdvancedBrep(outer));
}
} else
#endif
/// @todo this is not necessarily correct as the shell is not necessarily facetted.
if (inner->size()) {
items->push(new IfcSchema::IfcFacetedBrepWithVoids(outer, inner));
} else {
items->push(new IfcSchema::IfcFacetedBrep(outer));
}
}
if (items->size() > 0) {
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Body"), std::string("Brep"), items);
} else {
// If not, see if there is a shell
IfcSchema::IfcOpenShell::list::ptr shells(new IfcSchema::IfcOpenShell::list);
for (TopExp_Explorer exp(shape, TopAbs_SHELL); exp.More(); exp.Next()) {
IfcSchema::IfcOpenShell* shell;
if (!convert_to_ifc(exp.Current(), shell, advanced)) {
return 0;
}
shells->push(shell);
}
if (shells->size() > 0) {
items->push(new IfcSchema::IfcShellBasedSurfaceModel(shells->generalize()));
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Body"), std::string("Brep"), items);
} else {
// If not, see if there is are one of more faces. Note that they will be grouped into a shell.
IfcSchema::IfcOpenShell* shell;
int face_count = convert_to_ifc(shape, shell, advanced);
if (face_count > 0) {
items->push(shell);
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Body"), std::string("Brep"), items);
} else {
// If not, see if there are any edges. Note that wires are skipped as
// they are not commonly top-level geometrical descriptions in IFC.
// Also note that edges are written as trimmed curves rather than edges.
IfcEntityList::ptr edges(new IfcEntityList);
for (TopExp_Explorer exp(shape, TopAbs_EDGE); exp.More(); exp.Next()) {
IfcSchema::IfcCurve* c;
if (!convert_to_ifc(TopoDS::Edge(exp.Current()), c, advanced)) {
return 0;
}
edges->push(c);
}
if (edges->size() == 0) {
return 0;
} else if (edges->size() == 1) {
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Axis"), std::string("Curve2D"), edges->as<IfcSchema::IfcRepresentationItem>());
} else {
// A geometric set is created as that probably (?) makes more sense in IFC
IfcSchema::IfcGeometricCurveSet* curves = new IfcSchema::IfcGeometricCurveSet(edges);
items->push(curves);
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Axis"), std::string("GeometricCurveSet"), items->as<IfcSchema::IfcRepresentationItem>());
}
}
}
}
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
reps->push(rep);
return new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
}
IfcUtil::IfcBaseClass* IfcGeom::POSTFIX_SCHEMA(tesselate_)(const TopoDS_Shape& shape, double deflection) {
BRepMesh_IncrementalMesh(shape, deflection);
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
for (TopExp_Explorer exp(shape, TopAbs_FACE); exp.More(); exp.Next()) {
const TopoDS_Face& face = TopoDS::Face(exp.Current());
TopLoc_Location loc;
Handle(Poly_Triangulation) tri = BRep_Tool::Triangulation(face, loc);
if (!tri.IsNull()) {
const TColgp_Array1OfPnt& nodes = tri->Nodes();
std::vector<IfcSchema::IfcCartesianPoint*> vertices;
for (int i = 1; i <= nodes.Length(); ++i) {
gp_Pnt pnt = nodes(i).Transformed(loc);
std::vector<double> xyz; xyz.push_back(pnt.X()); xyz.push_back(pnt.Y()); xyz.push_back(pnt.Z());
IfcSchema::IfcCartesianPoint* cpnt = new IfcSchema::IfcCartesianPoint(xyz);
vertices.push_back(cpnt);
}
const Poly_Array1OfTriangle& triangles = tri->Triangles();
for (int i = 1; i <= triangles.Length(); ++i) {
int n1, n2, n3;
triangles(i).Get(n1, n2, n3);
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
points->push(vertices[n1 - 1]);
points->push(vertices[n2 - 1]);
points->push(vertices[n3 - 1]);
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, face.Orientation() != TopAbs_REVERSED);
IfcSchema::IfcFaceBound::list::ptr bounds(new IfcSchema::IfcFaceBound::list);
bounds->push(bound);
IfcSchema::IfcFace* face2 = new IfcSchema::IfcFace(bounds);
faces->push(face2);
}
}
}
IfcSchema::IfcOpenShell* shell = new IfcSchema::IfcOpenShell(faces);
IfcSchema::IfcConnectedFaceSet::list::ptr shells(new IfcSchema::IfcConnectedFaceSet::list);
shells->push(shell);
IfcSchema::IfcFaceBasedSurfaceModel* surface_model = new IfcSchema::IfcFaceBasedSurfaceModel(shells);
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
items->push(surface_model);
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
0, std::string("Facetation"), std::string("SurfaceModel"), items);
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shapedef = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
return shapedef;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,288 @@
/********************************************************************************
* *
* 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 IFCGEOMTREE_H
#define IFCGEOMTREE_H
#include "../../../ifcparse/IfcFile.h"
#include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h"
#include "../../../ifcgeom/schema_agnostic/IfcGeomIterator.h"
#include "../../../ifcgeom/schema_agnostic/Converter.h"
#include "../../../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h"
#include <NCollection_UBTree.hxx>
#include <BRepBndLib.hxx>
#include <Bnd_Box.hxx>
#include <BRepAlgoAPI_Common.hxx>
#include <BRepAlgoAPI_Cut.hxx>
#include <BRepClass3d_SolidClassifier.hxx>
namespace ifcopenshell { namespace geometry {
namespace impl {
template <typename T>
class tree {
public:
void add(const T& t, const Bnd_Box& b) {
tree_.Add(t, b);
}
void add(const T& t, const TopoDS_Shape& s) {
Bnd_Box b;
BRepBndLib::AddClose(s, b);
add(t, b);
shapes_[t] = s;
}
std::vector<T> select_box(const T& t, bool completely_within = false, double extend=-1.e-5) const {
typename map_t::const_iterator it = shapes_.find(t);
if (it == shapes_.end()) {
return std::vector<T>();
}
Bnd_Box b;
BRepBndLib::AddClose(it->second, b);
// Gap is assumed to be positive throughout the codebase,
// but at least for IsOut() in the selector a negative
// Gap should work as well.
b.SetGap(b.GetGap() + extend);
return select_box(b, completely_within);
}
std::vector<T> select_box(const gp_Pnt& p) const {
Bnd_Box b;
b.Add(p);
return select_box(b);
}
std::vector<T> select_box(const Bnd_Box& b, bool completely_within = false) const {
selector s(b);
tree_.Select(s);
if (completely_within) {
std::vector<T> ts = s.results();
std::vector<T> ts_filtered;
ts_filtered.reserve(ts.size());
typename std::vector<T>::const_iterator it = ts.begin();
for (; it != ts.end(); ++it) {
const TopoDS_Shape& shp = shapes_.find(*it)->second;
Bnd_Box B;
BRepBndLib::AddClose(shp, B);
// BndBox::CornerMin() /-Max() introduced in OCCT 6.8
double x1, y1, z1, x2, y2, z2;
b.Get(x1, y1, z1, x2, y2, z2);
double gap = B.GetGap();
gp_Pnt p1(x1 - gap, y1 - gap, z1 - gap);
gp_Pnt p2(x2 + gap, y2 + gap, z2 + gap);
if (!b.IsOut(p1) && !b.IsOut(p2)) {
ts_filtered.push_back(*it);
}
}
return ts_filtered;
} else {
return s.results();
}
}
std::vector<T> select(const T& t, bool completely_within = false) const {
std::vector<T> ts = select_box(t);
if (ts.empty()) {
return ts;
}
std::vector<T> ts_filtered;
const TopoDS_Shape& A = shapes_.find(t)->second;
OpenCascadeShape SA(A);
if (IfcGeom::Kernel::count(&SA, (int) TopAbs_SHELL) == 0) {
return ts_filtered;
}
ts_filtered.reserve(ts.size());
typename std::vector<T>::const_iterator it = ts.begin();
for (it = ts.begin(); it != ts.end(); ++it) {
const TopoDS_Shape& B = shapes_.find(*it)->second;
OpenCascadeShape SB(B);
if (IfcGeom::Kernel::count(&SB, (int) TopAbs_SHELL) == 0) {
continue;
}
if (completely_within) {
BRepAlgoAPI_Cut cut(B, A);
if (cut.IsDone()) {
OpenCascadeShape Sc(cut.Shape());
if (IfcGeom::Kernel::count(&Sc, (int) TopAbs_SHELL) == 0) {
ts_filtered.push_back(*it);
}
}
} else {
BRepAlgoAPI_Common common(A, B);
if (common.IsDone()) {
OpenCascadeShape Sc(common.Shape());
if (IfcGeom::Kernel::count(&Sc, (int) TopAbs_SHELL) > 0) {
ts_filtered.push_back(*it);
}
}
}
}
return ts_filtered;
}
std::vector<T> select(const TopoDS_Shape& s) const {
Bnd_Box bb;
BRepBndLib::AddClose(s, bb);
std::vector<T> ts;
OpenCascadeShape Ss(s);
if (IfcGeom::Kernel::count(&Ss, (int) TopAbs_SHELL) == 0) {
return ts;
}
ts = select_box(bb);
if (ts.empty()) {
return ts;
}
std::vector<T> ts_filtered;
ts_filtered.reserve(ts.size());
typename std::vector<T>::const_iterator it = ts.begin();
for (it = ts.begin(); it != ts.end(); ++it) {
const TopoDS_Shape& B = shapes_.find(*it)->second;
OpenCascadeShape SB(B);
if (IfcGeom::Kernel::count(&SB, (int) TopAbs_SHELL) == 0) {
continue;
}
BRepAlgoAPI_Common common(s, B);
if (common.IsDone()) {
OpenCascadeShape Sc(common.Shape());;
if (IfcGeom::Kernel::count(&Sc, (int) TopAbs_SHELL) > 0) {
ts_filtered.push_back(*it);
}
}
}
return ts_filtered;
}
std::vector<T> select(const gp_Pnt& p) const {
std::vector<T> ts = select_box(p);
if (ts.empty()) {
return ts;
}
std::vector<T> ts_filtered;
ts_filtered.reserve(ts.size());
typename std::vector<T>::const_iterator it = ts.begin();
for (it = ts.begin(); it != ts.end(); ++it) {
const TopoDS_Shape& B = shapes_.find(*it)->second;
TopExp_Explorer exp(B, TopAbs_SOLID);
for (; exp.More(); exp.Next()) {
BRepClass3d_SolidClassifier cls(exp.Current(), p, 1e-5);
if (cls.State() != TopAbs_OUT) {
ts_filtered.push_back(*it);
break;
}
}
}
return ts_filtered;
}
protected:
typedef NCollection_UBTree<T, Bnd_Box> tree_t;
typedef std::map<T, TopoDS_Shape> map_t;
tree_t tree_;
map_t shapes_;
class selector : public tree_t::Selector
{
public:
selector(const Bnd_Box& b)
: tree_t::Selector()
, bounds_(b)
{}
Standard_Boolean Reject(const Bnd_Box& b) const {
return bounds_.IsOut(b);
}
Standard_Boolean Accept(const T& o) {
results_.push_back(o);
return Standard_True;
}
const std::vector<T>& results() const {
return results_;
}
private:
std::vector<T> results_;
const Bnd_Box& bounds_;
};
};
}
class tree : public impl::tree<IfcUtil::IfcBaseEntity*> {
public:
tree() {};
tree(IfcParse::IfcFile& f) {
add_file(f, ifcopenshell::geometry::settings());
}
tree(IfcParse::IfcFile& f, const ifcopenshell::geometry::settings& settings) {
add_file(f, settings);
}
void add_file(IfcParse::IfcFile& f, const ifcopenshell::geometry::settings& settings) {
ifcopenshell::geometry::settings settings_ = settings;
settings_.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true);
settings_.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, true);
settings_.set(ifcopenshell::geometry::settings::SEW_SHELLS, true);
Iterator it(settings_, &f);
if (it.initialize()) {
do {
NativeElement* elem = (NativeElement*)it.get();
add((IfcUtil::IfcBaseEntity*)f.instance_by_id(elem->id()), ((OpenCascadeShape*)elem->geometry().as_compound())->shape());
} while (it.next());
}
}
};
}}
#endif

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