Compare commits

...

195 Commits

Author SHA1 Message Date
Stefano Beccaletto 62386c663a Added default constructor to IfcHierarchyHelper 2021-01-22 11:00:14 +01:00
Thomas Krijnen a10e852a35 Fixes for placement cloning that affected layersets 2019-09-22 14:01:35 +02:00
Thomas Krijnen 7f5d733ed8 Propagate static runtime settings to voxel tk 2019-09-22 12:57:36 +02:00
Thomas Krijnen cdfbde8f18 Subtract interior voxel volumes 2019-09-01 08:56:56 +02:00
Thomas Krijnen 0d7f6af681 Mesh compound prior to voxelization 2019-08-28 16:15:28 +02:00
Thomas Krijnen d76c599477 geom server client getattr; yield from process() 2019-08-28 14:56:09 +02:00
Thomas Krijnen c09de2c568 Test geom server voxels 2019-08-24 13:44:42 +02:00
Thomas Krijnen 3f7290cdc6 Lower voxel resolution, use padding 2019-08-23 14:59:31 +02:00
Thomas Krijnen 7bd4699f65 Update geom server client to parse entity bodies 2019-08-23 14:54:16 +02:00
Thomas Krijnen e137036bbb Update .travis.yml 2019-08-09 13:59:24 +02:00
Thomas Krijnen b1a0e2a62b Update .travis.yml 2019-08-09 11:59:04 +02:00
Thomas Krijnen a97577d272 Update .travis.yml 2019-08-09 11:53:20 +02:00
Thomas Krijnen 53bcb333da Update .travis.yml 2019-08-09 11:34:55 +02:00
Thomas Krijnen 49fb919fbc thread_local define for clang 2019-08-09 10:06:55 +02:00
Thomas Krijnen 5dbbd917d1 gcc and clang on travis 2019-08-08 12:13:06 +02:00
Thomas Krijnen 10d11031e5 Remove redundant occt library links to executables and python wrapper 2019-08-04 12:49:22 +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 fd9c57b77d Merge branch 'v0.6.0' into v0.7.0 2019-08-02 17:56:45 +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 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 33bcf786fd MPIR and MPFR in win build script 2019-05-03 10:46:59 +02:00
Thomas Krijnen 8e6a6ec56d Add voxelization_toolkit to win build script 2019-04-30 14:36:55 +02:00
Thomas Krijnen b862f633db Fix voxel library in nix build script 2019-04-30 13:24:28 +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
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 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 9ae55ab303 Small fixes to transformations 2017-06-06 17:12:46 +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
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
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
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
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
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
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
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
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
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 619b4fbed5 Fix CGAL library linking on windows, conditional IfcTriangulatedFaceSet based on schema 2017-03-09 12:14:00 +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
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
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
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
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 4d12bf7e8d Cgal kernel skeleton (#3)
Cgal kernel skeleton
2017-01-16 14:04:31 +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
109 changed files with 6461 additions and 1989 deletions
+2
View File
@@ -12,3 +12,5 @@ __pycache__
.vscode
# PyCharm files
.idea
# OSX files
.DS_Store
+5 -3
View File
@@ -1,7 +1,9 @@
language: cpp
compiler: gcc
compiler:
- gcc
- clang
os: linux
dist: xenial
dist: bionic
sudo: required
before_install:
@@ -36,7 +38,7 @@ script:
-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" \
-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;/usr/lib/x86_64-linux-gnu/libicudata.so" \
-DGLTF_SUPPORT=On \
-DJSON_INCLUDE_DIR=/usr/include/json \
..
+139 -34
View File
@@ -42,6 +42,9 @@ 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." ON)
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)
@@ -111,6 +114,14 @@ 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)
if (GLTF_SUPPORT AND BUILD_CONVERT)
UNIFY_ENVVARS_AND_CACHE(JSON_INCLUDE_DIR)
@@ -140,8 +151,10 @@ ENDMACRO()
# 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_STATIC_RUNTIME 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
@@ -154,20 +167,29 @@ ELSE()
ENDIF()
set(BOOST_COMPONENTS system program_options regex thread date_time)
if(USE_MMAP)
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()
add_definitions(-DUSE_MMAP)
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}")
@@ -255,6 +277,61 @@ foreach(lib ${OPENCASCADE_LIBRARY_NAMES})
list(APPEND OPENCASCADE_LIBRARIES "${lib_path}")
endforeach()
list(APPEND GEOMETRY_KERNELS opencascade)
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()
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("${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()
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()
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()
if(MSVC)
add_definitions(-DHAVE_NO_DLL)
add_debug_variants(OPENCASCADE_LIBRARIES "${OPENCASCADE_LIBRARIES}" d)
@@ -274,7 +351,7 @@ 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 ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
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()
@@ -412,22 +489,25 @@ IF(MSVC)
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))
add_definitions(-permissive-)
# @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()
# Link against the static VC runtime
# TODO Make this configurable
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()
ElSE()
add_definitions(-Wall -Wextra)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
@@ -447,6 +527,7 @@ 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}
)
function(files_for_ifc_version IFC_VERSION RESULT_NAME)
@@ -549,20 +630,44 @@ TARGET_LINK_LIBRARIES(IfcParse ${Boost_LIBRARIES} ${BCRYPT_LIBRARIES} ${LIBXML2_
if (BUILD_IFCGEOM)
# IfcGeom
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/*.h)
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp)
foreach(kernel ${GEOMETRY_KERNELS})
string(TOUPPER ${kernel} KERNEL_UPPER)
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/schema_agnostic/${kernel}/*.h)
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/schema_agnostic/${kernel}/*.cpp)
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES})
foreach(s ${SCHEMA_VERSIONS})
add_library(IfcGeom_ifc${s} STATIC ${IFCGEOM_FILES})
set_target_properties(IfcGeom_ifc${s} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${s}")
TARGET_LINK_LIBRARIES(IfcGeom_ifc${s} IfcParse ${OPENCASCADE_LIBRARIES})
add_library(IfcGeom_${kernel} STATIC ${IFCGEOM_FILES})
set_target_properties(IfcGeom_${kernel} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS")
target_link_libraries(IfcGeom_${kernel} IfcParse ${${KERNEL_UPPER}_LIBRARIES})
list(APPEND IfcGeom_libraries IfcGeom_${kernel})
endforeach()
# IfcGeom (schema agnostic)
file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom_schema_agnostic/*.h)
file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom_schema_agnostic/*.cpp)
foreach(schema ${SCHEMA_VERSIONS})
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/kernel_agnostic/*.h)
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/kernel_agnostic/*.cpp)
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES})
add_library(IfcGeom_ifc${schema} STATIC ${IFCGEOM_FILES})
set_target_properties(IfcGeom_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema}")
target_link_libraries(IfcGeom_ifc${schema} IfcParse)
list(APPEND IfcGeom_libraries IfcGeom_ifc${schema})
foreach(kernel ${GEOMETRY_KERNELS})
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(IfcGeom_${kernel}_ifc${schema} STATIC ${IFCGEOM_FILES})
set_target_properties(IfcGeom_${kernel}_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema}")
target_link_libraries(IfcGeom_${kernel}_ifc${schema} IfcGeom_${kernel} IfcGeom_ifc${schema})
list(APPEND IfcGeom_libraries IfcGeom_${kernel}_ifc${schema})
endforeach()
endforeach()
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})
@@ -572,7 +677,7 @@ if (UNIX)
find_package(Threads)
endif()
TARGET_LINK_LIBRARIES(IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
TARGET_LINK_LIBRARIES(IfcGeom ${IfcGeom_libraries} ${CMAKE_THREAD_LIBS_INIT})
endif(BUILD_IFCGEOM)
@@ -604,7 +709,7 @@ 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})
TARGET_LINK_LIBRARIES(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES})
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
# Only set RPATHs when building shared libraries (i.e. IfcParse and
@@ -628,7 +733,7 @@ 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})
TARGET_LINK_LIBRARIES(IfcGeomServer ${IFCOPENSHELL_LIBRARIES} ${Boost_LIBRARIES} ${VOXEL_LIBRARIES})
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
SET_INSTALL_RPATHS(IfcGeomServer "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS}")
@@ -671,10 +776,10 @@ INSTALL(FILES ${IFCGEOM_H_FILES}
)
INSTALL(FILES ${SCHEMA_AGNOSTIC_H_FILES}
DESTINATION ${INCLUDEDIR}/ifcgeom_schema_agnostic
DESTINATION ${INCLUDEDIR}/ifcgeom/schema_agnostic
)
INSTALL(TARGETS ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom
INSTALL(TARGETS IfcGeom ${IfcGeom_libraries}
ARCHIVE DESTINATION ${LIBDIR}
LIBRARY DESTINATION ${LIBDIR}
RUNTIME DESTINATION ${BINDIR}
+58 -12
View File
@@ -84,7 +84,7 @@ OCE_VERSION="0.18"
# OCCT_VERSION="7.2.0"
# OCCT_HASH="88af392"
OCCT_VERSION="7.3.0p3"
BOOST_VERSION="1.59.0"
BOOST_VERSION="1.69.0"
#PCRE_VERSION="8.39"
PCRE_VERSION="8.41"
#LIBXML2_VERSION="2.9.3"
@@ -95,8 +95,9 @@ 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"
@@ -216,17 +217,19 @@ cecho(""" - How many compiler processes may be run in parallel.
dependency_tree = {
'IfcParse': ('boost', 'libxml2'),
'IfcGeom': ('IfcParse', 'occ'),
'IfcGeom': ('IfcParse', 'occ', 'cgal', 'voxel'),
'IfcConvert': ('IfcGeom', 'OpenCOLLADA', 'json'),
'OpenCOLLADA': ('libxml2', 'pcre'),
'IfcGeomServer': ('IfcGeom',),
'IfcGeomServer': ('IfcGeom', ),
'IfcOpenShell-Python': ('python', 'swig', 'IfcGeom'),
'voxel': ('occ',),
'swig': ('pcre',),
'boost': (),
'libxml2': (),
'python': (),
'swig': (),
'occ': (),
'cgal': (),
'pcre': (),
'json': ()
}
@@ -257,7 +260,7 @@ 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"]:
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,))
@@ -310,10 +313,14 @@ BOOST_LOCATION="http://downloads.sourceforge.net/project/boost/boost/%s/boost_%s
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" % (os.path.realpath("%s/install/%s" % (DEPS_DIR, arg1)),)], cwd=cwd)
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:
@@ -547,6 +554,8 @@ if USE_OCCT and "occ" in targets:
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()),
@@ -563,6 +572,9 @@ elif "occ" in targets:
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(
@@ -656,6 +668,34 @@ if "boost" in targets:
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")
@@ -685,21 +725,27 @@ cmake_args=[
"-DJSON_INCLUDE_DIR=" "{DEPS_DIR}/install/json".format(**locals())
]
if "occ" in targets and USE_OCCT:
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())
if "occ" in targets:
cmake_args.extend([
"-DOCC_INCLUDE_DIR=" +occ_include_dir,
"-DOCC_LIBRARY_DIR=" +occ_library_dir
])
elif "occ" in targets:
occ_include_dir = "{DEPS_DIR}/install/oce-{OCE_VERSION}/include/oce".format(**locals())
occ_library_dir = "{DEPS_DIR}/install/oce-{OCE_VERSION}/lib"
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()),
+4 -9
View File
@@ -38,18 +38,13 @@
#include <Standard_Version.hxx>
#ifdef USE_IFC4
#include "../ifcparse/Ifc4.h"
#define IfcSchema Ifc4
#else
#include "../ifcparse/Ifc2x3.h"
#define IfcSchema Ifc2x3
#endif
#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"
#include "../ifcgeom/schema_agnostic/Serialization.h"
#if USE_VLD
#include <vld.h>
+6 -9
View File
@@ -33,18 +33,15 @@
#include <BRepGProp.hxx>
#include <GProp_GProps.hxx>
#ifdef USE_IFC4
#include "../ifcparse/Ifc4.h"
#define IfcSchema Ifc4
#else
#include "../ifcparse/Ifc2x3.h"
#define IfcSchema Ifc2x3
#endif
#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"
#include "../ifcgeom/schema_agnostic/Serialization.h"
#if USE_VLD
#include <vld.h>
+12 -9
View File
@@ -34,9 +34,9 @@
#include "../serializers/XmlSerializer.h"
#include "../serializers/SvgSerializer.h"
#include "../ifcgeom_schema_agnostic/IfcGeomFilter.h"
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
#include "../ifcgeom/schema_agnostic/IfcGeomFilter.h"
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
#include "../ifcgeom/schema_agnostic/IfcGeomRenderStyles.h"
#include "../ifcparse/utils.h"
@@ -194,6 +194,7 @@ int main(int argc, char** argv) {
exclusion_traverse_filter exclude_traverse_filter;
path_t filter_filename;
path_t default_material_filename;
std::string geometry_kernel;
std::string log_format;
po::options_description generic_options("Command line options");
@@ -214,7 +215,7 @@ int main(int argc, char** argv) {
#endif
("input-file", new po::typed_value<path_t, char_t>(0), "input IFC file")
("output-file", new po::typed_value<path_t, char_t>(0), "output geometry file");
po::options_description ifc_options("IFC options");
ifc_options.add_options()
("calculate-quantities", "Calculate or fix the physical quantity definitions "
@@ -224,6 +225,8 @@ int main(int argc, char** argv) {
po::options_description geom_options("Geometry options");
geom_options.add_options()
("kernel", po::value<std::string>(&geometry_kernel)->default_value("opencascade"),
"Geometry kernel to use (opencascade or cgal).")
("threads,j", po::value<int>(&num_threads)->default_value(1),
"Number of parallel processing threads for geometry interpretation.")
("plan",
@@ -746,7 +749,7 @@ int main(int argc, char** argv) {
Logger::SetOutput(quiet ? nullptr : &cout_, &log_stream);
IfcGeom::Iterator<real_t> context_iterator(settings, ifc_file, filter_funcs, num_threads);
IfcGeom::Iterator<real_t> context_iterator(settings, ifc_file, filter_funcs, geometry_kernel, num_threads);
if (!context_iterator.initialize()) {
/// @todo It would be nice to know and print separate error prints for a case where we found no entities
/// and for a case we found no entities that satisfy our filtering criteria.
@@ -810,7 +813,7 @@ int main(int argc, char** argv) {
// The functions IfcGeom::Iterator::get() and IfcGeom::Iterator::next()
// wrap an iterator of all geometrical products in the Ifc file.
// IfcGeom::Iterator::get() returns an IfcGeom::TriangulationElement or
// -BRepElement pointer, based on current settings. (see IfcGeomIterator.h
// -NativeElement pointer, based on current settings. (see IfcGeomIterator.h
// for definition) IfcGeom::Iterator::next() is used to poll whether more
// geometrical entities are available. None of these functions throw
// exceptions, neither for parsing errors or geometrical errors. Upon
@@ -828,7 +831,7 @@ int main(int argc, char** argv) {
}
else
{
serializer->write(static_cast<const IfcGeom::BRepElement<real_t>*>(geom_object));
serializer->write(static_cast<const IfcGeom::NativeElement<real_t>*>(geom_object));
}
if (!no_progress) {
@@ -1264,7 +1267,7 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std
if (num_created) {
has_more = context_iterator.next();
}
IfcGeom::BRepElement<double>* geom_object = nullptr;
IfcGeom::NativeElement<double>* geom_object = nullptr;
if (has_more) {
geom_object = context_iterator.get_native();
}
@@ -1317,7 +1320,7 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std
auto quantity_count = latebound_access::create(f, "IfcQuantityCount");
latebound_access::set(quantity_count, "Name", std::string("Surface Genus"));
latebound_access::set(quantity_count, "Description", '#' + boost::lexical_cast<std::string>(part.ItemId()));
latebound_access::set(quantity_count, "CountValue", IfcGeom::Kernel::surface_genus(part.Shape()));
latebound_access::set(quantity_count, "CountValue", part.Shape()->surface_genus());
quantities_2->push(quantity_count);
}
-140
View File
@@ -1,140 +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"
namespace {
bool process_colour(IfcSchema::IfcColourRgb* colour, double* 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, double* 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, double* rgb) {
if (colour_or_factor == 0) {
return false;
} else if (colour_or_factor->declaration().is(IfcSchema::IfcColourRgb::Class())) {
return process_colour(static_cast<IfcSchema::IfcColourRgb*>(colour_or_factor), rgb);
} else if (colour_or_factor->declaration().is(IfcSchema::IfcNormalisedRatioMeasure::Class())) {
return process_colour(static_cast<IfcSchema::IfcNormalisedRatioMeasure*>(colour_or_factor), rgb);
} else {
return false;
}
}
}
#define Kernel MAKE_TYPE_NAME(Kernel)
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::internalize_surface_style(const std::pair<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*>& shading_styles) {
if (shading_styles.second == 0) {
return 0;
}
int surface_style_id = shading_styles.first->data().id();
std::map<int,SurfaceStyle>::const_iterator it = style_cache.find(surface_style_id);
if (it != style_cache.end()) {
return &(it->second);
}
SurfaceStyle surface_style;
IfcSchema::IfcSurfaceStyle* style = shading_styles.first->as<IfcSchema::IfcSurfaceStyle>();
IfcSchema::IfcSurfaceStyleShading* shading = shading_styles.second->as<IfcSchema::IfcSurfaceStyleShading>();
if (style->hasName()) {
surface_style = SurfaceStyle(surface_style_id, style->Name());
} else {
surface_style = SurfaceStyle(surface_style_id);
}
double rgb[3];
if (process_colour(shading->SurfaceColour(), rgb)) {
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
}
if (shading_styles.second->declaration().is(IfcSchema::IfcSurfaceStyleRendering::Class())) {
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->declaration().is(IfcSchema::IfcSpecularRoughness::Class())) {
double roughness = *((IfcSchema::IfcSpecularRoughness*)highlight);
if (roughness >= 1e-9) {
surface_style.Specularity().reset(1.0 / roughness);
}
} else if (highlight->declaration().is(IfcSchema::IfcSpecularExponent::Class())) {
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 &(style_cache[surface_style_id] = surface_style);
}
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepresentationItem* item) {
return internalize_surface_style(get_surface_style<IfcSchema::IfcSurfaceStyleShading>(item));
}
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcMaterial* material) {
IfcSchema::IfcMaterialDefinitionRepresentation::list::ptr defs = material->HasRepresentation();
for (IfcSchema::IfcMaterialDefinitionRepresentation::list::it jt = defs->begin(); jt != defs->end(); ++jt) {
IfcSchema::IfcRepresentation::list::ptr reps = (*jt)->Representations();
IfcSchema::IfcStyledItem::list::ptr styles(new IfcSchema::IfcStyledItem::list);
for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) {
styles->push((**it).Items()->as<IfcSchema::IfcStyledItem>());
}
for (IfcSchema::IfcStyledItem::list::it it = styles->begin(); it != styles->end(); ++it) {
const std::pair<IfcSchema::IfcSurfaceStyle*, IfcSchema::IfcSurfaceStyleShading*> ss = get_surface_style<IfcSchema::IfcSurfaceStyleShading>(*it);
if (ss.second) {
return internalize_surface_style(ss);
}
}
}
IfcGeom::SurfaceStyle material_style = IfcGeom::SurfaceStyle(material->data().id(), material->Name());
return &(style_cache[material->data().id()] = material_style);
}
-415
View File
@@ -1,415 +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 <TopoDS.hxx>
#include <BRepTools.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <GCPnts_QuasiUniformDeflection.hxx>
#include <Geom_SphericalSurface.hxx>
#include "../ifcgeom/IfcGeomIteratorSettings.h"
#include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h"
#include "../ifcgeom/IfcRepresentationShapeItem.h"
#include <TopoDS_Compound.hxx>
namespace IfcGeom {
namespace Representation {
class IFC_GEOM_API Representation {
Representation(const Representation&); //N/A
Representation& operator =(const Representation&); //N/A
protected:
const ElementSettings settings_;
public:
explicit Representation(const ElementSettings& settings)
: settings_(settings)
{}
const ElementSettings& settings() const { return settings_; }
virtual ~Representation() {}
};
class IFC_GEOM_API BRep : public Representation {
private:
std::string id_;
const IfcGeom::IfcRepresentationShapeItems shapes_;
BRep(const BRep& other);
BRep& operator=(const BRep& other);
public:
BRep(const ElementSettings& settings, const std::string& id, const IfcGeom::IfcRepresentationShapeItems& shapes)
: Representation(settings)
, id_(id)
, shapes_(shapes)
{}
virtual ~BRep() {}
IfcGeom::IfcRepresentationShapeItems::const_iterator begin() const { return shapes_.begin(); }
IfcGeom::IfcRepresentationShapeItems::const_iterator end() const { return shapes_.end(); }
const IfcGeom::IfcRepresentationShapeItems& shapes() const { return shapes_; }
const std::string& id() const { return id_; }
TopoDS_Compound as_compound(bool force_meters = false) const;
bool calculate_volume(double&) const;
bool calculate_surface_area(double&) const;
bool calculate_projected_surface_area(const gp_Ax3& ax, double& along_x, double& along_y, double& along_z) const;
};
class IFC_GEOM_API Serialization : public Representation {
private:
std::string id_;
std::string brep_data_;
std::vector<double> surface_styles_;
public:
const std::string& brep_data() const { return brep_data_; }
const std::vector<double>& surface_styles() const { return surface_styles_; }
Serialization(const BRep& brep);
virtual ~Serialization() {}
const std::string& id() const { return id_; }
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;
std::string id_;
std::vector<P> _verts;
std::vector<int> _faces;
std::vector<int> _edges;
std::vector<P> _normals;
std::vector<P> uvs_;
std::vector<int> _material_ids;
std::vector<Material> _materials;
VertexKeyMap welds;
public:
const std::string& 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<P>& uvs() const { return uvs_; }
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.id())
{
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++ iit ) {
int surface_style_id = -1;
if (iit->hasStyle()) {
Material adapter(&iit->Style());
std::vector<Material>::const_iterator jt = std::find(_materials.begin(), _materials.end(), adapter);
if (jt == _materials.end()) {
surface_style_id = (int)_materials.size();
_materials.push_back(adapter);
} else {
surface_style_id = (int)(jt - _materials.begin());
}
}
if (settings().get(IteratorSettings::APPLY_DEFAULT_MATERIALS) && surface_style_id == -1) {
Material material(IfcGeom::get_default_style(settings().element_type()));
std::vector<Material>::const_iterator mit = std::find(_materials.begin(), _materials.end(), material);
if (mit == _materials.end()) {
surface_style_id = (int)_materials.size();
_materials.push_back(material);
} else {
surface_style_id = (int)(mit - _materials.begin());
}
}
const TopoDS_Shape& s = iit->Shape();
const gp_GTrsf& trsf = iit->Placement();
// Triangulate the shape
try {
BRepMesh_IncrementalMesh(s, settings().deflection_tolerance());
} catch(...) {
Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape");
continue;
}
// Iterates over the faces of the shape
int num_faces = 0;
TopExp_Explorer exp;
for ( exp.Init(s,TopAbs_FACE); exp.More(); exp.Next(), ++num_faces ) {
TopoDS_Face face = TopoDS::Face(exp.Current());
TopLoc_Location loc;
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face,loc);
if ( ! tri.IsNull() ) {
// A 3x3 matrix to rotate the vertex normals
const gp_Mat rotation_matrix = trsf.VectorialPart();
// Keep track of the number of times an edge is used
// Manifold edges (i.e. edges used twice) are deemed invisible
std::map<std::pair<int,int>,int> edgecount;
std::vector<std::pair<int,int> > edges_temp;
const TColgp_Array1OfPnt& nodes = tri->Nodes();
const TColgp_Array1OfPnt2d& uvs = tri->UVNodes();
std::vector<gp_XYZ> coords;
BRepGProp_Face prop(face);
std::map<int,int> dict;
// Vertex normals are only calculated if vertices are not welded and calculation is not disable explicitly.
const bool calculate_normals = !settings().get(IteratorSettings::WELD_VERTICES) &&
!settings().get(IteratorSettings::NO_NORMALS);
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() > 1.e-9) {
normal = gp_Dir(normal_direction.XYZ() * rotation_matrix);
} else {
Handle_Geom_Surface surf = BRep_Tool::Surface(face);
// Special case the normal at the poles of a spherical surface
if (surf->DynamicType() == STANDARD_TYPE(Geom_SphericalSurface)) {
if (fabs(fabs(uv.Y()) - M_PI / 2.) < 1.e-9) {
const bool is_top = uv.Y() > 0;
const bool is_forward = face.Orientation() == TopAbs_FORWARD;
const double z = (is_top == is_forward) ? 1. : -1.;
normal = gp_Dir(gp_XYZ(0, 0, z) * rotation_matrix);
}
}
// TODO: Do the same for conical surfaces, but they are rare in IFC.
}
_normals.push_back(static_cast<P>(normal.X()));
_normals.push_back(static_cast<P>(normal.Y()));
_normals.push_back(static_cast<P>(normal.Z()));
}
}
const Poly_Array1OfTriangle& triangles = tri->Triangles();
for( int i = 1; i <= triangles.Length(); ++ i ) {
int n1,n2,n3;
if ( face.Orientation() == TopAbs_REVERSED )
triangles(i).Get(n3,n2,n1);
else triangles(i).Get(n1,n2,n3);
/* An alternative would be to calculate normals based
* on the coordinates of the mesh vertices */
/*
const gp_XYZ pt1 = coords[n1-1];
const gp_XYZ pt2 = coords[n2-1];
const gp_XYZ pt3 = coords[n3-1];
const gp_XYZ v1 = pt2-pt1;
const gp_XYZ v2 = pt3-pt2;
gp_Dir normal = gp_Dir(v1^v2);
_normals.push_back((float)normal.X());
_normals.push_back((float)normal.Y());
_normals.push_back((float)normal.Z());
*/
_faces.push_back(dict[n1]);
_faces.push_back(dict[n2]);
_faces.push_back(dict[n3]);
_material_ids.push_back(surface_style_id);
addEdge(dict[n1], dict[n2], edgecount, edges_temp);
addEdge(dict[n2], dict[n3], edgecount, edges_temp);
addEdge(dict[n3], dict[n1], edgecount, edges_temp);
}
for ( std::vector<std::pair<int,int> >::const_iterator jt = edges_temp.begin(); jt != edges_temp.end(); ++jt ) {
if (edgecount[*jt] == 1) {
// non manifold edge, face boundary
_edges.push_back(jt->first);
_edges.push_back(jt->second);
}
}
}
}
if (!_normals.empty() && settings().get(IfcGeom::IteratorSettings::GENERATE_UVS)) {
uvs_ = box_project_uvs(_verts, _normals);
}
if (num_faces == 0) {
// Edges are only emitted if there are no faces. A mixed representation of faces
// and loose edges is discouraged by the standard. An alternative would be to use
// TopExp_Explorer texp(s, TopAbs_EDGE, TopAbs_FACE) to find edges that do not
// belong to any face.
for (TopExp_Explorer texp(s, TopAbs_EDGE); texp.More(); texp.Next()) {
BRepAdaptor_Curve crv(TopoDS::Edge(texp.Current()));
GCPnts_QuasiUniformDeflection tessellater(crv, settings().deflection_tolerance());
int n = tessellater.NbPoints();
int start = (int)_verts.size() / 3;
for (int i = 1; i <= n; ++i) {
gp_XYZ p = tessellater.Value(i).XYZ();
/*
// In case you want direction arrows on your edges
double u = tessellater.Parameter(i);
gp_XYZ p2, p3;
gp_Pnt tmp;
gp_Vec tmp2;
crv.D1(u, tmp, tmp2);
gp_Dir d1, d2, d3, d4;
d1 = tmp2;
if (texp.Current().Orientation() == TopAbs_REVERSED) {
d1 = -d1;
}
if (fabs(d1.Z()) < 0.5) {
d2 = d1.Crossed(gp::DZ());
} else {
d2 = d1.Crossed(gp::DY());
}
d3 = d1.XYZ() + d2.XYZ();
d4 = d1.XYZ() - d2.XYZ();
p2 = p - d3.XYZ() / 10.;
p3 = p - d4.XYZ() / 10.;
trsf.Transforms(p2);
trsf.Transforms(p3);
_material_ids.push_back(surface_style_id);
_material_ids.push_back(surface_style_id);
_verts.push_back(static_cast<P>(p2.X()));
_verts.push_back(static_cast<P>(p2.Y()));
_verts.push_back(static_cast<P>(p2.Z()));
_verts.push_back(static_cast<P>(p3.X()));
_verts.push_back(static_cast<P>(p3.Y()));
_verts.push_back(static_cast<P>(p3.Z()));
*/
trsf.Transforms(p);
_material_ids.push_back(surface_style_id);
_verts.push_back(static_cast<P>(p.X()));
_verts.push_back(static_cast<P>(p.Y()));
_verts.push_back(static_cast<P>(p.Z()));
if (i > 1) {
_edges.push_back(start + i - 2);
_edges.push_back(start + i - 1);
// _edges.push_back(start + 3 * (i - 2) + 2);
// _edges.push_back(start + 3 * (i - 1) + 2);
}
// _edges.push_back(start + 3 * (i - 1) + 0);
// _edges.push_back(start + 3 * (i - 1) + 2);
// _edges.push_back(start + 3 * (i - 1) + 1);
// _edges.push_back(start + 3 * (i - 1) + 2);
}
}
}
BRepTools::Clean(s);
}
}
virtual ~Triangulation() {}
/// Generates UVs for a single mesh using box projection.
/// @todo Very simple impl. Assumes that input vertices and normals match 1:1.
static std::vector<P> box_project_uvs(const std::vector<P> &vertices, const std::vector<P> &normals)
{
std::vector<P> uvs;
uvs.resize(vertices.size() / 3 * 2);
for (size_t uv_idx = 0, v_idx = 0;
uv_idx < uvs.size() && v_idx < vertices.size() && v_idx < normals.size();
uv_idx += 2, v_idx += 3) {
P n_x = normals[v_idx], n_y = normals[v_idx + 1], n_z = normals[v_idx + 2];
P v_x = vertices[v_idx], v_y = vertices[v_idx + 1], v_z = vertices[v_idx + 2];
if (std::abs(n_x) > std::abs(n_y) && std::abs(n_x) > std::abs(n_z)) {
uvs[uv_idx] = v_z;
uvs[uv_idx + 1] = v_y;
}
if (std::abs(n_y) > std::abs(n_x) && std::abs(n_y) > std::abs(n_z)) {
uvs[uv_idx] = v_x;
uvs[uv_idx + 1] = v_z;
}
if (std::abs(n_z) > std::abs(n_x) && std::abs(n_z) > std::abs(n_y)) {
uvs[uv_idx] = v_x;
uvs[uv_idx + 1] = v_y;
}
}
return uvs;
}
private:
// Welds vertices that belong to different faces
int addVertex(int material_index, const gp_XYZ& p) {
const bool convert = settings().get(IteratorSettings::CONVERT_BACK_UNITS);
const P X = static_cast<P>(convert ? (p.X() / settings().unit_magnitude()) : p.X());
const P Y = static_cast<P>(convert ? (p.Y() / settings().unit_magnitude()) : p.Y());
const P Z = static_cast<P>(convert ? (p.Z() / settings().unit_magnitude()) : p.Z());
int i = (int) _verts.size() / 3;
if (settings().get(IteratorSettings::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
-55
View File
@@ -1,55 +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_schema_agnostic/IfcGeomRenderStyles.h"
namespace IfcGeom {
class IFC_GEOM_API IfcRepresentationShapeItem {
private:
int id;
gp_GTrsf placement;
TopoDS_Shape shape;
const SurfaceStyle* style;
public:
IfcRepresentationShapeItem(int id, const gp_GTrsf& placement, const TopoDS_Shape& shape, const SurfaceStyle* style)
: id(id), placement(placement), shape(shape), style(style) {}
IfcRepresentationShapeItem(int id, const gp_GTrsf& placement, const TopoDS_Shape& shape)
: id(id), placement(placement), shape(shape), style(0) {}
IfcRepresentationShapeItem(int id, const TopoDS_Shape& shape, const SurfaceStyle* style)
: id(id), shape(shape), style(style) {}
IfcRepresentationShapeItem(int id, const TopoDS_Shape& shape)
: id(id), 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; }
void setStyle(const SurfaceStyle* newStyle) { style = newStyle; }
int ItemId() const { return id; }
};
typedef std::vector<IfcRepresentationShapeItem> IfcRepresentationShapeItems;
}
#endif
@@ -0,0 +1,552 @@
#include "AbstractKernel.h"
#include "../../ifcgeom/schema_agnostic/IfcGeomElement.h"
#define AbstractKernel MAKE_TYPE_NAME(AbstractKernel)
void IfcGeom::AbstractKernel::set_conversion_placement_rel_to(const IfcParse::declaration* type) {
placement_rel_to = type;
}
void IfcGeom::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 IfcGeom::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;
}
const IfcSchema::IfcMaterial* IfcGeom::AbstractKernel::get_single_material_association(const IfcSchema::IfcProduct* product) {
IfcSchema::IfcMaterial* single_material = 0;
IfcSchema::IfcRelAssociatesMaterial::list::ptr associated_materials = product->HasAssociations()->as<IfcSchema::IfcRelAssociatesMaterial>();
if (associated_materials->size() == 1) {
IfcSchema::IfcMaterialSelect* associated_material = (*associated_materials->begin())->RelatingMaterial();
single_material = associated_material->as<IfcSchema::IfcMaterial>();
// NB: Single-layer layersets are also considered, regardless of --enable-layerset-slicing, this
// in accordance with other viewers.
if (!single_material && associated_material->as<IfcSchema::IfcMaterialLayerSetUsage>()) {
IfcSchema::IfcMaterialLayerSet* layerset = associated_material->as<IfcSchema::IfcMaterialLayerSetUsage>()->ForLayerSet();
if (layerset->MaterialLayers()->size() == 1) {
IfcSchema::IfcMaterialLayer* layer = (*layerset->MaterialLayers()->begin());
if (layer->hasMaterial()) {
single_material = layer->Material();
}
}
}
}
return single_material;
}
IfcSchema::IfcRepresentation* IfcGeom::AbstractKernel::representation_mapped_to(const IfcSchema::IfcRepresentation* representation) {
IfcSchema::IfcRepresentation* representation_mapped_to = 0;
IfcSchema::IfcRepresentationItem::list::ptr items = representation->Items();
if (items->size() == 1) {
IfcSchema::IfcRepresentationItem* item = *items->begin();
if (item->declaration().is(IfcSchema::IfcMappedItem::Class())) {
if (item->StyledByItem()->size() == 0) {
IfcSchema::IfcMappedItem* mapped_item = item->as<IfcSchema::IfcMappedItem>();
if (is_identity_transform(mapped_item->MappingTarget())) {
IfcSchema::IfcRepresentationMap* map = mapped_item->MappingSource();
if (is_identity_transform(map->MappingOrigin())) {
representation_mapped_to = map->MappedRepresentation();
}
}
}
}
}
return representation_mapped_to;
}
IfcSchema::IfcProduct::list::ptr IfcGeom::AbstractKernel::products_represented_by(const IfcSchema::IfcRepresentation* representation) {
IfcSchema::IfcProduct::list::ptr products(new IfcSchema::IfcProduct::list);
IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation();
for (IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it) {
// 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
products->push((*it)->data().getInverse((&IfcSchema::IfcProduct::Class()), -1)->as<IfcSchema::IfcProduct>());
}
IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap();
if (maps->size() == 1) {
IfcSchema::IfcRepresentationMap* map = *maps->begin();
if (is_identity_transform(map->MappingOrigin())) {
IfcSchema::IfcMappedItem::list::ptr items = map->MapUsage();
for (IfcSchema::IfcMappedItem::list::it it = items->begin(); it != items->end(); ++it) {
IfcSchema::IfcMappedItem* item = *it;
if (item->StyledByItem()->size() != 0) continue;
if (!is_identity_transform(item->MappingTarget())) {
continue;
}
IfcSchema::IfcRepresentation::list::ptr reps = item->data().getInverse((&IfcSchema::IfcRepresentation::Class()), -1)->as<IfcSchema::IfcRepresentation>();
for (IfcSchema::IfcRepresentation::list::it jt = reps->begin(); jt != reps->end(); ++jt) {
IfcSchema::IfcRepresentation* rep = *jt;
if (rep->Items()->size() != 1) continue;
IfcSchema::IfcProductRepresentation::list::ptr prodreps_mapped = rep->OfProductRepresentation();
for (IfcSchema::IfcProductRepresentation::list::it kt = prodreps_mapped->begin(); kt != prodreps_mapped->end(); ++kt) {
IfcSchema::IfcProduct::list::ptr ps = (*kt)->data().getInverse((&IfcSchema::IfcProduct::Class()), -1)->as<IfcSchema::IfcProduct>();
products->push(ps);
}
}
}
}
}
return products;
}
namespace {
const IfcSchema::IfcRepresentationItem* find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item) {
if (item->StyledByItem()->size()) {
return item;
}
while (item->declaration().is(IfcSchema::IfcBooleanClippingResult::Class())) {
// All instantiations of IfcBooleanOperand (type of FirstOperand) are subtypes of
// IfcGeometricRepresentationItem
item = (IfcSchema::IfcGeometricRepresentationItem*) ((IfcSchema::IfcBooleanClippingResult*) item)->FirstOperand();
if (item->StyledByItem()->size()) {
return item;
}
}
// TODO: Ideally this would be done for other entities (such as IfcCsgSolid) as well.
// But neither are these very prevalent, nor does the current IfcOpenShell style
// mechanism enable to conveniently style subshapes, which would be necessary for
// distinctly styled union operands.
return item;
}
template <typename T>
std::pair<IfcSchema::IfcSurfaceStyle*, T*> _get_surface_style(const IfcSchema::IfcStyledItem* si) {
#ifdef SCHEMA_HAS_IfcStyleAssignmentSelect
IfcEntityList::ptr style_assignments = si->Styles();
for (IfcEntityList::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
if (!(*kt)->declaration().is(IfcSchema::IfcPresentationStyleAssignment::Class())) {
continue;
}
IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt;
#else
IfcSchema::IfcPresentationStyleAssignment::list::ptr style_assignments = si->Styles();
for (IfcSchema::IfcPresentationStyleAssignment::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
IfcSchema::IfcPresentationStyleAssignment* style_assignment = *kt;
#endif
IfcEntityList::ptr styles = style_assignment->Styles();
for (IfcEntityList::it lt = styles->begin(); lt != styles->end(); ++lt) {
IfcUtil::IfcBaseClass* style = *lt;
if (style->declaration().is(IfcSchema::IfcSurfaceStyle::Class())) {
IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style;
if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) {
IfcEntityList::ptr styles_elements = surface_style->Styles();
for (IfcEntityList::it mt = styles_elements->begin(); mt != styles_elements->end(); ++mt) {
if ((*mt)->declaration().is(T::Class())) {
return std::make_pair(surface_style, (T*)*mt);
}
}
}
}
}
}
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0, 0);
}
template <typename T>
std::pair<IfcSchema::IfcSurfaceStyle*, T*> get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) {
// For certain representation items, most notably boolean operands,
// a style definition might reside on one of its operands.
representation_item = find_item_carrying_style(representation_item);
if (representation_item->as<IfcSchema::IfcStyledItem>()) {
return _get_surface_style<T>(representation_item->as<IfcSchema::IfcStyledItem>());
}
IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem();
if (styled_items->size()) {
// StyledByItem is a SET [0:1] OF IfcStyledItem, so we return after the first IfcStyledItem:
return _get_surface_style<T>(*styled_items->begin());
}
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0, 0);
}
bool process_colour(IfcSchema::IfcColourRgb* colour, double* 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, double* 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, double* rgb) {
if (colour_or_factor == 0) {
return false;
} else if (colour_or_factor->declaration().is(IfcSchema::IfcColourRgb::Class())) {
return process_colour(static_cast<IfcSchema::IfcColourRgb*>(colour_or_factor), rgb);
} else if (colour_or_factor->declaration().is(IfcSchema::IfcNormalisedRatioMeasure::Class())) {
return process_colour(static_cast<IfcSchema::IfcNormalisedRatioMeasure*>(colour_or_factor), rgb);
} else {
return false;
}
}
}
const IfcGeom::SurfaceStyle* IfcGeom::AbstractKernel::get_style(const IfcSchema::IfcRepresentationItem* item) {
return internalize_surface_style(get_surface_style<IfcSchema::IfcSurfaceStyleShading>(item));
}
const IfcGeom::SurfaceStyle* IfcGeom::AbstractKernel::get_style(const IfcSchema::IfcMaterial* material) {
IfcSchema::IfcMaterialDefinitionRepresentation::list::ptr defs = material->HasRepresentation();
for (IfcSchema::IfcMaterialDefinitionRepresentation::list::it jt = defs->begin(); jt != defs->end(); ++jt) {
IfcSchema::IfcRepresentation::list::ptr reps = (*jt)->Representations();
IfcSchema::IfcStyledItem::list::ptr styles(new IfcSchema::IfcStyledItem::list);
for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) {
styles->push((**it).Items()->as<IfcSchema::IfcStyledItem>());
}
for (IfcSchema::IfcStyledItem::list::it it = styles->begin(); it != styles->end(); ++it) {
const std::pair<IfcSchema::IfcSurfaceStyle*, IfcSchema::IfcSurfaceStyleShading*> ss = get_surface_style<IfcSchema::IfcSurfaceStyleShading>(*it);
if (ss.second) {
return internalize_surface_style(ss);
}
}
}
IfcGeom::SurfaceStyle material_style = IfcGeom::SurfaceStyle(material->data().id(), material->Name());
return &(style_cache[material->data().id()] = material_style);
}
const IfcGeom::SurfaceStyle* IfcGeom::AbstractKernel::internalize_surface_style(const std::pair<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*>& shading_styles) {
if (shading_styles.second == 0) {
return 0;
}
int surface_style_id = shading_styles.first->data().id();
std::map<int, SurfaceStyle>::const_iterator it = style_cache.find(surface_style_id);
if (it != style_cache.end()) {
return &(it->second);
}
SurfaceStyle surface_style;
IfcSchema::IfcSurfaceStyle* style = shading_styles.first->as<IfcSchema::IfcSurfaceStyle>();
IfcSchema::IfcSurfaceStyleShading* shading = shading_styles.second->as<IfcSchema::IfcSurfaceStyleShading>();
if (style->hasName()) {
surface_style = SurfaceStyle(surface_style_id, style->Name());
} else {
surface_style = SurfaceStyle(surface_style_id);
}
double rgb[3];
if (process_colour(shading->SurfaceColour(), rgb)) {
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
}
if (shading_styles.second->declaration().is(IfcSchema::IfcSurfaceStyleRendering::Class())) {
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->declaration().is(IfcSchema::IfcSpecularRoughness::Class())) {
double roughness = *((IfcSchema::IfcSpecularRoughness*)highlight);
if (roughness >= 1e-9) {
surface_style.Specularity().reset(1.0 / roughness);
}
} else if (highlight->declaration().is(IfcSchema::IfcSpecularExponent::Class())) {
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 &(style_cache[surface_style_id] = surface_style);
}
template <typename P, typename PP>
IfcGeom::NativeElement<P, PP>* IfcGeom::AbstractKernel::create_brep_for_representation_and_product(
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product) {
std::stringstream representation_id_builder;
representation_id_builder << representation->data().id();
IfcGeom::Representation::BRep* shape;
IfcGeom::ConversionResults shapes;
if (!convert_shapes(representation, shapes)) {
return 0;
}
if (settings.get(IteratorSettings::APPLY_LAYERSETS)) {
if (apply_layerset(product, shapes)) {
IfcSchema::IfcRelAssociates::list::ptr associations = product->HasAssociations();
for (IfcSchema::IfcRelAssociates::list::it it = associations->begin(); it != associations->end(); ++it) {
IfcSchema::IfcRelAssociatesMaterial* associates_material = (**it).as<IfcSchema::IfcRelAssociatesMaterial>();
if (associates_material) {
unsigned layerset_id = associates_material->RelatingMaterial()->data().id();
representation_id_builder << "-layerset-" << layerset_id;
break;
}
}
}
}
bool material_style_applied = false;
const IfcSchema::IfcMaterial* single_material = get_single_material_association(product);
if (single_material) {
const IfcGeom::SurfaceStyle* s = get_style(single_material);
for (IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++it) {
if (!it->hasStyle() && s) {
it->setStyle(s);
material_style_applied = true;
}
}
} else {
bool some_items_without_style = false;
for (IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++it) {
if (!it->hasStyle()) {
some_items_without_style = true;
break;
}
}
if (some_items_without_style) {
Logger::Warning("No material and surface styles for:", product);
}
}
if (material_style_applied) {
representation_id_builder << "-material-" << single_material->data().id();
}
int parent_id = -1;
try {
IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product);
if (parent_object && parent_object->as<IfcSchema::IfcObjectDefinition>()) {
parent_id = parent_object->data().id();
}
} catch (const std::exception& e) {
Logger::Error(e);
}
const std::string name = product->hasName() ? product->Name() : "";
const std::string guid = product->GlobalId();
ConversionResultPlacement* trsf = nullptr;
try {
convert_placement(product->ObjectPlacement(), trsf);
} catch (const std::exception& e) {
Logger::Error(e);
} catch (...) {
Logger::Error("Failed to construct placement");
}
// Does the IfcElement have any IfcOpenings?
// Note that openings for IfcOpeningElements are not processed
IfcSchema::IfcRelVoidsElement::list::ptr openings = find_openings(product)->as<IfcSchema::IfcRelVoidsElement>();
const std::string product_type = product->declaration().name();
ElementSettings element_settings(settings, getValue(GV_LENGTH_UNIT), product_type);
if (!settings.get(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && openings && openings->size()) {
representation_id_builder << "-openings";
for (IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++it) {
representation_id_builder << "-" << (*it)->data().id();
}
IfcGeom::ConversionResults opened_shapes;
bool caught_error = false;
try {
convert_openings(product, openings, shapes, trsf, opened_shapes);
} catch (const std::exception& e) {
Logger::Message(Logger::LOG_ERROR, std::string("Error processing openings for: ") + e.what() + ":", product);
caught_error = true;
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Error processing openings for:", product);
}
if (caught_error && opened_shapes.size() < shapes.size()) {
opened_shapes = shapes;
}
if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
for (IfcGeom::ConversionResults::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++it) {
it->prepend(trsf);
}
trsf = nullptr;
representation_id_builder << "-world-coords";
}
shape = new IfcGeom::Representation::BRep(element_settings, representation_id_builder.str(), opened_shapes);
} else if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
for (IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++it) {
it->prepend(trsf);
}
trsf = nullptr;
representation_id_builder << "-world-coords";
shape = new IfcGeom::Representation::BRep(element_settings, representation_id_builder.str(), shapes);
} else {
shape = new IfcGeom::Representation::BRep(element_settings, representation_id_builder.str(), shapes);
}
std::string context_string = "";
if (representation->hasRepresentationIdentifier()) {
context_string = representation->RepresentationIdentifier();
} else if (representation->ContextOfItems()->hasContextType()) {
context_string = representation->ContextOfItems()->ContextType();
}
auto elem = new NativeElement<P, PP>(
product->data().id(),
parent_id,
name,
product_type,
guid,
context_string,
trsf,
boost::shared_ptr<IfcGeom::Representation::BRep>(shape),
product
);
if (settings.get(IteratorSettings::VALIDATE_QUANTITIES)) {
validate_quantities(product, elem->geometry());
}
return elem;
}
template <typename P, typename PP>
IfcGeom::NativeElement<P, PP>* IfcGeom::AbstractKernel::create_brep_for_processed_representation(
const IteratorSettings& /*settings*/, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product,
IfcGeom::NativeElement<P, PP>* brep) {
int parent_id = -1;
try {
IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product);
if (parent_object && parent_object->as<IfcSchema::IfcObjectDefinition>()) {
parent_id = parent_object->data().id();
}
} catch (const std::exception& e) {
Logger::Error(e);
}
const std::string name = product->hasName() ? product->Name() : "";
const std::string guid = product->GlobalId();
ConversionResultPlacement* trsf = nullptr;
try {
convert_placement(product->ObjectPlacement(), trsf);
} catch (const std::exception& e) {
Logger::Error(e);
} catch (...) {
Logger::Error("Failed to construct placement");
}
std::string context_string = "";
if (representation->hasRepresentationIdentifier()) {
context_string = representation->RepresentationIdentifier();
} else if (representation->ContextOfItems()->hasContextType()) {
context_string = representation->ContextOfItems()->ContextType();
}
const std::string product_type = product->declaration().name();
return new NativeElement<P, PP>(
product->data().id(),
parent_id,
name,
product_type,
guid,
context_string,
trsf,
brep->geometry_pointer(),
product
);
}
template IFC_GEOM_API IfcGeom::NativeElement<float, float>* IfcGeom::AbstractKernel::create_brep_for_representation_and_product<float, float>(
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product);
template IFC_GEOM_API IfcGeom::NativeElement<float, double>* IfcGeom::AbstractKernel::create_brep_for_representation_and_product<float, double>(
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product);
template IFC_GEOM_API IfcGeom::NativeElement<double, double>* IfcGeom::AbstractKernel::create_brep_for_representation_and_product<double, double>(
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product);
template IFC_GEOM_API IfcGeom::NativeElement<float, float>* IfcGeom::AbstractKernel::create_brep_for_processed_representation<float, float>(
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement<float, float>* brep);
template IFC_GEOM_API IfcGeom::NativeElement<float, double>* IfcGeom::AbstractKernel::create_brep_for_processed_representation<float, double>(
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement<float, double>* brep);
template IFC_GEOM_API IfcGeom::NativeElement<double, double>* IfcGeom::AbstractKernel::create_brep_for_processed_representation<double, double>(
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement<double, double>* brep);
@@ -0,0 +1,77 @@
#ifndef ABSTRACT_KERNEL_H
#define ABSTRACT_KERNEL_H
#include "../../ifcparse/macros.h"
#include "../../ifcgeom/schema_agnostic/ifc_geom_api.h"
#include "../../ifcgeom/schema_agnostic/Kernel.h"
#include "../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
#define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x.h)
#include INCLUDE_SCHEMA(IfcSchema)
#undef INCLUDE_SCHEMA
#define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x-definitions.h)
#include INCLUDE_SCHEMA(IfcSchema)
#undef INCLUDE_SCHEMA
namespace IfcGeom {
class IFC_GEOM_API MAKE_TYPE_NAME(AbstractKernel) : public IfcGeom::Kernel {
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::map<int, SurfaceStyle> style_cache;
public:
MAKE_TYPE_NAME(AbstractKernel)(const std::string& geometry_library)
: IfcGeom::Kernel(geometry_library, nullptr)
, 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)
{}
void set_conversion_placement_rel_to(const IfcParse::declaration* type);
virtual void setValue(GeomValue var, double value);
virtual double getValue(GeomValue var) const;
const IfcSchema::IfcMaterial* get_single_material_association(const IfcSchema::IfcProduct*);
IfcSchema::IfcRepresentation* representation_mapped_to(const IfcSchema::IfcRepresentation* representation);
IfcSchema::IfcProduct::list::ptr products_represented_by(const IfcSchema::IfcRepresentation*);
const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem*);
const SurfaceStyle* get_style(const IfcSchema::IfcMaterial*);
virtual bool is_identity_transform(const IfcUtil::IfcBaseClass*) = 0;
virtual bool convert_shapes(const IfcUtil::IfcBaseClass*, IfcGeom::ConversionResults&) = 0;
virtual bool apply_layerset(const IfcSchema::IfcProduct* product, IfcGeom::ConversionResults& shapes) = 0;
virtual bool validate_quantities(const IfcSchema::IfcProduct* product, const IfcGeom::Representation::BRep& brep) = 0;
virtual bool convert_openings(const IfcSchema::IfcProduct* product, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcGeom::ConversionResults& shapes, const ConversionResultPlacement* trsf, IfcGeom::ConversionResults& opened_shapes) = 0;
const SurfaceStyle* internalize_surface_style(const std::pair<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*>& shading_style);
template <typename P, typename PP>
IfcGeom::NativeElement<P, PP>* create_brep_for_representation_and_product(
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*);
template <typename P, typename PP>
IfcGeom::NativeElement<P, PP>* create_brep_for_processed_representation(
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::NativeElement<P, PP>*);
};
}
#endif
@@ -1,5 +1,4 @@
#include "IfcGeomIteratorImplementation.h"
#include "../ifcgeom_schema_agnostic/IteratorImplementation.h"
namespace IfcGeom {
template class MAKE_TYPE_NAME(IteratorImplementation_)<float, float>;
@@ -14,8 +13,8 @@ namespace IfcGeom {
namespace {
template <typename P, typename PP>
struct MAKE_TYPE_NAME(factory_t) {
IfcGeom::IteratorImplementation<P, PP>* operator()(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads) const {
return new IfcGeom::MAKE_TYPE_NAME(IteratorImplementation_)<P, PP>(settings, file, filters, num_threads);
IfcGeom::IteratorImplementation<P, PP>* operator()(const std::string& geometry_engine, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads) const {
return new IfcGeom::MAKE_TYPE_NAME(IteratorImplementation_)<P, PP>(geometry_engine, settings, file, filters, num_threads);
}
};
}
@@ -78,16 +78,22 @@
#include <gp_Trsf.hxx>
#include <gp_Trsf2d.hxx>
#include "../ifcparse/IfcFile.h"
#include "../../ifcparse/macros.h"
#include "../../ifcparse/IfcFile.h"
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom/IfcGeomElement.h"
#include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h"
#include "../ifcgeom/IfcGeomIteratorSettings.h"
#include "../ifcgeom/IfcRepresentationShapeItem.h"
#include "../../ifcgeom/schema_agnostic/IfcGeomElement.h"
#include "../../ifcgeom/schema_agnostic/IfcGeomMaterial.h"
#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
#include "../../ifcgeom/schema_agnostic/ConversionResult.h"
#include "../ifcgeom_schema_agnostic/IfcGeomFilter.h"
#include "../ifcgeom_schema_agnostic/IteratorImplementation.h"
#include "../../ifcgeom/schema_agnostic/IfcGeomFilter.h"
#include "../../ifcgeom/schema_agnostic/IteratorImplementation.h"
#include "../../ifcgeom/kernel_agnostic/AbstractKernel.h"
#define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x.h)
#include INCLUDE_SCHEMA(IfcSchema)
#undef INCLUDE_SCHEMA
#include <atomic>
@@ -105,14 +111,14 @@ namespace {
int index;
IfcSchema::IfcRepresentation *representation;
IfcSchema::IfcProduct::list::ptr products;
std::vector<IfcGeom::BRepElement<P, PP>*> breps;
std::vector<IfcGeom::NativeElement<P, PP>*> breps;
std::vector<IfcGeom::Element<P, PP>*> elements;
};
template <typename P, typename PP=P>
IfcGeom::Element<P, PP>* process_based_on_settings(
const IfcGeom::IteratorSettings& settings,
IfcGeom::BRepElement<P, PP>* elem,
IfcGeom::NativeElement<P, PP>* elem,
IfcGeom::TriangulationElement<P, PP>* previous=nullptr)
{
if (settings.get(IfcGeom::IteratorSettings::USE_BREP_DATA)) {
@@ -140,7 +146,7 @@ namespace {
template <typename P, typename PP = P>
void create_element(
IfcGeom::MAKE_TYPE_NAME(Kernel)* kernel,
IfcGeom::MAKE_TYPE_NAME(AbstractKernel)* kernel,
const IfcGeom::IteratorSettings& settings,
geometry_conversion_task<P, PP>* rep)
{
@@ -182,14 +188,16 @@ namespace IfcGeom {
std::atomic<int> progress_;
std::vector<geometry_conversion_task<P, PP>> tasks_;
std::vector<IfcGeom::Element<P, PP>*> all_processed_elements_;
std::vector<IfcGeom::BRepElement<P, PP>*> all_processed_native_elements_;
std::vector<IfcGeom::NativeElement<P, PP>*> all_processed_native_elements_;
typename std::vector<IfcGeom::Element<P, PP>*>::const_iterator task_result_iterator_;
typename std::vector<IfcGeom::BRepElement<P, PP>*>::const_iterator native_task_result_iterator_;
typename std::vector<IfcGeom::NativeElement<P, PP>*>::const_iterator native_task_result_iterator_;
std::string geometry_library_;
MAKE_TYPE_NAME(IteratorImplementation_)(const MAKE_TYPE_NAME(IteratorImplementation_)&); // N/I
MAKE_TYPE_NAME(IteratorImplementation_)& operator=(const MAKE_TYPE_NAME(IteratorImplementation_)&); // N/I
MAKE_TYPE_NAME(Kernel) kernel;
MAKE_TYPE_NAME(AbstractKernel)* kernel;
IteratorSettings settings;
IfcParse::IfcFile* ifc_file;
@@ -200,7 +208,7 @@ namespace IfcGeom {
// The object is fetched beforehand to be sure that get() returns a valid element
TriangulationElement<P, PP>* current_triangulation;
BRepElement<P, PP>* current_shape_model;
NativeElement<P, PP>* current_shape_model;
SerializedElement<P, PP>* current_serialization;
// A container and iterator for IfcBuildingElements for the current IfcRepresentation referenced by *representation_iterator
@@ -229,29 +237,12 @@ namespace IfcGeom {
IfcSchema::IfcProduct* product;
};
void initUnits() {
IfcSchema::IfcProject::list::ptr projects = ifc_file->instances_by_type<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 = length_unit.second;
} else {
Logger::Warning("A single IfcProject is expected (encountered " + boost::lexical_cast<std::string>(projects->size()) + "); unable to read unit information.");
}
}
/// @todo public/private sections all over the place: move all public to the beginning of the class
public:
typedef P Precision;
typedef PP PlacementPrecision;
bool initialize() {
try {
initUnits();
} catch (const std::exception& e) {
Logger::Error(e);
}
std::set<std::string> allowed_context_types;
allowed_context_types.insert("model");
@@ -273,9 +264,6 @@ namespace IfcGeom {
context_types.insert("plan");
}
double lowest_precision_encountered = std::numeric_limits<double>::infinity();
bool any_precision_encountered = false;
representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
ok_mapped_representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
@@ -325,15 +313,7 @@ namespace IfcGeom {
IfcSchema::IfcGeometricRepresentationContext* context = *it;
representations->push(context->RepresentationsInContext());
try {
if (context->hasPrecision() && context->Precision() < lowest_precision_encountered) {
lowest_precision_encountered = context->Precision();
any_precision_encountered = true;
}
} catch (const std::exception& e) {
Logger::Error(e);
}
IfcSchema::IfcGeometricRepresentationSubContext::list::ptr sub_contexts = context->HasSubContexts();
for (jt = sub_contexts->begin(); jt != sub_contexts->end(); ++jt) {
representations->push((*jt)->RepresentationsInContext());
@@ -342,21 +322,6 @@ namespace IfcGeom {
// 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) {
Logger::Warning("No representations encountered in relevant contexts, using all");
representations = ifc_file->instances_by_type<IfcSchema::IfcRepresentation>();
@@ -412,10 +377,10 @@ namespace IfcGeom {
conc_threads = tasks_.size();
}
std::vector<MAKE_TYPE_NAME(Kernel)*> kernel_pool;
std::vector<MAKE_TYPE_NAME(AbstractKernel)*> kernel_pool;
kernel_pool.reserve(conc_threads);
for (unsigned i = 0; i < conc_threads; ++i) {
kernel_pool.push_back(new MAKE_TYPE_NAME(Kernel)(kernel));
kernel_pool.push_back((MAKE_TYPE_NAME(AbstractKernel)*) impl::kernel_implementations().construct(ifc_file->schema()->name(), geometry_library_, ifc_file));
}
std::vector<std::future<void>> threadpool;
@@ -426,7 +391,7 @@ namespace IfcGeom {
Logger::ProgressBar(0);
for (auto& rep : tasks_) {
MAKE_TYPE_NAME(Kernel)* K = nullptr;
MAKE_TYPE_NAME(AbstractKernel)* K = nullptr;
if (threadpool.size() < kernel_pool.size()) {
K = kernel_pool[threadpool.size()];
}
@@ -496,11 +461,11 @@ namespace IfcGeom {
IfcSchema::IfcProduct* product = *iter;
if (product->hasObjectPlacement()) {
// Use a fresh trsf every time in order to prevent the result to be concatenated
gp_Trsf trsf;
ConversionResultPlacement* trsf;
bool success = false;
try {
success = kernel.convert(product->ObjectPlacement(), trsf);
success = kernel->convert_placement(product->ObjectPlacement(), trsf);
} catch (const std::exception& e) {
Logger::Error(e);
} catch (...) {
@@ -511,13 +476,14 @@ namespace IfcGeom {
continue;
}
const gp_XYZ& pos = trsf.TranslationPart();
bounds_min_.SetX(std::min(bounds_min_.X(), pos.X()));
bounds_min_.SetY(std::min(bounds_min_.Y(), pos.Y()));
bounds_min_.SetZ(std::min(bounds_min_.Z(), pos.Z()));
bounds_max_.SetX(std::max(bounds_max_.X(), pos.X()));
bounds_max_.SetY(std::max(bounds_max_.Y(), pos.Y()));
bounds_max_.SetZ(std::max(bounds_max_.Z(), pos.Z()));
double X, Y, Z;
trsf->TranslationPart(X, Y, Z);
bounds_min_.SetX(std::min(bounds_min_.X(), X));
bounds_min_.SetY(std::min(bounds_min_.Y(), Y));
bounds_min_.SetZ(std::min(bounds_min_.Z(), Z));
bounds_max_.SetX(std::max(bounds_max_.X(), X));
bounds_max_.SetY(std::max(bounds_max_.Y(), Y));
bounds_max_.SetZ(std::max(bounds_max_.Z(), Z));
}
}
}
@@ -548,13 +514,6 @@ namespace IfcGeom {
private:
// Move to the next IfcRepresentation
void _nextShape() {
// In order to conserve memory and reduce cache insertion times, the cache is
// cleared after an arbitrary number of processed representations. This has been
// benchmarked extensively: https://github.com/IfcOpenShell/IfcOpenShell/pull/47
static const int clear_interval = 64;
if (done % clear_interval == clear_interval - 1) {
kernel.purge_cache();
}
ifcproducts.reset();
++ representation_iterator;
++ done;
@@ -574,7 +533,7 @@ namespace IfcGeom {
for (IfcSchema::IfcProduct::list::it it = products->begin(); it != products->end(); ++it) {
IfcSchema::IfcProduct* product = *it;
if (!settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && kernel.find_openings(product)->size()) {
if (!settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && kernel->find_openings(product)->size()) {
return false;
}
@@ -592,7 +551,7 @@ namespace IfcGeom {
}
// Note that this can be a nullptr (!), but the fact that set size should be one still holds
associated_single_materials.insert(kernel.get_single_material_association(product));
associated_single_materials.insert(kernel->get_single_material_association(product));
if (associated_single_materials.size() > 1) return false;
}
@@ -612,14 +571,14 @@ namespace IfcGeom {
if (!ifcproducts) {
// Init. the list of filtered IfcProducts for this representation
ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list);
IfcSchema::IfcProduct::list::ptr unfiltered_products = kernel.products_represented_by(representation);
// Include only the desired products for processing.
for (IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin(); jt != unfiltered_products->end(); ++jt) {
IfcSchema::IfcProduct* prod = *jt;
if (boost::all(filters_, filter_match(prod))) {
ifcproducts->push(prod);
}
}
IfcSchema::IfcProduct::list::ptr unfiltered_products = kernel->products_represented_by(representation);
// Include only the desired products for processing.
for (IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin(); jt != unfiltered_products->end(); ++jt) {
IfcSchema::IfcProduct* prod = *jt;
if (boost::all(filters_, filter_match(prod))) {
ifcproducts->push(prod);
}
}
if (ifcproducts->size() == 0) {
_nextShape();
@@ -646,10 +605,10 @@ namespace IfcGeom {
// Check if this represenation has (or will be) processed as part its mapped representation
bool representation_processed_as_mapped_item = false;
IfcSchema::IfcRepresentation* representation_mapped_to = kernel.representation_mapped_to(representation);
IfcSchema::IfcRepresentation* representation_mapped_to = kernel->representation_mapped_to(representation);
if (representation_mapped_to) {
representation_processed_as_mapped_item = geometry_reuse_ok_for_current_representation_ && (
ok_mapped_representations->contains(representation_mapped_to) || reuse_ok_(kernel.products_represented_by(representation_mapped_to)));
representation_processed_as_mapped_item = geometry_reuse_ok_for_current_representation_ && (
ok_mapped_representations->contains(representation_mapped_to) || reuse_ok_(kernel->products_represented_by(representation_mapped_to)));
}
if (representation_processed_as_mapped_item) {
@@ -674,7 +633,7 @@ namespace IfcGeom {
}
}
BRepElement<P, PP>* create_shape_model_for_next_entity() {
NativeElement<P, PP>* create_shape_model_for_next_entity() {
for (;;) {
auto rp = get_next_task();
if (!rp) {
@@ -685,11 +644,11 @@ namespace IfcGeom {
Logger::SetProduct(product);
BRepElement<P, PP>* element;
NativeElement<P, PP>* element;
if (ifcproduct_iterator == ifcproducts->begin() || !geometry_reuse_ok_for_current_representation_) {
element = kernel.create_brep_for_representation_and_product<P, PP>(settings, representation, product);
element = kernel->create_brep_for_representation_and_product<P, PP>(settings, representation, product);
} else {
element = kernel.create_brep_for_processed_representation(settings, representation, product, current_shape_model);
element = kernel->create_brep_for_processed_representation(settings, representation, product, current_shape_model);
}
Logger::SetProduct(boost::none);
@@ -818,7 +777,7 @@ namespace IfcGeom {
}
/// Gets the native (Open Cascade) representation of the current geometrical entity.
BRepElement<P, PP>* get_native()
NativeElement<P, PP>* get_native()
{
// TODO: Test settings and throw
if (num_threads_ != 1) {
@@ -829,7 +788,7 @@ namespace IfcGeom {
}
const Element<P, PP>* get_object(int id) {
gp_Trsf trsf;
ConversionResultPlacement* trsf;
int parent_id = -1;
std::string instance_type, product_name, product_guid;
IfcSchema::IfcProduct* ifc_product = 0;
@@ -848,7 +807,7 @@ namespace IfcGeom {
ifc_product = ifc_entity->as<IfcSchema::IfcProduct>();
parent_id = -1;
try {
IfcSchema::IfcObjectDefinition* parent_object = kernel.get_decomposing_entity(ifc_product)->template as<IfcSchema::IfcObjectDefinition>();
IfcSchema::IfcObjectDefinition* parent_object = kernel->get_decomposing_entity(ifc_product)->template as<IfcSchema::IfcObjectDefinition>();
if (parent_object) {
parent_id = parent_object->data().id();
}
@@ -859,7 +818,7 @@ namespace IfcGeom {
}
try {
kernel.convert(ifc_product->ObjectPlacement(), trsf);
kernel->convert_placement(ifc_product->ObjectPlacement(), trsf);
} catch (const std::exception& e) {
Logger::Error(e);
} catch (...) {
@@ -885,7 +844,7 @@ namespace IfcGeom {
}
IfcUtil::IfcBaseClass* create() {
IfcGeom::BRepElement<P, PP>* next_shape_model = 0;
IfcGeom::NativeElement<P, PP>* next_shape_model = 0;
IfcGeom::SerializedElement<P, PP>* next_serialization = 0;
IfcGeom::TriangulationElement<P, PP>* next_triangulation = 0;
@@ -940,28 +899,31 @@ namespace IfcGeom {
unit_name = "METER";
unit_magnitude = 1.f;
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_ORIENT, settings.get(IteratorSettings::SEW_SHELLS) ? std::numeric_limits<double>::infinity() : -1);
kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.get(IteratorSettings::INCLUDE_CURVES)
kernel->setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_ORIENT, settings.get(IteratorSettings::SEW_SHELLS) ? std::numeric_limits<double>::infinity() : -1);
kernel->setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.get(IteratorSettings::INCLUDE_CURVES)
? (settings.get(IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES) ? -1. : 0.) : +1.));
if (settings.get(IteratorSettings::BUILDING_LOCAL_PLACEMENT)) {
if (settings.get(IteratorSettings::SITE_LOCAL_PLACEMENT)) {
Logger::Message(Logger::LOG_WARNING, "building-local-placement takes precedence over site-local-placement");
}
kernel.set_conversion_placement_rel_to(&IfcSchema::IfcBuilding::Class());
kernel->set_conversion_placement_rel_to(&IfcSchema::IfcBuilding::Class());
} else if (settings.get(IteratorSettings::SITE_LOCAL_PLACEMENT)) {
kernel.set_conversion_placement_rel_to(&IfcSchema::IfcSite::Class());
kernel->set_conversion_placement_rel_to(&IfcSchema::IfcSite::Class());
}
}
bool owns_ifc_file;
public:
MAKE_TYPE_NAME(IteratorImplementation_)(const IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads)
MAKE_TYPE_NAME(IteratorImplementation_)(const std::string& geometry_library, const IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads)
: settings(settings)
, ifc_file(file)
, filters_(filters)
, owns_ifc_file(false)
, num_threads_(num_threads)
, geometry_library_(geometry_library)
{
kernel = (MAKE_TYPE_NAME(AbstractKernel)*) impl::kernel_implementations().construct(file->schema()->name(), geometry_library, file);
// kernel = new Kernel(geometry_library, file);
_initialize();
}
@@ -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,96 @@
/********************************************************************************
* *
* 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"
#define CgalKernel MAKE_TYPE_NAME(CgalKernel)
using namespace IfcUtil;
bool IfcGeom::CgalKernel::convert_shapes(const IfcBaseClass* l, ConversionResults& r) {
if (shape_type(l) != ST_SHAPELIST) {
cgal_shape_t shp;
if (convert_shape(l, shp)) {
r.push_back(IfcGeom::ConversionResult(l->data().id(), new CgalShape(shp), get_style(l->as<IfcSchema::IfcRepresentationItem>())));
return true;
}
return false;
}
#include "CgalEntityMappingShapes.h"
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
return false;
}
IfcGeom::ShapeType IfcGeom::CgalKernel::shape_type(const IfcBaseClass* l) {
#include "CgalEntityMappingShapeType.h"
return ST_OTHER;
}
bool IfcGeom::CgalKernel::convert_shape(const IfcBaseClass* l, cgal_shape_t& r) {
const unsigned int id = l->data().id();
bool success = false;
bool processed = false;
bool ignored = false;
#ifndef NO_CACHE
std::map<int, cgal_shape_t>::const_iterator it = cache.Shape.find(id);
if ( it != cache.Shape.end() ) { r = it->second; return true; }
#endif
const bool include_curves = getValue(GV_DIMENSIONALITY) != +1;
const bool include_solids_and_surfaces = getValue(GV_DIMENSIONALITY) != -1;
IfcGeom::ShapeType st = shape_type(l);
ignored = (!include_solids_and_surfaces && (st == ST_SHAPE || st == ST_FACE)) || (!include_curves && (st == ST_WIRE || st == ST_CURVE));
if (st == ST_SHAPE && include_solids_and_surfaces) {
#include "CgalEntityMappingShape.h"
}
if ( processed && success ) {
// const double precision = getValue(GV_PRECISION);
// apply_tolerance(r, precision);
#ifndef NO_CACHE
cache.Shape[id] = r;
#endif
} else if (!ignored) {
const char* const msg = processed
? "Failed to convert:"
: "No operation defined for:";
Logger::Message(Logger::LOG_ERROR, msg, l);
}
return success;
}
bool IfcGeom::CgalKernel::convert_wire(const IfcBaseClass* l, cgal_wire_t& r) {
#include "CgalEntityMappingWire.h"
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
return false;
}
bool IfcGeom::CgalKernel::convert_face(const IfcBaseClass* l, cgal_face_t& r) {
#include "CgalEntityMappingFace.h"
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
return false;
}
bool IfcGeom::CgalKernel::convert_curve(const IfcBaseClass* l, cgal_curve_t& r) {
#include "CgalEntityMappingCurve.h"
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
return false;
}
@@ -0,0 +1,121 @@
/********************************************************************************
* *
* 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 "../../../ifcparse/IfcParse.h"
SHAPES(IfcShellBasedSurfaceModel);
SHAPES(IfcFaceBasedSurfaceModel);
SHAPES(IfcRepresentation);
SHAPES(IfcMappedItem);
// IfcFacetedBrep included
// IfcAdvancedBrep included
// IfcFacetedBrepWithVoids included
// IfcAdvancedBrepWithVoids included
SHAPES(IfcManifoldSolidBrep);
SHAPES(IfcGeometricSet);
#ifdef USE_IFC4
//SHAPE(IfcCylindricalSurface);
//SHAPE(IfcAdvancedBrep);
//SHAPE(IfcBSplineSurfaceWithKnots);
SHAPE(IfcTriangulatedFaceSet);
SHAPE(IfcExtrudedAreaSolidTapered);
#endif
//SHAPE(IfcPlane);
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);
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);
// IfcFaceSurface included
// IfcAdvancedFace included in case of IFC4
FACE(IfcFace);
//WIRE(IfcEdgeCurve);
//WIRE(IfcSubedge);
WIRE(IfcOrientedEdge);
WIRE(IfcEdge);
WIRE(IfcEdgeLoop);
WIRE(IfcPolyline);
WIRE(IfcPolyLoop);
WIRE(IfcCompositeCurve);
WIRE(IfcTrimmedCurve);
//WIRE(IfcArbitraryOpenProfileDef);
CURVE(IfcCircle);
CURVE(IfcEllipse);
CURVE(IfcLine);
#ifdef USE_IFC4
// IfcRationalBSplineCurveWithKnots included
//CURVE(IfcBSplineCurveWithKnots);
#endif
CLASS(IfcCartesianPoint,cgal_point_t);
CLASS(IfcDirection,cgal_direction_t);
CLASS(IfcAxis2Placement2D,cgal_placement_t);
CLASS(IfcAxis2Placement3D,cgal_placement_t);
CLASS(IfcAxis1Placement,cgal_placement_t);
CLASS(IfcCartesianTransformationOperator2DnonUniform,cgal_placement_t);
CLASS(IfcCartesianTransformationOperator3DnonUniform,cgal_placement_t);
CLASS(IfcCartesianTransformationOperator2D,cgal_placement_t);
CLASS(IfcCartesianTransformationOperator3D,cgal_placement_t);
CLASS(IfcObjectPlacement,cgal_placement_t);
CLASS(IfcVector,cgal_vector_t);
CLASS(IfcPlane,cgal_plane_t);
@@ -0,0 +1,6 @@
#include "CgalEntityMappingUndefine.h"
#define CLASS(T,V) \
std::map<int,V> T;
#include "CgalEntityMappingDefine.h"
#include "CgalEntityMapping.h"
@@ -0,0 +1,6 @@
#include "CgalEntityMappingUndefine.h"
#define CURVE(T) \
if (l->declaration().is(IfcSchema::T::Class())) return convert((IfcSchema::T*)l,r);
#include "CgalEntityMappingDefine.h"
#include "CgalEntityMapping.h"
@@ -0,0 +1,10 @@
#include "CgalEntityMappingUndefine.h"
#define CLASS(T,V) bool convert(const IfcSchema::T* L, V& r);
#define SHAPES(T) CLASS(T,ConversionResults)
#define SHAPE(T) CLASS(T,cgal_shape_t)
#define WIRE(T) CLASS(T,cgal_wire_t)
#define FACE(T) CLASS(T,cgal_face_t)
#define CURVE(T) CLASS(T,cgal_curve_t)
#include "CgalEntityMappingDefine.h"
#include "CgalEntityMapping.h"
@@ -0,0 +1,6 @@
#include "CgalEntityMappingUndefine.h"
#define FACE(T) \
if (l->declaration().is(IfcSchema::T::Class())) return convert((IfcSchema::T*)l,r);
#include "CgalEntityMappingDefine.h"
#include "CgalEntityMapping.h"
@@ -0,0 +1,6 @@
#include "CgalEntityMappingUndefine.h"
#define CLASS(T,V) \
T.clear();
#include "CgalEntityMappingDefine.h"
#include "CgalEntityMapping.h"
@@ -0,0 +1,20 @@
#include "CgalEntityMappingUndefine.h"
#define SHAPE(T) \
if ( !processed && l->declaration().is(IfcSchema::T::Class()) ) { \
processed = true; \
try { \
if (convert((IfcSchema::T*)l, r) ) { \
success = true; \
} \
} catch (const std::exception& e) { \
Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \
return false; \
} \
if (!success) { \
Logger::Message(Logger::LOG_ERROR,"Failed to convert:", l); \
return false; \
} \
}
#include "CgalEntityMappingDefine.h"
#include "CgalEntityMapping.h"
@@ -0,0 +1,14 @@
#include "CgalEntityMappingUndefine.h"
#define SHAPES(T) \
if (l->declaration().is(IfcSchema::T::Class())) return ST_SHAPELIST;
#define SHAPE(T) \
if (l->declaration().is(IfcSchema::T::Class())) return ST_SHAPE;
#define WIRE(T) \
if (l->declaration().is(IfcSchema::T::Class())) return ST_WIRE;
#define FACE(T) \
if (l->declaration().is(IfcSchema::T::Class())) return ST_FACE;
#define CURVE(T) \
if (l->declaration().is(IfcSchema::T::Class())) return ST_CURVE;
#include "CgalEntityMappingDefine.h"
#include "CgalEntityMapping.h"
@@ -0,0 +1,13 @@
#include "CgalEntityMappingUndefine.h"
#define SHAPES(T) \
if (l->declaration().is(IfcSchema::T::Class())) { \
try { \
return convert((IfcSchema::T*)l,r); \
} catch (const std::exception& e) { \
Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \
} \
return false; \
}
#include "CgalEntityMappingDefine.h"
#include "CgalEntityMapping.h"
@@ -0,0 +1,6 @@
#include "CgalEntityMappingUndefine.h"
#define WIRE(T) \
if (l->declaration().is(IfcSchema::T::Class())) return convert((IfcSchema::T*)l,r);
#include "CgalEntityMappingDefine.h"
#include "CgalEntityMapping.h"
@@ -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;
}
+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;
}
+167
View File
@@ -0,0 +1,167 @@
/********************************************************************************
* *
* 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>
#define 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;
}
#include "../../../ifcparse/macros.h"
#include "../../../ifcgeom/kernel_agnostic/AbstractKernel.h"
#include "../../../ifcgeom/schema_agnostic/Kernel.h"
#include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h"
#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h"
// @todo create separate shapetype enum?
#include "../../../ifcgeom/kernels/opencascade/IfcGeomShapeType.h"
#define INCLUDE_SCHEMA(x) STRINGIFY(../../../ifcparse/x.h)
#include INCLUDE_SCHEMA(IfcSchema)
#undef INCLUDE_SCHEMA
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 IfcGeom {
class IFC_GEOM_API CgalCache {
public:
#include "CgalEntityMappingCreateCache.h"
std::map<int, cgal_shape_t> Shape;
};
class IFC_GEOM_API MAKE_TYPE_NAME(CgalKernel) : public MAKE_TYPE_NAME(AbstractKernel) {
public:
MAKE_TYPE_NAME(CgalKernel)()
: MAKE_TYPE_NAME(AbstractKernel)("cgal") {}
#ifndef NO_CACHE
CgalCache cache;
#endif
IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseClass* L);
bool convert_shapes(const IfcUtil::IfcBaseClass* L, ConversionResults& result);
bool convert_shape(const IfcUtil::IfcBaseClass* L, cgal_shape_t& result);
bool convert_wire(const IfcUtil::IfcBaseClass* L, cgal_wire_t& result);
bool convert_curve(const IfcUtil::IfcBaseClass* L, cgal_curve_t& result);
bool convert_face(const IfcUtil::IfcBaseClass* L, cgal_face_t& result);
bool convert_wire_to_face(const cgal_wire_t& wire, cgal_face_t& face);
void remove_duplicate_points_from_loop(cgal_wire_t& polygon);
bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const cgal_placement_t& entity_trsf, ConversionResults& cut_shapes);
// CGAL::Polyhedron_3<Kernel_> triangulate_faces(CGAL::Polyhedron_3<Kernel_> &polyhedron);
CGAL::Polyhedron_3<Kernel_> create_polyhedron(std::list<cgal_face_t> &face_list);
CGAL::Polyhedron_3<Kernel_> create_polyhedron(CGAL::Nef_polyhedron_3<Kernel_> &nef_polyhedron);
CGAL::Nef_polyhedron_3<Kernel_> create_nef_polyhedron(std::list<cgal_face_t> &face_list);
CGAL::Nef_polyhedron_3<Kernel_> create_nef_polyhedron(CGAL::Polyhedron_3<Kernel_> &polyhedron);
void purge_cache() {
// Rather hack-ish, but a stopgap solution to keep memory under control
// for large files. SurfaceStyles need to be kept at all costs, as they
// are read later on when serializing Collada files.
#ifndef NO_CACHE
cache = CgalCache();
#endif
}
virtual bool is_identity_transform(const IfcUtil::IfcBaseClass*);
virtual bool apply_layerset(const IfcSchema::IfcProduct* product, IfcGeom::ConversionResults& shapes);
virtual bool validate_quantities(const IfcSchema::IfcProduct* product, const IfcGeom::Representation::BRep& brep);
virtual bool convert_openings(const IfcSchema::IfcProduct* product, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcGeom::ConversionResults& shapes, const ConversionResultPlacement* trsf, IfcGeom::ConversionResults& opened_shapes);
virtual bool convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf);
#include "CgalEntityMappingDeclaration.h"
private:
double deflection_tolerance;
double dimensionality;
};
}
#endif
@@ -48,18 +48,21 @@ inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMO
#include <BRep_Builder.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include "../ifcparse/macros.h"
#include "../ifcparse/IfcParse.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../../../ifcparse/macros.h"
#include "../../../ifcparse/IfcParse.h"
#include "../../../ifcparse/IfcBaseClass.h"
#include "../ifcgeom/IfcGeomElement.h"
#include "../ifcgeom/IfcGeomRepresentation.h"
#include "../ifcgeom/IfcRepresentationShapeItem.h"
#include "../ifcgeom/IfcGeomShapeType.h"
#include "../../../ifcgeom/kernel_agnostic/AbstractKernel.h"
#include "../ifcgeom_schema_agnostic/Kernel.h"
#include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h"
#include "../../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
#include "../../../ifcgeom/schema_agnostic/ConversionResult.h"
#include "../../../ifcgeom/kernels/opencascade/IfcGeomShapeType.h"
#include "ifc_geom_api.h"
#include "../../../ifcgeom/schema_agnostic/Kernel.h"
#include "../../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h"
#include "../../../ifcgeom/schema_agnostic/ifc_geom_api.h"
// Define this in case you want to conserve memory usage at all cost. This has been
// benchmarked extensively: https://github.com/IfcOpenShell/IfcOpenShell/pull/47
@@ -78,11 +81,12 @@ if ( it != cache.T.end() ) { e = it->second; return true; }
#endif
#define INCLUDE_PARENT_DIR(x) STRINGIFY(../ifcparse/x.h)
#include INCLUDE_PARENT_DIR(IfcSchema)
#undef INCLUDE_PARENT_DIR
#define INCLUDE_PARENT_DIR(x) STRINGIFY(../ifcparse/x-definitions.h)
#include INCLUDE_PARENT_DIR(IfcSchema)
#define INCLUDE_SCHEMA(x) STRINGIFY(../../../ifcparse/x.h)
#include INCLUDE_SCHEMA(IfcSchema)
#undef INCLUDE_SCHEMA
#define INCLUDE_SCHEMA(x) STRINGIFY(../../../ifcparse/x-definitions.h)
#include INCLUDE_SCHEMA(IfcSchema)
#undef INCLUDE_SCHEMA
namespace IfcGeom {
class IFC_GEOM_API geometry_exception : public std::exception {
@@ -109,7 +113,7 @@ public:
std::map<int, TopoDS_Shape> Shape;
};
class IFC_GEOM_API MAKE_TYPE_NAME(Kernel) : public IfcGeom::Kernel {
class IFC_GEOM_API MAKE_TYPE_NAME(Kernel) : public IfcGeom::MAKE_TYPE_NAME(AbstractKernel) {
private:
/*
@@ -213,42 +217,23 @@ private:
double epsilon() const {
return eps_;
}
};
double deflection_tolerance;
double ifc_length_unit;
double ifc_planeangle_unit;
double modelling_precision;
double dimensionality;
double max_faces_to_orient;
};
#ifndef NO_CACHE
MAKE_TYPE_NAME(Cache) cache;
#endif
std::map<int, SurfaceStyle> style_cache;
const SurfaceStyle* internalize_surface_style(const std::pair<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*>& shading_style);
// For stopping PlacementRelTo recursion in convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf)
const IfcParse::declaration* placement_rel_to;
faceset_helper* faceset_helper_;
public:
MAKE_TYPE_NAME(Kernel)()
: IfcGeom::Kernel(0)
, deflection_tolerance(0.001)
, max_faces_to_orient(-1.0)
, ifc_length_unit(1.0)
, ifc_planeangle_unit(-1.0)
, modelling_precision(0.00001)
, dimensionality(1.)
, placement_rel_to(0)
: IfcGeom::MAKE_TYPE_NAME(AbstractKernel)("opencascade")
, faceset_helper_(nullptr)
{}
MAKE_TYPE_NAME(Kernel)(const MAKE_TYPE_NAME(Kernel)& other) : IfcGeom::Kernel(0) {
MAKE_TYPE_NAME(Kernel)(const MAKE_TYPE_NAME(Kernel)& other)
: IfcGeom::MAKE_TYPE_NAME(AbstractKernel)("opencascade")
{
*this = other;
}
@@ -265,21 +250,20 @@ public:
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 convert_shapes(const IfcUtil::IfcBaseClass* L, ConversionResults& result);
IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseClass* L);
bool convert_shape(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
bool flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse);
bool flatten_shape_list(const IfcGeom::ConversionResults& shapes, TopoDS_Shape& result, bool fuse);
bool convert_wire(const IfcUtil::IfcBaseClass* L, TopoDS_Wire& result);
bool convert_curve(const IfcUtil::IfcBaseClass* L, Handle(Geom_Curve)& result);
bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
bool convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const ConversionResultPlacement* entity_trsf, ConversionResults& cut_shapes);
void assert_closed_wire(TopoDS_Wire& wire);
bool convert_layerset(const IfcSchema::IfcProduct*, std::vector<Handle_Geom_Surface>&, std::vector<const SurfaceStyle*>&, std::vector<double>&);
bool apply_layerset(const IfcRepresentationShapeItems&, const std::vector<Handle_Geom_Surface>&, const std::vector<const SurfaceStyle*>&, IfcRepresentationShapeItems&);
bool apply_folded_layerset(const IfcRepresentationShapeItems&, const std::vector< std::vector<Handle_Geom_Surface> >&, const std::vector<const SurfaceStyle*>&, IfcRepresentationShapeItems&);
bool fold_layers(const IfcSchema::IfcWall*, const IfcRepresentationShapeItems&, const std::vector<Handle_Geom_Surface>&, const std::vector<double>&, std::vector< std::vector<Handle_Geom_Surface> >&);
bool apply_layerset(const ConversionResults&, const std::vector<Handle_Geom_Surface>&, const std::vector<const SurfaceStyle*>&, ConversionResults&);
bool apply_folded_layerset(const ConversionResults&, const std::vector< std::vector<Handle_Geom_Surface> >&, const std::vector<const SurfaceStyle*>&, ConversionResults&);
bool fold_layers(const IfcSchema::IfcWall*, const ConversionResults&, const std::vector<Handle_Geom_Surface>&, const std::vector<double>&, std::vector< std::vector<Handle_Geom_Surface> >&);
bool split_solid_by_surface(const TopoDS_Shape&, const Handle_Geom_Surface&, TopoDS_Shape&, TopoDS_Shape&);
bool split_solid_by_shell(const TopoDS_Shape&, const TopoDS_Shape& s, TopoDS_Shape&, TopoDS_Shape&);
@@ -307,8 +291,6 @@ public:
bool find_wall_end_points(const IfcSchema::IfcWall*, gp_Pnt& start, gp_Pnt& end);
IfcSchema::IfcSurfaceStyleShading* get_surface_style(IfcSchema::IfcRepresentationItem* item);
const IfcSchema::IfcRepresentationItem* find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item);
bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid);
bool create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& solid);
bool is_compound(const TopoDS_Shape& shape);
@@ -334,105 +316,38 @@ public:
static double shape_volume(const TopoDS_Shape& s);
static double face_area(const TopoDS_Face& f);
static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const OpenCascadePlacement*);
static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_Trsf&);
static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_GTrsf&);
bool is_identity_transform(IfcUtil::IfcBaseClass*);
IfcSchema::IfcRelVoidsElement::list::ptr find_openings(IfcSchema::IfcProduct* product);
virtual bool is_identity_transform(const IfcUtil::IfcBaseClass*);
virtual bool apply_layerset(const IfcSchema::IfcProduct* product, IfcGeom::ConversionResults& shapes);
virtual bool validate_quantities(const IfcSchema::IfcProduct* product, const IfcGeom::Representation::BRep& brep);
IfcSchema::IfcRepresentation* find_representation(const IfcSchema::IfcProduct*, const std::string&);
std::pair<std::string, double> initializeUnits(IfcSchema::IfcUnitAssignment*);
template <typename P, typename PP>
IfcGeom::BRepElement<P, PP>* create_brep_for_representation_and_product(
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*);
template <typename P, typename PP>
IfcGeom::BRepElement<P, PP>* create_brep_for_processed_representation(
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::BRepElement<P, PP>*);
const IfcSchema::IfcMaterial* get_single_material_association(const IfcSchema::IfcProduct*);
IfcSchema::IfcRepresentation* representation_mapped_to(const IfcSchema::IfcRepresentation* representation);
IfcSchema::IfcProduct::list::ptr products_represented_by(const IfcSchema::IfcRepresentation*);
const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem*);
const SurfaceStyle* get_style(const IfcSchema::IfcMaterial*);
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> _get_surface_style(const IfcSchema::IfcStyledItem* si) {
#ifdef SCHEMA_HAS_IfcStyleAssignmentSelect
IfcEntityList::ptr style_assignments = si->Styles();
for (IfcEntityList::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
if (!(*kt)->declaration().is(IfcSchema::IfcPresentationStyleAssignment::Class())) {
continue;
}
IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt;
#else
IfcSchema::IfcPresentationStyleAssignment::list::ptr style_assignments = si->Styles();
for (IfcSchema::IfcPresentationStyleAssignment::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
IfcSchema::IfcPresentationStyleAssignment* style_assignment = *kt;
#endif
IfcEntityList::ptr styles = style_assignment->Styles();
for (IfcEntityList::it lt = styles->begin(); lt != styles->end(); ++lt) {
IfcUtil::IfcBaseClass* style = *lt;
if (style->declaration().is(IfcSchema::IfcSurfaceStyle::Class())) {
IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style;
if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) {
IfcEntityList::ptr styles_elements = surface_style->Styles();
for (IfcEntityList::it mt = styles_elements->begin(); mt != styles_elements->end(); ++mt) {
if ((*mt)->declaration().is(T::Class())) {
return std::make_pair(surface_style, (T*) *mt);
}
}
}
}
}
}
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0,0);
}
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) {
// For certain representation items, most notably boolean operands,
// a style definition might reside on one of its operands.
representation_item = find_item_carrying_style(representation_item);
if (representation_item->as<IfcSchema::IfcStyledItem>()) {
return _get_surface_style<T>(representation_item->as<IfcSchema::IfcStyledItem>());
}
IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem();
if (styled_items->size()) {
// StyledByItem is a SET [0:1] OF IfcStyledItem, so we return after the first IfcStyledItem:
return _get_surface_style<T>(*styled_items->begin());
}
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0,0);
}
void purge_cache() {
void purge_cache() {
// Rather hack-ish, but a stopgap solution to keep memory under control
// for large files. SurfaceStyles need to be kept at all costs, as they
// are read later on when serializing Collada files.
#ifndef NO_CACHE
cache = MAKE_TYPE_NAME(Cache)();
#endif
}
void set_conversion_placement_rel_to(const IfcParse::declaration* type);
}
#include "IfcRegisterGeomHeader.h"
virtual void setValue(GeomValue var, double value);
virtual double getValue(GeomValue var) const;
virtual IfcGeom::BRepElement<double>* convert(
virtual IfcGeom::NativeElement<double>* convert(
const IteratorSettings& settings, IfcUtil::IfcBaseClass* representation,
IfcUtil::IfcBaseClass* product)
{
return create_brep_for_representation_and_product<double, double>(settings, (IfcSchema::IfcRepresentation*) representation, (IfcSchema::IfcProduct*) product);
}
virtual IfcRepresentationShapeItems convert(IfcUtil::IfcBaseClass* item) {
IfcRepresentationShapeItems items;
virtual ConversionResults convert(IfcUtil::IfcBaseClass* item) {
ConversionResults items;
bool success = convert_shapes(item, items);
if (!success) {
throw IfcParse::IfcException("Failed to process representation item");
@@ -440,12 +355,15 @@ public:
return items;
}
virtual bool convert_placement(IfcUtil::IfcBaseClass* item, gp_Trsf& trsf) {
virtual bool convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf) {
if (item->as<IfcSchema::IfcObjectPlacement>()) {
return convert(item->as<IfcSchema::IfcObjectPlacement>(), trsf);
} else {
return false;
gp_Trsf occt_trsf;
if (convert(item->as<IfcSchema::IfcObjectPlacement>(), occt_trsf)) {
trsf = new OpenCascadePlacement(occt_trsf);
return true;
}
}
return false;
}
};
@@ -77,7 +77,7 @@
#include <TopLoc_Location.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h"
#ifdef SCHEMA_HAS_IfcBSplineCurveWithKnots
#include <Geom_BSplineCurve.hxx>
@@ -97,7 +97,7 @@
#include <BRepLib_FindSurface.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h"
#ifdef SCHEMA_HAS_IfcBSplineSurfaceWithKnots
#include <Geom_BSplineSurface.hxx>
@@ -75,7 +75,7 @@
#include <TopLoc_Location.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -385,10 +385,6 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d
return true;
}
void IfcGeom::Kernel::set_conversion_placement_rel_to(const IfcParse::declaration* type) {
placement_rel_to = type;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf) {
IN_CACHE(IfcObjectPlacement,l,gp_Trsf,trsf)
if ( ! l->declaration().is(IfcSchema::IfcLocalPlacement::Class()) ) {
@@ -101,7 +101,7 @@
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h"
#include <memory>
@@ -366,7 +366,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRevolvedAreaSolid* l, TopoDS_S
return !shape.IsNull();
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, IfcRepresentationShapeItems& shape) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, ConversionResults& shape) {
TopoDS_Shape s;
const SurfaceStyle* collective_style = get_style(l);
if (convert_shape(l->Outer(),s) ) {
@@ -391,13 +391,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, IfcRepre
}
}
shape.push_back(IfcRepresentationShapeItem(l->data().id(), s, indiv_style ? indiv_style : collective_style));
shape.push_back(ConversionResult(l->data().id(), new OpenCascadeShape(s), indiv_style ? indiv_style : collective_style));
return true;
}
return false;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFaceBasedSurfaceModel* l, IfcRepresentationShapeItems& shapes) {
bool IfcGeom::Kernel::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);
@@ -405,7 +405,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFaceBasedSurfaceModel* l, IfcR
TopoDS_Shape s;
const SurfaceStyle* shell_style = get_style(*it);
if (convert_shape(*it,s)) {
shapes.push_back(IfcRepresentationShapeItem(l->data().id(), s, shell_style ? shell_style : collective_style));
shapes.push_back(ConversionResult(l->data().id(), new OpenCascadeShape(s), shell_style ? shell_style : collective_style));
part_success |= true;
}
}
@@ -459,7 +459,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l,
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, IfcRepresentationShapeItems& shapes) {
bool IfcGeom::Kernel::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 ) {
@@ -469,7 +469,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, Ifc
shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it);
}
if (convert_shape(*it,s)) {
shapes.push_back(IfcRepresentationShapeItem(l->data().id(), s, shell_style ? shell_style : collective_style));
shapes.push_back(ConversionResult(l->data().id(), new OpenCascadeShape(s), shell_style ? shell_style : collective_style));
}
}
return true;
@@ -477,8 +477,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, Ifc
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) {
TopoDS_Shape s1;
IfcRepresentationShapeItems items1;
TopoDS_Shape s1, s2;
ConversionResults items1;
TopoDS_Wire boundary_wire;
IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand();
IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand();
@@ -556,7 +556,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
{
if (shape_type(op2) == ST_SHAPELIST) {
IfcRepresentationShapeItems items2;
ConversionResults items2;
shape2_processed = convert_shapes(op2, items2) && flatten_shape_list(items2, s2, true);
} else if (shape_type(op2) == ST_SHAPE) {
shape2_processed = convert_shape(op2, s2);
@@ -711,7 +711,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Sh
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentationShapeItems& shapes) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, ConversionResults& shapes) {
gp_GTrsf gtrsf;
IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget();
if ( transform->declaration().is(IfcSchema::IfcCartesianTransformationOperator3DnonUniform::Class()) ) {
@@ -746,7 +746,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentati
bool b = convert_shapes(map->MappedRepresentation(), shapes);
for (size_t i = previous_size; i < shapes.size(); ++ i ) {
shapes[i].prepend(gtrsf);
OpenCascadePlacement p(gtrsf);
shapes[i].prepend(&p);
// Apply styles assigned to the mapped item only if on
// a more granular level no styles have been applied
@@ -758,7 +759,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentati
return b;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRepresentation* l, IfcRepresentationShapeItems& shapes) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRepresentation* l, ConversionResults& shapes) {
IfcSchema::IfcRepresentationItem::list::ptr items = l->Items();
bool part_succes = false;
if ( items->size() ) {
@@ -769,7 +770,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRepresentation* l, IfcRepresen
} else {
TopoDS_Shape s;
if (convert_shape(representation_item,s)) {
shapes.push_back(IfcRepresentationShapeItem(representation_item->data().id(), s, get_style(representation_item)));
shapes.push_back(ConversionResult(representation_item->data().id(), new OpenCascadeShape(s), get_style(representation_item)));
part_succes |= true;
}
}
@@ -778,7 +779,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRepresentation* l, IfcRepresen
return part_succes;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcGeometricSet* l, IfcRepresentationShapeItems& shapes) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcGeometricSet* l, ConversionResults& shapes) {
IfcEntityList::ptr elements = l->Elements();
if ( !elements->size() ) return false;
bool part_succes = false;
@@ -796,7 +797,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcGeometricSet* l, IfcRepresenta
} else if (element->declaration().is(IfcSchema::IfcSurface::Class())) {
style = get_style((IfcSchema::IfcSurface*) element);
}
shapes.push_back(IfcRepresentationShapeItem(l->data().id(), s, style ? style : parent_style));
shapes.push_back(ConversionResult(l->data().id(), new OpenCascadeShape(s), style ? style : parent_style));
}
}
return part_succes;
@@ -20,10 +20,11 @@
#ifndef IFCGEOMTREE_H
#define IFCGEOMTREE_H
#include "../ifcparse/IfcFile.h"
#include "../ifcgeom/IfcGeomElement.h"
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
#include "../ifcgeom_schema_agnostic/Kernel.h"
#include "../../../ifcparse/IfcFile.h"
#include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h"
#include "../../../ifcgeom/schema_agnostic/IfcGeomIterator.h"
#include "../../../ifcgeom/schema_agnostic/Kernel.h"
#include "../../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h"
#include <NCollection_UBTree.hxx>
#include <BRepBndLib.hxx>
@@ -113,7 +114,8 @@ namespace IfcGeom {
std::vector<T> ts_filtered;
const TopoDS_Shape& A = shapes_.find(t)->second;
if (IfcGeom::Kernel::count(A, TopAbs_SHELL) == 0) {
OpenCascadeShape SA(A);
if (IfcGeom::Kernel::count(&SA, (int) TopAbs_SHELL) == 0) {
return ts_filtered;
}
@@ -122,21 +124,24 @@ namespace IfcGeom {
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;
if (IfcGeom::Kernel::count(B, TopAbs_SHELL) == 0) {
OpenCascadeShape SB(B);
if (IfcGeom::Kernel::count(&SB, (int) TopAbs_SHELL) == 0) {
continue;
}
if (completely_within) {
BRepAlgoAPI_Cut cut(B, A);
if (cut.IsDone()) {
if (IfcGeom::Kernel::count(cut.Shape(), TopAbs_SHELL) == 0) {
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()) {
if (IfcGeom::Kernel::count(common.Shape(), TopAbs_SHELL) > 0) {
OpenCascadeShape Sc(common.Shape());
if (IfcGeom::Kernel::count(&Sc, (int) TopAbs_SHELL) > 0) {
ts_filtered.push_back(*it);
}
}
@@ -152,7 +157,8 @@ namespace IfcGeom {
std::vector<T> ts;
if (IfcGeom::Kernel::count(s, TopAbs_SHELL) == 0) {
OpenCascadeShape Ss(s);
if (IfcGeom::Kernel::count(&Ss, (int) TopAbs_SHELL) == 0) {
return ts;
}
@@ -169,13 +175,15 @@ namespace IfcGeom {
for (it = ts.begin(); it != ts.end(); ++it) {
const TopoDS_Shape& B = shapes_.find(*it)->second;
if (IfcGeom::Kernel::count(B, TopAbs_SHELL) == 0) {
OpenCascadeShape SB(B);
if (IfcGeom::Kernel::count(&SB, (int) TopAbs_SHELL) == 0) {
continue;
}
BRepAlgoAPI_Common common(s, B);
if (common.IsDone()) {
if (IfcGeom::Kernel::count(common.Shape(), TopAbs_SHELL) > 0) {
OpenCascadeShape Sc(common.Shape());;
if (IfcGeom::Kernel::count(&Sc, (int) TopAbs_SHELL) > 0) {
ts_filtered.push_back(*it);
}
}
@@ -268,8 +276,8 @@ namespace IfcGeom {
if (it.initialize()) {
do {
IfcGeom::BRepElement<double>* elem = (IfcGeom::BRepElement<double>*)it.get();
add((IfcUtil::IfcBaseEntity*)f.instance_by_id(elem->id()), elem->geometry().as_compound());
IfcGeom::NativeElement<double>* elem = (IfcGeom::NativeElement<double>*)it.get();
add((IfcUtil::IfcBaseEntity*)f.instance_by_id(elem->id()), ((OpenCascadeShape*)elem->geometry().as_compound())->shape());
} while (it.next());
}
}
@@ -95,7 +95,7 @@
#include <BRepAdaptor_HCompCurve.hxx>
#include <Approx_Curve3d.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -24,11 +24,11 @@
using namespace IfcUtil;
bool IfcGeom::Kernel::convert_shapes(const IfcBaseClass* l, IfcRepresentationShapeItems& r) {
bool IfcGeom::Kernel::convert_shapes(const IfcBaseClass* l, ConversionResults& r) {
if (shape_type(l) != ST_SHAPELIST) {
TopoDS_Shape shp;
if (convert_shape(l, shp)) {
r.push_back(IfcGeom::IfcRepresentationShapeItem(l->data().id(), shp, get_style(l->as<IfcSchema::IfcRepresentationItem>())));
r.push_back(IfcGeom::ConversionResult(l->data().id(), new OpenCascadeShape(shp), get_style(l->as<IfcSchema::IfcRepresentationItem>())));
return true;
}
return false;
@@ -61,7 +61,7 @@ bool IfcGeom::Kernel::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) {
ignored = (!include_solids_and_surfaces && (st == ST_SHAPE || st == ST_FACE)) || (!include_curves && (st == ST_WIRE || st == ST_CURVE));
if (st == ST_SHAPELIST) {
processed = true;
IfcRepresentationShapeItems items;
ConversionResults items;
success = convert_shapes(l, items) && flatten_shape_list(items, r, false);
} else if (st == ST_SHAPE && include_solids_and_surfaces) {
#include "IfcRegisterConvertShape.h"
@@ -38,8 +38,8 @@
#include <gp_Trsf.hxx>
#include <gp_Trsf2d.hxx>
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcParse.h"
#include "../../../ifcparse/IfcBaseClass.h"
#include "../../../ifcparse/IfcParse.h"
SHAPES(IfcShellBasedSurfaceModel);
SHAPES(IfcFaceBasedSurfaceModel);
@@ -0,0 +1,18 @@
#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
@@ -1,6 +1,6 @@
#include "IfcRegisterUndef.h"
#define CLASS(T,V) bool convert(const IfcSchema::T* L, V& r);
#define SHAPES(T) CLASS(T,IfcRepresentationShapeItems)
#define SHAPES(T) CLASS(T,ConversionResults)
#define SHAPE(T) CLASS(T,TopoDS_Shape)
#define WIRE(T) CLASS(T,TopoDS_Wire)
#define FACE(T) CLASS(T,TopoDS_Shape)
@@ -0,0 +1,18 @@
#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
@@ -0,0 +1,94 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef IFCSHAPELIST_H
#define IFCSHAPELIST_H
#include "../../ifcgeom/schema_agnostic/IfcGeomRenderStyles.h"
#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
namespace IfcGeom {
namespace Representation {
template <typename P>
class IFC_GEOM_API Triangulation;
}
class IFC_GEOM_API ConversionResultPlacement {
public:
virtual void Multiply(const ConversionResultPlacement*) = 0;
virtual void PreMultiply(const ConversionResultPlacement*) = 0;
virtual void TranslationPart(double& X, double& Y, double& Z) const = 0;
virtual ConversionResultPlacement* inverted() const = 0;
virtual ConversionResultPlacement* multiplied(const ConversionResultPlacement*) const = 0;
virtual double Value(int i, int j) const = 0;
virtual ConversionResultPlacement* clone() const = 0;
virtual ~ConversionResultPlacement() {}
};
class IFC_GEOM_API ConversionResultShape {
public:
virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement* place, IfcGeom::Representation::Triangulation<float>* t, int surface_style_id) const = 0;
virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement* place, IfcGeom::Representation::Triangulation<double>* t, int surface_style_id) const = 0;
virtual void Serialize(std::string&) const = 0;
virtual ConversionResultShape* clone() const = 0;
virtual int surface_genus() const = 0;
virtual ~ConversionResultShape() {}
};
class IFC_GEOM_API ConversionResult {
private:
int id;
ConversionResultPlacement* placement;
ConversionResultShape* shape;
const SurfaceStyle* style;
public:
ConversionResult(int id, const ConversionResultPlacement* placement, const ConversionResultShape* shape, const SurfaceStyle* style)
: id(id), placement(placement ? placement->clone() : nullptr), shape(shape->clone()), style(style) {}
ConversionResult(int id, const ConversionResultPlacement* placement, const ConversionResultShape* shape)
: id(id), placement(placement ? placement->clone() : nullptr), shape(shape->clone()), style(0) {}
ConversionResult(int id, const ConversionResultShape* shape, const SurfaceStyle* style)
: id(id), placement(0), shape(shape->clone()), style(style) {}
ConversionResult(int id, const ConversionResultShape* shape)
: id(id), placement(0), shape(shape->clone()), style(0) {}
void append(const ConversionResultPlacement* trsf) {
if (placement == 0) {
placement = trsf->clone();
} else {
placement->Multiply(trsf);
}
}
void prepend(const ConversionResultPlacement* trsf) {
if (placement == 0) {
placement = trsf->clone();
} else {
placement->PreMultiply(trsf);
}
}
const ConversionResultShape* Shape() const { return shape; }
const ConversionResultPlacement* Placement() const { return placement; }
bool hasStyle() const { return style != 0; }
const SurfaceStyle& Style() const { return *style; }
void setStyle(const SurfaceStyle* newStyle) { style = newStyle; }
int ItemId() const { return id; }
};
typedef std::vector<ConversionResult> ConversionResults;
}
#endif
@@ -23,11 +23,12 @@
#include <string>
#include <algorithm>
#include "../ifcparse/Argument.h"
#include "../ifcparse/IfcGlobalId.h"
#include "../../ifcparse/IfcGlobalId.h"
#include "../../ifcparse/Argument.h"
#include "../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
#include "../ifcgeom/IfcGeomRepresentation.h"
#include "../ifcgeom/IfcGeomIteratorSettings.h"
#include "ifc_geom_api.h"
namespace IfcGeom {
@@ -37,7 +38,7 @@ namespace IfcGeom {
private:
std::vector<P> _data;
public:
Matrix(const ElementSettings& settings, const gp_Trsf& trsf) {
Matrix(const ElementSettings& settings, const IfcGeom::ConversionResultPlacement* 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
@@ -45,8 +46,10 @@ namespace IfcGeom {
// 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.get(IteratorSettings::CONVERT_BACK_UNITS)
const double trsf_value = (trsf == nullptr)
? (i == j ? 1. : 0.)
: trsf->Value(j,i);
const double matrix_value = (i == 4 && settings.get(IteratorSettings::CONVERT_BACK_UNITS))
? trsf_value / settings.unit_magnitude()
: trsf_value;
_data.push_back(static_cast<P>(matrix_value));
@@ -60,23 +63,23 @@ namespace IfcGeom {
class Transformation {
private:
ElementSettings settings_;
gp_Trsf trsf_;
ConversionResultPlacement* trsf_;
Matrix<P> matrix_;
public:
Transformation(const ElementSettings& settings, const gp_Trsf& trsf)
Transformation(const ElementSettings& settings, const IfcGeom::ConversionResultPlacement* trsf)
: settings_(settings)
, trsf_(trsf)
, trsf_(trsf ? trsf->clone() : nullptr)
, matrix_(settings, trsf)
{}
const gp_Trsf& data() const { return trsf_; }
const IfcGeom::ConversionResultPlacement* data() const { return trsf_; }
const Matrix<P>& matrix() const { return matrix_; }
Transformation inverted() const {
return Transformation(settings_, trsf_.Inverted());
return Transformation(settings_, trsf_->inverted());
}
Transformation multiplied(const Transformation& other) const {
return Transformation(settings_, trsf_.Multiplied(other.data()));
return Transformation(settings_, trsf_->multiplied(other.data()));
}
};
@@ -130,7 +133,7 @@ namespace IfcGeom {
void SetParents(std::vector<const IfcGeom::Element<P, PP>*> newparents) { _parents = newparents; }
Element(const ElementSettings& settings, int id, int parent_id, const std::string& name, const std::string& type,
const std::string& guid, const std::string& context, const gp_Trsf& trsf, IfcUtil::IfcBaseEntity* product)
const std::string& guid, const std::string& context, const IfcGeom::ConversionResultPlacement* trsf, IfcUtil::IfcBaseEntity* product)
: _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _context(context), _transformation(settings, trsf)
, product_(product)
{
@@ -160,28 +163,25 @@ namespace IfcGeom {
};
template <typename P = double, typename PP = P>
class BRepElement : public Element<P, PP> {
class NativeElement : public Element<P, PP> {
private:
boost::shared_ptr<Representation::BRep> _geometry;
public:
const boost::shared_ptr<Representation::BRep>& geometry_pointer() const { return _geometry; }
const Representation::BRep& geometry() const { return *_geometry; }
BRepElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid,
const std::string& context, const gp_Trsf& trsf, const boost::shared_ptr<Representation::BRep>& geometry,
NativeElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid,
const std::string& context, const IfcGeom::ConversionResultPlacement* trsf, const boost::shared_ptr<Representation::BRep>& geometry,
IfcUtil::IfcBaseEntity* product)
: Element<P, PP>(geometry->settings() ,id, parent_id, name, type, guid, context, trsf, product)
, _geometry(geometry)
{}
bool calculate_projected_surface_area(double& along_x, double& along_y, double& along_z) const {
const auto& trsf = this->transformation().data();
const gp_Mat& mat = trsf.HVectorialPart();
gp_Ax3 ax(trsf.TranslationPart(), mat.Column(3), mat.Column(1));
return geometry().calculate_projected_surface_area(ax, along_x, along_y, along_z);
return geometry().calculate_projected_surface_area(this->transformation().data(), along_x, along_y, along_z);
}
private:
BRepElement(const BRepElement& other);
BRepElement& operator=(const BRepElement& other);
NativeElement(const NativeElement& other);
NativeElement& operator=(const NativeElement& other);
};
template <typename P = double, typename PP = P>
@@ -191,7 +191,7 @@ namespace IfcGeom {
public:
const Representation::Triangulation<P>& geometry() const { return *_geometry; }
const boost::shared_ptr< Representation::Triangulation<P> >& geometry_pointer() const { return _geometry; }
TriangulationElement(const BRepElement<P, PP>& shape_model)
TriangulationElement(const NativeElement<P, PP>& shape_model)
: Element<P, PP>(shape_model)
, _geometry(boost::shared_ptr<Representation::Triangulation<P> >(new Representation::Triangulation<P>(shape_model.geometry())))
{}
@@ -210,7 +210,7 @@ namespace IfcGeom {
Representation::Serialization* _geometry;
public:
const Representation::Serialization& geometry() const { return *_geometry; }
SerializedElement(const BRepElement<P, PP>& shape_model)
SerializedElement(const NativeElement<P, PP>& shape_model)
: Element<P, PP>(shape_model)
, _geometry(new Representation::Serialization(shape_model.geometry()))
{}
@@ -23,8 +23,8 @@
#ifndef IFCGEOMFILTER_H
#define IFCGEOMFILTER_H
#include "Kernel.h"
#include "../ifcparse/IfcFile.h"
#include "../../ifcgeom/schema_agnostic/Kernel.h"
#include "../../ifcparse/IfcFile.h"
#include <boost/foreach.hpp>
#include <boost/function.hpp>
@@ -58,7 +58,7 @@
#ifndef IFCGEOMITERATOR_H
#define IFCGEOMITERATOR_H
#include "../ifcgeom_schema_agnostic/IteratorImplementation.h"
#include "../../ifcgeom/schema_agnostic/IteratorImplementation.h"
// The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration
#ifdef min
@@ -83,19 +83,19 @@ namespace IfcGeom {
IteratorImplementation<P, PP>* implementation_;
public:
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, int num_threads = 1)
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::string& geometry_library="opencascade", int num_threads = 1)
: file_(file)
, settings_(settings)
{
implementation_ = iterator_implementations<P, PP>().construct(file_->schema()->name(), settings, file, filters_, num_threads);
implementation_ = iterator_implementations<P, PP>().construct(file_->schema()->name(), geometry_library, settings, file, filters_, num_threads);
}
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, size_t num_threads = 1)
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, const std::string& geometry_library = "opencascade", int num_threads = 1)
: file_(file)
, settings_(settings)
, filters_(filters)
{
implementation_ = iterator_implementations<P, PP>().construct(file_->schema()->name(), settings, file, filters_, num_threads);
implementation_ = iterator_implementations<P, PP>().construct(file_->schema()->name(), geometry_library, settings, file, filters_, num_threads);
}
bool initialize() {
@@ -119,7 +119,7 @@ namespace IfcGeom {
Element<P, PP>* get() { return implementation_->get(); }
BRepElement<P, PP>* get_native() { return implementation_->get_native(); }
NativeElement<P, PP>* get_native() { return implementation_->get_native(); }
const Element<P, PP>* get_object(int id) { return implementation_->get_object(id); }
@@ -21,8 +21,9 @@
#define IFCGEOMITERATORSETTINGS_H
#include "ifc_geom_api.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../../ifcparse/IfcException.h"
#include "../../ifcparse/IfcBaseClass.h"
#include "../../ifcparse/IfcLogger.h"
namespace IfcGeom
{
@@ -22,7 +22,7 @@
#include <string>
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
#include "../../ifcgeom/schema_agnostic/IfcGeomRenderStyles.h"
namespace IfcGeom {
@@ -20,7 +20,7 @@
#ifndef IFCGEOMRENDERSTYLES_H
#define IFCGEOMRENDERSTYLES_H
#include "../ifcgeom/ifc_geom_api.h"
#include "../../ifcgeom/schema_agnostic/ifc_geom_api.h"
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string/replace.hpp>
@@ -21,21 +21,25 @@
#include <BRepTools.hxx>
#include <BRep_Builder.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Compound.hxx>
#include <Geom_Plane.hxx>
#include <GProp_GProps.hxx>
#include <BRepGProp.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "IfcGeomRepresentation.h"
#include "../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h"
#include "../../ifcgeom/schema_agnostic/Kernel.h"
IfcGeom::Representation::Serialization::Serialization(const BRep& brep)
: Representation(brep.settings())
, id_(brep.id())
{
TopoDS_Compound compound = brep.as_compound();
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++ it) {
IfcGeom::ConversionResultShape* shape = brep.as_compound();
TopoDS_Compound compound = TopoDS::Compound(((OpenCascadeShape*) shape)->shape());
delete shape;
for (IfcGeom::ConversionResults::const_iterator it = brep.begin(); it != brep.end(); ++ it) {
if (it->hasStyle() && it->Style().Diffuse()) {
const IfcGeom::SurfaceStyle::ColorComponent& clr = *it->Style().Diffuse();
surface_styles_.push_back(clr.R());
@@ -57,7 +61,7 @@ IfcGeom::Representation::Serialization::Serialization(const BRep& brep)
brep_data_ = sstream.str();
}
// todo copied from kernel
// @todo copied from kernel
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepBuilderAPI_GTransform.hxx>
@@ -82,13 +86,17 @@ TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const gp_GTrsf& t) {
}
}
TopoDS_Compound IfcGeom::Representation::BRep::as_compound(bool force_meters) const {
IfcGeom::ConversionResultShape* IfcGeom::Representation::BRep::as_compound(bool force_meters) const {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) {
const TopoDS_Shape& s = it->Shape();
gp_GTrsf trsf = it->Placement();
for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) {
const TopoDS_Shape& s = *(OpenCascadeShape*) it->Shape();
gp_GTrsf trsf;
if (it->Placement()) {
trsf = ((OpenCascadePlacement*)it->Placement())->trsf();
}
if (!force_meters && settings().get(IteratorSettings::CONVERT_BACK_UNITS)) {
gp_Trsf scale;
@@ -99,7 +107,8 @@ TopoDS_Compound IfcGeom::Representation::BRep::as_compound(bool force_meters) co
const TopoDS_Shape moved_shape = apply_transformation(s, trsf);
builder.Add(compound, moved_shape);
}
return compound;
return new OpenCascadeShape(compound);
}
namespace {
@@ -166,7 +175,7 @@ namespace {
const gp_Vec v2 = pt3 - pt2;
const gp_Vec v3 = pt1 - pt3;
const gp_Vec normal_vector = v1 ^ v2;
if (normal_vector.Magnitude() > ALMOST_ZERO) {
if (normal_vector.Magnitude() > 1.e-9) {
gp_Dir normal = gp_Dir();
double edge_lengths[3] = { v1.Magnitude(), v2.Magnitude(), v3.Magnitude() };
@@ -190,9 +199,9 @@ bool IfcGeom::Representation::BRep::calculate_surface_area(double& area) const {
try {
area = 0.;
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) {
for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) {
GProp_GProps prop;
BRepGProp::SurfaceProperties(it->Shape(), prop);
BRepGProp::SurfaceProperties(*(OpenCascadeShape*)it->Shape(), prop);
area += prop.Mass();
}
@@ -207,10 +216,10 @@ bool IfcGeom::Representation::BRep::calculate_volume(double& volume) const {
try {
volume = 0.;
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) {
for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) {
if (Kernel::is_manifold(it->Shape())) {
GProp_GProps prop;
BRepGProp::VolumeProperties(it->Shape(), prop);
BRepGProp::VolumeProperties(*(OpenCascadeShape*)it->Shape(), prop);
volume += prop.Mass();
} else {
return false;
@@ -224,13 +233,17 @@ bool IfcGeom::Representation::BRep::calculate_volume(double& volume) const {
}
}
bool IfcGeom::Representation::BRep::calculate_projected_surface_area(const gp_Ax3 & ax, double & along_x, double & along_y, double & along_z) const {
bool IfcGeom::Representation::BRep::calculate_projected_surface_area(const ConversionResultPlacement* place, double & along_x, double & along_y, double & along_z) const {
try {
gp_Trsf trsf = ((OpenCascadePlacement*)place)->trsf().Trsf();
gp_Mat mat = trsf.HVectorialPart();
gp_Ax3 ax(trsf.TranslationPart(), mat.Column(3), mat.Column(1));
along_x = along_y = along_z = 0.;
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) {
for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) {
double x, y, z;
surface_area_along_direction(settings().deflection_tolerance(), it->Shape(), ax, x, y, z);
surface_area_along_direction(settings().deflection_tolerance(), *(OpenCascadeShape*)it->Shape(), ax, x, y, z);
if (Kernel::is_manifold(it->Shape())) {
x /= 2.;
@@ -0,0 +1,238 @@
/********************************************************************************
* *
* 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 "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
#include "../../ifcgeom/schema_agnostic/IfcGeomMaterial.h"
#include "../../ifcgeom/schema_agnostic/ConversionResult.h"
#include <map>
namespace IfcGeom {
namespace Representation {
class IFC_GEOM_API Representation {
Representation(const Representation&); //N/A
Representation& operator =(const Representation&); //N/A
protected:
const ElementSettings settings_;
public:
explicit Representation(const ElementSettings& settings)
: settings_(settings)
{}
const ElementSettings& settings() const { return settings_; }
virtual ~Representation() {}
};
class IFC_GEOM_API BRep : public Representation {
private:
std::string id_;
const IfcGeom::ConversionResults shapes_;
BRep(const BRep& other);
BRep& operator=(const BRep& other);
public:
BRep(const ElementSettings& settings, const std::string& id, const IfcGeom::ConversionResults& shapes)
: Representation(settings)
, id_(id)
, shapes_(shapes)
{}
virtual ~BRep() {}
IfcGeom::ConversionResults::const_iterator begin() const { return shapes_.begin(); }
IfcGeom::ConversionResults::const_iterator end() const { return shapes_.end(); }
const IfcGeom::ConversionResults& shapes() const { return shapes_; }
const std::string& id() const { return id_; }
IfcGeom::ConversionResultShape* as_compound(bool force_meters = false) const;
bool calculate_volume(double&) const;
bool calculate_surface_area(double&) const;
bool calculate_projected_surface_area(const IfcGeom::ConversionResultPlacement* ax, double& along_x, double& along_y, double& along_z) const;
};
class IFC_GEOM_API Serialization : public Representation {
private:
std::string id_;
std::string brep_data_;
std::vector<double> surface_styles_;
public:
const std::string& brep_data() const { return brep_data_; }
const std::vector<double>& surface_styles() const { return surface_styles_; }
Serialization(const BRep& brep);
virtual ~Serialization() {}
const std::string& id() const { return id_; }
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;
std::string id_;
std::vector<P> _verts;
std::vector<int> _faces;
std::vector<int> _edges;
std::vector<P> _normals;
std::vector<P> uvs_;
std::vector<int> _material_ids;
std::vector<Material> _materials;
VertexKeyMap welds;
public:
const std::string& 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<P>& uvs() const { return uvs_; }
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.id())
{
for ( IfcGeom::ConversionResults::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++ iit ) {
int surface_style_id = -1;
if (iit->hasStyle()) {
Material adapter(&iit->Style());
std::vector<Material>::const_iterator jt = std::find(_materials.begin(), _materials.end(), adapter);
if (jt == _materials.end()) {
surface_style_id = (int)_materials.size();
_materials.push_back(adapter);
} else {
surface_style_id = (int)(jt - _materials.begin());
}
}
if (settings().get(IteratorSettings::APPLY_DEFAULT_MATERIALS) && surface_style_id == -1) {
Material material(IfcGeom::get_default_style(settings().element_type()));
std::vector<Material>::const_iterator mit = std::find(_materials.begin(), _materials.end(), material);
if (mit == _materials.end()) {
surface_style_id = (int)_materials.size();
_materials.push_back(material);
} else {
surface_style_id = (int)(mit - _materials.begin());
}
}
iit->Shape()->Triangulate(settings(), iit->Placement(), this, surface_style_id);
}
}
virtual ~Triangulation() {}
/// Generates UVs for a single mesh using box projection.
/// @todo Very simple impl. Assumes that input vertices and normals match 1:1.
static std::vector<P> box_project_uvs(const std::vector<P> &vertices, const std::vector<P> &normals)
{
std::vector<P> uvs;
uvs.resize(vertices.size() / 3 * 2);
for (size_t uv_idx = 0, v_idx = 0;
uv_idx < uvs.size() && v_idx < vertices.size() && v_idx < normals.size();
uv_idx += 2, v_idx += 3) {
P n_x = normals[v_idx], n_y = normals[v_idx + 1], n_z = normals[v_idx + 2];
P v_x = vertices[v_idx], v_y = vertices[v_idx + 1], v_z = vertices[v_idx + 2];
if (std::abs(n_x) > std::abs(n_y) && std::abs(n_x) > std::abs(n_z)) {
uvs[uv_idx] = v_z;
uvs[uv_idx + 1] = v_y;
}
if (std::abs(n_y) > std::abs(n_x) && std::abs(n_y) > std::abs(n_z)) {
uvs[uv_idx] = v_x;
uvs[uv_idx + 1] = v_z;
}
if (std::abs(n_z) > std::abs(n_x) && std::abs(n_z) > std::abs(n_y)) {
uvs[uv_idx] = v_x;
uvs[uv_idx + 1] = v_y;
}
}
return uvs;
}
public:
// Welds vertices that belong to different faces
int addVertex(int material_index, P X, P Y, P Z) {
const bool convert = settings().get(IteratorSettings::CONVERT_BACK_UNITS);
X = static_cast<P>(convert ? (X / settings().unit_magnitude()) : X);
Y = static_cast<P>(convert ? (Y / settings().unit_magnitude()) : Y);
Z = static_cast<P>(convert ? (Z / settings().unit_magnitude()) : Z);
int i = (int) _verts.size() / 3;
if (settings().get(IteratorSettings::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);
}
inline void addNormal(P X, P Y, P Z) {
_normals.push_back(X);
_normals.push_back(Y);
_normals.push_back(Z);
}
inline void addFace(int style, int i0, int i1, int i2) {
_faces.push_back(i0);
_faces.push_back(i1);
_faces.push_back(i2);
_material_ids.push_back(style);
}
inline void registerEdge(int i0, int i1) {
_edges.push_back(i0);
_edges.push_back(i1);
}
private:
Triangulation();
Triangulation(const Triangulation&);
Triangulation& operator=(const Triangulation&);
};
}
}
#endif
@@ -31,14 +31,14 @@ void IteratorFactoryImplementation<P, PP>::bind(const std::string& schema_name,
}
template <typename P, typename PP>
IfcGeom::IteratorImplementation<P, PP>* IteratorFactoryImplementation<P, PP>::construct(const std::string& schema_name, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads) {
IfcGeom::IteratorImplementation<P, PP>* IteratorFactoryImplementation<P, PP>::construct(const std::string& schema_name, const std::string& geometry_library, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads) {
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
typename std::map<std::string, typename get_factory_type<P, PP>::type>::const_iterator it;
it = this->find(schema_name_lower);
if (it == this->end()) {
throw IfcParse::IfcException("No geometry iterator registered for " + schema_name);
}
return it->second(settings, file, filters, num_threads);
return it->second(geometry_library, settings, file, filters, num_threads);
}
@@ -1,9 +1,9 @@
#ifndef ITERATOR_IMPLEMENTATION_H
#define ITERATOR_IMPLEMENTATION_H
#include "../ifcgeom_schema_agnostic/IfcGeomFilter.h"
#include "../ifcparse/IfcFile.h"
#include "../ifcgeom/IfcGeomIteratorSettings.h"
#include "../../ifcparse/IfcFile.h"
#include "../../ifcgeom/schema_agnostic/IfcGeomFilter.h"
#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
#include <gp_XYZ.hxx>
@@ -20,12 +20,12 @@ namespace IfcGeom {
class Element;
template <typename P, typename PP>
class BRepElement;
class NativeElement;
}
typedef boost::function4<IfcGeom::IteratorImplementation<float, float>*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int> iterator_float_float_fn;
typedef boost::function4<IfcGeom::IteratorImplementation<float, double>*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int> iterator_float_double_fn;
typedef boost::function4<IfcGeom::IteratorImplementation<double, double>*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int> iterator_double_double_fn;
typedef boost::function5<IfcGeom::IteratorImplementation<float, float>*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int> iterator_float_float_fn;
typedef boost::function5<IfcGeom::IteratorImplementation<float, double>*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int> iterator_float_double_fn;
typedef boost::function5<IfcGeom::IteratorImplementation<double, double>*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int> iterator_double_double_fn;
template <typename P, typename PP>
struct get_factory_type {};
@@ -50,7 +50,7 @@ class IteratorFactoryImplementation : public std::map<std::string, typename get_
public:
IteratorFactoryImplementation();
void bind(const std::string& schema_name, typename get_factory_type<P, PP>::type fn);
IfcGeom::IteratorImplementation<P, PP>* construct(const std::string& schema_name, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int);
IfcGeom::IteratorImplementation<P, PP>* construct(const std::string& schema_name, const std::string& geometry_library, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int);
};
template <typename P, typename PP>
@@ -71,7 +71,7 @@ namespace IfcGeom {
virtual IfcParse::IfcFile* file() const = 0;
virtual IfcUtil::IfcBaseClass* next() = 0;
virtual Element<P, PP>* get() = 0;
virtual BRepElement<P, PP>* get_native() = 0;
virtual NativeElement<P, PP>* get_native() = 0;
virtual const Element<P, PP>* get_object(int id) = 0;
virtual IfcUtil::IfcBaseClass* create() = 0;
};
@@ -1,22 +1,32 @@
#include "Kernel.h"
#include "../../ifcparse/Ifc2x3.h"
#include "../../ifcparse/Ifc4.h"
// @todo remove
#include "../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h"
#include <TopExp.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
IfcGeom::Kernel::Kernel(IfcParse::IfcFile* file) {
IfcGeom::Kernel::Kernel(const std::string& geometry_library, IfcParse::IfcFile* file) {
if (file != 0) {
if (file->schema() == 0) {
throw IfcParse::IfcException("No schema associated with file");
}
const std::string& schema_name = file->schema()->name();
implementation_ = impl::kernel_implementations().construct(schema_name, file);
implementation_ = impl::kernel_implementations().construct(schema_name, geometry_library, file);
}
}
int IfcGeom::Kernel::count(const TopoDS_Shape& s, TopAbs_ShapeEnum t, bool unique) {
int IfcGeom::Kernel::count(const ConversionResultShape* s_, int t_, bool unique) {
// @todo make kernel agnostic
const TopoDS_Shape& s = ((OpenCascadeShape*) s_)->shape();
TopAbs_ShapeEnum t = (TopAbs_ShapeEnum) t_;
if (unique) {
TopTools_IndexedMapOfShape map;
TopExp::MapShapes(s, t, map);
@@ -32,10 +42,14 @@ int IfcGeom::Kernel::count(const TopoDS_Shape& s, TopAbs_ShapeEnum t, bool uniqu
}
int IfcGeom::Kernel::surface_genus(const TopoDS_Shape& s) {
int nv = count(s, TopAbs_VERTEX, true);
int ne = count(s, TopAbs_EDGE, true);
int nf = count(s, TopAbs_FACE, true);
int IfcGeom::Kernel::surface_genus(const ConversionResultShape* s_) {
// @todo make kernel agnostic
const TopoDS_Shape& s = ((OpenCascadeShape*) s_)->shape();
OpenCascadeShape Ss(s);
int nv = count(&Ss, (int) TopAbs_VERTEX, true);
int ne = count(&Ss, (int) TopAbs_EDGE, true);
int nf = count(&Ss, (int) TopAbs_FACE, true);
const int euler = nv - ne + nf;
const int genus = (2 - euler) / 2;
@@ -48,23 +62,31 @@ IfcGeom::impl::KernelFactoryImplementation& IfcGeom::impl::kernel_implementation
return impl;
}
extern void init_KernelImplementation_Ifc2x3(IfcGeom::impl::KernelFactoryImplementation*);
extern void init_KernelImplementation_Ifc4(IfcGeom::impl::KernelFactoryImplementation*);
extern void init_KernelImplementation_opencascade_Ifc2x3(IfcGeom::impl::KernelFactoryImplementation*);
extern void init_KernelImplementation_opencascade_Ifc4(IfcGeom::impl::KernelFactoryImplementation*);
#ifdef IFOPSH_USE_CGAL
extern void init_KernelImplementation_cgal_Ifc2x3(IfcGeom::impl::KernelFactoryImplementation*);
extern void init_KernelImplementation_cgal_Ifc4(IfcGeom::impl::KernelFactoryImplementation*);
#endif
IfcGeom::impl::KernelFactoryImplementation::KernelFactoryImplementation() {
init_KernelImplementation_Ifc2x3(this);
init_KernelImplementation_Ifc4(this);
init_KernelImplementation_opencascade_Ifc2x3(this);
init_KernelImplementation_opencascade_Ifc4(this);
#ifdef IFOPSH_USE_CGAL
init_KernelImplementation_cgal_Ifc2x3(this);
init_KernelImplementation_cgal_Ifc4(this);
#endif
}
void IfcGeom::impl::KernelFactoryImplementation::bind(const std::string& schema_name, IfcGeom::impl::kernel_fn fn) {
void IfcGeom::impl::KernelFactoryImplementation::bind(const std::string& schema_name, const std::string& geometry_library, IfcGeom::impl::kernel_fn fn) {
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
this->insert(std::make_pair(schema_name_lower, fn));
this->insert(std::make_pair(std::make_pair(schema_name_lower, geometry_library), fn));
}
IfcGeom::Kernel* IfcGeom::impl::KernelFactoryImplementation::construct(const std::string& schema_name, IfcParse::IfcFile* file) {
IfcGeom::Kernel* IfcGeom::impl::KernelFactoryImplementation::construct(const std::string& schema_name, const std::string& geometry_library, IfcParse::IfcFile* file) {
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
std::map<std::string, IfcGeom::impl::kernel_fn>::const_iterator it;
it = this->find(schema_name_lower);
std::map<std::pair<std::string, std::string>, IfcGeom::impl::kernel_fn>::const_iterator it;
it = this->find(std::make_pair(schema_name_lower, geometry_library));
if (it == end()) {
throw IfcParse::IfcException("No geometry kernel registered for " + schema_name);
}
@@ -158,7 +180,7 @@ namespace {
std::map<std::string, IfcUtil::IfcBaseEntity*> layers;
if (prod->hasRepresentation()) {
IfcEntityList::ptr r = IfcParse::traverse(prod->Representation());
typename Schema::IfcRepresentation::list::ptr representations = r->as<typename Schema::IfcRepresentation>();
typename Schema::IfcRepresentation::list::ptr representations = r->template as<typename Schema::IfcRepresentation>();
for (typename Schema::IfcRepresentation::list::it it = representations->begin(); it != representations->end(); ++it) {
typename Schema::IfcPresentationLayerAssignment::list::ptr a = (*it)->LayerAssignments();
for (typename Schema::IfcPresentationLayerAssignment::list::it jt = a->begin(); jt != a->end(); ++jt) {
@@ -180,11 +202,15 @@ std::map<std::string, IfcUtil::IfcBaseEntity*> IfcGeom::Kernel::get_layers(IfcUt
}
}
bool IfcGeom::Kernel::is_manifold(const TopoDS_Shape& a) {
bool IfcGeom::Kernel::is_manifold(const ConversionResultShape* s_) {
// @todo make kernel agnostic
const TopoDS_Shape& a = ((OpenCascadeShape*) s_)->shape();
if (a.ShapeType() == TopAbs_COMPOUND || a.ShapeType() == TopAbs_SOLID) {
TopoDS_Iterator it(a);
for (; it.More(); it.Next()) {
if (!is_manifold(it.Value())) {
OpenCascadeShape s(it.Value());
if (!is_manifold(&s)) {
return false;
}
}
@@ -201,4 +227,42 @@ bool IfcGeom::Kernel::is_manifold(const TopoDS_Shape& a) {
return true;
}
}
}
namespace {
template <typename Schema>
IfcEntityList::ptr find_openings_helper(typename Schema::IfcProduct* product) {
typename IfcEntityList::ptr openings(new IfcEntityList);
if (product->declaration().is(Schema::IfcElement::Class()) && !product->declaration().is(Schema::IfcOpeningElement::Class())) {
typename Schema::IfcElement* element = (typename Schema::IfcElement*)product;
openings = element->HasOpenings()->generalize();
}
// Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements?
typename Schema::IfcObjectDefinition* obdef = product->template as<typename Schema::IfcObjectDefinition>();
for (;;) {
auto decomposes = obdef->Decomposes()->generalize();
if (decomposes->size() != 1) break;
typename Schema::IfcObjectDefinition* rel_obdef = (*decomposes->begin())->template as<typename Schema::IfcRelAggregates>()->RelatingObject();
if (rel_obdef->declaration().is(Schema::IfcElement::Class()) && !rel_obdef->declaration().is(Schema::IfcOpeningElement::Class())) {
typename Schema::IfcElement* element = (typename Schema::IfcElement*)rel_obdef;
openings->push(element->HasOpenings()->generalize());
}
obdef = rel_obdef;
}
return openings;
}
}
IfcEntityList::ptr IfcGeom::Kernel::find_openings(IfcUtil::IfcBaseEntity* inst) {
if (inst->as<Ifc2x3::IfcProduct>()) {
return find_openings_helper<Ifc2x3>(inst->as<Ifc2x3::IfcProduct>());
} else if (inst->as<Ifc4::IfcProduct>()) {
return find_openings_helper<Ifc4>(inst->as<Ifc4::IfcProduct>());
} else {
throw IfcParse::IfcException("Unexpected entity " + inst->declaration().name());
}
}
@@ -1,21 +1,16 @@
#ifndef ITERATOR_KERNEL_H
#define ITERATOR_KERNEL_H
#include "../ifcparse/IfcFile.h"
#include "../ifcgeom/IfcGeomIteratorSettings.h"
#include "../ifcgeom/IfcRepresentationShapeItem.h"
#include "../ifcparse/Ifc2x3.h"
#include "../ifcparse/Ifc4.h"
#include "../../ifcparse/IfcFile.h"
#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
#include "../../ifcgeom/schema_agnostic/ConversionResult.h"
#include <boost/function.hpp>
#include <TopExp_Explorer.hxx>
namespace IfcGeom {
template <typename P, typename PP>
class BRepElement;
class NativeElement;
class Kernel {
private:
@@ -52,7 +47,7 @@ namespace IfcGeom {
GV_DIMENSIONALITY
};
Kernel(IfcParse::IfcFile* file_ = 0);
Kernel(const std::string& geometry_library, IfcParse::IfcFile* file_ = 0);
virtual ~Kernel() {}
@@ -64,37 +59,38 @@ namespace IfcGeom {
return implementation_->getValue(var);
}
virtual BRepElement<double, double>* convert(
virtual NativeElement<double, double>* convert(
const IteratorSettings& settings, IfcUtil::IfcBaseClass* representation,
IfcUtil::IfcBaseClass* product)
{
return implementation_->convert(settings, representation, product);
}
virtual IfcRepresentationShapeItems convert(IfcUtil::IfcBaseClass* item) {
virtual ConversionResults convert(IfcUtil::IfcBaseClass* item) {
return implementation_->convert(item);
}
virtual bool convert_placement(IfcUtil::IfcBaseClass* item, gp_Trsf& trsf) {
virtual bool convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf) {
return implementation_->convert_placement(item, trsf);
}
static int count(const TopoDS_Shape&, TopAbs_ShapeEnum, bool unique=false);
static int surface_genus(const TopoDS_Shape&);
static int count(const ConversionResultShape*, int, bool unique=false);
static int surface_genus(const ConversionResultShape*);
static bool is_manifold(const TopoDS_Shape& a);
static bool is_manifold(const ConversionResultShape*);
static IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity*, bool include_openings=true);
static std::map<std::string, IfcUtil::IfcBaseEntity*> get_layers(IfcUtil::IfcBaseEntity*);
static IfcEntityList::ptr find_openings(IfcUtil::IfcBaseEntity* product);
};
namespace impl {
typedef boost::function1<Kernel*, IfcParse::IfcFile*> kernel_fn;
class KernelFactoryImplementation : public std::map<std::string, kernel_fn> {
class KernelFactoryImplementation : public std::map<std::pair<std::string, std::string>, kernel_fn> {
public:
KernelFactoryImplementation();
void bind(const std::string& schema_name, kernel_fn);
Kernel* construct(const std::string& schema_name, IfcParse::IfcFile*);
void bind(const std::string& schema_name, const std::string& geometry_library, kernel_fn);
Kernel* construct(const std::string& schema_name, const std::string& geometry_library, IfcParse::IfcFile*);
};
KernelFactoryImplementation& kernel_implementations();
@@ -1,5 +1,6 @@
#include "../ifcgeom/ifc_geom_api.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../../ifcparse/IfcBaseClass.h"
#include "../../ifcgeom/schema_agnostic/ifc_geom_api.h"
#include <TopoDS_Shape.hxx>
@@ -1,4 +1,4 @@
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
#include "../../ifcgeom/schema_agnostic/IfcGeomRenderStyles.h"
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
@@ -0,0 +1,88 @@
#include "CgalConversionResult.h"
#include "../../../ifcparse/IfcLogger.h"
#include "../../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
template <typename Precision>
void triangulate_helper(const cgal_shape_t& shape_const, const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<Precision>* t, int surface_style_id) {
// Copy is made because triangulate_faces() does not accept a const argument
cgal_shape_t s = shape_const;
const cgal_placement_t& trsf = dynamic_cast<const IfcGeom::CgalPlacement*>(place)->trsf();
// std::cout << "Model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl;
// std::cout << "Valid: " << s.is_valid() << std::endl;
// Apply transformation
if (place != NULL) 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);
CGAL::Polygon_mesh_processing::compute_face_normals(s, face_normals_map);
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();
do {
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)));
const double nx = CGAL::to_double(face_normals_map[face].cartesian(0));
const double ny = CGAL::to_double(face_normals_map[face].cartesian(1));
const double nz = CGAL::to_double(face_normals_map[face].cartesian(2));
t->addNormal(nx, ny, nz);
++num_vertices;
++current_halfedge;
} while (current_halfedge != face->facet_begin());
t->addFace(surface_style_id, num_vertices-3, num_vertices-2, num_vertices-1);
++num_faces;
}
}
void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<float>* t, int surface_style_id) const {
triangulate_helper(shape_, settings, place, t, surface_style_id);
}
void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<double>* t, int surface_style_id) const {
triangulate_helper(shape_, settings, place, t, surface_style_id);
}
@@ -0,0 +1,134 @@
/********************************************************************************
* *
* 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/Kernel.h"
#include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h"
#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h"
// @todo create separate shapetype enum?
#include "../../../ifcgeom/kernels/opencascade/IfcGeomShapeType.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 IfcGeom {
class CgalPlacement : public ConversionResultPlacement {
public:
CgalPlacement(const cgal_placement_t& trsf)
: trsf_(trsf)
{}
const cgal_placement_t& trsf() const { return trsf_; }
operator const cgal_placement_t& () { return trsf_; }
virtual double Value(int i, int j) const {
return CGAL::to_double(trsf_.cartesian(i-1, j-1));
}
virtual void Multiply(const ConversionResultPlacement* other) {
trsf_ = trsf_ * ((CgalPlacement *)other)->trsf_;
}
virtual void PreMultiply(const ConversionResultPlacement* other) {
trsf_ = ((CgalPlacement *)other)->trsf_ * trsf_;
}
virtual ConversionResultPlacement* clone() const {
return new CgalPlacement(trsf_);
}
virtual ConversionResultPlacement* inverted() const {
throw std::runtime_error("Not implemented");
}
virtual ConversionResultPlacement* multiplied(const ConversionResultPlacement*) const {
throw std::runtime_error("Not implemented");
}
virtual void TranslationPart(double& X, double& Y, double& Z) const {
throw std::runtime_error("Not implemented");
}
private:
cgal_placement_t trsf_;
};
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 IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<float> * t, int surface_style_id) const;
virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<double>* 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 int surface_genus() const {
throw std::runtime_error("Not implemented");
}
private:
cgal_shape_t shape_;
};
}
#endif
@@ -0,0 +1,201 @@
#include "OpenCascadeConversionResult.h"
#include "../../../ifcparse/IfcLogger.h"
#include "../../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
#include <TopoDS.hxx>
#include <map>
template <typename Precision>
void triangulate_helper(const TopoDS_Shape& s, const IfcGeom::IteratorSettings& settings, const IfcGeom::ConversionResultPlacement* place, IfcGeom::Representation::Triangulation<Precision>* t, int surface_style_id) {
gp_GTrsf trsf;
if (place) {
trsf = dynamic_cast<const IfcGeom::OpenCascadePlacement*>(place)->trsf();
}
// 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");
return;
}
// Iterates over the faces of the shape
int num_faces = 0;
TopExp_Explorer exp;
for (exp.Init(s, TopAbs_FACE); exp.More(); exp.Next(), ++num_faces) {
TopoDS_Face face = TopoDS::Face(exp.Current());
TopLoc_Location loc;
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face, loc);
if (!tri.IsNull()) {
// A 3x3 matrix to rotate the vertex normals
const gp_Mat rotation_matrix = trsf.VectorialPart();
// Keep track of the number of times an edge is used
// Manifold edges (i.e. edges used twice) are deemed invisible
std::map<std::pair<int, int>, int> edgecount;
std::vector<std::pair<int, int> > edges_temp;
const TColgp_Array1OfPnt& nodes = tri->Nodes();
const TColgp_Array1OfPnt2d& uvs = tri->UVNodes();
std::vector<gp_XYZ> coords;
BRepGProp_Face prop(face);
std::map<int, int> dict;
// Vertex normals are only calculated if vertices are not welded and calculation is not disable explicitly.
const bool calculate_normals = !settings.get(IfcGeom::IteratorSettings::WELD_VERTICES) &&
!settings.get(IfcGeom::IteratorSettings::NO_NORMALS);
for (int i = 1; i <= nodes.Length(); ++i) {
coords.push_back(nodes(i).Transformed(loc).XYZ());
trsf.Transforms(*coords.rbegin());
const gp_XYZ& last = *coords.rbegin();
dict[i] = t->addVertex(surface_style_id, last.X(), last.Y(), last.Z());
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() > 1.e-9) {
normal = gp_Dir(normal_direction.XYZ() * rotation_matrix);
}
t->addNormal(normal.X(), normal.Y(), 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());
*/
t->addFace(surface_style_id, dict[n1], dict[n2], dict[n3]);
t->addEdge(dict[n1], dict[n2], edgecount, edges_temp);
t->addEdge(dict[n2], dict[n3], edgecount, edges_temp);
t->addEdge(dict[n3], dict[n1], edgecount, edges_temp);
}
for (std::vector<std::pair<int, int> >::const_iterator jt = edges_temp.begin(); jt != edges_temp.end(); ++jt) {
if (edgecount[*jt] == 1) {
// non manifold edge, face boundary
t->registerEdge(jt->first, jt->second);
}
}
}
}
/*
TODO: Unimplemented
if (!t.normals().empty() && settings().get(IfcGeom::IteratorSettings::GENERATE_UVS)) {
t.uvs() = box_project_uvs(t.verts(), t.normals());
}
if (num_faces == 0) {
// Edges are only emitted if there are no faces. A mixed representation of faces
// and loose edges is discouraged by the standard. An alternative would be to use
// TopExp_Explorer texp(s, TopAbs_EDGE, TopAbs_FACE) to find edges that do not
// belong to any face.
for (TopExp_Explorer texp(s, TopAbs_EDGE); texp.More(); texp.Next()) {
BRepAdaptor_Curve crv(TopoDS::Edge(texp.Current()));
GCPnts_QuasiUniformDeflection tessellater(crv, settings.deflection_tolerance());
int n = tessellater.NbPoints();
int start = (int)t->verts().size() / 3;
for (int i = 1; i <= n; ++i) {
gp_XYZ p = tessellater.Value(i).XYZ();
// // In case you want direction arrows on your edges
// double u = tessellater.Parameter(i);
// gp_XYZ p2, p3;
// gp_Pnt tmp;
// gp_Vec tmp2;
// crv.D1(u, tmp, tmp2);
// gp_Dir d1, d2, d3, d4;
// d1 = tmp2;
// if (texp.Current().Orientation() == TopAbs_REVERSED) {
// d1 = -d1;
// }
// if (fabs(d1.Z()) < 0.5) {
// d2 = d1.Crossed(gp::DZ());
// } else {
// d2 = d1.Crossed(gp::DY());
// }
// d3 = d1.XYZ() + d2.XYZ();
// d4 = d1.XYZ() - d2.XYZ();
// p2 = p - d3.XYZ() / 10.;
// p3 = p - d4.XYZ() / 10.;
// trsf.Transforms(p2);
// trsf.Transforms(p3);
// _material_ids.push_back(surface_style_id);
// _material_ids.push_back(surface_style_id);
// _verts.push_back(static_cast<P>(p2.X()));
// _verts.push_back(static_cast<P>(p2.Y()));
// _verts.push_back(static_cast<P>(p2.Z()));
// _verts.push_back(static_cast<P>(p3.X()));
// _verts.push_back(static_cast<P>(p3.Y()));
// _verts.push_back(static_cast<P>(p3.Z()));
trsf.Transforms(p);
t->material_ids().push_back(surface_style_id);
t->verts().push_back(static_cast<double>(p.X()));
t->verts().push_back(static_cast<double>(p.Y()));
t->verts().push_back(static_cast<double>(p.Z()));
if (i > 1) {
t->edges().push_back(start + i - 2);
t->edges().push_back(start + i - 1);
// _edges.push_back(start + 3 * (i - 2) + 2);
// _edges.push_back(start + 3 * (i - 1) + 2);
}
// _edges.push_back(start + 3 * (i - 1) + 0);
// _edges.push_back(start + 3 * (i - 1) + 2);
// _edges.push_back(start + 3 * (i - 1) + 1);
// _edges.push_back(start + 3 * (i - 1) + 2);
}
}
}
*/
BRepTools::Clean(s);
}
void IfcGeom::OpenCascadeShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<float>* t, int surface_style_id) const {
triangulate_helper(shape_, settings, place, t, surface_style_id);
}
void IfcGeom::OpenCascadeShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<double>* t, int surface_style_id) const {
triangulate_helper(shape_, settings, place, t, surface_style_id);
}
int IfcGeom::OpenCascadeShape::surface_genus() const {
throw std::runtime_error("Not implemented");
// return IfcGeom::Kernel::surface_genus(shape_);
}
@@ -0,0 +1,110 @@
/********************************************************************************
* *
* 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 IFCGEOMOPENCASCADEREPRESENTATION_H
#define IFCGEOMOPENCASCADEREPRESENTATION_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 <BRepTools.hxx>
#include <gp_GTrsf.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <GCPnts_QuasiUniformDeflection.hxx>
#include "../../../ifcgeom/schema_agnostic/ConversionResult.h"
namespace IfcGeom {
class OpenCascadePlacement : public ConversionResultPlacement {
public:
OpenCascadePlacement(const gp_GTrsf& trsf)
: trsf_(trsf) {}
const gp_GTrsf& trsf() const { return trsf_; }
operator const gp_GTrsf& () { return trsf_; }
virtual double Value(int i, int j) const {
return trsf_.Value(i, j);
}
virtual void Multiply(const ConversionResultPlacement* other) {
trsf_.Multiply(((OpenCascadePlacement*)other)->trsf_);
}
virtual void PreMultiply(const ConversionResultPlacement* other) {
trsf_.PreMultiply(((OpenCascadePlacement*)other)->trsf_);
}
virtual ConversionResultPlacement* clone() const {
return new OpenCascadePlacement(trsf_);
}
virtual ConversionResultPlacement* inverted() const {
return new OpenCascadePlacement(trsf_.Inverted());
}
virtual ConversionResultPlacement* multiplied(const ConversionResultPlacement* other) const {
return new OpenCascadePlacement(trsf_.Multiplied(((OpenCascadePlacement*)other)->trsf_));
}
virtual void TranslationPart(double& X, double& Y, double& Z) const {
X = trsf_.TranslationPart().X();
Y = trsf_.TranslationPart().Y();
Z = trsf_.TranslationPart().Z();
}
private:
gp_GTrsf trsf_;
};
class OpenCascadeShape : public ConversionResultShape {
public:
OpenCascadeShape(const TopoDS_Shape& shape)
: shape_(shape)
{}
const TopoDS_Shape& shape() const { return shape_; }
operator const TopoDS_Shape& () { return shape_; }
virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<float>* t, int surface_style_id) const;
virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<double>* t, int surface_style_id) const;
virtual void Serialize(std::string&) const {
throw std::runtime_error("Not implemented");
}
virtual ConversionResultShape* clone() const {
return new OpenCascadeShape(shape_);
}
virtual int surface_genus() const;
private:
TopoDS_Shape shape_;
};
}
#endif
+86 -14
View File
@@ -38,8 +38,8 @@
#include <fcntl.h>
#endif
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
#include "../ifcgeom/IfcGeomElement.h"
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
#include "../ifcgeom/schema_agnostic/IfcGeomElement.h"
#include "../ifcparse/IfcFile.h"
#include "../ifcparse/IfcLogger.h"
@@ -47,14 +47,24 @@
#include <vld.h>
#endif
#include "../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h"
#include <GProp_GProps.hxx>
#include <BRepGProp.hxx>
#include <BRepBndLib.hxx>
#include <Bnd_Box.hxx>
#include <Geom_Plane.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Compound.hxx>
#include <memory>
#ifdef USE_VOXELS
#include <voxel/storage.h>
#include <voxel/traversal.h>
#include <voxel/processor.h>
#endif
template <typename T>
union data_field {
char buffer[sizeof(T)];
@@ -429,6 +439,7 @@ public:
static const std::string TOTAL_SURFACE_AREA = "TOTAL_SURFACE_AREA";
static const std::string TOTAL_SHAPE_VOLUME = "TOTAL_SHAPE_VOLUME";
static const std::string TOTAL_SHAPE_VOLUME_VOXELS = "TOTAL_SHAPE_VOLUME_VOXELS";
static const std::string SURFACE_AREA_ALONG_X = "SURFACE_AREA_ALONG_X";
static const std::string SURFACE_AREA_ALONG_Y = "SURFACE_AREA_ALONG_Y";
static const std::string SURFACE_AREA_ALONG_Z = "SURFACE_AREA_ALONG_Z";
@@ -440,9 +451,9 @@ static const std::array<std::string, 3> XYZ = { "X", "Y", "Z" };
class QuantityWriter_v0 : public EntityExtension {
private:
const IfcGeom::BRepElement<double, double>* elem_;
const IfcGeom::NativeElement<double, double>* elem_;
public:
QuantityWriter_v0(const IfcGeom::BRepElement<double, double>* elem) :
QuantityWriter_v0(const IfcGeom::NativeElement<double, double>* elem) :
elem_(elem)
{
put_json(TOTAL_SURFACE_AREA, 0.);
@@ -453,21 +464,32 @@ public:
}
};
#ifdef USE_VOXELS
namespace {
void write_voxels(const std::string& fn, abstract_voxel_storage* voxels) {
voxel_writer w;
w.SetVoxels(voxels);
w.Write(fn);
}
}
#endif
class QuantityWriter_v1 : public EntityExtension {
private:
const IfcGeom::BRepElement<double, double>* elem_;
const IfcGeom::NativeElement<double, double>* elem_;
public:
QuantityWriter_v1(const IfcGeom::BRepElement<double, double>* elem) :
elem_(elem) {
QuantityWriter_v1(const IfcGeom::NativeElement<double, double>* elem) :
elem_(elem)
{
double a, b, c, largest_face_area = 0.;
if (elem_->geometry().calculate_surface_area(a)) {
put_json(TOTAL_SURFACE_AREA, a);
}
if (elem_->geometry().calculate_volume(a)) {
put_json(TOTAL_SHAPE_VOLUME, a);
}
TopoDS_Compound compound = TopoDS::Compound(((IfcGeom::OpenCascadeShape*) elem_->geometry().as_compound(true))->shape());
double bbox_xyz[6];
bool has_boundingbox = false;
if (elem_->calculate_projected_surface_area(a, b, c)) {
put_json(SURFACE_AREA_ALONG_X, a);
@@ -478,7 +500,6 @@ public:
boost::optional<gp_Dir> largest_face_dir;
{
TopoDS_Compound compound = elem_->geometry().as_compound(true);
TopExp_Explorer exp(compound, TopAbs_FACE);
for (; exp.More(); exp.Next()) {
GProp_GProps prop;
@@ -498,19 +519,70 @@ public:
}
Bnd_Box box;
double xyz[6];
BRepBndLib::AddClose(compound, box);
if (!box.IsVoid()) {
box.Get(xyz[0], xyz[1], xyz[2], xyz[3], xyz[4], xyz[5]);
has_boundingbox = true;
box.Get(bbox_xyz[0], bbox_xyz[1], bbox_xyz[2], bbox_xyz[3], bbox_xyz[4], bbox_xyz[5]);
for (int i = 0; i < 3; ++i) {
const double bsz = xyz[i + 3] - xyz[i];
const double bsz = bbox_xyz[i + 3] - bbox_xyz[i];
put_json(BOUNDING_BOX_SIZE_ALONG_ + XYZ[i], bsz);
}
}
}
if (elem_->geometry().calculate_volume(a)) {
put_json(TOTAL_SHAPE_VOLUME, a);
}
#ifdef USE_VOXELS
// Sometimes geometries are not a topologically valid manifold,
// but still (approximately) enclose a volume. In this case
// we can voxlize the geometry and fill the interior solid volume.
else if (has_boundingbox) {
std::array< vec_n<3, double>, 2 > bounds;
for (int i = 0; i < 3; ++i) {
bounds[0].get(i) = bbox_xyz[i + 0];
bounds[1].get(i) = bbox_xyz[i + 3];
}
progress_writer silent;
// At least one padding voxel need to be in place as the traversal happens outside
// of the surface voxel bounds and is subsequently inverted to find the interior
// voxels.
auto surface = storage_for(bounds, 256U, 4U, 16U);
processor proc(surface, silent);
// @todo is scanline entirely reliable due to rounding from float to int?
// This is also observed in voxec dump_surfaces().
// proc.use_scanline() = false;
BRepMesh_IncrementalMesh(compound, 0.001);
std::vector<std::pair<int, TopoDS_Compound > > geometries = { {1, compound} };
proc.process(geometries.begin(), geometries.end(), SURFACE(), output(MERGED()));
surface = (regular_voxel_storage*) proc.voxels();
double vsize = surface->voxel_size();
auto surface_count = surface->count();
traversal_voxel_filler_inverse filler;
double total_volume = 0.;
if (surface->count() != 0) {
auto volume = filler(surface);
auto volume_count = volume->count();
auto inner_surface = (regular_voxel_storage*) volume->boolean_intersection(surface);
if (inner_surface->count() != 0) {
// Or, use a boolean intersection of surface and volume and subtract any subsequent
// interior void volumes.
auto inner_volume = filler(inner_surface);
volume_count -= inner_volume->count();
delete inner_volume;
}
delete inner_surface;
delete volume;
total_volume = (volume_count + surface_count / 2) * (vsize * vsize * vsize);
}
delete surface;
put_json(TOTAL_SHAPE_VOLUME, total_volume);
put_json(TOTAL_SHAPE_VOLUME_VOXELS, total_volume);
}
#endif
if (largest_face_dir) {
put_json(LARGEST_FACE_DIRECTION, *largest_face_dir);
put_json(LARGEST_FACE_AREA, largest_face_area);
@@ -0,0 +1,174 @@
###############################################################################
# #
# 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/>. #
# #
###############################################################################
"""
Rough draft of a client application for the C++ IfcGeomServer binary
"""
import os
import numpy
import subprocess
from collections import namedtuple
class message_headers(object):
HELLO = 0xff00
IFC_MODEL = HELLO + 1
GET = IFC_MODEL + 1
ENTITY = GET + 1
MORE = ENTITY + 1
NEXT = MORE + 1
BYE = NEXT + 1
GET_LOG = BYE + 1
LOG = GET_LOG + 1
DEFLECTION = LOG + 1
SETTING = DEFLECTION + 1
CALCULATE_QUANTITIES = numpy.int32((1 << 4))
APPLY_LAYERSETS = numpy.int32((1 << 13))
def cast(data, dtype, n=None):
arr = numpy.frombuffer(data, dtype=dtype)
if n is None: return arr[0]
else: return arr
def read(stream, dtype, n=None):
data = stream.read(dtype().nbytes * (n or 1))
x = cast(data, dtype, n)
# print(x)
return x
def readString(s):
l = read(s, numpy.int32)
S = s.read(int(l)).decode('ascii')
while (l % 4 != 0):
s.read(1);
l += 1
# print(S)
return S
def readDoubleArray(s):
l = read(s, numpy.int32) // 8
return read(s, numpy.float64, int(l))
def readByteBuffer(s):
l = read(s, numpy.int32)
return s.read(int(l))
class entity_contents(object):
def __init__(self, data):
import json
from io import BytesIO
s = BytesIO(data)
self.structure = [
("id" , read(s, numpy.int32)),
("guid" , readString(s)),
("name" , readString(s)),
("type" , readString(s)),
("parentId" , read(s, numpy.int32)),
("matrix" , readDoubleArray(s)),
("repId" , read(s, numpy.int32)),
("positions" , readByteBuffer(s)),
("normals" , readByteBuffer(s)),
("indices" , readByteBuffer(s)),
("colors" , readByteBuffer(s)),
("materialIndices" , readByteBuffer(s)),
("extendedData" , json.loads(s.read().strip(b'\x00').decode('ascii').strip(' ')))
]
def __getattr__(self, k):
return [kv for kv in self.structure if kv[0] == k][0][1]
def __repr__(self):
def format(x):
a, b = x
if isinstance(b, bytes):
b = "<bytes>"
elif isinstance(b, dict):
padding = " " * (len(a) + 2)
b = ("\n".join("%s%%s: %%s" % padding % format(x) for x in b.items())).strip()
return a, b
return "ENTITY: \n" + "\n".join("%s: %s" % format(x) for x in self.structure)
content_factory = {
message_headers.ENTITY: entity_contents
}
identity = lambda x: x
def parse_contents(header, contents):
return (content_factory.get(header, identity))(contents)
message = namedtuple("message", ("header", "contents"))
def process(geomserver_exe, ifc_filename):
proc = subprocess.Popen([geomserver_exe], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
def read_message(header_assertion=None):
header, size = read(proc.stdout, numpy.int32, 2)
assert header_assertion is None or header_assertion == header
contents = b""
if size > 0:
contents = proc.stdout.read(size)
contents = parse_contents(header, contents)
return message(header, contents)
def write(header, contents=None):
if contents is None: contents = []
proc.stdin.write(numpy.int32(header).tobytes())
integers_as_int32 = list(map(lambda s: numpy.int32(s) if isinstance(s, int) else s, contents))
to_bytes = list(map(lambda s: s.tobytes() if hasattr(s, 'tobytes') else s, integers_as_int32))
total_length = numpy.int32(sum(map(len, to_bytes)))
proc.stdin.write(total_length.tobytes())
for b in to_bytes:
proc.stdin.write(b)
proc.stdin.flush()
read_message(message_headers.HELLO)
# @todo: no need to read the entire file in memory
s = open(ifc_filename, "rb").read()
write(message_headers.SETTING, [CALCULATE_QUANTITIES, numpy.int32(1)])
write(message_headers.SETTING, [APPLY_LAYERSETS, numpy.int32(1)])
write(message_headers.IFC_MODEL, [numpy.int32(len(s)), s, b"\x00" * ((4 - (len(s) % 4)) % 4)])
while True:
has_more = cast(read_message(message_headers.MORE).contents, numpy.int32) == 1
if not has_more: break
write(message_headers.GET)
geom_data = read_message(message_headers.ENTITY).contents
yield geom_data
write(message_headers.NEXT)
write(message_headers.BYE)
read_message(message_headers.BYE)
proc.wait()
assert proc.returncode == 0
if __name__ == "__main__":
import sys
import platform
exe_extension = ".exe" if platform.system() == 'Windows' else ""
exe = os.environ.get("IFCGEOMSERVER") or ("IfcGeomServer" + exe_extension)
for fn in sys.argv[1:]:
for geom_data in process(exe, fn):
print(geom_data)
+1
View File
@@ -100,6 +100,7 @@ namespace {
template <typename Schema>
class IFC_PARSE_API IfcHierarchyHelper : public IfcParse::IfcFile {
public:
IfcHierarchyHelper(const IfcParse::schema_definition* schema) :IfcFile(schema) {}
template <class T>
T* addTriplet(double x, double y, double z) {
std::vector<double> a; a.push_back(x); a.push_back(y); a.push_back(z);
+4 -3
View File
@@ -27,7 +27,7 @@
#ifndef IFCPARSE_H
#define IFCPARSE_H
#define IFCOPENSHELL_VERSION "0.6.0b0"
#define IFCOPENSHELL_VERSION "0.7.0-dev"
#include <string>
#include <sstream>
@@ -49,8 +49,9 @@
#include "../ifcparse/IfcSpfStream.h"
/* gcc doesn't know _Thread_local from C11 yet */
#ifdef __GNUC__
#if defined(__clang__)
# define my_thread_local thread_local
#elif defined(__GNUC__)
# define my_thread_local __thread
#elif __STDC_VERSION__ >= 201112L
# define my_thread_local _Thread_local
+2 -2
View File
@@ -56,9 +56,9 @@ SET_SOURCE_FILES_PROPERTIES(IfcPython.i PROPERTIES CPLUSPLUS ON)
SWIG_ADD_MODULE(ifcopenshell_wrapper python IfcPython.i)
if("$ENV{LDFLAGS}" MATCHES ".undefined.suppress")
# On osx there is some state in the python dylib. With `-Wl,undefined,suppress` we can ignore the missing symbols at compile time.
SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES})
SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${IFCOPENSHELL_LIBRARIES})
else()
SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${IFCOPENSHELL_LIBRARIES} ${PYTHON_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES})
SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${IFCOPENSHELL_LIBRARIES} ${PYTHON_LIBRARIES})
endif()
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
SET_INSTALL_RPATHS(${SWIG_MODULE_ifcopenshell_wrapper_REAL_NAME} "${IFCDIRS};${OCC_LIBRARY_DIR}")
+12 -11
View File
@@ -38,16 +38,16 @@
%ignore IfcGeom::impl::tree::selector;
%include "../ifcgeom/ifc_geom_api.h"
%include "../ifcgeom/IfcGeomIteratorSettings.h"
%include "../ifcgeom/IfcGeomElement.h"
%include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h"
%include "../ifcgeom/IfcGeomRepresentation.h"
%include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
%include "../ifcgeom/schema_agnostic/ifc_geom_api.h"
%include "../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
%include "../ifcgeom/schema_agnostic/IfcGeomElement.h"
%include "../ifcgeom/schema_agnostic/IfcGeomMaterial.h"
%include "../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
%include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
// A Template instantantation should be defined before it is used as a base class.
// But frankly I don't care as most methods are subtlely different anyway.
%include "../ifcgeom/IfcGeomTree.h"
%include "../ifcgeom/kernels/opencascade/IfcGeomTree.h"
%extend IfcGeom::tree {
@@ -277,8 +277,9 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
template <typename Schema>
static boost::variant<IfcGeom::Element<double>*, IfcGeom::Representation::Representation*> helper_fn_create_shape(IfcGeom::IteratorSettings& settings, IfcUtil::IfcBaseClass* instance, IfcUtil::IfcBaseClass* representation = 0) {
IfcParse::IfcFile* file = instance->data().file;
IfcGeom::Kernel kernel(file);
// @todo Default to opencascade for now.
IfcGeom::Kernel kernel("opencascade", file);
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_ORIENT, settings.get(IfcGeom::IteratorSettings::SEW_SHELLS) ? std::numeric_limits<double>::infinity() : -1);
kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.get(IfcGeom::IteratorSettings::INCLUDE_CURVES) ? (settings.get(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES) ? -1. : 0.) : +1.));
@@ -360,7 +361,7 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
}
}
IfcGeom::BRepElement<double>* brep = kernel.convert(settings, ifc_representation, product);
IfcGeom::NativeElement<double>* brep = kernel.convert(settings, ifc_representation, product);
if (!brep) {
throw IfcParse::IfcException("Failed to process shape");
}
@@ -378,7 +379,7 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
} else {
if (!representation) {
if (instance->declaration().is(Schema::IfcRepresentationItem::Class()) || instance->declaration().is(Schema::IfcRepresentation::Class())) {
IfcGeom::IfcRepresentationShapeItems shapes = kernel.convert(instance);
IfcGeom::ConversionResults shapes = kernel.convert(instance);
IfcGeom::ElementSettings element_settings(settings, kernel.getValue(IfcGeom::Kernel::GV_LENGTH_UNIT), instance->declaration().name());
IfcGeom::Representation::BRep brep(element_settings, boost::lexical_cast<std::string>(instance->data().id()), shapes);
+3 -3
View File
@@ -70,9 +70,9 @@
}
%module ifcopenshell_wrapper %{
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
#include "../ifcgeom_schema_agnostic/Serialization.h"
#include "../ifcgeom/IfcGeomTree.h"
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
#include "../ifcgeom/schema_agnostic/Serialization.h"
#include "../ifcgeom/kernels/opencascade/IfcGeomTree.h"
#include "../ifcparse/Ifc2x3.h"
#include "../ifcparse/Ifc4.h"
+2 -2
View File
@@ -41,7 +41,7 @@
#pragma GCC diagnostic pop
#endif
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
#include "../serializers/GeometrySerializer.h"
@@ -230,7 +230,7 @@ public:
bool ready();
void writeHeader();
void write(const IfcGeom::TriangulationElement<real_t>* o);
void write(const IfcGeom::BRepElement<real_t>* /*o*/) {}
void write(const IfcGeom::NativeElement<real_t>* /*o*/) {}
void finalize();
bool isTesselated() const { return true; }
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
+3 -3
View File
@@ -27,8 +27,8 @@ typedef float real_t;
#endif
#include "../serializers/Serializer.h"
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
#include "../ifcgeom/IfcGeomElement.h"
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
#include "../ifcgeom/schema_agnostic/IfcGeomElement.h"
class SerializerSettings : public IfcGeom::IteratorSettings
{
@@ -77,7 +77,7 @@ public:
virtual bool isTesselated() const = 0;
virtual void write(const IfcGeom::TriangulationElement<real_t>* o) = 0;
virtual void write(const IfcGeom::BRepElement<real_t>* o) = 0;
virtual void write(const IfcGeom::NativeElement<real_t>* o) = 0;
virtual void setUnitNameAndMagnitude(const std::string& name, float magnitude) = 0;
const SerializerSettings& settings() const { return settings_; }
+1 -1
View File
@@ -43,7 +43,7 @@ public:
bool ready();
void writeHeader();
void write(const IfcGeom::TriangulationElement<real_t>* o);
void write(const IfcGeom::BRepElement<real_t>* /*o*/) {}
void write(const IfcGeom::NativeElement<real_t>* /*o*/) {}
void finalize();
bool isTesselated() const { return true; }
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
+2 -2
View File
@@ -42,8 +42,8 @@ public:
: OpenCascadeBasedSerializer(out_filename, settings)
{}
virtual ~IgesSerializer() {}
void writeShape(const TopoDS_Shape& shape) {
writer.AddShape(shape);
void writeShape(const IfcGeom::ConversionResultShape* shape) {
writer.AddShape(*(IfcGeom::OpenCascadeShape*)shape);
}
void finalize() {
writer.Write(out_filename.c_str());
@@ -36,8 +36,10 @@ bool OpenCascadeBasedSerializer::ready() {
return succeeded;
}
void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement<real_t>* o) {
TopoDS_Shape compound = o->geometry().as_compound();
void OpenCascadeBasedSerializer::write(const IfcGeom::NativeElement<real_t>* o) {
IfcGeom::OpenCascadeShape* occt_shape = ((IfcGeom::OpenCascadeShape*) o->geometry().as_compound());
TopoDS_Shape compound = occt_shape->shape();
delete occt_shape;
if (o->geometry().settings().get(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS)) {
gp_Trsf scale;
@@ -46,7 +48,8 @@ void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement<real_t>* o) {
compound = BRepBuilderAPI_Transform(compound, scale, true).Shape();
}
writeShape(compound);
IfcGeom::OpenCascadeShape s(compound);
writeShape(&s);
}
#define RATHER_SMALL (1e-3)
+4 -4
View File
@@ -20,8 +20,8 @@
#ifndef OPENCASCADEBASEDSERIALIZER_H
#define OPENCASCADEBASEDSERIALIZER_H
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
#include "../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h"
#include "../serializers/GeometrySerializer.h"
class OpenCascadeBasedSerializer : public GeometrySerializer {
@@ -38,9 +38,9 @@ public:
virtual ~OpenCascadeBasedSerializer() {}
void writeHeader() {}
bool ready();
virtual void writeShape(const TopoDS_Shape& shape) = 0;
virtual void writeShape(const IfcGeom::ConversionResultShape* shape) = 0;
void write(const IfcGeom::TriangulationElement<real_t>* /*o*/) {}
void write(const IfcGeom::BRepElement<real_t>* o);
void write(const IfcGeom::NativeElement<real_t>* o);
bool isTesselated() const { return false; }
void setFile(IfcParse::IfcFile*) {}
};
+3 -3
View File
@@ -23,7 +23,7 @@
#include <STEPControl_Writer.hxx>
#include <Interface_Static.hxx>
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
#include "../serializers/OpenCascadeBasedSerializer.h"
@@ -36,10 +36,10 @@ public:
: OpenCascadeBasedSerializer(out_filename, settings)
{}
virtual ~StepSerializer() {}
void writeShape(const TopoDS_Shape& shape) {
void writeShape(const IfcGeom::ConversionResultShape* shape) {
std::stringstream ss;
std::streambuf *sb = std::cout.rdbuf(ss.rdbuf());
writer.Transfer(shape, STEPControl_AsIs);
writer.Transfer(((IfcGeom::OpenCascadeShape*)shape)->shape(), STEPControl_AsIs);
std::cout.rdbuf(sb);
}
void finalize() {
+12 -5
View File
@@ -19,6 +19,8 @@
* *
********************************************************************************/
#include "../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h"
#include <string>
#include <fstream>
#include <cstdio>
@@ -283,7 +285,7 @@ SvgSerializer::path_object& SvgSerializer::start_path(IfcUtil::IfcBaseEntity* st
return p;
}
void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
void SvgSerializer::write(const IfcGeom::NativeElement<real_t>* o)
{
IfcUtil::IfcBaseEntity* storey = storey_;
boost::optional<double> storey_elevation = boost::none;
@@ -310,7 +312,10 @@ void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
path_object& p = start_path(storey, nameElement(o));
TopoDS_Shape compound = o->geometry().as_compound();
IfcGeom::OpenCascadeShape* occt_shape = ((IfcGeom::OpenCascadeShape*) o->geometry().as_compound());
TopoDS_Shape compound = occt_shape->shape();
delete occt_shape;
TopoDS_Iterator it(compound);
// Iterate over components of compound to have better chance of matching section edges to closed wires
@@ -469,7 +474,7 @@ void SvgSerializer::setFile(IfcParse::IfcFile* f) {
auto storeys = f->instances_by_type("IfcBuildingStorey");
if (!storeys || storeys->size() == 0) {
IfcGeom::Kernel kernel(f);
IfcGeom::Kernel kernel("opencascade", f);
std::vector<const IfcParse::declaration*> to_derive_from;
to_derive_from.push_back(f->schema()->declaration_by_name("IfcBuilding"));
@@ -480,9 +485,11 @@ void SvgSerializer::setFile(IfcParse::IfcFile* f) {
for (auto jt = insts->begin(); jt != insts->end(); ++jt) {
IfcUtil::IfcBaseEntity* product = (IfcUtil::IfcBaseEntity*) *jt;
if (!product->get("ObjectPlacement")->isNull()) {
gp_Trsf trsf;
IfcGeom::ConversionResultPlacement* trsf;
if (kernel.convert_placement(*product->get("ObjectPlacement"), trsf)) {
setSectionHeight(trsf.TranslationPart().Z() + 1.);
double X, Y, Z;
trsf->TranslationPart(X, Y, Z);
setSectionHeight(Z + 1.);
Logger::Warning("No building storeys encountered, used for reference:", product);
return;
}
+1 -1
View File
@@ -64,7 +64,7 @@ public:
void writeHeader();
bool ready();
void write(const IfcGeom::TriangulationElement<real_t>* /*o*/) {}
void write(const IfcGeom::BRepElement<real_t>* o);
void write(const IfcGeom::NativeElement<real_t>* o);
void write(path_object& p, const TopoDS_Wire& wire);
path_object& start_path(IfcUtil::IfcBaseEntity* storey, const std::string& id);
bool isTesselated() const { return false; }
+1 -1
View File
@@ -20,7 +20,7 @@
#include "WavefrontObjSerializer.h"
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
#include "../ifcgeom/schema_agnostic/IfcGeomRenderStyles.h"
#include "../ifcparse/utils.h"
+1 -1
View File
@@ -41,7 +41,7 @@ public:
void writeHeader();
void writeMaterial(const IfcGeom::Material& style);
void write(const IfcGeom::TriangulationElement<real_t>* o);
void write(const IfcGeom::BRepElement<real_t>* /*o*/) {}
void write(const IfcGeom::NativeElement<real_t>* /*o*/) {}
void finalize() {}
bool isTesselated() const { return true; }
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
@@ -27,8 +27,8 @@
#include <algorithm>
#include "../../ifcparse/IfcSIPrefix.h"
#include "../../ifcgeom/IfcGeom.h"
#include "../../ifcparse/utils.h"
#include "../../ifcgeom/kernels/opencascade/IfcGeom.h"
using boost::property_tree::ptree;

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