Compare commits

...

777 Commits

Author SHA1 Message Date
Thomas Krijnen 5609cbdde9 Fix missing symbols for boost 1.67 and BOOST_ALL_NO_LIB 2018-08-15 09:07:40 +02:00
Thomas Krijnen caa6056f01 Conda bld.bat python version 2018-08-14 17:09:00 +02:00
Thomas Krijnen 3ea3627639 Conda bld.bat python version 2018-08-14 16:15:32 +02:00
Thomas Krijnen 175387bd88 Fix IfcOpenHouse 2018-08-13 11:43:28 +02:00
Thomas Krijnen d09abbd260 Merge pull request #409 from IfcOpenShell/master
Additional potential occt lib location
2018-07-08 15:08:32 +02:00
Thomas Krijnen 5359e88f0e Additional potential occt lib location 2018-07-08 15:07:30 +02:00
Thomas Krijnen 2dc01aec2d Update conda meta 2018-07-08 15:06:12 +02:00
Thomas Krijnen 20b35ec4ea Preprocessor stuff for stp and igs serializers 2018-07-08 11:08:07 +02:00
Thomas Krijnen 5245341cdc Correct previous commit 2018-07-08 11:06:45 +02:00
Thomas Krijnen 49932ba5c0 Python wrapper precision updates 2018-07-08 10:32:26 +02:00
Thomas Krijnen 7a7aab01bb IfcGeomServer matrices in double precision 2018-07-07 21:14:27 +02:00
Thomas Krijnen d105292817 Merge branch 'master' into v0.6.0
# Conflicts:
#	src/ifcconvert/IfcConvert.cpp
#	src/ifcgeom/IfcGeomFilter.h
#	src/ifcgeom/IfcGeomIteratorImplementation.h
#	src/ifcgeom/IfcGeomWires.cpp
#	src/ifcparse/IfcFile.h
#	src/ifcparse/IfcLogger.cpp
#	src/ifcparse/IfcLogger.h
#	src/ifcparse/IfcParse.cpp
#	src/serializers/SvgSerializer.cpp
#	src/serializers/schema_dependent/XmlSerializer.cpp
2018-07-07 17:15:54 +02:00
Thomas Krijnen 6fdd2049a2 Restore previous boost version on nix 2018-07-01 11:37:36 +02:00
Thomas Krijnen 8428b93451 nix cmake download url 2018-07-01 09:16:34 +02:00
Thomas Krijnen 8e2a074d70 Correct accidentally committed lines 2018-06-30 18:53:16 +02:00
Thomas Krijnen 1b809ed849 Update boost version 2018-06-30 15:36:51 +02:00
Thomas Krijnen 8c0bcc4ce7 Silent extraction in build-deps.cmd 2018-06-30 10:21:11 +02:00
Victor Haefner 11d0c6ef56 compiles under ubuntu 18.04 2018-06-22 17:16:11 +02:00
Thomas Krijnen 4cfb2f1027 SetNonDestructive does not exist prior to OCCT 7.0 2018-06-15 12:39:29 +02:00
Thomas Krijnen 6d25047c6b higher fuzz on half spaces 2018-06-12 16:15:28 +02:00
Thomas Krijnen 136ec5b224 'nondestructive' boolean ops 2018-06-12 16:15:12 +02:00
Thomas Krijnen 3ac8379187 Set precision on fix after boolean op 2018-06-08 14:12:01 +02:00
Thomas Krijnen 6c1ad47481 Additional improvements for comp curve wire building 2018-06-01 15:38:08 +02:00
thorade 20cd383504 triple double-quoted docstring
and do not use builtin names for variables
2018-05-30 11:32:47 +02:00
Thomas Krijnen 5aebfe9f22 Fix for setting type decl instances 2018-05-29 10:34:38 +02:00
Thomas Krijnen fd821d08cd Dont fail on missing AIS_MultipleConnectedShape in earlier versions of pyocc 2018-05-17 15:54:12 +02:00
Thomas Krijnen 6b772d18b8 Fixes to qt5 port of viewer app 2018-05-17 15:53:40 +02:00
civilx64 33635c2c40 Port viewer app to PyQt5 2018-05-17 00:11:09 -04:00
civilx64 7e6b758450 Add instructions for install via conda. 2018-05-16 23:05:07 -04:00
Yorik van Havre 127bcaf96e adding exception for OCCT 7.3 2018-05-16 16:10:40 +02:00
Yorik van Havre 2d59f9d53a Removed one last remaining BOPCol_ListOfShapes
Replaced one last remaining BOPCol_ListOfShapes with TopTools_ListOfShapes (deprecated in OCC7.3)
2018-05-16 16:10:40 +02:00
Otso Alho 1014049b05 use unordered map for entity by id 2018-05-14 13:36:38 +02:00
Otso Alho 37460d3df9 do not calculate reuse_ok multiple times for mapped representations 2018-05-14 13:36:38 +02:00
Thomas Krijnen 637d3e2eb6 Optimize generation of faces with large (n > 128) number of edges. 2018-05-14 11:06:07 +02:00
Thomas Krijnen 2ed2e9cf86 Add include, missing depending on occt version 2018-05-13 18:52:53 +02:00
Thomas Krijnen c1635d65eb Add include, missing depending on occt version 2018-05-13 16:04:15 +02:00
Thomas Krijnen 495ad75b14 Proper scope around goto labels 2018-05-13 15:30:20 +02:00
Thomas Krijnen 966e57e94a #332 2018-05-13 14:41:39 +02:00
Thomas Krijnen ef7a1ab421 Limit boolean fuzz to edge length 2018-05-13 09:15:06 +02:00
Thomas Krijnen 089bb95c9f Fix previous commit on gcc 2018-05-13 08:45:33 +02:00
Thomas Krijnen 7786b89269 Machine readable progress with -q and --log-format json 2018-05-12 20:12:25 +02:00
Thomas Krijnen 589f4bda2e ... but keep close point removal at 10 times precision 2018-05-08 16:19:47 +02:00
Thomas Krijnen 8ffc12e6cd Reduce radius on wire intersections 2018-05-08 09:41:19 +02:00
thorade bd9875fae5 set TLS to 1.2 2018-05-07 10:53:03 +02:00
thorade 7994bcbb80 https plus original URL 2018-05-07 10:53:03 +02:00
thorade baa0211562 append download to the URL
https://sourceforge.net/p/forge/documentation/Downloading%20files%20via%20the%20command%20line/
2018-05-07 10:53:03 +02:00
thorade a24333486a use SF instead of mirror 2018-05-07 10:53:03 +02:00
thorade 452ba651d0 update SF.net download URL 2018-05-07 10:53:03 +02:00
Thomas Krijnen 161f24d804 Copy operands prior to boolean operation 2018-05-05 16:09:12 +02:00
Thomas Krijnen 6ee283dbae Don't fail on parse errors while resolving inverse attributes 2018-05-04 10:25:57 +02:00
Thomas Krijnen c748c8dcea Better instance not found error messages 2018-04-23 10:51:59 +02:00
Thomas Krijnen 1f68d9d5bc TColgp_SequenceOfPnt::Upper() does not exist on all versions of occt 2018-04-18 11:57:38 +02:00
Thomas Krijnen 120ff2f629 Fix download of occt in nix build 2018-04-18 11:50:59 +02:00
Thomas Krijnen 656346741e #288 #297 2018-04-18 11:33:57 +02:00
Thomas Krijnen e21277e80a nix: use and patch occt 7.2 2018-04-15 14:01:37 +02:00
Thomas Krijnen 9f55444d2e win: apply patch for HLR 2018-04-15 09:27:16 +02:00
Thomas Krijnen 05fd266a65 gcc compatibility 2018-04-14 20:06:25 +02:00
Thomas Krijnen 42c09deb8c #354 loose faces in SewedShape 2018-04-11 12:26:01 +02:00
Thomas Krijnen cb61873179 conda osx build 2018-04-10 19:55:56 +02:00
Thomas Krijnen dbf9f213fd Dont fail on adding length measure instances to empty files 2018-04-04 14:40:10 +02:00
Thomas Krijnen 77e0d9cca7 Freeing of lazily loaded inst attrs 2018-03-21 17:29:37 +01:00
Thomas Krijnen 0cbe984c71 Default to 2x3 for older schemas 2018-03-21 17:18:38 +01:00
Thomas Krijnen 93cca8f7b7 Update README.md 2018-03-16 16:36:36 +01:00
Thomas Krijnen 5082fe8be4 Revive XML serializer 2018-03-16 16:04:48 +01:00
Thomas Krijnen 834780b726 Schema dependent serializers 2018-03-16 13:49:11 +01:00
Thomas Krijnen d374fd3778 More changes to conda build 2018-03-16 12:17:49 +01:00
Thomas Krijnen b86b359563 Schema independent layer and transformation conv functions 2018-03-16 12:10:05 +01:00
Thomas Krijnen 6685ea6d7a Schema dependent serializers 2018-03-16 12:10:05 +01:00
Thomas Krijnen 0a809ba127 Schema dependent serializers 2018-03-16 12:10:05 +01:00
Thomas Krijnen 14be6b49fe #348 2018-03-16 11:03:02 +01:00
Thomas Krijnen e87a1a0b32 #329 Only auto close IfcCompositeCurve when used for profile 2018-03-09 10:41:22 +01:00
Thomas Krijnen 768f49dcc7 Update meta.yaml 2018-03-04 10:50:17 +01:00
Thomas Krijnen 27e335343e Win build script occt7.2 2018-03-04 10:45:44 +01:00
Thomas Krijnen 0920116178 Fix prompt 2018-03-04 10:45:05 +01:00
Thomas Krijnen 1a7a4bdc3e Update boost download path 2018-02-27 18:09:43 +01:00
Thomas Krijnen 5d0c04a077 Fix geometry reuse in case of IfcTypeProducts with maps 2018-02-21 14:54:38 +01:00
Anders Granskogen Bjørnstad 8a316e45ed IfcConvert: Add --building-local-placement argument
Similar to --site-local-placement. Motivated by dealing with at least
two examples where IFC files for the same construction site have
inconsistent ObjectPlacement hierarchy:

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

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

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

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

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

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

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

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

* Fixes for gcc and OCCT < v6.8

* Enable BVH selection by TopoDS_Shape

* Small fixes to tree

* Merge conflicted files and other changes

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

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

With ID assigned, it will look like this:

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

The correct way to serialze is:

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

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

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

* IfcConvert: Add --site-local-placement

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

Solve this by introducing --site-local-placement which will disregard
the ObjectPlacement at the IfcSite level.
2017-08-19 17:21:10 +02:00
Thomas Krijnen 7bea054c1e get_log in python 2017-08-19 16:54:06 +02:00
Thomas Krijnen 490c35bf60 Fix #244 and provide instances by entity type without subtypes 2017-08-16 21:46:39 +02:00
Stinkfist0 b019ff6aed build-deps.cmd: fix URL for Git download (TortoiseGit doesn't contain Git) 2017-08-16 14:12:12 +02:00
Thomas Krijnen 4c6ca83528 Add option to build with OCCT 7.1 in nix build script 2017-08-13 13:13:26 +02:00
Thomas Krijnen 9ba5e8fd88 Add win build script occt patches 2017-08-12 10:53:28 +02:00
Thomas Krijnen 2e36793af2 win build script OCCT 7.1.0 2017-08-12 10:29:23 +02:00
Thomas Krijnen e3d2621ea9 Alternative for CTRL+C in win build script 2017-08-12 10:28:05 +02:00
Thomas Krijnen ebfe8f9c54 Take into account Position is optional in IFC4 when processing layersets on slabs 2017-08-09 17:01:10 +02:00
Thomas Krijnen 132e5d5f6e Disable log_notice message on exceeding tolerance values 2017-08-09 17:00:41 +02:00
Thomas Krijnen 62794d4b07 Unused variable warning 2017-08-09 12:55:03 +02:00
Thomas Krijnen fd7f6e1f26 IfcIndexedPolyCurve 2017-08-05 12:39:15 +02:00
Thomas Krijnen b00acd3f67 only convert length unit if units are present in both files 2017-08-04 16:31:34 +02:00
Thomas Krijnen f12d8eeaa6 by_guid() and unicode in py2 2017-08-04 16:31:10 +02:00
Thomas Krijnen 85524170dd More advanced entity_instance.get_info() 2017-08-04 16:30:43 +02:00
Thomas Krijnen c67de4bbb3 Mark attributes as 'derived in supertype' also in getArgumentType() 2017-08-04 16:29:26 +02:00
Thomas Krijnen 36c52b3bea Update tests 2017-08-02 16:09:20 +02:00
Thomas Krijnen ceff8a8822 Fixes for IfcEntityInstanceData copy construction 2017-08-02 16:09:01 +02:00
Thomas Krijnen a58f23fae2 Missing introspection methods in Python 2017-08-02 16:08:07 +02:00
Thomas Krijnen b696df0da1 Missing semicolons in header 2017-08-02 16:07:30 +02:00
Thomas Krijnen 94224411a9 Recursive get_info() 2017-08-02 16:06:27 +02:00
Thomas Krijnen 5c7e7cab1a Raise IndexError 2017-08-02 16:05:56 +02:00
Thomas Krijnen 29323e4f74 Fix recursion in traverse() 2017-08-01 19:07:46 +02:00
Thomas Krijnen aa0a6aa5d1 Fix #178 2017-08-01 16:45:11 +02:00
Thomas Krijnen d10efe69cd Fix typo in test 2017-07-27 15:53:06 +02:00
Thomas Krijnen fb1fed247e Fix #243 2017-07-27 10:21:37 +02:00
Thomas Krijnen 59d7e0cad3 nix build script: fix compilation of boost.iostreams, disable USE_MMAP 2017-07-25 16:27:13 +02:00
Thomas Krijnen ae0afe2c0a mmap #22 2017-07-25 16:27:13 +02:00
Thomas Krijnen 3edb057178 Bring back id() to python wrapper. Fixes #241 2017-07-17 18:10:28 +02:00
Thomas Krijnen 04e3018f3c Use default logger 2017-07-17 18:09:49 +02:00
Thomas Krijnen f81616a6fb Narrow and wide unicode builds in nix build script 2017-07-03 20:42:18 +02:00
Thomas Krijnen f58539d6d8 Construct not only allocate token buffer 2017-07-03 20:39:40 +02:00
Thomas Krijnen 90bdf03f54 Disable exception 2017-07-03 16:38:04 +02:00
Thomas Krijnen 6e87a21806 Ignore some methods in wrapper to fix build 2017-07-03 15:43:56 +02:00
Thomas Krijnen d94eb9a96e IfcMaterialList in XML output 2017-07-03 15:18:07 +02:00
Thomas Krijnen ac5800326b Fix compilation on gcc 2017-07-03 14:42:08 +02:00
Thomas Krijnen 901ef57d60 Fix #180 2017-07-03 14:18:56 +02:00
Thomas Krijnen b604e5cf99 Fix #204 2017-07-02 19:57:10 +02:00
Thomas Krijnen 1e79eb535a Build comprehensive representation id. Fix #225 2017-06-28 15:59:03 +02:00
Thomas Krijnen 6f7afd4b2a Build comprehensive representation id. Fix #225 2017-06-28 15:24:49 +02:00
Thomas Krijnen a90936a7de Properly initialize parsed simple types 2017-06-24 21:35:38 +02:00
Thomas Krijnen 7c1cf6ebd0 Fix #233 2017-06-24 13:36:26 +02:00
Stinkfist0 7eb1346407 IfcConvert: prevent doing IfcFile::Init() "prematurely", e.g. before some additional program option parsing that might fail. 2017-06-23 14:12:07 +02:00
Stinkfist0 771b1f3d3c IfcConvert: consistent style for user error prints. 2017-06-23 14:12:07 +02:00
Stinkfist0 3fb96cad0b IfcConvert: make sure to delete temp file if no actual conversion occurs. Also fixes serializer memory leaks. Closes #199.
C
2017-06-23 14:12:07 +02:00
Thomas Krijnen 23beb096a0 Remove auto keywords 2017-06-20 19:47:53 +02:00
Thomas Krijnen 101ef69ae9 Fail serialize() if one of the faces cannot be mapped to IFC (2x3) 2017-06-20 18:55:52 +02:00
Thomas Krijnen e60202b738 Unique filter on IfcEntityList 2017-06-20 18:54:55 +02:00
Thomas Krijnen 1e8b1d9c9c traverse() as a global function rather than method on IfcFile 2017-06-20 18:54:30 +02:00
Thomas Krijnen a27e516011 Elided argument in ifcopenshell.file constructor 2017-06-20 18:53:39 +02:00
Thomas Krijnen 69c8b7c1c8 One more boost::blank() refactoring 2017-06-20 18:52:56 +02:00
Thomas Krijnen c25cff6bad Correct setting attributes on lazily loaded instances 2017-06-15 14:12:03 +02:00
Thomas Krijnen 48a61219f7 Fix #228 2017-06-14 12:42:38 +02:00
Stinkfist0 84813084d0 Fix/suppress signed-unsigned integer conversion warnings. 2017-06-05 19:53:10 +02:00
Thomas Krijnen 5e0da9725a ifcparse refactoring (#190)
Unify attribute containers, provide latebound attribute access on IfcBaseEntity, more basic tests on Travis
2017-06-05 17:26:58 +02:00
Thomas Krijnen 9a43658716 Correct verbosity check 2017-06-05 13:08:07 +02:00
Stinkfist0 f3f4c41f8d IfcConvert: add --no-progress option to suppress possible progress bar type of prints that use carriage return. 2017-06-05 11:41:55 +02:00
Stinkfist0 273c977f66 Remove extraneous spaces in geom filter description prints. 2017-06-05 11:41:55 +02:00
Stinkfist0 0adcb9ae20 IfcConvert --filter-file: Specifies a filter file that describes the used filtering criteria. 2017-06-05 11:41:55 +02:00
Thomas Krijnen 1751cf1c95 Generate example models on Travis 2017-06-05 11:29:23 +02:00
Thomas Krijnen 1704862d0d Correct test for when to reuse representation in iterator 2017-06-05 11:08:07 +02:00
Janus Troelsen d7c275e941 use boost's blank instead of none_t 2017-05-23 12:48:17 +02:00
Stinkfist0 1b9a28d799 CMakeLists.txt: fix Windows/MSVC lib search when only Debug versions of libs are found. 2017-05-20 20:19:15 +02:00
Stinkfist0 68b432f6c0 CMakeLists.txt: fix add_debug_variants() to work on Debug build. Re: #201 [ci skip] 2017-05-20 20:19:15 +02:00
Thomas Krijnen af2799acd4 Matrix multiplication in OCC rather than boost::ublas (re #211) 2017-05-20 19:50:10 +02:00
Thomas Krijnen c093dc0335 Merge pull request #211 from mitmadness/feature/hierarchy
Represent hierarchy in Collada files
2017-05-20 19:46:56 +02:00
Balleux Benjamin 834e05a01c Feature : For each parent element, include the type in the name if --use-element-types if used 2017-05-18 11:26:19 +02:00
Balleux Benjamin 4680298bee Clean : Remove debug logs 2017-05-16 16:34:50 +02:00
Balleux Benjamin be39f30029 Fix : fix build error 2017-05-16 15:54:26 +02:00
Balleux Benjamin 3919c1f32e Feature : Retrieve the full hierarchy
(merged from hierarchyDevelop branch)
2017-05-16 15:30:57 +02:00
Balleux Benjamin e02bbefa68 Clean : Removed debug logs 2017-05-16 15:20:30 +02:00
Balleux Benjamin 5c497c8f6c Fix : Handle the case where the first representation element has 0 parent 2017-05-16 15:01:55 +02:00
Balleux Benjamin 942d34ee39 Feature : Retrieve the full hierarchy. Fix the placement of the objects.
Check slab->HasObjectType before using slab->ObjectType
2017-05-16 14:27:36 +02:00
Balleux Benjamin 45ec08f840 feature (WIP) : retrieve the full hierarchy. The placement of several objects still be incorect 2017-05-16 11:27:45 +02:00
Balleux Benjamin be3dbce9f4 feature (WIP) : retrieve full hierarchy
Bug : the element are not at the right location
2017-05-15 17:45:05 +02:00
Stinkfist0 20c189c321 set-python-to-path.bat: fix for command for quoted filename 2017-05-13 14:03:15 +02:00
arzezniczak 97c5126a77 Authenticated proxy support for DownloadFile
DownloadFile subroutine gets credentials from system settings.
2017-05-13 14:02:42 +02:00
Balleux Benjamin ff64ce1e0e Fix : change wrong namespace 2017-05-11 14:02:34 +02:00
Balleux Benjamin 4f6e8a7d56 Fix : Change wrong namespace 2017-05-11 13:27:00 +02:00
Balleux Benjamin 93ece6b3ea Fix : Add missing include 2017-05-11 11:49:25 +02:00
Balleux Benjamin ced9d8c917 Merge branch 'feature/hierarchyDevelop' into feature/hierarchy 2017-05-11 11:22:11 +02:00
Balleux Benjamin ef0e9d9eb4 Feature : Handle every IfcSlabTypeEnum (3 were missing) and sort the floors by elevation 2017-05-09 15:55:37 +02:00
Balleux Benjamin 3c2fbcc4e1 Feature : Handle every IfcSlabTypeEnum (3 were missing) and sort the floors by elevation 2017-05-09 15:54:21 +02:00
Balleux Benjamin a6ffa7fc42 Fix : fill the storey property of an Element with NULL when we don't find any IfcBuildingStorey parent 2017-05-09 14:40:23 +02:00
Thomas Krijnen 0f825b7050 Fix missing import 2017-05-03 15:10:20 +02:00
Stinkfist0 845dd13870 Windows/MSVC: Fix OCCT deployment on VS 2017. 2017-05-03 14:13:24 +02:00
Thomas Krijnen d713b7e06a Limit retries for boolean op on OCCT 6.9 and higher 2017-05-03 12:07:10 +02:00
Tristan Zimpfer e3e4fba63a Clean of the double declaration of IfcSlabTypeEnum. 2017-04-26 10:59:07 +02:00
Tristan Zimpfer 78b904dfeb Differentiate slab types when option --use-element-types is used. 2017-04-26 10:28:38 +02:00
Thomas Krijnen 00c70fa8fb IfcOpenHouse fixes for IFC4 2017-04-25 17:38:59 +02:00
Thomas Krijnen d34c3b4b20 Example for #209 2017-04-25 16:53:35 +02:00
Thomas Krijnen 033075f809 Fix #208 2017-04-25 16:37:50 +02:00
Balleux Benjamin 1d8f6addf8 Get the information on the IfcSlab (floor or roof..) and put it in the element name.
To be cleaned
2017-04-25 16:27:14 +02:00
Balleux Benjamin 26a9167eea Add coments 2017-04-25 11:55:09 +02:00
Balleux Benjamin 5fae7a5992 Merge branch 'feature/hierarchy' of https://github.com/mitmadness/IfcOpenShell into feature/hierarchy 2017-04-25 10:13:37 +02:00
Balleux Benjamin 7edca081bf Raise an error when the option --use-element-hierarchy is used with a file different of .dae 2017-04-25 10:13:18 +02:00
Tristan Zimpfer 08e4d16f28 Modified the condition checking if the parent had changed so an object without parent isn't placed in a storey. 2017-04-21 18:05:35 +02:00
Tristan Zimpfer 470e8e772e Comments + conditions for sorting the deferred objects added. 2017-04-21 16:15:41 +02:00
Balleux Benjamin ea609af394 comments added 2017-04-21 16:02:13 +02:00
Balleux Benjamin 8ac18752b2 Remove temp file 2017-04-21 15:59:54 +02:00
Balleux Benjamin 95acd4c517 Clean : remove debug lines
Find the floor of an element in the IfcGeomIterator class
2017-04-21 15:49:34 +02:00
Balleux Benjamin 7ce795def3 clean WIP 2017-04-20 15:06:49 +02:00
Balleux Benjamin 8e4febecc0 clean : Remove the debug print
debug : don't display the name of the element in unity anymore
2017-04-19 16:38:35 +02:00
Balleux Benjamin 195979d4f0 Merge branch 'feature/hierarchy' of https://github.com/mitmadness/IfcOpenShell into feature/hierarchy
# Conflicts:
#	src/ifcconvert/ColladaSerializer.cpp
2017-04-19 15:09:59 +02:00
Balleux Benjamin ab0e47c55f Options added : --use-element-types and --use-element-hierarchy 2017-04-19 12:07:03 +02:00
Tristan Zimpfer 9f362853d6 Added a matrix for the parent node and a better id. 2017-04-19 11:48:52 +02:00
Tristan Zimpfer 79e1e0ec04 Hierarchy v1 2017-04-13 16:39:36 +02:00
Tristan Zimpfer f446f25cee Sort DeferredObject. 2017-04-12 17:28:29 +02:00
Balleux Benjamin a02b189f69 Bug Fix : the previous commit made the program crash when an object has no parent 2017-04-12 16:11:37 +02:00
Balleux Benjamin 8312853b99 add parent property to deffered objects 2017-04-12 15:49:05 +02:00
Balleux Benjamin be326e13ed Send Hierarchy data to the serializer 2017-04-12 14:56:00 +02:00
Balleux Benjamin a2aa2bf9eb Send hierarchy data to the serializer WIP 2017-04-12 14:38:54 +02:00
Balleux Benjamin b9e9bfeceb Handle errors : when an object has no parent 2017-04-12 13:36:12 +02:00
Stinkfist0 dd8ee915c3 ifcwrap/CMakeLists.txt: as PYTHONLIBS_FOUND and PYTHONINTERP_FOUND cannot seem to be trusted, perform further checks to see whether the packages were actually found or not.
E.g. one can doo set PYTHONHOME=C:/NoPythonHere
and when running CMake it will happily report:
-- Found PythonLibs: C:/NoPythonHere/libs/python34.lib
2017-04-12 10:39:41 +02:00
Stinkfist0 7fdbc9811d src/ifcwrap/CMakeLists.txt: use PYTHON_INCLUDE_DIRS instead of the deprecated PYTHON_INCLUDE_PATH 2017-04-12 10:39:41 +02:00
Stinkfist0 2edf867818 Use boost functions for string manipulation instead of std ones in order to silence char-int conversion warnings on VS 2017. 2017-04-12 10:39:41 +02:00
Stinkfist0 e4a7d2a149 Windows/MSVC build scripts: support for VS 2017 CMake generators, update Boost to 1.63.0, update ICU download to 58.2 in order to have VS 2107 download available, configure Boost using generic MSVC instead of specific version, make sure to 'git fetch' before 'git checkout <revision>'. 2017-04-12 10:39:41 +02:00
Balleux Benjamin 37f7fbecca Retrieve the type and the hierarchy of the IFC and write it in the .dae files 2017-04-11 17:26:30 +02:00
Alexandre Lemire 0f993b32f4 Fix generation of IfcOpenHouse.ifc which doesn't have its ground representation. See #200 2017-04-07 12:29:38 +02:00
Thomas Krijnen f71ee35f57 More 'tolerant' to tolerances higher than the modeling precision 2017-04-03 14:55:34 +02:00
Thomas Krijnen 1856c499b7 Fix misalignment between enum and boost::variant. See #200 2017-04-03 11:41:14 +02:00
Thomas Krijnen 06cad59fa2 Fix missing python module installation 2017-03-24 10:11:44 +01:00
Thomas Krijnen 8e69f84430 Trigger license redetection 2017-03-19 09:47:28 +01:00
Thomas Krijnen 9e3fe84c66 Trigger license redetection 2017-03-19 09:46:07 +01:00
Thomas Krijnen 9ad68db0dc set OCE_VERSION, executable flags in win build script 2017-03-12 11:38:23 +01:00
Thomas Krijnen 40f3447ad1 Update dependency versions in nix build script 2017-03-09 14:36:00 +01:00
Thomas Krijnen c8cc8ab1c8 Resolve python library linking issues on OSX 2017-03-09 13:59:54 +01:00
Thomas Krijnen 4faa66f9b8 Fix for python 2.7 2017-03-09 12:04:07 +01:00
Thomas Krijnen 5705f24f3e python: make logging import conditional in case time is not built 2017-03-09 11:47:54 +01:00
Thomas Krijnen 52d035d09a python: don't import platform module as it may depend on select which might be unavailable 2017-03-09 10:16:22 +01:00
Stinkfist0 921e343187 Fix assertion. Closes #192 2017-03-08 09:31:51 +01:00
Thomas Krijnen 50ea73a28f Update IfcConvert help text 2017-03-04 14:16:54 +01:00
Stinkfist0 3275119d1d TokenFunc::asStringRef: protect against null token. 2017-03-04 13:54:19 +01:00
Stinkfist0 026b4853a2 IfcConvert: single point for IFC file parsing and potential parsing error reporting. 2017-03-04 13:54:19 +01:00
Stinkfist0 cd132473f5 IfcConvert: instead of global --traverse option provide --include+ and --exclude+ options that control traversal on per filter basis. 2017-03-04 13:54:19 +01:00
Stinkfist0 06c1ea9d2c Doc tweaks [ci skip] 2017-03-04 13:54:19 +01:00
Stinkfist0 b058647d46 IfcLogger: convenience shorthands Notice(), Warnings() and Error() 2017-03-04 13:54:19 +01:00
Stinkfist0 8e44290341 string_arg_filter: make sure the argument type is string 2017-03-04 13:54:19 +01:00
Stinkfist0 5d7b392415 IfcGeomIterator: use fully qualified symbol for filter_t to fix SWIT code generation + fix getObject() 2017-03-04 13:54:19 +01:00
Stinkfist0 0383221d00 IfcConvert: print information about the used filters. 2017-03-04 13:54:19 +01:00
Stinkfist0 678d422ec8 Fix errors in rebase merge. 2017-03-04 13:54:19 +01:00
Stinkfist0 eade74c919 Fix --traverse --exlucde=<entities|layers> + clean up duplicate code. filter::traverse_match: dynamic_cast instead of static_cast as the decomposing entity is not guaranteed to be IfcProduct 2017-03-04 13:54:19 +01:00
Stinkfist0 9074f25e93 Fix --exclude=arg when --traverse used also. 2017-03-04 13:54:19 +01:00
Stinkfist0 4b5790e83a IfcConvert: minor cleanup + fix guid exclusion filter's value population. 2017-03-04 13:54:19 +01:00
Stinkfist0 470b08cd04 IfcConvert: output regular prints to cout instead of cerr. 2017-03-04 13:54:19 +01:00
Stinkfist0 d88c93a150 Cleaning up geom filters. 2017-03-04 13:54:19 +01:00
Stinkfist0 7101ac22c8 Refactor template class arg_filter into string_arg_filter instead, support for IfcProxy.Tag (untested, did not find suitable test input yet). 2017-03-04 13:54:19 +01:00
Stinkfist0 1b7d38a56d support for IfcConvert -include=arg <Description|Tag> (for IfcElement.Tag, not yet for IfcProxy.Tag). 2017-03-04 13:54:19 +01:00
Stinkfist0 de5864fc72 IfcConvert: change syntax of --<include|exclude>=<names|guids> to --<include|exclude>=arg <Name|GlobalId>. The plan is to support arbitrary arguments in the future. 2017-03-04 13:54:19 +01:00
Stinkfist0 195d68cd0a Generalize IfcGeom::Iterator filtering and move make the filter specification external to the Iterator. 2017-03-04 13:54:19 +01:00
Stinkfist0 d8a11dd096 Refactoring and cleaning up geom iterator filtering. 2017-03-04 13:54:19 +01:00
Stinkfist0 63b0488909 Implement filtering created geometry by layer assignments. 2017-03-04 13:54:19 +01:00
Stinkfist0 3abee03b9b Filtering by entity GUID and layer name w.i.p. 2017-03-04 13:54:19 +01:00
Stinkfist0 f1709dc71a IfcConvert/IfcGeom: Possibility to include and exclude simultaneously by type and name, w.i.p. 2017-03-04 13:54:19 +01:00
Carles 6b2c8ad23e Update vs-cfg.cmd
prepend win/utils path instead of append it.
It should force the build-deps.cmd to call 7za.exe within utils and not any other old-version that users might already have. 
Discussed in https://sourceforge.net/p/ifcopenshell/discussion/1782717/thread/53803197/
2017-02-23 15:48:37 +01:00
Thomas Krijnen 8ce4bbdf61 Adaptive tolerance boolean ops 2017-02-16 15:54:34 +01:00
Thomas Krijnen e2cf5f4826 Typo in build script 2017-02-16 15:53:58 +01:00
Thomas Krijnen 332a9a571f Special case the normal at the poles of a spherical surface 2017-01-24 14:56:28 +01:00
Thomas Krijnen ac9505506c Extend IfcGeomServer with calculated quantities 2017-01-22 16:09:14 +01:00
Thomas Krijnen 257c28d450 Take into account IfcTrimmedCurves with unspecified preference 2017-01-22 11:06:36 +01:00
Thomas Krijnen f95ad29c7a Extra check for single-face IfcConnectedFaceSets. Fixes #181. 2017-01-19 10:42:03 +01:00
Thomas Krijnen 93c2f93c44 Download PCRE from sourcefore in nix build script. Fixes #182 2017-01-19 10:24:09 +01:00
Stinkfist0 77d53429e3 Make sure to link ifcwrap to Boost libs + fix integer conversion warning. 2017-01-14 20:13:46 +01:00
Stinkfist0 fa76aa9bb0 IfcConvert: add --unicode=utf8|escape when UNICODE_SUPPORT enabled. 2017-01-14 20:13:46 +01:00
Stinkfist0 f0e07f3447 Add status prints for writing XML output. Re: #122 2017-01-14 20:13:46 +01:00
Stinkfist0 80f0ff688d IfcConvert: add --model-ofset x;y;z option. Remove SerializerSettings::CENTER_MODEL as unneeded. 2017-01-14 20:13:46 +01:00
Stinkfist0 222cbe73d3 Use unnamed enum instead of static const member variable for SerializerSettings::DEFAULT_PRECISION in order to fix compilation on GCC & Clang. 2017-01-14 20:13:46 +01:00
Stinkfist0 ecff54c480 IfcConvert --precision option.
Sets the decimal precision to be used to format floating-point values, 15 by default.
Use a negative value to use the system's default precision (should be 6 typically).
Applicable for OBJ and DAE output. For DAE output, value >= 15 means that up to 16 decimals are used,
and any other value means that 6 or 7 decimals are used.
2017-01-14 20:13:46 +01:00
Stinkfist0 2d58a1bc7c Separate serialization-specific settings from IteratorSettings into its own class, SerializerSettings. 2017-01-14 20:13:46 +01:00
Thomas Krijnen 5667f3f94a build script changes for boost 2017-01-09 13:10:01 +01:00
Jelle Feringa 5d6160b47a log exceptions on get_info method
these exceptions currently are actively being hidden, which is
intransparent / could make debugging challenging

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

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

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

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

* build-deps.cmd: fix OCCT download

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

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

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

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

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

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

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

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

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

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

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

* Fix newline.

* README.md tweak

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

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

* Fix some GCC warnings.

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

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

* Add IfcParse_EXPORT for IfcInvalidTokenException

* Fix potentially uninitialized pointer variables.

* Note about OpenCASCADE cyclic dependencies fix.

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

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

* Remove unused variable.

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

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

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

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

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

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

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

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

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

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

* Implemented simple way to remove spaces in parsing.

* Tokens are now created without allocations.

* Call RemoveTokenSeparators once for every token.

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

* Reimplemented asString without allocations.

* Parsing keywords without allocations.

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

* Added IfcParse_Export header for declaring export macro.

* Added IFCPARSE_STATIC_DEFINE macro to all projects.

* Added include for export macro to swig file.

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

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

* Fixed bug in deletion of ICU converter.

* Added export macro to most of the classes across headers

* Fixed memory leak: delete nested IfcAbstractEntity in EntityArgument.

* Fixed memory leak in destructor of IfcWritableEntity (args values).
2016-05-29 14:12:57 +02:00
Thomas Krijnen a298903fdd IfcGeomServer settings 2016-05-28 16:08:31 +02:00
Fredounet ccb24948df Merge pull request #1 from IfcOpenShell/master
Fresh-Upgrade-1
2016-05-28 09:43:59 +01:00
iNEHCi 5bdb4ce668 Add IfcReinforcingBar/IfcSweptDiskSolid generation example 2016-05-27 10:18:39 +02:00
Thomas Krijnen 9909e2f7e2 Don't emit OBJ vertex normal if absent (e.g --weld-vertices) 2016-05-24 15:01:34 +02:00
Thomas Krijnen 38d1ec7a78 #28 2016-05-24 13:50:50 +02:00
Thomas Krijnen 85ddae1228 Do not set wire tolerance prior to creating face 2016-05-24 12:51:00 +02:00
Thomas Krijnen 06c3f8d6a9 Record conversion status on IfcFaceBasedSurfaceModel 2016-05-24 12:50:32 +02:00
Thomas Krijnen b04ca74308 Derive minimal face area from modeling precision 2016-05-24 12:50:05 +02:00
Thomas Krijnen 7c0944e43b Defer pythonOCC imports in order not to break if unavailable 2016-05-19 13:31:54 +02:00
Thomas Krijnen a1c660f4ab Fix static linking 2016-05-19 11:34:04 +02:00
Thomas Krijnen 2a5974fde1 Remove superfluous error message 2016-05-18 17:28:58 +02:00
Thomas Krijnen e2ffd0b6d6 Fix IFC4 compilation 2016-05-18 17:15:44 +02:00
Thomas Krijnen 9bff4876c5 Don't apply rpaths on windows due to possible path separator conflicts 2016-05-15 15:51:12 +02:00
Johannes Obermayr 42188904af Fixes to build on openSUSE/Packman. (#67)
- Support different BINDIR, INCLUDEDIR and LIBDIR on install
- Take right python dir on x86_64 arch
- Fix build against Boost >= 1.58
- Make it possible to build libIfcGeom shared to reduce size of dependent binaries
- Fix INSTALL_RPATH
- Fix some more compiler warnings
2016-05-15 15:47:21 +02:00
Lars Moastuen 414d7bb810 OBJ precision and log messages
* Fixes #68: Increase precision in OBJ files (regression in commit 43f5d44)
* Add some verbose logging of a few geometry errors
2016-05-13 12:59:00 +02:00
Thomas Krijnen 01269e5dd5 Fix missing include for debug build 2016-05-11 14:01:38 +02:00
Ivano Ras 0253c1ddbe Extended error logging
Fixes #33
2016-05-11 10:56:40 +02:00
Thomas Krijnen 3f5d30f497 Merge pull request #65 from iras/nested_argument_list_bug
separated nested argument lists to avoid an error when compiling with…
2016-05-05 11:03:38 +02:00
iras 3d2ab25175 separated nested argument lists to avoid an error when compiling with gcc. 2016-05-05 08:09:45 +01:00
Thomas Krijnen d4dc933b99 Qualify auto keyword 2016-05-04 17:30:31 +02:00
Thomas Krijnen d54c1cdc9c Remove compiler warning 2016-05-03 16:32:36 +02:00
Thomas Krijnen c848a7dbe0 remove redundant type attribute on latebound entity instance 2016-05-03 11:24:26 +02:00
Thomas Krijnen 60cf4ab757 Additional check pertaining to face surfaces 2016-05-03 11:22:15 +02:00
Thomas Krijnen 2c3fa89dd0 Preprocessor consistency 2016-05-03 11:21:39 +02:00
Thomas Krijnen e9c7cf235b Fix compiler warning 2016-05-03 11:19:46 +02:00
Thomas Krijnen fefa8a0563 option to pass settings to pyqt4 app 2016-05-03 11:05:46 +02:00
Thomas Krijnen 04acfe1169 Fix #63 2016-05-03 11:01:47 +02:00
Thomas Krijnen 0e25787df3 Merge pull request #64 from aothms/layerset_slicing
Layerset slicing
2016-05-02 16:14:14 +02:00
Thomas Krijnen 3c3bee71d1 Don't process mapped items in case of material layer associations 2016-05-02 16:11:06 +02:00
Thomas Krijnen 37f0e09947 Fix compiler warnings 2016-05-02 15:56:08 +02:00
Thomas Krijnen 39e26dff46 Merge branch 'master' into layerset_slicing
# Conflicts:
#	src/ifcconvert/IfcConvert.cpp
#	src/ifcgeom/IfcGeom.h
#	src/ifcgeom/IfcGeomFunctions.cpp
#	src/ifcgeom/IfcGeomIteratorSettings.h
2016-05-02 15:13:30 +02:00
Thomas Krijnen 2f129556fd Merge pull request #47 from aothms/performance_improvements
Performance improvements
2016-05-01 20:43:37 +02:00
Thomas Krijnen a1d584796a Set reasonable defaults for caching behavior 2016-05-01 20:38:10 +02:00
Thomas Krijnen c6d5adfa42 Merge branch 'master' into performance_improvements
# Conflicts:
#	src/ifcexpressparser/implementation.py
#	src/ifcgeom/IfcGeomFunctions.cpp
#	src/ifcparse/Ifc4.cpp
2016-04-24 15:22:10 +02:00
Thomas Krijnen 1e262c8768 Update build script to install pyqt app 2016-04-23 11:42:11 +02:00
Thomas Krijnen d8919c50ab Fix serialization of list of list of entity instance 2016-04-19 16:44:08 +02:00
Thomas Krijnen 416b163050 Correct display_shape on TopoDS_Shape 2016-04-19 15:42:59 +02:00
Thomas Krijnen 1d1fb6d27a First steps towards a PyQt4 application 2016-04-17 15:27:05 +02:00
Thomas Krijnen 9fedbbff6d Only convert faces once if sewing shell fails pt.2 2016-04-17 15:12:02 +02:00
Thomas Krijnen 1c1097c8a4 Only convert faces once if sewing shell fails 2016-04-16 14:47:34 +02:00
Thomas Krijnen 884b3fe850 Project wires onto a plane if non-planar. Fixes #57. 2016-04-16 14:47:09 +02:00
Thomas Krijnen 81ee60079e Enable per-item styles in the pythonOCC viewer 2016-04-11 11:50:43 +02:00
Thomas Krijnen 426b1279e3 Implement __hash__ and __eq__ functions on entity_instance 2016-04-09 20:20:08 +02:00
Thomas Krijnen 1142db3265 remove msvc specific leniencies 2016-04-09 17:54:23 +02:00
Thomas Krijnen 191c029546 Correctly allow rule labels to be optional 2016-04-09 13:29:35 +02:00
Thomas Krijnen 9bcfe2f50e Generate code for IFC4_ADD1 2016-04-08 23:24:35 +02:00
Thomas Krijnen fa585e60ee Update EXPRESS code generator to work on ancient IFC schemas 2016-04-08 23:23:45 +02:00
Thomas Krijnen 0ff9de3cd9 Update EXPRESS code generator to work on ancient IFC schemas 2016-04-08 23:23:29 +02:00
Thomas Krijnen 63c3b54762 Merge pull request #56 from Tridify/obj_mtl_fix
Fix temp name usage of .mtl file
2016-03-28 11:17:20 +02:00
Stinkfist0 d7f990d8bd IfcConvert: Do not use temp file for MTL as it's such a small file. Fixes #55. 2016-03-28 11:47:21 +03:00
Stinkfist0 b59e8e22a7 IfcConvert: Show an error msg if renaming from temp to final file fails. 2016-03-28 11:47:02 +03:00
Thomas Krijnen 25a5135e8d Disable geometry re-use with world coords 2016-03-27 21:18:28 +02:00
Thomas Krijnen 4c574df1a4 Immediately emit to serializer and remove option to obtain ownership of objects 2016-03-27 21:17:51 +02:00
Thomas Krijnen f3d5954aee Merge pull request #53 from shsteven/fix_build_script_osx_boost
Fix build script under os x
2016-03-24 10:42:03 +01:00
Steven Zhang 7d145a5f69 fix build script under os x 2016-03-24 15:07:52 +08:00
Thomas Krijnen 5b30dfc580 Set required boost components again after merge 2016-03-23 10:27:34 +01:00
Thomas Krijnen e1bb6c95c3 Merge pull request #51 from shsteven/osx_build_fix
Fix build script under os x
2016-03-23 10:15:56 +01:00
Steven Zhang edc6f8ebd4 fix build script under os x 2016-03-23 15:27:03 +08:00
Thomas Krijnen ee56aad90d Merge branch 'master' into performance_improvements
# Conflicts:
#	src/ifcconvert/ColladaSerializer.cpp
#	src/ifcconvert/ColladaSerializer.h
#	src/ifcgeom/IfcGeomIterator.h
#	src/ifcgeom/IfcGeomRenderStyles.h
2016-03-22 16:15:28 +01:00
Thomas Krijnen 5c1ac39f19 Merge pull request #42 from Tridify/ifcconvert_enhancements
IfcConvert enhancements
2016-03-22 13:28:15 +01:00
Stinkfist0 0fd2f04f08 Utilise Collada stream's double precision feature 2016-03-21 11:42:40 +02:00
Stinkfist0 b171bd4a14 Add note/todo regarding Collada stream's double precision feature. 2016-03-20 13:13:15 +02:00
Stinkfist0 54a9d72e25 IfcConvert: use temp file when writing output. 2016-03-20 12:48:20 +02:00
Stinkfist0 798597d5d9 IfcConvert: check that input file exist early, print filenames in error prints 2016-03-18 22:33:03 +02:00
Stinkfist0 f7453c033a IfcConvert: check if output file already exists and ask user for confirmation for overwriting. Overwriting can be forced with -y/--yes 2016-03-18 22:14:05 +02:00
Stinkfist0 bf76bd17b2 Add large_offset.ifc (wallwindow.ifc, courtesy of @klokoy) as test input case. 2016-03-18 14:45:00 +02:00
Thomas Krijnen 59d2d227d9 Directly re-use IfcMappedItem triangulated elements when not using world coordinates 2016-03-18 11:23:25 +01:00
Thomas Krijnen 4a3a0bff71 Cleanup triangulations after use 2016-03-18 11:21:23 +01:00
Thomas Krijnen 8ecc1269d7 Compile-time options to manipulate caching behaviour 2016-03-18 11:21:04 +01:00
Thomas Krijnen 614148e5e4 Don't iterate past material indices in collada serializer 2016-03-18 11:18:02 +01:00
Thomas Krijnen 74e495cec0 python2.7 compatibility on code generator 2016-03-18 11:17:26 +01:00
Thomas Krijnen 0ceef8fe67 Use constant time parent enumeration lookup 2016-03-18 11:14:14 +01:00
Stinkfist0 562f38756f Calculate and store min. and max. placements IfcGeom::Iterator. Implement --center-model for OBJ. 2016-03-17 23:25:53 +02:00
Stinkfist0 76d3823bd4 Make UVs a property of IfcGeom::Representation::Triangulation. Implement writing of UVs for OBJ output. 2016-03-17 00:25:33 +02:00
Thomas Krijnen 28560d164c Add IfcGeomServer description 2016-03-12 16:54:21 +01:00
Stinkfist0 923f1212f5 Clean up program_options printings 2016-03-11 10:05:33 +02:00
Stinkfist0 e9f551ea71 --names for filtering included or excluded entities by name, e.g. --include --names "Wall Compound*" 2016-03-10 21:15:50 +02:00
Stinkfist0 b9c5b0e6c8 Add IFCCONVERT_DOUBLE_PRECISION build option 2016-03-10 17:00:06 +02:00
Stinkfist0 4953b35849 --generate-uvs, applicable for DAE only currently 2016-03-10 16:46:20 +02:00
Stinkfist0 83e5096570 Support for --deflection-tolerance 2016-03-10 16:09:39 +02:00
Stinkfist0 5008c3503d --center-model for DAE output, fixes #8 (TODO: implement also for OBJ) 2016-03-10 14:39:42 +02:00
Stinkfist0 ce38854cff Add --no-normals 2016-03-10 13:29:22 +02:00
Stinkfist0 24e2aece0b Rename --use-guids and --use-names to --use-element-guids and --use-element-names. Add explicit --use-material-names for controlling material naming. 2016-03-10 12:01:04 +02:00
Stinkfist0 43f5d446ec Implement --use-names and --use-guids for DAE, OBJ, and SVG output. 2016-03-10 11:35:32 +02:00
Stinkfist0 50a467fda5 Fix IfcUtil::wildcard_string_to_regex() 2016-03-07 23:15:29 +02:00
Stinkfist0 0da0e63687 Begin to implement IfcConvert enhancements discussed in #20. Remove C++-specific getters and setters and use the same set() and get() functions in in both C++ and Python. Enhance output of IfcConvert, especially in error situations (spamming a hundred lines of options always hides the original error message), utilize Boost's foreach macro to provide cleaner iteration code. 2016-03-07 22:37:36 +02:00
Stinkfist0 e35cefac52 Fix crash (deleting garbage ptr) when nonexisting file passed to IfcSpfStream ctor. Bug surfaced due to recent memory leak fix. 2016-03-07 22:37:04 +02:00
Stinkfist0 84e7a86e77 XmlSerializer: handle openings. Original author of the commit/idea @otsoa. 2016-03-07 22:37:03 +02:00
Thomas Krijnen 82a1e33386 Merge pull request #39 from Tridify/fixed_opencollada_revision
Use a fixed revision of OpenCOLLADA...
2016-03-05 13:50:41 +01:00
Thomas Krijnen 827c6fd407 Build script fixes and compatibility with OSX / bash 3.2 2016-03-03 20:36:16 +01:00
Stinkfist0 851fadb4ec build-deps.cmd: GitCloneAndCheckoutRevision - always checkout the revision, so that users don't have the nuke their existing clones before running the script. 2016-02-27 17:44:45 +02:00
Thomas Krijnen 90f72c4b2c Merge pull request #35 from Tridify/ifcmax
Create CMake file for building IfcMax
2016-02-27 15:52:10 +01:00
Stinkfist0 7ed219af70 Use a fixed revision of OpenCOLLADA in order to prevent introducing breaking changes. Closes #36, related to #38 2016-02-25 17:34:41 +02:00
Stinkfist0 d1a1759016 Use a fixed revision of OpenCOLLADA in order to prevent introducing breaking changes. Closes #36, related to #38 2016-02-25 17:23:04 +02:00
Thomas Krijnen acc4af87d6 Merge pull request #34 from yilativs/master
Set cmake search paths to ubuntu 16.04 package manager defaults
2016-02-24 09:03:06 +01:00
Stinkfist0 ee75545ecd README tweaks 2016-02-21 16:52:00 +02:00
Stinkfist0 58b5838da9 README.md tweaks 2016-02-20 00:43:35 +02:00
Stinkfist0 e171e308d0 Enable solution folders 2016-02-20 00:13:04 +02:00
Stinkfist0 645315a8f4 remove win/sln as these are not needed anymore 2016-02-19 23:02:09 +02:00
Stinkfist0 5ee9bed590 CMakeLists.txt for IfcMax. Tested with VS 2015 and 3ds Max + SDK 2016 2016-02-19 22:53:09 +02:00
yilativs 0f88520e75 [fix] CmakeLists.txt now works on ubuntu 16.04 without the need to compile oce
instead you can
apt-get install git swig cmake gcc g++ libftgl-dev libtbb2 libtbb-dev libboost-all-dev libgl1-mesa-dev libfreetype6-dev liboce-modeling-dev opencollada-dev liboce-foundation-dev
2016-02-19 20:28:46 +03:00
aothms 481515f5ae Add missing include 2016-02-18 16:57:22 +01:00
Thomas Krijnen a33f5b6e17 Merge pull request #31 from aothms/cmake_compile_schema
Add option to compile (external) schema by cmake + general improvements
2016-02-18 15:43:52 +01:00
aothms 10bec3eee0 Replace PYTHONPATH with PYTHONHOME 2016-02-18 14:57:57 +01:00
aothms da0af77570 Compatibility for older versions of cmake, python, open cascade, boost 2016-02-18 13:17:15 +01:00
aothms a6094f50b9 Let CMake find python interpreter for schema compilation and installation dir
Remove unused compiled schema in cpp installation target
2016-02-17 12:03:38 +01:00
aothms c3f1b41860 Fix https://github.com/IfcOpenShell/IfcOpenShell/issues/30 2016-02-15 17:59:31 +01:00
aothms 4122759f1a Add option to compile (external) schema by cmake 2016-02-15 16:59:47 +01:00
Thomas Krijnen a583339492 Merge pull request #29 from Tridify/win_build_script_improvements
Windows build script improvements
2016-02-15 16:14:51 +01:00
Stinkfist0 f12e980bfe build-all.cmd: simplify "yes" trick 2016-02-15 15:08:13 +02:00
Stinkfist0 4979deb111 CMakeLists.txt: Remove sources specific to an IFC release we are not using from the project 2016-02-09 15:51:18 +02:00
Stinkfist0 c575352d20 ~IfcCharacterDecoder: call ucnv_flushCache() to fix two ICU mem leaks. 2016-02-07 23:01:34 +02:00
Stinkfist0 2f8fa3282b Fix mem leak in IfcSpfStream (not closed upon destruction), make Entity's dtor virtual. 2016-02-07 22:45:42 +02:00
Stinkfist0 993e322a8e Fix memory leakage from IfcSpfHeader 2016-02-07 13:14:14 +02:00
Stinkfist0 61ccd8a7cf VLD, not VLC... 2016-02-07 12:28:05 +02:00
Stinkfist0 450baf224f Remove accidentally committed lines 2016-02-07 00:51:10 +02:00
Stinkfist0 7b2197fa37 add /test/__pycache__ to ignore list 2016-02-07 00:31:29 +02:00
Stinkfist0 cde1c5f2ee Add build option for using Visual Leak Detector for debugging memory leaks. Initial report:
- IfcConvert (no arguments): 2 leaks (140 bytes) (from OCE)
- IfcConvert (acad2010_objects.ifc): 47 memory leaks (6,158 bytes)
- IfcGeomServer: 2 leaks (from OCE)
- IfcOpenHouse: 11,952 leaks (1,169,658 bytes)!
- IfcParseExamples (acad2010_objects.ifc): 40 memory leaks (4,564 bytes)
2016-02-07 00:30:08 +02:00
Stinkfist0 33772a4710 run-cmake.bat & build-all.cmd: fix cmake arguments parsing when arguments passed for the batch scripts 2016-02-06 18:48:18 +02:00
Stinkfist0 178c34fb22 README.md: document the supported IFC releases with links 2016-02-05 14:48:51 +02:00
Stinkfist0 17ecc43f78 vs-cfg.cmd: remove if-clause, an erroneous syntax print comes if this script is called when VS env vars not set but that's OK. 2016-02-04 11:46:53 +02:00
Stinkfist0 72999e04d9 vs-cfg.cmd: clean up output when used wrongly (VS tools not in path and empty/no generator argument passed). 2016-02-04 00:43:52 +02:00
Stinkfist0 f191b1fdd2 Fix warning regarding shadowing variable names. 2016-02-03 22:34:50 +02:00
Stinkfist0 d095bfecde Fix command-line argument parsing in run-cmake.bat and build-all.cmd 2016-02-03 22:16:50 +02:00
Stinkfist0 2e1699beea build-all.cmd: support for passing arguments, e.g. build-all.cmd vs2015-x64 RelWithDebInfo -DUSE_IFC4=1 -DENABLE_BUILD_OPTIMIZATIONS=1 2016-02-03 16:36:07 +02:00
Stinkfist0 5c07c8dc95 run-cmake.bat print tweak 2016-02-03 16:15:40 +02:00
Stinkfist0 0fa05faee8 Simplify run-cmake.bat, the script can now be used e.g. run-cmake.bat vs2015-x64 -UDUSE_IFC4=1 -DCMAKE_INSTALL_PREFIX=C:/IfcOpenShell/Ifc4 2016-02-03 16:12:52 +02:00
Stinkfist0 21e8a1e8e6 vs-cfg.cmd: provide support for user-friendly VS generators, e.g. vs2013-x86, and converted them to the appropriate CMake ones. 2016-02-03 16:10:55 +02:00
Stinkfist0 2e6601b3e7 build-deps.cmd: do not print build times if build did not even start properly. 2016-02-03 16:10:55 +02:00
Stinkfist0 634932e6e7 run-cmake.bat: set CMAKE_INSTALL_PREFIX also when passing extra parameters for the script 2016-02-03 16:10:55 +02:00
Stinkfist0 a041d289c6 Add build-all.cmd script for convenience. 2016-02-03 16:10:55 +02:00
Stinkfist0 01f8882311 adjust build-ifcopenshell & install-ifcopenshell to the build cfg batch file change 2016-02-03 16:10:54 +02:00
Stinkfist0 f2bdfbd049 Windows build scripts: move build configuration type to a separate file. 2016-02-03 16:10:32 +02:00
Stinkfist0 c7bf03e8f8 Add set-python-to-path.bat helper, add instructions for using preinstalled Python. 2016-02-03 16:10:32 +02:00
Stinkfist0 18e451b874 Windows build scripts: detect case where user installed Visual Studio but not the C++ toolset. Also detect case where user's CMake version is too old for the desired generator. 2016-02-03 16:10:32 +02:00
aothms f4d58b3969 Fix for IfcAdvancedFace when compiling for 2x3 2016-02-01 14:58:42 +01:00
aothms 76a3146b70 Fix one statement deleted too much in https://github.com/IfcOpenShell/IfcOpenShell/commit/f3af39546be9ecd485737ff0954cfb92807fca1d 2016-01-29 15:25:18 +01:00
aothms fe70acb541 Fix https://github.com/IfcOpenShell/IfcOpenShell/issues/26 2016-01-26 16:45:39 +01:00
Stinkfist0 a52901344c build-deps.cmd: print start, end, and elapsed time + .gitignore doc tweak 2016-01-26 13:41:19 +02:00
Thomas Krijnen d0e26f07fc Merge pull request #25 from aothms/master
Refactoring shared_ptr and array usage
2016-01-25 16:00:49 +01:00
aothms 5270710fc2 Use vanilla C arrays instead of std::tr::array
Fixes https://github.com/IfcOpenShell/IfcOpenShell/issues/17
2016-01-25 14:44:35 +01:00
aothms ed8cc620ea Use boost::shared_ptr
Fixes https://github.com/IfcOpenShell/IfcOpenShell/issues/17
2016-01-25 14:42:41 +01:00
aothms 9b13ed3f38 Emit more debug information when failing to join curve segments 2016-01-25 14:25:24 +01:00
aothms 801c7da40f Use multiple argument boolean operands for IfcOpeningElement subtractions 2016-01-25 13:30:33 +01:00
aothms 4be7da1a43 Use fuzzy boolean subtraction if available
Remove collinear points from polygonal halfspace boundary
Lookup styled items on boolean operation operands

Fixes https://github.com/IfcOpenShell/IfcOpenShell/issues/6
Fixes https://sourceforge.net/p/ifcopenshell/discussion/1782717/thread/a7f99e41/?limit=25#5c36
2016-01-22 17:27:28 +01:00
aothms a0db3a3406 chmod +x on *nix build script 2016-01-09 06:42:35 +01:00
aothms 18f8d7b3a3 Add *nix build script
Set paths by CMake cache entries or env vars
Windows build script: Don't fail on non-zero exit code returned by `git fetch`
2016-01-09 06:38:33 +01:00
Thomas Krijnen 010e05308d Merge pull request #19 from aothms/master
Fixes for sequences of extended control directives
2016-01-08 09:20:50 +01:00
aothms 973fa9ccb5 Fixes for sequences of extended control directives 2016-01-08 09:17:49 +01:00
aothms 0d42a293ad Add license header to occ_utils 2016-01-08 08:38:21 +01:00
Thomas Krijnen a02a06a0e3 Merge pull request #16 from Tridify/win_oce_update
Windows build scripts: OCE & OpenCOLLADA updates
2016-01-06 07:29:06 +01:00
Stinkfist0 d3438335a2 Work around https://github.com/KhronosGroup/OpenCOLLADA/issues/377 2015-12-30 16:26:16 +02:00
Stinkfist0 a0bb589ed3 build-deps.cmd: use OCE and oce-win-bundle from the official repos. 2015-12-30 13:32:22 +02:00
Thomas Krijnen 056bcd12d0 Merge pull request #14 from aothms/master
Various fixes
2015-12-21 11:51:45 +01:00
aothms fe699e0a81 Fix python module import 2015-12-21 11:47:38 +01:00
aothms 4eee9a1936 Merge remote-tracking branch 'official/master'
Conflicts:
	src/ifcconvert/IfcConvert.cpp
	src/ifcgeom/IfcGeomIterator.h
2015-12-21 11:36:23 +01:00
Thomas Krijnen 8c1710cae1 Merge pull request #11 from Tridify/windows_build_scripts
build-ifcopenshell & install-ifcopenshell batch files
2015-12-07 19:21:24 +01:00
Stinkfist0 e2d3b3734f Use IFCOS_NUM_BUILD_PROCS also in build-ifcopenshell.cmd and install-ifcopenshell.cmd. 2015-12-07 16:30:08 +02:00
aothms b243572d23 Don't fail on opening elements lacking representation or placement 2015-12-05 17:14:10 +01:00
Stinkfist0 3224a2cf83 build-ifcopenshell & install-ifcopenshell batch files 2015-12-04 17:33:13 +02:00
aothms a2d91f9331 Fix compilation error reported by bezumenez 2015-12-04 11:56:54 +01:00
aothms 0301e2fb1b Emit an error message on extrusions with negative height or under model precision 2015-12-02 10:17:59 +01:00
Thomas Krijnen 0036bd2dc2 Merge pull request #9 from Tridify/windows_build_scripts
Windows & Visual Studio build scripts continued
2015-12-01 14:27:34 +01:00
Stinkfist0 0877bb0ac3 Windows build scripts: if CMake generator not passed, deduce the generator from VS env vars. 2015-12-01 14:53:16 +02:00
aothms e62ce005dc Work on unit issues with step and iges files 2015-12-01 11:14:50 +01:00
aothms b6e2d78bfa Catch syntax errors during iterator initialization 2015-11-30 23:41:27 +01:00
aothms bf292cccd0 Precision fixes 2015-11-30 22:59:21 +01:00
aothms 9d730054dd Merge branch 'master' into layerset_slicing 2015-11-24 17:19:05 +01:00
Stinkfist0 2dc5cd44b7 Enable warning C4100 ("'identifier' : unreferenced formal parameter") and fix warnings. 2015-11-23 15:52:12 +02:00
Stinkfist0 fcbe93c4c2 vs-cfg.cmd: support CMake pre-3.0 Visual Studio generator strings. 2015-11-23 15:27:58 +02:00
Stinkfist0 89b3b96f1e .gitignore: add /src/ifcexpressparser/__pycache__ & /src/ifcexpressparser/express_parser.py 2015-11-22 02:39:45 +02:00
Stinkfist0 16a82f035f templates.py: disable C4100 warnings for headers created by this file + move <map> inclusion to .cpp as it's not needed in .h + use spaces instead of tabs consistently for these files as seems to be the convention. 2015-11-22 02:26:28 +02:00
Stinkfist0 b562508f5b win/readme.md tweak 2015-11-22 00:04:21 +02:00
Stinkfist0 a13042f227 Fix warnings: unused variables, shadowing variable names, constant conditional expressions, integer conversions, inability to generate copy-ctor and/or assignment operator, etc. 2015-11-21 23:05:28 +02:00
Stinkfist0 3cbb47a831 Bump up MSVC warning level. 2015-11-21 23:01:29 +02:00
Stinkfist0 7d806296c1 vs-cfg.cmd: use the longer generator names for all generator so that VS version can be identified in generic fashion 2015-11-21 13:16:47 +02:00
Stinkfist0 d6bd0c861b README.md formatting fix 2015-11-21 13:15:31 +02:00
Thomas Krijnen 8164c90ba0 Merge pull request #5 from Tridify/windows_build_scripts
Windows & Visual Studio build scripts
2015-11-20 13:38:45 +01:00
Stinkfist0 fff6f97651 build-deps: when building OpenCOLLADA, enforce that the embedded LibXml2 and PCRE are used as there might be problems with arbitrary versions of the libraries. 2015-11-20 12:45:56 +02:00
Stinkfist0 6a5d5dcb12 Further cleanup for the batch scripts. 2015-11-20 12:34:31 +02:00
Stinkfist0 bb3dc351b8 Batch file tweaks, fix printing of the used generator 2015-11-20 11:44:17 +02:00
Stinkfist0 90946e0877 Windows build scripts: TODO & indentation tweaks. 2015-11-20 00:45:01 +02:00
Stinkfist0 7895835ca3 build-deps.cmd: check that powershell, git and cmake are in path using where.exe. Print instructions upon missing VS env vars or tools in PATH. 2015-11-19 18:01:03 +02:00
Stinkfist0 7caa4e3e1d Replace cecho.exe with PowerShell snippet, fix exit bug in vs-cfg.cmd, fix Visual Studio download URL, rename IFCOS_NUM_BUILD_PROCESSES -> IFCOS_NUM_BUILD_PROCS 2015-11-19 17:30:55 +02:00
Stinkfist0 d721dabf3b Replace wget usage with PowerShell. 2015-11-17 16:02:06 +02:00
Stinkfist0 9087bc65a7 win/readme.md tweaks 2015-11-14 20:18:29 +02:00
Stinkfist0 ccf4e84e18 CMakeLists.txt: Clean up addition of debug lib variants on MSVC. 2015-11-14 19:19:55 +02:00
Stinkfist0 0f1db1267b Rename readme.txt to readme.md, link to the Windows readme.md from the main README.md. 2015-11-11 17:41:38 +02:00
Stinkfist0 431e993ba3 CMake biz: Instead of providing elusive prints of missing dependencies for required features and continuing the build configuration, fail fast instead; user can easily disable the feature or fix the paths for the dependency. 2015-11-11 13:30:30 +02:00
Stinkfist0 d912e73282 Allow both debug and release variants of dependencies to co-exist allowing effortless switching between IfcOpenShell debug and release builds. 2015-11-10 23:18:02 +02:00
Stinkfist0 106da12444 build-deps.cmd: make debug libs of OpenCOLADA and ICU to have "d" postfix so that release and debug variants can co-exist in the same dir as is the default with OCE. 2015-11-10 20:05:11 +02:00
Stinkfist0 89a015724b CMake biz: rename OCE_LIBRARIES to OPENCASCADE_LIBRARIES, use this variable also in examples & qtviewer CMakeLists.txt 2015-11-09 17:42:46 +02:00
Stinkfist0 8b63959509 Use separate BuildDepsCache.txt for x86 and x64 builds. 2015-11-09 16:04:06 +02:00
Stinkfist0 0a8791e04e Clean up CMake biz by using OCE_LIBRARIES variable for defining OCE libs + fix setting of PYTHON_INCLUDE_DIR + PYTHON_LIBRARY vars + small README.md cleanup. 2015-11-09 15:36:57 +02:00
Stinkfist0 318779196b Use BuildDepsCache.txt to store information about used Python version so that it's available for "autonomic" run-cmake.bat runs. 2015-11-05 18:05:20 +02:00
aothms d076fa588b Work on runtime representation of schema 2015-11-05 11:55:19 +01:00
Stinkfist0 6190771817 Fix/suppress signed-unsigned int conversion warnings on Windows x64. 2015-11-04 18:27:46 +02:00
Stinkfist0 206a9cf5d0 Work around https://github.com/swig/swig/issues/325 2015-11-04 16:25:13 +02:00
Stinkfist0 d4b51a82e7 Fix/suppress plethora of integer conversion warnings on x64 Visual Studio build. 2015-11-03 17:58:08 +02:00
Stinkfist0 a749775045 build-deps.cmd: use OpenCOLLADA from the official repo now that it has the static MSVC run-time option. 2015-11-03 16:55:33 +02:00
Stinkfist0 26ed16ba52 Make possible to switch between Python 2 & 3 easily. Fixes also possible confusion when having both 32-bit and 64-bit Python installations side by side. 2015-11-03 16:28:30 +02:00
Stinkfist0 7b4d8734ed run-cmake.bat: ensure Python packages are installed to the right direction. 2015-10-30 22:49:52 +02:00
Stinkfist0 455d382a9e build-deps.cmd: add option to use Python 2 instead of 3, fix Boost build variant (for some reason error did not manifest itself until clean build) 2015-10-30 21:12:08 +02:00
Stinkfist0 c9313c8e02 build-deps.cmd: update SWIG, build Boost as debug or release, not both, each run. 2015-10-29 00:23:19 +02:00
Stinkfist0 b44a88d203 CMakeLists.txt: install IfcGeomServer executable. 2015-10-28 21:25:48 +02:00
Stinkfist0 921c3eb2d3 SvgSerializer.cpp: add missing #include <Standard_Version.hxx> 2015-10-28 21:25:23 +02:00
Stinkfist0 d5efe45b0b Update READMEs. 2015-10-28 21:21:23 +02:00
Stinkfist0 b8a7b5426d build-deps.cmd: fix Python installation. Also uninstall Python if build type is Clean or Rebuild. 2015-10-28 21:08:08 +02:00
Stinkfist0 89bea19b75 Enhanced CMakeLists.txt for Windows build scripts. 2015-10-28 19:45:45 +02:00
Stinkfist0 5c0eb05482 Add Windows build scripts from https://github.com/Tridify/IfcOpenShell-SourceForge 2015-10-28 19:43:10 +02:00
Stinkfist0 c9ff455812 Move Visual Studio solution files from win\ to win\sln 2015-10-28 19:41:59 +02:00
aothms fdf1b29682 Return shape for arbitrary representation items in ifcopenshell.geom.create_shape() 2015-10-22 12:04:49 +02:00
aothms f3af39546b Don't construct transformation from matrix, but use original data. 2015-10-13 11:15:45 +02:00
aothms 44ddc5e6dc Don't use IfcMappedItems for IfcOpenHouse walls, as suggested by Ian Clévy in https://sourceforge.net/p/ifcopenshell/discussion/1782716/thread/f9b586ca/?limit=25#ab87 2015-10-09 14:23:38 +02:00
aothms c9db70c7c3 Initial implementation of layerset slicing 2015-10-07 17:33:30 +02:00
aothms c7ddc0643e Fixes to flatten_shape_list() 2015-10-07 16:14:34 +02:00
aothms 3a9e90f94f Mark IfcGeom::Kernel::getValue as const 2015-10-07 16:13:25 +02:00
aothms db6630c1f8 Use boost::to_lower() 2015-10-05 13:34:43 +02:00
aothms c20afd24a5 Remove unnecessary precision cast 2015-10-05 13:09:16 +02:00
aothms 7b82bfb477 Update log messages in parser 2015-10-05 13:08:24 +02:00
aothms 3e00139a87 Add const pointer cast to IfcBaseClass 2015-10-05 13:07:40 +02:00
Thomas Krijnen 23beb5691c Detect abstract entities in schema parser 2015-09-17 10:33:19 +02:00
Thomas Krijnen c6a265adf8 Merge pull request #2 from aothms/master
Assorted fixes
2015-09-13 15:05:46 +02:00
aothms 94d214808e Use boost::to_upper() and -::to_upper_copy() for string manipulation throughout codebase 2015-09-13 15:00:21 +02:00
aothms a58b2ede63 Fixes for unicode handling in Python 2015-09-13 14:43:42 +02:00
aothms e5c20a009d Add convenience method for relating objects to types. As suggested by Cadline St2. 2015-09-12 14:27:58 +02:00
aothms b590747db9 Add version information and schema identifier to Python wrapper 2015-09-10 15:53:59 +02:00
aothms 2532ba30e4 Fix addRelatedObject, fix by Cadline St2 2015-09-10 13:58:27 +02:00
aothms 9096895bdb Support for schemas using TYPE definitions to redeclare BINARY types 2015-09-08 15:27:05 +02:00
aothms 82143f226e Small changes to SVG serialization 2015-09-06 14:50:07 +02:00
aothms 22a8d9a17b Don't leave MakeFace in an invalid state when one of the face boundaries cannot be processed or is not planar 2015-09-04 11:48:53 +02:00
aothms 4385f3b14d Revert some of the typemap work in b96cf38e17 and rely on a general mapping from const vector to tuple 2015-09-04 11:46:52 +02:00
aothms 3cba242295 When built without ICU filter characters outside of unencoded range 2015-08-14 22:11:32 +02:00
aothms 822fa91f4d Work on a C++ representation of the parsed EXPRESS schema 2015-08-13 14:28:50 +02:00
aothms 266d6f4c97 Cache the output of the parsed express schema as a Python pickle stream for speedier code generation 2015-08-13 14:26:14 +02:00
Thomas Krijnen 8406c5243c Merge pull request #1 from aothms/master
Ignore tail remarks in the express schema parser
2015-08-13 14:20:12 +02:00
aothms 810d3eab1e Ignore tail remarks in the express schema parser 2015-08-13 14:18:59 +02:00
aothms 17f6e67706 Update README 2015-08-10 11:38:43 +02:00
Thomas Krijnen f5c32adff1 Be sure to flush fstream when finalizing SVG export 2015-07-26 17:59:52 +00:00
Thomas Krijnen bb43dec90f Fix typos 2015-07-26 17:58:08 +00:00
Thomas Krijnen 0e5edbcd84 Reverse preprocessor statement to work without definition, defaulting to 2x3 2015-07-26 15:26:34 +00:00
Thomas Krijnen 68fc361d96 Add SvgSerializer developed in collaboration with ROOT B.V. 2015-07-26 14:26:13 +00:00
Thomas Krijnen 06b4fcb066 Remove orphaned file. Thanks Stinkfist 2015-07-26 14:22:50 +00:00
Thomas Krijnen 85d5d86c84 Update code examples for recent changes 2015-07-09 13:52:55 +00:00
Thomas Krijnen 78f4d7d592 Fix build with Boost 1.58.0. Patch by stinkfist0. Thanks. 2015-07-09 13:23:40 +00:00
Thomas Krijnen 92bc7b13cb Use custom typemaps for geometry related classes as well 2015-06-26 13:06:28 +00:00
Thomas Krijnen e518146bd6 Fix IfcCurveBoundedPlane implementation 2015-06-21 16:15:15 +00:00
Thomas Krijnen e9eb7db620 Fix ensure_fit_for_subtraction() function when input shape is a solid 2015-06-21 16:14:37 +00:00
Thomas Krijnen 1068070037 Do not free the IFC file if it has not been constructed by the iterator 2015-06-20 14:23:59 +00:00
Thomas Krijnen 3d302619c5 Check for numbers.Integral instead of int, to catch py2.7's long type as well 2015-06-20 14:22:54 +00:00
Thomas Krijnen 48febb7eff Check for null values when setting attributes in IfcOpenShell-Python, also return value being set 2015-06-18 13:15:33 +00:00
Thomas Krijnen feaa13a809 gcc compatibility 2015-06-18 08:55:29 +00:00
Thomas Krijnen 76cbb79c75 Correctly wrap arbitrarily nested aggregates of entity instance attributes in IfcOpenShell-Python 2015-06-17 19:46:11 +00:00
Thomas Krijnen 6aabbd4a55 Correctly interpret SWIG return code of type check 2015-06-17 19:44:15 +00:00
Thomas Krijnen 48676a733f Rework SWIG python binding not to rely on polymorhpic functions. Use hand-written typemaps that map vectors to tuples and iterables to vectors. Add support for multidimensional aggregates in Python. 2015-06-17 11:27:02 +00:00
Thomas Krijnen f8c45b2a99 Fix serialization of binary values 2015-06-17 11:22:43 +00:00
Thomas Krijnen 1ec14118fe Introduce specific exception for out of range attribute indexing 2015-06-17 11:04:28 +00:00
Thomas Krijnen 381f711103 Update string representation of ArgumentTypeToString 2015-06-16 14:47:03 +00:00
Thomas Krijnen b748c0a573 Add source code for generation of IfcTriangulatedFaceSet test case 2015-06-16 13:00:19 +00:00
Thomas Krijnen c4e8a409de Add another IfcTriangulatedFaceSet test case 2015-06-16 12:59:49 +00:00
Thomas Krijnen 28863f90b9 Add support for IFC4.IfcTriangulatedFaceSet 2015-06-16 12:58:51 +00:00
Thomas Krijnen 4f60c7d48c Provide concrete C++ implementations for all multidimensional aggregate types in IFC4 2015-06-16 12:58:07 +00:00
Thomas Krijnen f70b37137d Emit an error message rather than exception for GlobalId parsing inconsistencies to accomodate files with invalid GlobalIds. 2015-06-04 14:33:13 +00:00
Thomas Krijnen 49d491704e Add support for IfcBSplineCurveWithKnots 2015-06-02 15:56:09 +00:00
Thomas Krijnen a3f17cd4e7 Enable passing explicit IfcRepresentation in IfcOpenShell-Python create_shape() 2015-06-02 13:30:02 +00:00
Thomas Krijnen b96cf38e17 Minimize passing STL objects past dynamic library boundaries to improve stability of IfcOpenShell-Python 2015-06-02 13:29:08 +00:00
Thomas Krijnen 5a994ebe28 vc9 compatibility 2015-05-26 12:56:00 +00:00
Thomas Krijnen ffc008228d gcc compatibility 2015-05-26 12:55:00 +00:00
Thomas Krijnen 77ba3f5a80 Perform shape healing after opening subtraction 2015-05-22 15:41:56 +00:00
Thomas Krijnen 04d4095ffe Correctly mark face boundary edges in case of vertex welding 2015-05-22 13:13:48 +00:00
Thomas Krijnen 569fa49796 Prevent an issue with obtaining precision from sub contexts 2015-05-22 13:13:16 +00:00
Thomas Krijnen 7abe2df066 Update implementation of IfcBSplineSurfaceWithKnots for IfcAdvancedFace in IFC4 2015-05-21 13:02:10 +00:00
Thomas Krijnen 9b64c6f4b9 Check for orientation of wires when creating outer boundary of face 2015-05-21 13:01:01 +00:00
Thomas Krijnen 771f78a671 Fix surface style association when compiling with IFC4 2015-05-21 12:55:54 +00:00
Thomas Krijnen 3d6b330366 Reintroduce binary type in express parser 2015-05-21 12:53:17 +00:00
Thomas Krijnen 37d4e9bcbd Fix express parser for simple types that redefine aggregates of entities 2015-05-21 12:09:57 +00:00
Thomas Krijnen 7390faa654 Adapt XML serializer for changes in IFC4 decomposition and property set types 2015-05-21 12:06:38 +00:00
Thomas Krijnen b7d4eb62d5 Add IfcFaceSurface example 2015-05-21 12:05:23 +00:00
Thomas Krijnen 40a60386c8 Brand new implementation of IfcFace(Surface) 2015-05-20 08:55:02 +00:00
Thomas Krijnen 9bf9f82b3b Format obj and dae output predictably based on rfc notation of GlobalId. As discussed in https://sourceforge.net/p/ifcopenshell/discussion/1782717/thread/cbb0c8ca/ 2015-05-13 14:30:21 +00:00
Thomas Krijnen b37a684eb9 Append line segment indices in the IfcGeomServer 2015-04-25 09:13:14 +00:00
Thomas Krijnen c97cf661a2 1. Also emit Plan and Axis shape representations and IfcTopologyRepresentations if requested. 2. Add serialization for curves. 3. In Python add option to specify representation for which to generate shape. 2015-04-22 09:15:48 +00:00
Thomas Krijnen 53f625346f Fix compilation with gcc 2015-04-07 19:26:01 +00:00
Thomas Krijnen 608c7d9841 Don't rely on exceptions for testing whether a Python attribute names a valid (inverse) IFC attribute 2015-04-07 15:49:38 +00:00
Thomas Krijnen 955190b517 Add support for reading and writing BINARY attributes. Rename members of the IfcUtil::ArgumentType enumeration. 2015-04-07 15:06:56 +00:00
Thomas Krijnen 462425f61d Update README 2015-03-22 20:06:04 +00:00
Thomas Krijnen 0a0f44b674 Reduce link time for MSVC release builds. Patch by ch0kee. 2015-03-22 19:52:29 +00:00
Thomas Krijnen 9f9a0ea3dc Update generated code for IFC4 2015-03-20 20:58:05 +00:00
221 changed files with 111858 additions and 62048 deletions
+14
View File
@@ -0,0 +1,14 @@
# Dependency and build folders created by the build scripts
/deps*/
/build*/
/install*/
/win/BuildDepsCache*.txt
# IfcExpressParser residue
/src/ifcexpressparser/express_parser.py
# General Python residue
__pycache__
*.py.bak
# Visual Studio Code files
.vscode
# PyCharm files
.idea
+56
View File
@@ -0,0 +1,56 @@
language: cpp
compiler: gcc
os: linux
dist: trusty
sudo: required
before_install:
- sudo apt-get update -qq
install:
- sudo apt-get install -qq gcc-4.8 g++-4.8
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 90
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 90
- sudo apt-get install -y libboost1.55-dev
- sudo apt-get install -y libboost-regex1.55-dev
- sudo apt-get install -y libboost-system1.55-dev
- sudo apt-get install -y libboost-thread1.55-dev
- sudo apt-get install -y libboost-program-options1.55-dev
- sudo apt-get install -y cmake
- sudo apt-get install -y libicu-dev
- sudo apt-get install -y python-all-dev
- sudo apt-get install -y swig
- sudo apt-get install -y liboce-foundation-dev
- sudo apt-get install -y liboce-modeling-dev
- sudo apt-get install -y liboce-ocaf-dev
- sudo apt-get install -y liboce-visualization-dev
- sudo apt-get install -y liboce-ocaf-lite-dev
- sudo apt-get install -y libpcre3-dev
script:
- pwd
- cd ..
- git clone https://github.com/KhronosGroup/OpenCOLLADA.git
- cd OpenCOLLADA
- git checkout 064a60b65c2c31b94f013820856bc84fb1937cc6
- mkdir build
- cd build
- cmake ..
- sudo make -j2 install
- cd ..
- cd ..
- pwd
- cd IfcOpenShell
- pwd
- cd cmake
- mkdir build
- cd build
- cmake -DCOLLADA_SUPPORT=True -DOPENCOLLADA_INCLUDE_DIR=/usr/local/include/opencollada -DOPENCOLLADA_LIBRARY_DIR=/usr/local/lib/opencollada -DPCRE_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu -DBUILD_IFCPYTHON=True -DUNICODE_SUPPORT=True -DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu -DPYTHON_LIBRARY=/usr/lib/python2.7/config-x86_64-linux-gnu/libpython2.7.so -DPYTHON_INCLUDE_DIR=/usr/include/python2.7 -DPYTHON_EXECUTABLE=/usr/bin/python2.7 ..
- sudo make install
- cd ../../test
- /usr/bin/python2.7 tests.py
-65
View File
@@ -1,65 +0,0 @@
IfcOpenShell
============
open source (LGPL) software library for working with the IFC file format
http://IfcOpenShell.org
Compiling on Windows
====================
Users are advised to use the Visual Studio .sln file in the win/ folder.
For Windows users a prebuilt Open CASCADE version is available from the
http://opencascade.org website. Download and install this version and
provide the paths to the Open CASCADE header and library files to MS
Visual Studio C++.
For building the Autodesk 3ds Max plugin, the 3ds Max SDK needs to be
installed as well as 3ds Max itself. Please provide the include and
library paths to Visual Studio.
For building the IfcPython wrapper, SWIG needs to be installed. Please
download the latest swigwin version from http://www.swig.org/download.html.
After extracting the .zip file, please add the extracted folder to the PATH
environment variable. Python needs to be installed, please provide the
include and library paths to Visual Studio.
Compiling on *nix
====================
Users are advised to build IfcOpenShell using the cmake file provided in
the cmake/ folder. There might be an Open CASCADE package in your operating
system's software repository. If not, you will need to compile Open
CASCADE yourself. See http://opencascade.org.
For building the IfcPython wrapper, SWIG and Python development are
required.
To build IfcOpenShell please take the following steps:
$ cd /path/to/IfcOpenShell/cmake
$ mkdir build
$ cd build
Optionally:
$ OCC_INCLUDE_PATH="/path/to/OpenCASCADE/include"
$ OCC_LIBRARY_PATH="/path/to/OpenCASCADE/lib"
$ export OCC_INCLUDE_PATH
$ export OCC_LIBRARY_PATH
$ cmake ../
$ make
If all worked out correctly you can now use IfcOpenShell. For example:
$ wget ftp://ftp.dds.no/pub/ifc/Munkerud/Munkerud_hus6_BE.zip
$ unzip Munkerud_hus6_BE.zip
$ ./IfcObj Munkerud_hus6_BE.ifc
$ less Munkerud_hus6_BE.obj
Or:
$ wget ftp://ftp.dds.no/pub/ifc/Munkerud/Munkerud_hus6_BE.zip
$ unzip Munkerud_hus6_BE.zip
$ python
>>> import IfcImport
>>> IfcImport.Init('Munkerud_hus6_BE.ifc')
>>> geom = IfcImport.Get()
>>> geom.name
>>> for v in geom.mesh.verts: v
+228
View File
@@ -0,0 +1,228 @@
IfcOpenShell
============
IfcOpenShell is an open source ([LGPL]) software library for working with the Industry Foundation Classes ([IFC])
file format. Currently supported IFC releases are [IFC2x3 TC1] and [IFC4 Add1].
For more information, see
* [http://ifcopenshell.org](http://ifcopenshell.org)
* [http://academy.ifcopenshell.org](http://academy.ifcopenshell.org)
[![Build Status](https://api.travis-ci.org/IfcOpenShell/IfcOpenShell.png)](https://api.travis-ci.org/IfcOpenShell/IfcOpenShell)
Prerequisites
-------------
* Git
* CMake (2.6 or newer)
* Windows: [Visual Studio] 2008 or newer with C++ toolset (or [Visual C++ Build Tools]) or [MSYS2] + MinGW
* *nix: GCC 4.7 or newer, or Clang (any version)
Dependencies
-------------
* [Boost](http://www.boost.org/)
* [Open Cascade](http://opencascade.org) - *optional*, but required for building IfcGeom
([official](http://www.opencascade.org/getocc/download/loadocc/), "OCCT", or [community edition](https://github.com/tpaviot/oce), "OCE")
For converting IFC representation items into BRep solids and tesselated meshes
* [ICU](http://site.icu-project.org/) - *optional*
For handling code pages and Unicode in the parser
* [OpenCOLLADA](https://github.com/khronosGroup/OpenCOLLADA/) - *optional*
For IfcConvert to be able to write tessellated Collada (.dae) files
* [SWIG](http://www.swig.org/) and [Python](https://www.python.org/) - *optional*
For building the IfcOpenShell Python interface and the Blender add-on
* [3ds Max SDK](http://www.autodesk.com/products/3ds-max/free-trial) - *optional*
For building the 3ds Max plug-in.
All recent versions of 3ds Max (2014 and newer) are 64-bit only, so a 64-bit installation is assumed.
Building IfcOpenShell
---------------------
**Note:** The path where the source code is cloned to can contain spaces but non-ASCII characters are very likely to cause problems with the build.
### Compiling on Windows
The preferred way to fetch and build this project's dependencies is to use the build scripts
in win/ folder. **See [win/readme.md] for more information**.
#### Using Visual Studio
Instructions in a nutshell (**assuming Visual Studio 2015 x64 environment variables set**):
> cd IfcOpenShell\win
> build-deps.cmd
> run-cmake.bat
You can now open and build the solution file in Visual Studio:
> ..\build-vs2015-x64\IfcOpenShell.sln
As the scripts default to using the `RelWithDebInfo` configuration, and a freshly created solution by CMake defaults
to `Debug`, make sure to switch the used build configuration. Build the `INSTALL` project (right-click -> Project
Only) to deploy the headers and binaries into a single location if wanted/needed.
Alternatively, one can use the utility batch file(s) to build and install the project easily from the command-line
(installing a project will build it also, if required):
> install-ifcopenshell.bat
#### Using MSYS2 + MinGW
Start the MSYS2 Shell and then:
$ cd IfcOpenShell/win
$ ./build-deps.sh
$ ./run-cmake.sh
$ ./install-ifcopenshell.sh
#### Using Bash on Ubuntu on Windows
Start Bash on Ubuntu on Windows and follow the instructions below. Compiling on Ubuntu 14.04.4 LTS using GCC 4.8.4
or Clang 3.5 has been confirmed to work.
### Compiling on *nix
The following instructions are for Ubuntu, modify as required for other operating systems. [nix/build-all.py] script
can be experimented with and studied for pointers for other operating systems, but note that this script is not currently
meant to be used for a typical IfcOpenShell workspace setup.
Note: where `make -j` is written, add a number roughly equal to the amount of CPU cores + 1.
**1)** Install most of the prerequisites and dependencies:
$ sudo apt-get install git cmake gcc g++ libboost-all-dev libicu-dev
**2a)** Either use an OCE package from your operating system's software repository
$ sudo apt-get install liboce-foundation-dev liboce-modeling-dev liboce-ocaf-dev liboce-visualization-dev liboce-ocaf-lite-dev
**2b)** or (if not available, or the latest code is wanted) compile OCE yourself (note that the build takes a long time):
$ sudo apt-get install libftgl-dev libtbb2 libtbb-dev libgl1-mesa-dev libfreetype6-dev
$ git clone https://github.com/tpaviot/oce.git
$ cd oce
$ mkdir build && cd build
$ cmake ..
$ make -j
$ sudo make install
**2c)** or obtain and compile OCCT from http://www.opencascade.org/getocc/download/loadocc/
**3)** For building IfcConvert with COLLADA (.dae) support (on by default), OpenCOLLADA is needed:
$ sudo apt-get install libpcre3-dev libxml2-dev
$ git clone https://github.com/KhronosGroup/OpenCOLLADA.git
$ cd OpenCOLLADA
Using a known good revision, but HEAD should work too:
$ git checkout 064a60b65c2c31b94f013820856bc84fb1937cc6
$ mkdir build && cd build
$ cmake ..
$ make -j
$ sudo make install
**4)** For building the IfcPython wrapper (on by default), SWIG and Python development are needed, if not already available:
$ sudo apt-get install python-all-dev swig
**5)** To build IfcOpenShell please take the following steps. Alternatively use environment variables for setting the
dependencies' paths. `OCC_INCLUDE_DIR` might be needed to set also. `OPENCOLLADA_INCLUDE_DIR` and `OPENCOLLADA_LIBRARY_DIR`
(and potentially `PCRE_LIBRARY_DIR`) are needed if building with COLLADA support. (`-DCOLLADA_SUPPORT=0` disables it).
$ cd /path/to/IfcOpenShell
$ mkdir build && cd build
$ cmake ../cmake -DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu/ \
-DOPENCOLLADA_INCLUDE_DIR="/usr/local/include/opencollada" \
-DOPENCOLLADA_LIBRARY_DIR="/usr/local/lib/opencollada" \
-DPCRE_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu/
$ make -j
If all worked out correctly you can now use IfcOpenShell. See the examples below.
**6)** Install the project if wanted:
$ sudo make install
Installing IfcOpenShell with Conda
----------------------------------
Another option for building and installing IfcOpenShell is to use the popular
[Anaconda Python Distribution](https://www.anaconda.com/download).
The requirements are spread across a number of channels.
You can add these channels to your configuration, or specify them all on the command line:
$ conda install -c conda-forge -c oce -c dlr-sc -c ifcopenshell ifcopenshell
Usage examples
--------------
**Invoking IfcConvert from the command line**
$ wget ftp://ftp.dds.no/pub/ifc/Munkerud/Munkerud_hus6_BE.zip
$ unzip Munkerud_hus6_BE.zip
$ ./IfcConvert Munkerud_hus6_BE.ifc
$ less Munkerud_hus6_BE.obj
**Using the IfcOpenShell Python interface**
$ wget -O duplex.zip http://projects.buildingsmartalliance.org/files/?artifact_id=4278
$ unzip duplex.zip
$ python
>>> import ifcopenshell
>>> f = ifcopenshell.open("Duplex_A_20110907_optimized.ifc")
>>>
>>> # Accessing entity instances by type:
>>> f.by_type("ifcwall")[:2]
[#91=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FL9r',#1,'Basic Wall:Interior - Partition (92mm Stud):144586',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5198,#18806,'144586'), #92=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FLIE',#1,'Basic Wall:Interior - Partition (92mm Stud):143921',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5206,#18805,'143921')]
>>> wall = _[0]
>>> len(wall) # number of EXPRESS attributes
8
>>>
>>> # Accessing EXPRESS attributes by name:
>>> wall.GlobalId
'2O2Fr$t4X7Zf8NOew3FL9r'
>>> wall.Name = "My wall"
>>> wall.NonExistingAttr
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".\ifcopenshell.py", line 14, in __getattr__
except: raise AttributeError("entity instance of type '%s' has no attribute'%s'"%(self.wrapped_data.is_a(), name)) from None
AttributeError: entity instance of type 'IfcWallStandardCase' has no attribute 'NonExistingAttr'
>>> wall.GlobalId = 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".\ifcopenshell.py", line 26, in __setattr__
self[self.wrapped_data.get_argument_index(key)] = value
File ".\ifcopenshell.py", line 30, in __setitem__
self.wrapped_data.set_argument(idx, entity_instance.map_value(value))
File ".\ifc_wrapper.py", line 118, in <lambda>
set_argument = lambda self,x,y: self._set_argument(x) if y is None else self
._set_argument(x,y)
File ".\ifc_wrapper.py", line 114, in _set_argument
def _set_argument(self, *args): return _ifc_wrapper.entity_instance__set_argument(self, *args)
RuntimeError: INT is not a valid type for 'GlobalId'
>>> # Creating new entity instances
>>> f.createIfcCartesianPoint(Coordinates=(1.0,1.5,2.0))
#27530=IfcCartesianPoint((1.,1.5,2.))
>>>
>>> # Working with GlobalId attributes:
>>> import uuid
>>> ifcopenshell.guid.compress(uuid.uuid1().hex)
'3x4C8Q_6qHuv$P$FYkANRX'
>>> new_guid = _
>>> owner_hist = f.by_type("IfcOwnerHistory")[0]
>>> new_wall = f.createIfcWallStandardCase(new_guid, owner_hist, None, None, Tag='my_tag')
>>> new_wall.ObjectType = ''
>>> new_wall.ObjectPlacement = new_wall.Representation = None
>>>
>>> # Accessing entity instances by instance id or GlobalId:
>>> f[92]
#92=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FLIE',#1,'Basic Wall:Interior - Partition (92mm Stud):143921',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5206,#18805,'143921')
>>> f['2O2Fr$t4X7Zf8NOew3FLIE']
#92=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FLIE',#1,'Basic Wall:Interior - Partition (92mm Stud):143921',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5206,#18805,'143921')
>>>
>>> # Writing IFC-SPF files to disk:
>>> f.write("out.ifc")
[LGPL]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/COPYING "LGPL"
[IFC]: http://www.buildingsmart-tech.org/specifications/ifc-overview "IFC"
[IFC2x3 TC1]: http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc2x3-tc1-release "IFC2x3 TC1"
[IFC4 Add1]: http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc4-add1-release "IFC4 Add1"
[Visual Studio]: https://www.visualstudio.com/ "Visual Studio"
[Visual C++ Build Tools]: http://landinghub.visualstudio.com/visual-cpp-build-tools "Visual C++ Build Tools"
[MSYS2]: https://msys2.github.io/ "MSYS2"
[win/readme.md]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/win/readme.md "win/readme.md"
[nix/build-all.py]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/nix/build-all.py "nix/build-all.py"
+649 -188
View File
@@ -1,235 +1,696 @@
cmake_minimum_required (VERSION 2.6)
################################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
################################################################################
cmake_minimum_required (VERSION 2.8.5)
project (IfcOpenShell)
FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options)
OPTION(UNICODE_SUPPORT "Build IfcOpenShell with Unicode support (requires ICU)." ON)
OPTION(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON)
OPTION(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF)
OPTION(IFCCONVERT_DOUBLE_PRECISION "IfcConvert: Use double precision floating-point numbers." ON)
OPTION(BUILD_IFCPYTHON "Build IfcPython." ON)
OPTION(BUILD_EXAMPLES "Build example applications." ON)
OPTION(BUILD_GEOMSERVER "Build IfcGeomServer executable." ON)
OPTION(BUILD_CONVERT "Build IfcConvert executable." ON)
OPTION(USE_VLD "Use Visual Leak Detector for debugging memory leaks, MSVC-only." OFF)
OPTION(USE_MMAP "Adds a command line options to parse IFC files from memory mapped files using Boost.Iostreams" OFF)
OPTION(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." OFF)
OPTION(BUILD_SHARED_LIBS "Build IfcParse and IfcGeom as shared libs (SO/DLL)." OFF)
# TODO QtViewer is deprecated ATM as it uses the 0.4 API
# OPTION(BUILD_QTVIEWER "Build IfcOpenShell Qt GUI Viewer (requires Qt 4 framework)." OFF)
# Specify where to install files
IF(NOT BINDIR)
set(BINDIR bin)
ENDIF()
IF(NOT IS_ABSOLUTE ${BINDIR})
set(BINDIR ${CMAKE_INSTALL_PREFIX}/${BINDIR})
ENDIF()
MESSAGE(STATUS "BINDIR: ${BINDIR}")
IF(NOT INCLUDEDIR)
set(INCLUDEDIR include)
ENDIF()
IF(NOT IS_ABSOLUTE ${INCLUDEDIR})
set(INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/${INCLUDEDIR})
ENDIF()
MESSAGE(STATUS "INCLUDEDIR: ${INCLUDEDIR}")
IF(NOT LIBDIR)
set(LIBDIR lib)
ENDIF()
IF(NOT IS_ABSOLUTE ${LIBDIR})
set(LIBDIR ${CMAKE_INSTALL_PREFIX}/${LIBDIR})
ENDIF()
MESSAGE(STATUS "LIBDIR: ${LIBDIR}")
set(IFCOPENSHELL_LIBARY_DIR "") # for *nix rpaths
if (BUILD_SHARED_LIBS)
add_definitions(-DIFC_SHARED_BUILD)
if (MSVC)
message(WARNING "Building DLLs against the static VC run-time. This is not recommended if the DLLs are to be redistributed.")
# C4521: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
# There will be couple hundreds of these so suppress them away, https://msdn.microsoft.com/en-us/library/esew7y1w.aspx
add_definitions(-wd4251)
endif()
set(IFCOPENSHELL_LIBARY_DIR "${LIBDIR}")
endif()
# Create cache entries if absent for environment variables
MACRO(UNIFY_ENVVARS_AND_CACHE VAR)
IF ((NOT DEFINED ${VAR}) AND (NOT "$ENV{${VAR}}" STREQUAL ""))
SET(${VAR} "$ENV{${VAR}}" CACHE STRING "${VAR}" FORCE)
ENDIF()
ENDMACRO()
UNIFY_ENVVARS_AND_CACHE(OCC_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(OCC_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(ICU_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(ICU_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(PCRE_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE)
IF(WIN32)
UNIFY_ENVVARS_AND_CACHE(THREEDS_MAX_SDK_HOME)
ENDIF()
# Set INSTALL_RPATH for target
MACRO(SET_INSTALL_RPATHS _target _paths)
SET(${_target}_rpaths "")
FOREACH(_path ${_paths})
LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${_path}" isSystemDir)
IF("${isSystemDir}" STREQUAL "-1")
LIST(APPEND ${_target}_rpaths ${_path})
ENDIF()
ENDFOREACH()
MESSAGE(STATUS "Set INSTALL_RPATH for ${_target}: ${${_target}_rpaths}")
SET_TARGET_PROPERTIES(${_target} PROPERTIES INSTALL_RPATH "${${_target}_rpaths}")
ENDMACRO()
# Find Boost: On win32 the (hardcoded) default is to use static libraries and
# runtime, when doing running conda-build we pick what conda prepared for us.
IF(WIN32 AND ("$ENV{CONDA_BUILD}" STREQUAL ""))
SET(Boost_USE_STATIC_LIBS ON)
SET(Boost_USE_STATIC_RUNTIME ON)
SET(Boost_USE_MULTITHREADED ON)
ELSE()
# Disable Boost's autolinking as the libraries to be linked to are supplied
# already by CMake, and it's going to conflict if there are multiple, as is
# the case in conda-forge's libboost feedstock.
ADD_DEFINITIONS(-DBOOST_ALL_NO_LIB)
IF(WIN32)
# Necessary for boost version >= 1.67
SET(BCRYPT_LIBRARIES "bcrypt.lib")
ENDIF()
ENDIF()
set(BOOST_COMPONENTS system program_options regex thread date_time)
if(USE_MMAP)
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)
endif()
FIND_PACKAGE(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
MESSAGE(STATUS "Boost include files found in ${Boost_INCLUDE_DIRS}")
MESSAGE(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}")
# Find Open CASCADE header files
IF("$ENV{OCC_INCLUDE_DIR}" STREQUAL "")
SET(OCC_INCLUDE_DIR "/usr/include/opencascade/" CACHE FILEPATH "Open CASCADE header files")
MESSAGE(STATUS "Looking for opencascade include files in: ${OCC_INCLUDE_DIR}")
# Usage:
# set(SOME_LIRARIES foo bar)
# add_debug_variants(SOME_LIRARIES "${SOME_LIRARIES}" d)
# "foo bar" -> "optimized foo debug food optimized bar debug bard"
# or
# set(SOME_LIRARIES path/foo.lib)
# add_debug_variants(SOME_LIRARIES "${SOME_LIRARIES}" "d")
# "path/foo.lib" -> "optimized path/foo.lib debug path/food.lib"
# TODO Could be refined: take the library file extension as a parameter and
# make sure the lib variable ends with not just contains it.
function(add_debug_variants NAME LIBRARIES POSTFIX)
set(LIBRARIES_STR "${LIBRARIES}")
set(LIBRARIES "")
# the result, "optimized <lib> debug <lib>", needs to be a list instead of a string
foreach(lib ${LIBRARIES_STR})
list(APPEND LIBRARIES optimized)
if ("${lib}" MATCHES ".lib")
string(REPLACE ".lib" "" lib ${lib})
list(APPEND LIBRARIES ${lib}.lib)
else()
list(APPEND LIBRARIES ${lib})
endif()
list(APPEND LIBRARIES debug)
if ("${lib}" MATCHES ".lib")
string(REPLACE ".lib" "" lib ${lib})
list(APPEND LIBRARIES ${lib}${POSTFIX}.lib)
else()
list(APPEND LIBRARIES ${lib}${POSTFIX})
endif()
endforeach()
set(${NAME} ${LIBRARIES} PARENT_SCOPE)
endfunction()
# Find Open CASCADE
IF("${OCC_INCLUDE_DIR}" STREQUAL "")
SET(OCC_INCLUDE_DIR "/usr/include/oce/" CACHE FILEPATH "Open CASCADE header files")
MESSAGE(STATUS "Looking for Open CASCADE include files in: ${OCC_INCLUDE_DIR}")
MESSAGE(STATUS "Use OCC_INCLUDE_DIR to specify another directory")
ELSE()
SET(OCC_INCLUDE_DIR $ENV{OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files")
MESSAGE(STATUS "Looking for opencascade include files in: ${OCC_INCLUDE_DIR}")
SET(OCC_INCLUDE_DIR ${OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files")
MESSAGE(STATUS "Looking for Open CASCADE include files in: ${OCC_INCLUDE_DIR}")
ENDIF()
FIND_FILE(gp_Pnt_hxx "gp_Pnt.hxx" ${OCC_INCLUDE_DIR} /usr/inc /usr/local/inc /usr/local/include/oce)
FIND_FILE(gp_Pnt_hxx "gp_Pnt.hxx" ${OCC_INCLUDE_DIR})
IF(gp_Pnt_hxx)
MESSAGE(STATUS "Header files found")
ELSE()
MESSAGE(FATAL_ERROR "Unable to find header files, aborting")
ENDIF()
# Find Open CASCADE library files
IF("$ENV{OCC_LIBRARY_DIR}" STREQUAL "")
SET(OPENCASCADE_LIBRARY_NAMES
TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO
TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset
)
IF("${OCC_LIBRARY_DIR}" STREQUAL "")
SET(OCC_LIBRARY_DIR "/usr/lib/" CACHE FILEPATH "Open CASCADE library files")
MESSAGE(STATUS "Looking for opencascade library files in: ${OCC_LIBRARY_DIR}")
MESSAGE(STATUS "Looking for Open CASCADE library files in: ${OCC_LIBRARY_DIR}")
MESSAGE(STATUS "Use OCC_LIBRARY_DIR to specify another directory")
ELSE()
SET(OCC_LIBRARY_DIR $ENV{OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files")
MESSAGE(STATUS "Looking for opencascade library files in: ${OCC_LIBRARY_DIR}")
SET(OCC_LIBRARY_DIR ${OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files")
MESSAGE(STATUS "Looking for Open CASCADE library files in: ${OCC_LIBRARY_DIR}")
ENDIF()
FIND_LIBRARY(libTKernel "TKernel" ${OCC_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64)
FIND_LIBRARY(libTKernel NAMES TKernel TKerneld PATHS ${OCC_LIBRARY_DIR} NO_DEFAULT_PATH)
IF(libTKernel)
MESSAGE(STATUS "Library files found")
ELSE()
MESSAGE(FATAL_ERROR "Unable to find library files, aborting")
ENDIF()
IF("$ENV{ICU_INCLUDE_DIR}" STREQUAL "")
MESSAGE(STATUS "No ICU include directory specified")
ElSE()
SET(ICU_INCLUDE_DIR CACHE FILEPATH "ICU header files")
# Use the found libTKernel as a template for all other OCC libraries
# TODO Extract this into macro/function
foreach(lib ${OPENCASCADE_LIBRARY_NAMES})
# Make sure we'll handle the Windows/MSVC debug postfix convetion too.
string(REPLACE TKerneld "${lib}" lib_path "${libTKernel}")
string(REPLACE TKernel "${lib}" lib_path "${lib_path}")
list(APPEND OPENCASCADE_LIBRARIES "${lib_path}")
endforeach()
if(MSVC)
add_definitions(-DHAVE_NO_DLL)
add_debug_variants(OPENCASCADE_LIBRARIES "${OPENCASCADE_LIBRARIES}" d)
endif()
if (WIN32)
# OCC might require linking to Winsock depending on the version and build configuration
list(APPEND OPENCASCADE_LIBRARIES ws2_32.lib)
endif()
IF(UNICODE_SUPPORT)
# Find ICU
IF("${ICU_INCLUDE_DIR}" STREQUAL "")
MESSAGE(STATUS "No ICU include directory specified")
ENDIF()
IF("${ICU_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No ICU library directory specified")
FIND_LIBRARY(icu NAMES icuuc icuucd PATHS ${ICU_LIBRARY_DIR})
ELSE()
FIND_LIBRARY(icu NAMES icuuc icuucd PATHS ${ICU_LIBRARY_DIR} NO_DEFAULT_PATH)
ENDIF()
IF(icu)
GET_FILENAME_COMPONENT(ICU_LIBRARY_DIR ${icu} PATH)
ADD_DEFINITIONS(-DHAVE_ICU)
MESSAGE(STATUS "ICU libraries found")
# NOTE icudata appears to be icudt on Windows/MSVC and icudata on others
# dl is included to resolve dlopen and friends symbols
IF(WIN32)
FIND_LIBRARY(icudt NAMES icudt PATHS ${ICU_LIBRARY_DIR} NO_DEFAULT_PATH)
SET(ICU_LIBRARIES ${icu} ${icudt})
add_debug_variants(ICU_LIBRARIES "${ICU_LIBRARIES}" d)
# TODO MinGW build would appear to be using dynamic ICU regardless of this definition.
ADD_DEFINITIONS(-DU_STATIC_IMPLEMENTATION) # required for static ICU
ELSE()
FIND_LIBRARY(icudt NAMES icudata PATHS ${ICU_LIBRARY_DIR} NO_DEFAULT_PATH)
FIND_LIBRARY(icui18n NAMES icui18n PATHS ${ICU_LIBRARY_DIR} NO_DEFAULT_PATH)
FIND_LIBRARY(dl NAMES dl)
SET(ICU_LIBRARIES ${icu} ${icudt} ${dl} ${icui18n})
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR "UNICODE_SUPPORT enabled, but unable to find ICU. Disable UNICODE_SUPPORT or fix ICU paths to proceed.")
ENDIF()
ENDIF()
IF("$ENV{ICU_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No ICU library directory specified")
ElSE()
SET(ICU_LIBRARY_DIR CACHE FILEPATH "ICU library files")
IF(COLLADA_SUPPORT)
# Find OpenCOLLADA
IF("${OPENCOLLADA_INCLUDE_DIR}" STREQUAL "")
MESSAGE(STATUS "No OpenCOLLADA include directory specified")
SET(OPENCOLLADA_INCLUDE_DIR "/usr/include/opencollada" CACHE FILEPATH "OpenCOLLADA header files")
ELSE()
SET(OPENCOLLADA_INCLUDE_DIR "${OPENCOLLADA_INCLUDE_DIR}" CACHE FILEPATH "OpenCOLLADA header files")
ENDIF()
IF("${OPENCOLLADA_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No OpenCOLLADA library directory specified")
FIND_LIBRARY(OPENCOLLADA_FRAMEWORK_LIB NAMES OpenCOLLADAFramework
PATHS /usr/lib64/opencollada /usr/lib/opencollada /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib)
GET_FILENAME_COMPONENT(OPENCOLLADA_LIBRARY_DIR ${OPENCOLLADA_FRAMEWORK_LIB} PATH)
ENDIF()
FIND_LIBRARY(OpenCOLLADAFramework NAMES OpenCOLLADAFramework OpenCOLLADAFrameworkd PATHS ${OPENCOLLADA_LIBRARY_DIR} NO_DEFAULT_PATH)
if (OpenCOLLADAFramework)
message(STATUS "OpenCOLLADA library files found")
else()
message(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find OpenCOLLADA libraries. "
"Disable COLLADA_SUPPORT or fix OpenCOLLADA paths to proceed.")
endif()
SET(OPENCOLLADA_LIBRARY_DIR "${OPENCOLLADA_LIBRARY_DIR}" CACHE FILEPATH "OpenCOLLADA library files")
SET(OPENCOLLADA_INCLUDE_DIRS "${OPENCOLLADA_INCLUDE_DIR}/COLLADABaseUtils" "${OPENCOLLADA_INCLUDE_DIR}/COLLADAStreamWriter")
FIND_FILE(COLLADASWStreamWriter_h "COLLADASWStreamWriter.h" ${OPENCOLLADA_INCLUDE_DIRS})
IF(COLLADASWStreamWriter_h)
MESSAGE(STATUS "OpenCOLLADA header files found")
ADD_DEFINITIONS(-DWITH_OPENCOLLADA)
SET(OPENCOLLADA_LIBRARY_NAMES
GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader
OpenCOLLADAStreamWriter UTF buffer ftoa
)
# Use the found OpenCOLLADAFramework as a template for all other OpenCOLLADA libraries
foreach(lib ${OPENCOLLADA_LIBRARY_NAMES})
# Make sure we'll handle the Windows/MSVC debug postfix convetion too.
string(REPLACE OpenCOLLADAFrameworkd "${lib}" lib_path "${OpenCOLLADAFramework}")
string(REPLACE OpenCOLLADAFramework "${lib}" lib_path "${lib_path}")
list(APPEND OPENCOLLADA_LIBRARIES "${lib_path}")
endforeach()
if("${PCRE_LIBRARY_DIR}" STREQUAL "")
if(WIN32)
find_library(pcre_library NAMES pcre pcred PATHS ${OPENCOLLADA_LIBRARY_DIR} NO_DEFAULT_PATH)
else()
find_library(pcre_library NAMES pcre PATHS ${OPENCOLLADA_LIBRARY_DIR})
endif()
GET_FILENAME_COMPONENT(PCRE_LIBRARY_DIR ${pcre_library} PATH)
else()
find_library(pcre_library NAMES pcre pcred PATHS ${PCRE_LIBRARY_DIR} NO_DEFAULT_PATH)
endif()
if (pcre_library)
SET(OPENCOLLADA_LIBRARY_DIR ${OPENCOLLADA_LIBRARY_DIR} ${PCRE_LIBRARY_DIR})
if (MSVC)
# Add release lib regardless whether release or debug found. Debug version will be appended below.
list(APPEND OPENCOLLADA_LIBRARIES "${PCRE_LIBRARY_DIR}/pcre.lib")
else()
list(APPEND OPENCOLLADA_LIBRARIES "${pcre_library}")
endif()
else()
message(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find PCRE. "
"Disable COLLADA_SUPPORT or fix PCRE_LIBRARY_DIR path to proceed.")
endif()
IF(MSVC)
add_debug_variants(OPENCOLLADA_LIBRARIES "${OPENCOLLADA_LIBRARIES}" d)
ENDIF()
ELSE()
message(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find OpenCOLLADA headers. "
"Disable COLLADA_SUPPORT or fix OpenCOLLADA paths to proceed.")
ENDIF()
ENDIF()
FIND_LIBRARY(icu "icuuc" /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR})
IF(icu)
MESSAGE(STATUS "ICU libraries found")
ADD_DEFINITIONS(-DHAVE_ICU)
ELSE()
MESSAGE(STATUS "Unable to find ICU library files, continuing")
ENDIF()
IF("$ENV{OPENCOLLADA_INCLUDE_DIR}" STREQUAL "")
MESSAGE(STATUS "No OpenCOLLADA include directory specified")
SET(OPENCOLLADA_INCLUDE_DIR "/usr/local/include/opencollada" CACHE FILEPATH "OpenCOLLADA header files")
ElSE()
SET(OPENCOLLADA_INCLUDE_DIR "$ENV{OPENCOLLADA_INCLUDE_DIR}" CACHE FILEPATH "OpenCOLLADA header files")
ENDIF()
IF("$ENV{OPENCOLLADA_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No OpenCOLLADA library directory specified")
SET(OPENCOLLADA_LIBRARY_DIR "/usr/local/lib/opencollada" CACHE FILEPATH "OpenCOLLADA library files")
ElSE()
SET(OPENCOLLADA_LIBRARY_DIR "$ENV{OPENCOLLADA_LIBRARY_DIR}" CACHE FILEPATH "OpenCOLLADA library files")
ENDIF()
SET(OPENCOLLADA_INCLUDE_DIRS "${OPENCOLLADA_INCLUDE_DIR}/COLLADABaseUtils" "${OPENCOLLADA_INCLUDE_DIR}/COLLADAStreamWriter")
FIND_FILE(COLLADASWStreamWriter_h "COLLADASWStreamWriter.h" ${OPENCOLLADA_INCLUDE_DIRS})
IF(COLLADASWStreamWriter_h)
MESSAGE(STATUS "OpenCOLLADA header files found")
ADD_DEFINITIONS(-DWITH_OPENCOLLADA)
SET(OPENCOLLADA_LIBRARIES
GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils
OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader
OpenCOLLADAStreamWriter UTF buffer ftoa pcre
)
ELSE()
MESSAGE(STATUS "OpenCOLLADA header files not found, continuing without COLLADA support")
ENDIF()
INCLUDE(CheckIncludeFileCXX)
MACRO(CHECK_ADD_OCE_OCC_DEF INCLUDE)
STRING(REPLACE . _ STR ${INCLUDE})
STRING(TOUPPER ${STR} STR)
CHECK_INCLUDE_FILE_CXX("${INCLUDE}" FOUND_${STR})
IF(FOUND_${STR})
ADD_DEFINITIONS(-DOCE_HAVE_${STR})
ADD_DEFINITIONS(-DHAVE_${STR})
ENDIF(FOUND_${STR})
ENDMACRO(CHECK_ADD_OCE_OCC_DEF)
CHECK_ADD_OCE_OCC_DEF(limits)
CHECK_ADD_OCE_OCC_DEF(climits)
CHECK_ADD_OCE_OCC_DEF(limits.h)
CHECK_ADD_OCE_OCC_DEF(fstream)
CHECK_ADD_OCE_OCC_DEF(fstream.h)
CHECK_ADD_OCE_OCC_DEF(iomanip)
CHECK_ADD_OCE_OCC_DEF(iomanip.h)
CHECK_ADD_OCE_OCC_DEF(iostream)
CHECK_ADD_OCE_OCC_DEF(iostream.h)
# Make sure cross-referenced symbols between static OCC libraries get
# resolved. Also add thread and rt libraries.
get_filename_component(libTKernelExt ${libTKernel} EXT)
if("${libTKernelExt}" STREQUAL ".a")
find_package(Threads)
# 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})
if (NOT APPLE AND NOT WIN32)
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} "rt")
endif()
if (NOT WIN32)
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} "dl")
endif()
endif()
IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE "Release")
ENDIF(NOT CMAKE_BUILD_TYPE)
IF(MSVC)
ADD_DEFINITIONS(-D_UNICODE)
ElSE(MSVC)
ADD_DEFINITIONS(-fPIC -Wno-non-virtual-dtor)
ENDIF(MSVC)
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} /usr/inc /usr/local/inc /usr/local/include/oce ${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS})
ADD_LIBRARY(IfcParse STATIC
../src/ifcparse/Ifc2x3-latebound.cpp
../src/ifcparse/Ifc2x3.cpp
../src/ifcparse/Ifc4-latebound.cpp
../src/ifcparse/Ifc4.cpp
../src/ifcparse/IfcCharacterDecoder.cpp
../src/ifcparse/IfcGuidHelper.cpp
../src/ifcparse/IfcHierarchyHelper.cpp
../src/ifcparse/IfcLateBoundEntity.cpp
../src/ifcparse/IfcParse.cpp
../src/ifcparse/IfcSIPrefix.cpp
../src/ifcparse/IfcSpfHeader.cpp
../src/ifcparse/IfcUtil.cpp
../src/ifcparse/IfcWrite.cpp
)
ADD_LIBRARY(IfcGeom STATIC
../src/ifcgeom/IfcGeomCurves.cpp
../src/ifcgeom/IfcGeomFaces.cpp
../src/ifcgeom/IfcGeomFunctions.cpp
../src/ifcgeom/IfcGeomHelpers.cpp
../src/ifcgeom/IfcGeomMaterial.cpp
../src/ifcgeom/IfcGeomRenderStyles.cpp
../src/ifcgeom/IfcGeomRepresentation.cpp
../src/ifcgeom/IfcGeomShapes.cpp
../src/ifcgeom/IfcGeomWires.cpp
../src/ifcgeom/IfcRegister.cpp
)
IF(icu)
TARGET_LINK_LIBRARIES(IfcParse icuuc)
SET(CMAKE_BUILD_TYPE "Release")
ENDIF()
TARGET_LINK_LIBRARIES(IfcGeom IfcParse)
if(ENABLE_BUILD_OPTIMIZATIONS)
if(MSVC)
# NOTE: RelWithDebInfo and Release use O2 (= /Ox /Gl /Gy/ = Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy) by default,
# with the exception with RelWithDebInfo has /Ob1 instead. /Ob2 has been observed to improve the performance
# of IfcConvert significantly.
# TODO Setting of /GL and /LTCG don't seem to apply for static libraries (IfcGeom, IfcParse)
# C++
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /GL")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
# Linker
# /OPT:REF enables also /OPT:ICF and disables INCREMENTAL
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
# /OPT:NOICF is recommended when /DEBUG is used (http://msdn.microsoft.com/en-us/library/xe4t6fc1.aspx)
set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
else()
# GCC-like: Release should use O3 but RelWithDebInfo 02 so enforce 03. Anything other useful that could be added here?
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -O3")
endif()
endif()
LINK_DIRECTORIES (${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} ${OPENCOLLADA_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS})
IF(MSVC)
# Enable solution folders (free VS versions prior to 2012 don't support solution folders)
if (MSVC_VERSION GREATER 1600)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
endif()
ADD_EXECUTABLE(IfcConvert
../src/ifcconvert/ColladaSerializer.cpp
../src/ifcconvert/IfcConvert.cpp
../src/ifcconvert/OpenCascadeBasedSerializer.cpp
../src/ifcconvert/WavefrontObjSerializer.cpp
../src/ifcconvert/XmlSerializer.cpp
IF(USE_VLD)
ADD_DEFINITIONS(-DUSE_VLD)
ENDIF()
# Enforce Unicode for CRT and Win32 API calls
ADD_DEFINITIONS(-D_UNICODE -DUNICODE)
# Disable warnings about unsafe C functions; we could use the safe C99 & C11 versions if we have no need for supporting old compilers.
ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS)
ADD_DEFINITIONS(-bigobj) # required for building the big ifcXXX.objs, https://msdn.microsoft.com/en-us/library/ms173499.aspx
# Bump up the warning level from the default 3 to 4.
ADD_DEFINITIONS(-W4)
IF(MSVC_VERSION GREATER 1800) # > 2013
# Disable overeager and false positives causing C4458 ("declaration of 'indentifier' hides class member"), at least for now.
ADD_DEFINITIONS(-wd4458)
ENDIF()
# 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")
add_definitions(-Wno-tautological-constant-out-of-range-compare)
endif()
# -fPIC is not relevant on Windows and creates pointless warnings
if (UNIX)
add_definitions(-fPIC)
endif()
ENDIF()
if (IFCCONVERT_DOUBLE_PRECISION)
SET(CONVERT_PRECISION "-DIFCCONVERT_DOUBLE_PRECISION")
endif()
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS}
${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS}
)
TARGET_LINK_LIBRARIES (IfcConvert IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES})
function(files_for_ifc_version IFC_VERSION RESULT_NAME)
set(IFC_PARSE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcparse)
set(${RESULT_NAME}
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.h
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}enum.h
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.cpp
PARENT_SCOPE
)
endfunction()
ADD_EXECUTABLE(IfcGeomServer
../src/ifcgeomserver/IfcGeomServer.cpp
)
if(COMPILE_SCHEMA)
find_package(PythonInterp)
IF(NOT PYTHONINTERP_FOUND)
MESSAGE(FATAL_ERROR "A Python interpreter is necessary when COMPILE_SCHEMA is enabled. Disable COMPILE_SCHEMA or fix Python paths to proceed.")
ENDIF()
set(IFC_RELEASE_NOT_USED "2x3" "4")
# Install pyparsing if necessary
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST)
if ("${PYTHON_PACKAGE_LIST}" STREQUAL "")
execute_process(COMMAND pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST)
if ("${PYTHON_PACKAGE_LIST}" STREQUAL "")
message(WARNING "Failed to find pip. Pip is required to automatically install pyparsing")
endif()
endif()
string(FIND "${PYTHON_PACKAGE_LIST}" pyparsing PYPARSING_FOUND)
if ("${PYPARSING_FOUND}" STREQUAL "-1")
message(STATUS "Installing pyparsing")
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip "install" --user pyparsing RESULT_VARIABLE SUCCESS)
if (NOT "${SUCCESS}" STREQUAL "0")
execute_process(COMMAND pip "install" --user pyparsing RESULT_VARIABLE SUCCESS)
if (NOT "${SUCCESS}" STREQUAL "0")
message(WARNING "Failed to automatically install pyparsing. Please install manually")
endif()
endif()
else()
message(STATUS "Python interpreter with pyparsing found")
endif()
# Bootstrap the parser
message(STATUS "Compiling schema, this will take a while...")
execute_process(COMMAND ${PYTHON_EXECUTABLE} bootstrap.py express.bnf
WORKING_DIRECTORY ../src/ifcexpressparser
OUTPUT_FILE express_parser.py
RESULT_VARIABLE SUCCESS)
TARGET_LINK_LIBRARIES (IfcGeomServer IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset)
if (NOT "${SUCCESS}" STREQUAL "0")
MESSAGE(FATAL_ERROR "Failed to bootstrap parser. Make sure pyparsing is installed")
endif()
# Generate code
execute_process(COMMAND ${PYTHON_EXECUTABLE} ../ifcexpressparser/express_parser.py ../../${COMPILE_SCHEMA}
WORKING_DIRECTORY ../src/ifcparse
OUTPUT_VARIABLE COMPILED_SCHEMA_NAME)
# Prevent the schema that had just been compiled from being excluded
if("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC2X3")
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "2x3")
add_definitions(-DUSE_IFC2x3)
elseif("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC4")
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "4")
add_definitions(-DUSE_IFC4)
endif()
endif()
# Build python wrapper using separate CMakeLists.txt
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
# Boost >= 1.58 requires BOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE to build on some Linux distros.
if(NOT Boost_VERSION LESS 105800)
add_definitions(-DBOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE)
endif()
# Build IfcParseExamples using separate CMakeLists.txt
ADD_SUBDIRECTORY(../src/examples examples)
# Detect OCC version on gcc/clang/mingw as
# -std=c++11 is needed for OCCT >= 7.0.0
if(NOT MSVC)
FIND_FILE(Standard_Version "Standard_Version.hxx" ${OCC_INCLUDE_DIR})
# ADD_SUBDIRECTORY(../src/qtviewer qtviewer)
set(CMAKE_CONFIGURABLE_FILE_CONTENT "
#include <Standard_Version.hxx>
#include <iostream>
int main(int argc, char** argv) {
std::cout << OCC_VERSION_COMPLETE;
}")
configure_file(
"${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
"${CMAKE_BINARY_DIR}/version.cxx" @ONLY)
try_compile(VERSION_CHECK
${CMAKE_BINARY_DIR}
"${CMAKE_BINARY_DIR}/version.cxx"
CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${OCC_INCLUDE_DIR}"
COPY_FILE "${CMAKE_BINARY_DIR}/version"
OUTPUT_VARIABLE OUT
COPY_FILE_ERROR ERR
)
if(${VERSION_CHECK})
EXECUTE_PROCESS(COMMAND ${CMAKE_BINARY_DIR}/version OUTPUT_VARIABLE OCC_VERSION)
else()
message(FATAL_ERROR "Failed to compile OCC version test:
${OUT}
------
${ERR}")
endif()
MESSAGE(STATUS "OCC version is ${OCC_VERSION}. Detected from: ${Standard_Version}")
if(NOT ("${OCC_VERSION}" LESS "7.0.0"))
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
if(COMPILER_SUPPORTS_CXX11)
add_definitions(-std=c++11)
else()
message(FATAL_ERROR "OCCT7 requires a compiler with C++11 support")
endif()
else()
add_definitions(-std=c++0x)
endif()
endif()
set(IFCOPENSHELL_LIBRARIES IfcParse IfcGeom_ifc2x3 IfcGeom_ifc4 IfcGeom IfcGeom_ifc2x3 IfcGeom_ifc4 IfcGeom Serializers_ifc2x3 Serializers_ifc4 Serializers Serializers_ifc2x3 Serializers_ifc4 Serializers)
# IfcParse
file(GLOB IFCPARSE_H_FILES ../src/ifcparse/*.h)
file(GLOB IFCPARSE_CPP_FILES ../src/ifcparse/*.cpp)
set(IFCPARSE_FILES ${IFCPARSE_CPP_FILES} ${IFCPARSE_H_FILES})
add_library(IfcParse ${IFCPARSE_FILES})
set_target_properties(IfcParse PROPERTIES COMPILE_FLAGS -DIFC_PARSE_EXPORTS)
TARGET_LINK_LIBRARIES(IfcParse ${Boost_LIBRARIES} ${BCRYPT_LIBRARIES})
IF(UNICODE_SUPPORT)
TARGET_LINK_LIBRARIES(IfcParse ${ICU_LIBRARIES})
ENDIF()
# IfcGeom
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/*.h)
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp)
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES})
add_library(IfcGeom_ifc2x3 ${IFCGEOM_FILES})
add_library(IfcGeom_ifc4 ${IFCGEOM_FILES})
set_target_properties(IfcGeom_ifc2x3 PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc2x3")
# TODO: Detect based on IfcSchema
set_target_properties(IfcGeom_ifc4 PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc4 -DUSE_IFC4")
TARGET_LINK_LIBRARIES(IfcGeom_ifc2x3 IfcParse ${OPENCASCADE_LIBRARIES})
TARGET_LINK_LIBRARIES(IfcGeom_ifc4 IfcParse ${OPENCASCADE_LIBRARIES})
# 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)
set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES})
add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES})
set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS)
TARGET_LINK_LIBRARIES(IfcGeom IfcGeom_ifc2x3 IfcGeom_ifc4)
# Serializers
file(GLOB SERIALIZERS_H_FILES ../src/serializers/*.h)
file(GLOB SERIALIZERS_CPP_FILES ../src/serializers/*.cpp)
set(SERIALIZERS_FILES ${SERIALIZERS_H_FILES} ${SERIALIZERS_CPP_FILES})
file(GLOB SERIALIZERS_S_H_FILES ../src/serializers/schema_dependent/*.h)
file(GLOB SERIALIZERS_S_CPP_FILES ../src/serializers/schema_dependent/*.cpp)
set(SERIALIZERS_S_FILES ${SERIALIZERS_S_H_FILES} ${SERIALIZERS_S_CPP_FILES})
add_library(Serializers_ifc2x3 ${SERIALIZERS_S_FILES})
add_library(Serializers_ifc4 ${SERIALIZERS_S_FILES})
set_target_properties(Serializers_ifc2x3 PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc2x3 ${CONVERT_PRECISION}")
# TODO: Detect based on IfcSchema
set_target_properties(Serializers_ifc4 PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc4 -DUSE_IFC4 ${CONVERT_PRECISION}")
TARGET_LINK_LIBRARIES(Serializers_ifc2x3 IfcGeom ${OPENCASCADE_LIBRARIES})
TARGET_LINK_LIBRARIES(Serializers_ifc4 IfcGeom ${OPENCASCADE_LIBRARIES})
add_library(Serializers ${SERIALIZERS_FILES})
set_target_properties(Serializers PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS ${CONVERT_PRECISION}")
TARGET_LINK_LIBRARIES(Serializers Serializers_ifc2x3 Serializers_ifc4)
# IfcConvert
if(BUILD_CONVERT)
file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp)
file(GLOB IFCCONVERT_H_FILES ../src/ifcconvert/*.h)
set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES})
ADD_EXECUTABLE(IfcConvert ${IFCCONVERT_FILES})
set_target_properties(IfcConvert PROPERTIES COMPILE_FLAGS "${CONVERT_PRECISION}")
TARGET_LINK_LIBRARIES(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${ICU_LIBRARIES})
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
# Only set RPATHs when building shared libraries (i.e. IfcParse and
# IfcGeom are dynamically linked). Not necessarily a perfect solution
# but probably a good indication of whether RPATHs are necessary.
SET_INSTALL_RPATHS(IfcConvert "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS};${OPENCOLLADA_LIBRARY_DIR};${ICU_LIBRARY_DIR}")
endif()
INSTALL(TARGETS IfcConvert
ARCHIVE DESTINATION ${LIBDIR}
LIBRARY DESTINATION ${LIBDIR}
RUNTIME DESTINATION ${BINDIR}
)
endif()
# IfcGeomServer
if(BUILD_GEOMSERVER)
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} ${ICU_LIBRARIES})
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
SET_INSTALL_RPATHS(IfcGeomServer "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS};${ICU_LIBRARY_DIR}")
INSTALL(TARGETS IfcGeomServer
ARCHIVE DESTINATION ${LIBDIR}
LIBRARY DESTINATION ${LIBDIR}
RUNTIME DESTINATION ${BINDIR}
)
endif()
endif()
IF(BUILD_IFCPYTHON)
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
ENDIF()
IF(BUILD_EXAMPLES)
ADD_SUBDIRECTORY(../src/examples examples)
ENDIF()
IF(BUILD_IFCMAX)
ADD_SUBDIRECTORY(../src/ifcmax ifcmax)
ENDIF()
# CMake installation targets
SET(include_files_geom
../src/ifcgeom/IfcGeom.h
../src/ifcgeom/IfcGeomElement.h
../src/ifcgeom/IfcGeomIterator.h
../src/ifcgeom/IfcGeomIteratorSettings.h
../src/ifcgeom/IfcGeomMaterial.h
../src/ifcgeom/IfcGeomRenderStyles.h
../src/ifcgeom/IfcGeomRepresentation.h
../src/ifcgeom/IfcRegister.h
../src/ifcgeom/IfcRegisterConvertCurve.h
../src/ifcgeom/IfcRegisterConvertFace.h
../src/ifcgeom/IfcRegisterConvertShape.h
../src/ifcgeom/IfcRegisterConvertShapes.h
../src/ifcgeom/IfcRegisterConvertWire.h
../src/ifcgeom/IfcRegisterCreateCache.h
../src/ifcgeom/IfcRegisterDef.h
../src/ifcgeom/IfcRegisterGeomHeader.h
../src/ifcgeom/IfcRegisterIsShapeCollection.h
../src/ifcgeom/IfcRegisterPurgeCache.h
../src/ifcgeom/IfcRegisterUndef.h
../src/ifcgeom/IfcRepresentationShapeItem.h
INSTALL(FILES ${IFCPARSE_H_FILES}
DESTINATION ${INCLUDEDIR}/ifcparse
)
SET(include_files_parse
../src/ifcparse/Ifc2x3-latebound.h
../src/ifcparse/Ifc2x3.h
../src/ifcparse/Ifc2x3enum.h
../src/ifcparse/Ifc4-latebound.h
../src/ifcparse/Ifc4.h
../src/ifcparse/Ifc4enum.h
../src/ifcparse/IfcCharacterDecoder.h
../src/ifcparse/IfcEntityDescriptor.h
../src/ifcparse/IfcException.h
../src/ifcparse/IfcFile.h
../src/ifcparse/IfcHierarchyHelper.h
../src/ifcparse/IfcLateBoundEntity.h
../src/ifcparse/IfcParse.h
../src/ifcparse/IfcSIPrefix.h
../src/ifcparse/IfcSpfHeader.h
../src/ifcparse/IfcSpfStream.h
../src/ifcparse/IfcUtil.h
../src/ifcparse/IfcWritableEntity.h
../src/ifcparse/IfcWrite.h
../src/ifcparse/SharedPointer.h
INSTALL(FILES ${IFCGEOM_H_FILES}
DESTINATION ${INCLUDEDIR}/ifcgeom
)
INSTALL(FILES ${SCHEMA_AGNOSTIC_H_FILES}
DESTINATION ${INCLUDEDIR}/ifcgeom_schema_agnostic
)
INSTALL(TARGETS IfcParse IfcGeom_ifc2x3 IfcGeom_ifc4
ARCHIVE DESTINATION ${LIBDIR}
LIBRARY DESTINATION ${LIBDIR}
RUNTIME DESTINATION ${BINDIR}
)
INSTALL(FILES ${include_files_geom} DESTINATION include/ifcgeom)
INSTALL(FILES ${include_files_parse} DESTINATION include/ifcparse)
INSTALL(TARGETS IfcConvert DESTINATION bin)
INSTALL(TARGETS IfcParse IfcGeom DESTINATION lib)
+29
View File
@@ -0,0 +1,29 @@
mkdir build && cd build
REM Remove dot from PY_VER for use in library name
REM From https://github.com/tpaviot/pythonocc-core/blob/master/ci/conda/bld.bat
set MY_PY_VER=%PY_VER:.=%
cmake -G "NMake Makefiles" ^
-DCMAKE_INSTALL_PREFIX="%LIBRARY_PREFIX%" ^
-DCMAKE_BUILD_TYPE=Release ^
-DCMAKE_PREFIX_PATH="%LIBRARY_PREFIX%" ^
-DCMAKE_SYSTEM_PREFIX_PATH="%LIBRARY_PREFIX%" ^
-DPYTHON_EXECUTABLE="%PYTHON%" ^
-DPYTHON_INCLUDE_DIR="%PREFIX%"/include ^
-DPYTHON_LIBRARY="%PREFIX%"/libs/python%MY_PY_VER%.lib ^
-DBOOST_LIBRARYDIR="%LIBRARY_PREFIX%\lib" ^
-DBOOST_INCLUDEDIR="%LIBRARY_PREFIX%\include" ^
-DOCC_INCLUDE_DIR="%LIBRARY_PREFIX%\include\oce" ^
-DOCC_LIBRARY_DIR="%LIBRARY_PREFIX%\lib" ^
-DCOLLADA_SUPPORT=Off ^
-DBUILD_EXAMPLES=Off ^
-DBUILD_GEOMSERVER=Off ^
-DBUILD_CONVERT=Off ^
../cmake
if errorlevel 1 exit 1
cmake --build . --target INSTALL --config Release
if errorlevel 1 exit 1
+34
View File
@@ -0,0 +1,34 @@
# From https://github.com/tpaviot/pythonocc-core/blob/master/ci/conda/build.sh
if [ "$PY3K" == "1" ]; then
MY_PY_VER="${PY_VER}m"
else
MY_PY_VER="${PY_VER}"
fi
if [ `uname` == Darwin ]; then
PY_LIB="libpython${MY_PY_VER}.dylib"
export CFLAGS="$CFLAGS -Wl,-flat_namespace,-undefined,suppress"
export CXXFLAGS="$CXXFLAGS -Wl,-flat_namespace,-undefined,suppress"
export LDFLAGS="$LDFLAGS -Wl,-flat_namespace,-undefined,suppress"
else
PY_LIB="libpython${MY_PY_VER}.so"
fi
mkdir build && cd build
cmake \
-DCMAKE_INSTALL_PREFIX=$PREFIX \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH=$PREFIX \
-DCMAKE_SYSTEM_PREFIX_PATH=$PREFIX \
-DOCC_INCLUDE_DIR=$PREFIX/include/oce \
-DOCC_LIBRARY_DIR=$PREFIX/lib \
-DPYTHON_EXECUTABLE:FILEPATH=$PYTHON \
-DPYTHON_INCLUDE_DIR:PATH=$PREFIX/include/python$MY_PY_VER \
-DPYTHON_LIBRARY:FILEPATH=$PREFIX/lib/${PY_LIB} \
-DCOLLADA_SUPPORT=Off \
../cmake
make -j$CPU_COUNT _ifcopenshell_wrapper
cd ifcwrap
make install/local
+36
View File
@@ -0,0 +1,36 @@
package:
name: ifcopenshell
version: "0.6.0a1"
source:
git_rev: "v0.6.0a1"
git_url: https://github.com/IfcOpenShell/IfcOpenShell
build:
number: 0
features:
- vc9 # [win and py27]
- vc10 # [win and py34]
- vc14 # [win and py35]
- vc14 # [win and py36]
requirements:
build:
- gcc # [osx]
- make
- python
- oce ==0.18.3
- cmake
- swig >=3.0.9
- libboost
- icu
run:
- libgcc # [osx]
- python
- oce ==0.18.3
- libboost
- icu
about:
home: http://ifcopenshell.org
license: LGPL
+619
View File
@@ -0,0 +1,619 @@
#!/usr/bin/python
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
###############################################################################
# #
# This script builds IfcOpenShell and its dependencies #
# #
# Prerequisites for this script to function correctly: #
# * git * bzip2 * tar * c(++) compilers * yacc * autoconf #
# #
# if building with USE_OCCT additionally: #
# * freetype * glx.h #
# #
# on debian 7.8 these can be obtained with: #
# $ apt-get install git gcc g++ autoconf bison bzip2 #
# libfreetype6-dev mesa-common-dev #
# #
# on ubuntu 14.04: #
# $ apt-get install git gcc g++ autoconf bison make #
# libfreetype6-dev mesa-common-dev #
# #
# on OS X El Capitan with homebrew: #
# $ brew install git bison autoconf automake freetype #
# #
###############################################################################
import logging
import os
import sys
import subprocess as sp
import shutil
import time
import tarfile
import multiprocessing
import urllib
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
logger.addHandler(ch)
PROJECT_NAME="IfcOpenShell"
OCE_VERSION="0.18"
# OCCT_VERSION="7.1.0"
# OCCT_HASH="89aebde"
OCCT_VERSION="7.2.0"
OCCT_HASH="88af392"
PYTHON_VERSIONS=["2.7.12", "3.2.6", "3.3.6", "3.4.6", "3.5.3", "3.6.2"]
BOOST_VERSION="1.59.0"
PCRE_VERSION="8.39"
LIBXML_VERSION="2.9.3"
CMAKE_VERSION="3.4.1"
ICU_VERSION="56.1"
SWIG_VERSION="3.0.12"
# binaries
cp="cp"
bash="bash"
uname="uname"
git="git"
bunzip2="bunzip2"
tar="tar"
cc="cc"
cplusplus="c++"
autoconf="autoconf"
automake="automake"
yacc="yacc"
make="make"
date = "date"
curl="curl"
wget="wget"
strip="strip"
# Helper function for coloured printing
NO_COLOR="\033[0m" # <ref>http://stackoverflow.com/questions/5947742/how-to-change-the-output-color-of-echo-in-linux</ref>
BLACK_ON_WHITE="\033[0;30;107m"
RED="\033[31m"
GREEN="\033[32m"
YELLOW="\033[33m"
MAGENTA="\033[35m"
def cecho(message, color=NO_COLOR):
"""Logs message `message` in color `color`."""
logger.info("%s%s\033[0m" % (color, message))
def fullpath(arg):
return os.path.realpath(os.path.dirname(sys.argv[1]))
def which(cmd):
for path in os.environ["PATH"].split(":"):
if os.path.exists(path) and cmd in os.listdir(path):
return cmd
return None
def get_os():
ret_value = sp.check_output([uname, "-s"]).strip()
return ret_value
# Set defaults for missing empty environment variables
USE_OCCT = os.environ.get("USE_OCCT", "true").lower() == "true"
TOOLSET = None
if get_os() == "Darwin":
# C++11 features used in OCCT 7+ need a more recent stdlib
TOOLSET = "10.9" if USE_OCCT else "10.6"
try:
IFCOS_NUM_BUILD_PROCS = os.environ["IFCOS_NUM_BUILD_PROCS"]
except KeyError:
IFCOS_NUM_BUILD_PROCS=multiprocessing.cpu_count() + 1
os.environ["IFCOS_NUM_BUILD_PROCS"]=str(IFCOS_NUM_BUILD_PROCS)
try:
TARGET_ARCH = os.environ["TARGET_ARCH"]
del os.environ["TARGET_ARCH"]
except KeyError:
TARGET_ARCH = sp.check_output([uname, "-m"]).strip()
CMAKE_DIR=os.path.realpath(os.path.join("..", "cmake"))
try:
DEPS_DIR = os.environ["DEPS_DIR"]
except KeyError:
path = ["..", "build", sp.check_output(uname).strip(), TARGET_ARCH]
if TOOLSET:
path.append(TOOLSET)
DEPS_DIR = os.path.realpath(os.path.join(*path))
os.environ["DEPS_DIR"] = DEPS_DIR
if not os.path.exists(DEPS_DIR):
os.makedirs(DEPS_DIR)
try:
BUILD_CFG=os.environ["BUILD_CFG"]
except KeyError:
BUILD_CFG="RelWithDebInfo"
os.environ["BUILD_CFG"]=BUILD_CFG
# Print build configuration information
cecho ("""This script fetches and builds %s and its dependencies
""" % (PROJECT_NAME,), BLACK_ON_WHITE)
cecho("""Script configuration:
""", GREEN)
cecho("""* Target Architecture = %s""" % (TARGET_ARCH,), MAGENTA)
cecho(" - Whether 32-bit (i686) or 64-bit (x86_64) will be built.")
cecho("""* USE_OCCT = %r""" % (USE_OCCT,), MAGENTA)
if USE_OCCT:
cecho(" - Compiling against official Open Cascade")
else:
cecho(" - Compiling against Open Cascade Community Edition")
cecho("* Dependency Directory = %s" % (DEPS_DIR,), MAGENTA)
cecho(" - The directory where %s dependencies are installed." % (PROJECT_NAME,))
cecho("* Build Config Type = %s" % (BUILD_CFG,), MAGENTA)
cecho(""" - The used build configuration type for the dependencies.
Defaults to RelWithDebInfo if not specified.""")
if BUILD_CFG == "MinSizeRel":
cecho(" WARNING: MinSizeRel build can suffer from a significant performance loss.", RED)
cecho("* IFCOS_NUM_BUILD_PROCS = %s" % (IFCOS_NUM_BUILD_PROCS,), MAGENTA)
cecho(""" - How many compiler processes may be run in parallel.
""")
# Check that required tools are in PATH
for cmd in [git, bunzip2, tar, cc, cplusplus, autoconf, automake, yacc, make, "patch"]:
if which(cmd) is None:
raise ValueError("Required tool '%s' not installed or not added to PATH" % (cmd,))
# identifiers for the download tool (could be less memory consuming as ints, but are more verbose as strings)
download_tool_curl="curl"
download_tool_wget="wget"
download_tool_git = "git"
if which(wget) != None:
download_tool_default = download_tool_wget
elif which(curl) != None:
download_tool_default = download_tool_curl
else:
raise ValueError("No download application found, tried: curl, wget")
CURL = ["curl", "-sL"]
WGET= ["wget", "-q", "--no-check-certificate"]
# Create log directory and file
log_dir = os.path.join(DEPS_DIR, "logs")
if not os.path.exists(log_dir):
os.makedirs(log_dir)
LOG_FILE="%s.log" % (os.path.join(log_dir, sp.check_output([date, "+%Y%m%d"]).strip()),)
if not os.path.exists(LOG_FILE):
open(LOG_FILE, "w").close()
logger.info("using command log file '%s'" % (LOG_FILE,))
def __check_call__(cmds, cwd=None):
logger.debug("running command %r in directory %r" % (" ".join(cmds), cwd))
log_file_handle = open(LOG_FILE, "a")
proc = sp.Popen(cmds, cwd=cwd, stdout=log_file_handle, stderr=sp.PIPE)
_, stderr = proc.communicate()
log_file_handle.write(stderr)
log_file_handle.close()
if proc.returncode != 0:
print "-" * 70
print stderr
print "-" * 70
raise Exception("Command `%s` returned exit code %d" % (" ".join(cmds), proc.returncode))
def __check_output__(cmds, cwd=None):
"""Wraps `subprocess.check_output` and logs the command being executed,
sets up logging `stderr` to `LOG_FILE` (in append mode) and strips the
return value because it's unlikely that the newline at the end of output is
useful and it often causes errors"""
logger.debug("running command '%s' in directory %r" % (" ".join(cmds), cwd))
log_file_handle = open(LOG_FILE, "a")
ret_value = sp.check_output(cmds, cwd=cwd, stderr=log_file_handle).strip()
logger.debug("command returned %r" % ret_value)
log_file_handle.close()
return ret_value
BOOST_VERSION_UNDERSCORE=BOOST_VERSION.replace(".", "_")
ICU_VERSION_UNDERSCORE=ICU_VERSION.replace(".", "_")
CMAKE_VERSION_2=CMAKE_VERSION[:CMAKE_VERSION.rindex('.')]
OCE_LOCATION="https://github.com/tpaviot/oce/archive/OCE-%s.tar.gz" % (OCE_VERSION,)
BOOST_LOCATION="http://downloads.sourceforge.net/project/boost/boost/%s/boost_%s.tar.bz2" % (BOOST_VERSION, BOOST_VERSION_UNDERSCORE)
OPENCOLLADA_LOCATION="https://github.com/KhronosGroup/OpenCOLLADA.git"
OPENCOLLADA_COMMIT="f99d59e73e565a41715eaebc00c7664e1ee5e628"
# Helper functions
def run_autoconf(arg1, configure_args, cwd):
configure_path = os.path.realpath(os.path.join(cwd, "..", "configure"))
if not os.path.exists(configure_path):
__check_call__([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
__check_call__(["/bin/sh", "../configure"]+configure_args+["--prefix=%s" % (os.path.realpath("%s/install/%s" % (DEPS_DIR, arg1)),)], cwd=cwd)
def run_cmake(arg1, cmake_args, cmake_dir=None, cwd=None):
if cmake_dir is None:
P=".."
else:
P=cmake_dir
cmake_path= os.path.join(DEPS_DIR, "install", "cmake-%s" % (CMAKE_VERSION,), "bin", "cmake")
__check_call__([cmake_path, P]+cmake_args+["-DCMAKE_BUILD_TYPE=%s" % (BUILD_CFG,)], cwd=cwd)
def run_icu(arg1, icu_args, cwd):
PLATFORM=get_os()
if PLATFORM == "Darwin":
PLATFORM="MacOSX"
__check_call__([bash, "../source/runConfigureICU", PLATFORM]+icu_args+["--prefix=%s/install/%s" % (DEPS_DIR, arg1)], cwd=cwd)
def git_clone(clone_url, target_dir, revision=None):
"""Lazily clones the `git` repository denoted by `clone_url` into
`target_dir`, i.e. skips cloning if `target_dir` exists (naively assumes
that a working clone exists there) and optionally checks out a revision
`revision` after cloning or in the existing clone if `revision` is not
`None`."""
if not os.path.exists(target_dir):
logger.info("cloning '%s' into '%s'" % (clone_url, target_dir))
__check_call__([git, "clone", clone_url, target_dir])
else:
logger.info("directory '%s' exists, skipping cloning" % (target_dir,))
if revision != None:
__check_call__([git, "checkout", revision], cwd=target_dir)
def build_dependency(name, mode, build_tool_args, download_url, download_name, download_tool=download_tool_default, revision=None, patch=None, additional_files={}, no_append_name=False):
"""Handles building of dependencies with different tools (which are
distinguished with the `mode` argument. `build_tool_args` is expected to be
a list which is necessary in order to not mess up quoting of compiler and
linker flags."""
check_dir = os.path.join(DEPS_DIR, "install", name)
if os.path.exists(check_dir):
logger.info( "Found existing %s, skipping" % (name,))
return
build_dir = os.path.join(DEPS_DIR, "build")
if not os.path.exists(build_dir):
os.makedirs(build_dir)
logger.info("\rFetching %s... " % (name,))
if download_tool == download_tool_curl or download_tool == download_tool_wget:
if no_append_name:
url = download_url
else:
url = os.path.join(download_url, download_name)
if download_tool == download_tool_curl:
download_path = os.path.join(build_dir, download_name)
if not os.path.exists(download_path):
__check_call__(CURL + ["-o", download_name, url], cwd=build_dir)
else:
logger.info("Download '%s' already exists, assuming it's an undamaged download and that it has been extracted if possible, skipping" % (download_path,))
elif download_tool == download_tool_wget:
download_path = os.path.join(build_dir, download_name)
if not os.path.exists(download_path):
__check_call__(WGET + ["-O", download_name, url], cwd=build_dir)
else:
logger.info("Download '%s' already exists, assuming it's an undamaged download and that it has been extracted if possible, skipping" % (download_path,))
elif download_tool == download_tool_git:
git_clone(download_url, target_dir=os.path.join(build_dir, download_name), revision=revision)
else:
raise ValueError("download tool '%s' is not supported" % (download_tool,))
download_dir = os.path.join(build_dir, download_name)
if os.path.isdir(download_dir):
extract_dir_name=download_name
extract_dir = os.path.join(build_dir, extract_dir_name)
else:
download_tarfile_path = os.path.join(build_dir, download_name)
if download_name.endswith(".tar.gz") or download_name.endswith(".tgz"):
compr = "gz"
elif download_name.endswith(".tar.bz2"):
compr = "bz2"
else:
raise RuntimeError("fix source for new download type")
download_tarfile = tarfile.open(name=download_tarfile_path, mode="r:%s" % (compr,))
extract_dir_name= os.path.commonprefix(download_tarfile.getnames()) # tarfile seriously doesn't have a function to retrieve the root directory more easily
#__check_output__([tar, "--exclude=\"*/*\"", "-tf", download_name], cwd=build_dir).strip() no longer works
if extract_dir_name is None:
extract_dir_name= __check_output__([bash, "-c", "tar -tf %s 2> /dev/null | head -n 1 | cut -f1 -d /" % (download_name,)], cwd=build_dir)
extract_dir = os.path.join(build_dir, extract_dir_name)
if not os.path.exists(extract_dir):
__check_call__([tar, "-xf", download_name], cwd=build_dir)
for path, url in additional_files.items():
if not os.path.exists(path):
urllib.urlretrieve(url, os.path.join(extract_dir, path))
if patch is not None:
patch_abs = os.path.abspath(os.path.join(os.path.dirname(__file__), patch))
if os.path.exists(patch_abs):
try: __check_call__(["patch", "-p1", "--batch", "--forward", "-i", patch_abs], cwd=extract_dir)
except Exception as e:
# Assert that the patch has already been applied
__check_call__(["patch", "-p1", "--batch", "--reverse", "--dry-run", "-i", patch_abs], cwd=extract_dir)
if mode != "bjam":
extract_build_dir = os.path.join(extract_dir, "build")
if os.path.exists(extract_build_dir):
shutil.rmtree(extract_build_dir)
os.makedirs(extract_build_dir)
logger.info("\rConfiguring %s..." % (name,))
if mode == "icu":
run_icu(name, build_tool_args, cwd=extract_build_dir)
elif mode == "autoconf":
run_autoconf(name, build_tool_args, cwd=extract_build_dir)
elif mode == "cmake":
run_cmake(name, build_tool_args, cwd=extract_build_dir)
else:
raise ValueError()
logger.info("\rBuilding %s... " % (name,))
__check_call__([make, "-j%s" % (IFCOS_NUM_BUILD_PROCS,)], cwd=extract_build_dir)
logger.info( "\rInstalling %s... " % (name,))
__check_call__([make, "install"], cwd=extract_build_dir)
logger.info( "\rInstalled %s \n" % (name,))
else:
logger.info( "\rConfiguring %s..." % (name,))
__check_call__([bash, "./bootstrap.sh"], cwd=extract_dir)
logger.info("\rBuilding %s... " % (name,))
__check_call__(["./b2", "-j%s" % (IFCOS_NUM_BUILD_PROCS,)]+build_tool_args, cwd=extract_dir)
logger.info("\rInstalling %s... " % (name,))
shutil.copytree(os.path.join(extract_dir, "boost"), os.path.join(DEPS_DIR, "install", "boost-%s" % BOOST_VERSION, "boost"))
logger.info("\rInstalled %s \n" % (name,))
cecho("Collecting dependencies:", GREEN)
# Set compiler flags for 32bit builds on 64bit system
# TODO: This is untested
ADDITIONAL_ARGS=[]
BOOST_ADDRESS_MODEL=[]
if TARGET_ARCH == "i686" and __check_output__([uname, "-m"]).strip() == "x86_64":
ADDITIONAL_ARGS=["-m32", "-arch i386"]
BOOST_ADDRESS_MODEL=["architecture=x86", "address-model=32"]
if get_os() == "Darwin":
ADDITIONAL_ARGS=["-mmacosx-version-min=%s" % TOOLSET]+ADDITIONAL_ARGS
# If the linker supports GC sections, set it up to reduce binary file size
# -fPIC is required for the shared libraries to work
try:
CXXFLAGS=os.environ["CXXFLAGS"]
except KeyError:
CXXFLAGS=""
try:
CFLAGS=os.environ["CFLAGS"]
except KeyError:
CFLAGS=""
try:
LDFLAGS=os.environ["LDFLAGS"]
except KeyError:
LDFLAGS=""
if sp.call([bash, "-c", "ld --gc-sections 2>&1 | grep -- --gc-sections &> /dev/null"]) != 0:
CXXFLAGS_MINIMAL="%s -fPIC %s" % (CXXFLAGS, str.join(" ", ADDITIONAL_ARGS))
os.environ["CXXFLAGS_MINIMAL"]=CXXFLAGS_MINIMAL
CFLAGS_MINIMAL="%s -fPIC %s" % (CFLAGS, str.join(" ", ADDITIONAL_ARGS))
os.environ["CFLAGS_MINIMAL"]=CFLAGS_MINIMAL
CXXFLAGS="%s -fPIC -fdata-sections -ffunction-sections -fvisibility=hidden -fvisibility-inlines-hidden %s" % (CXXFLAGS, str.join(" ", ADDITIONAL_ARGS))
os.environ["CXXFLAGS"]=CXXFLAGS
CFLAGS="%s -fPIC -fdata-sections -ffunction-sections -fvisibility=hidden %s"% (CFLAGS, str.join(" ", ADDITIONAL_ARGS))
os.environ["CFLAGS"]=CFLAGS
LDFLAGS="%s -Wl,--gc-sections %s" % (LDFLAGS, str.join(" ", ADDITIONAL_ARGS))
os.environ["LDFLAGS"]=LDFLAGS
else:
CXXFLAGS_MINIMAL="%s -fPIC %s" % (CXXFLAGS, str.join(" ", ADDITIONAL_ARGS))
os.environ["CXXFLAGS_MINIMAL"]=CXXFLAGS_MINIMAL
CFLAGS_MINIMAL="%s -fPIC %s" % (CFLAGS, str.join(" ", ADDITIONAL_ARGS))
os.environ["CFLAGS_MINIMAL"]=CFLAGS_MINIMAL
CXXFLAGS="%s -fPIC -fvisibility=hidden -fvisibility-inlines-hidden %s" % (CXXFLAGS, str.join(" ", ADDITIONAL_ARGS))
os.environ["CXXFLAGS"]=CXXFLAGS
CFLAGS="%s -fPIC -fvisibility=hidden -fvisibility-inlines-hidden %s" % (CFLAGS, str.join(" ", ADDITIONAL_ARGS))
os.environ["CFLAGS"]=CFLAGS
LDFLAGS="%s %s" % (LDFLAGS, str.join(" ", ADDITIONAL_ARGS))
os.environ["LDFLAGS"]=LDFLAGS
# Some dependencies need a more recent CMake version than most distros provide
build_dependency(name="cmake-%s" % (CMAKE_VERSION,), mode="autoconf", build_tool_args=[], download_url="https://cmake.org/files/v%s" % (CMAKE_VERSION_2,), download_name="cmake-%s.tar.gz" % (CMAKE_VERSION,))
# Extract compiler flags from CMake to harmonize settings with other autoconf dependencies
CMAKE_FLAG_EXTRACT_DIR="ifcopenshell_cmake_test_%s" % (time.time(),)
# was sp.check_output([bash, "-c", "cat /dev/urandom | env LC_CTYPE=C tr -dc 'a-zA-Z0-9' | head -c 32"]), in bash script, unclear what the exact required format is and whether it's needed
if os.path.exists(CMAKE_FLAG_EXTRACT_DIR):
shutil.rmtree(CMAKE_FLAG_EXTRACT_DIR)
os.makedirs(CMAKE_FLAG_EXTRACT_DIR)
BUILD_CFG_UPPER=BUILD_CFG.upper()
for FL in ["C", "CXX"]:
__check_call__([bash, "-c", """echo "
message(\"\${CMAKE_%s_FLAGS_%s}\")
" > CMakeLists.txt""" % (FL, BUILD_CFG_UPPER)], cwd=CMAKE_FLAG_EXTRACT_DIR)
FL="%sFLAGS" % (FL,)
FLM="%sFLAGS_MINIMAL" % (FL,)
# @TODO: bash code unclear
# exec("%sFLAGS=%s" % (FL, sp.check_output([os.path.join(DEPS_DIR, "install", "cmake-%s" % (CMAKE_VERSION,), "bin", "cmake"), "."
# declare ${FL}FLAGS_MINIMAL="`$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake . 2>&1 >/dev/null` ${!FLM}"
shutil.rmtree(CMAKE_FLAG_EXTRACT_DIR)
build_dependency(name="pcre-%s" % (PCRE_VERSION,), mode="autoconf", build_tool_args=["--disable-shared"], download_url="https://downloads.sourceforge.net/project/pcre/pcre/%s/" % (PCRE_VERSION,), download_name="pcre-%s.tar.bz2" % (PCRE_VERSION,))
# An issue exists with swig-1.3 and python >= 3.2
# Therefore, build a recent copy from source
build_dependency(name="swig", mode="autoconf", build_tool_args=["--with-pcre-prefix=%s/install/pcre-%s" % (DEPS_DIR, PCRE_VERSION)], download_url="https://github.com/swig/swig.git", download_name="swig", download_tool=download_tool_git, revision="rel-%s" % SWIG_VERSION)
if USE_OCCT:
long_filenames = ["src/RWStepVisual/RWStepVisual_RWCharacterizedObjectAndCharacterizedRepresentationAndDraughtingModelAndRepresentation"]
if OCCT_VERSION == "7.2.0":
long_filenames += [
"src/StepVisual/StepVisual_AnnotationCurveOccurrenceAndAnnotationOccurrenceAndGeomReprItemAndReprItemAndStyledItem",
"src/RWStepVisual/RWStepVisual_RWAnnotationCurveOccurrenceAndAnnotationOccurrenceAndGeomReprItemAndReprItemAndStyledItem"
]
long_filenames_ext = [("%s.hxx" % fn) for fn in long_filenames] + [("%s.cxx" % fn) for fn in long_filenames]
patch_filename = "patches/occt/%s.patch" % OCCT_HASH
occt_gitweb = "http://git.dev.opencascade.org/gitweb/?p=occt.git"
build_dependency(
name="occt-%s" % OCCT_VERSION,
mode="cmake",
build_tool_args=[
"-DINSTALL_DIR=%s/install/occt-%s" % (DEPS_DIR, OCCT_VERSION),
"-DBUILD_LIBRARY_TYPE=Static",
"-DBUILD_MODULE_Draw=0",
],
download_url = "%s;a=snapshot;h=%s;sf=tgz" % (occt_gitweb, OCCT_HASH),
additional_files = {fn: "%s;a=blob_plain;hb=%s;f=%s" % (occt_gitweb, OCCT_HASH, fn) for fn in long_filenames_ext},
patch = patch_filename,
download_name = "occt-%s.tar.gz" % OCCT_HASH,
no_append_name = True)
else:
build_dependency(name="oce-%s" % (OCE_VERSION,), mode="cmake", build_tool_args=["-DOCE_DISABLE_TKSERVICE_FONT=ON", "-DOCE_TESTING=OFF", "-DOCE_BUILD_SHARED_LIB=OFF", "-DOCE_DISABLE_X11=ON", "-DOCE_VISUALISATION=OFF", "-DOCE_OCAF=OFF", "-DOCE_INSTALL_PREFIX=%s/install/oce-%s" % (DEPS_DIR, OCE_VERSION)], download_url="https://github.com/tpaviot/oce/archive/", download_name="OCE-%s.tar.gz" % (OCE_VERSION,))
build_dependency("libxml2-%s" % (LIBXML_VERSION,), "autoconf", build_tool_args=["--without-python", "--disable-shared", "--without-zlib", "--without-iconv", "--without-lzma"], download_url="ftp://xmlsoft.org/libxml2/", download_name="libxml2-%s.tar.gz" % (LIBXML_VERSION,))
build_dependency("OpenCOLLADA", "cmake", build_tool_args=["-DLIBXML2_INCLUDE_DIR=%s/install/libxml2-%s/include/libxml2" % (DEPS_DIR, LIBXML_VERSION), "-DLIBXML2_LIBRARIES=%s/install/libxml2-%s/lib/libxml2.a" % (DEPS_DIR, LIBXML_VERSION), "-DPCRE_INCLUDE_DIR=%s/install/pcre-%s/include" % (DEPS_DIR, PCRE_VERSION), "-DPCRE_PCREPOSIX_LIBRARY=%s/install/pcre-%s/lib/libpcreposix.a" % (DEPS_DIR, PCRE_VERSION), "-DPCRE_PCRE_LIBRARY=%s/install/pcre-%s/lib/libpcre.a" % (DEPS_DIR, PCRE_VERSION), "-DCMAKE_INSTALL_PREFIX=%s/install/OpenCOLLADA/" % (DEPS_DIR,)], download_url="https://github.com/KhronosGroup/OpenCOLLADA.git", download_name="OpenCOLLADA", download_tool=download_tool_git, revision=OPENCOLLADA_COMMIT)
# Python should not be built with -fvisibility=hidden, from experience that introduces segfaults
OLD_CXX_FLAGS=os.environ["CXXFLAGS"]
OLD_C_FLAGS=os.environ["CFLAGS"]
os.environ["CXXFLAGS"]=CXXFLAGS_MINIMAL
os.environ["CFLAGS"]=CFLAGS_MINIMAL
# On OSX a dynamic python library is built or it would not be compatible
# with the system python because of some threading initialization
PYTHON_CONFIGURE_ARGS=[]
if get_os() == "Darwin":
PYTHON_CONFIGURE_ARGS=["--disable-static", "--enable-shared"]
def get_python_unicode_confs(py_ver):
if py_ver < "3.3":
return [("--enable-unicode=ucs2",""), ("--enable-unicode=ucs4","u")]
else: return [("","")]
def PYTHON_VERSION_CONFS():
for v in PYTHON_VERSIONS:
for unicode_conf, abi_tag in get_python_unicode_confs(v):
yield v, unicode_conf, abi_tag
for PYTHON_VERSION, unicode_conf, abi_tag in PYTHON_VERSION_CONFS():
build_dependency("python-%s%s" % (PYTHON_VERSION,abi_tag), "autoconf", PYTHON_CONFIGURE_ARGS + [unicode_conf], "http://www.python.org/ftp/python/%s/" % (PYTHON_VERSION,), "Python-%s.tgz" % (PYTHON_VERSION,))
os.environ["CXXFLAGS"]=OLD_CXX_FLAGS
os.environ["CFLAGS"]=OLD_C_FLAGS
str_concat = lambda prefix: lambda postfix: "" if postfix.strip() == "" else "=".join((prefix, postfix.strip()))
build_dependency("boost-%s" % (BOOST_VERSION,), mode="bjam", build_tool_args=["--stagedir=%s/install/boost-%s" % (DEPS_DIR, BOOST_VERSION), "--with-system", "--with-program_options", "--with-regex", "--with-thread", "--with-date_time", "--with-iostreams", "link=static"]+BOOST_ADDRESS_MODEL+list(map(str_concat("cxxflags"), CXXFLAGS.strip().split(' '))) + list(map(str_concat("linkflags"), LDFLAGS.strip().split(' '))) + ["stage", "-s", "NO_BZIP2=1"], download_url="http://downloads.sourceforge.net/project/boost/boost/%s/" % (BOOST_VERSION,), download_name="boost_%s.tar.bz2" % (BOOST_VERSION_UNDERSCORE,))
build_dependency(name="icu-%s" % (ICU_VERSION,), mode="icu", build_tool_args=["--enable-static", "--disable-shared"], download_url="http://download.icu-project.org/files/icu4c/%s/" % (ICU_VERSION,), download_name="icu4c-%s-src.tgz" % (ICU_VERSION_UNDERSCORE,))
cecho("Building IfcOpenShell:", GREEN)
IFCOS_DIR=os.path.join(DEPS_DIR, "build", "ifcopenshell")
if os.path.exists(IFCOS_DIR):
shutil.rmtree(IFCOS_DIR)
os.makedirs(IFCOS_DIR)
executables_dir = os.path.join(IFCOS_DIR, "executables")
if not os.path.exists(executables_dir):
os.makedirs(executables_dir)
logger.info("\rConfiguring executables...")
if USE_OCCT:
occ_include_dir = "%s/install/occt-%s/include/opencascade" % (DEPS_DIR, OCCT_VERSION)
occ_library_dir = "%s/install/occt-%s/lib" % (DEPS_DIR, OCCT_VERSION)
else:
occ_include_dir = "%s/install/oce-%s/include/oce" % (DEPS_DIR, OCE_VERSION)
occ_library_dir = "%s/install/oce-%s/lib" % (DEPS_DIR, OCE_VERSION)
run_cmake("", cmake_args=[
"-DBOOST_ROOT=" "%s/install/boost-%s" % (DEPS_DIR, BOOST_VERSION),
"-DOCC_INCLUDE_DIR=" +occ_include_dir,
"-DOCC_LIBRARY_DIR=" +occ_library_dir,
"-DOPENCOLLADA_INCLUDE_DIR=" "%s/install/OpenCOLLADA/include/opencollada" % (DEPS_DIR,),
"-DOPENCOLLADA_LIBRARY_DIR=" "%s/install/OpenCOLLADA/lib/opencollada" % (DEPS_DIR,),
"-DICU_INCLUDE_DIR=" "%s/install/icu-%s/include" % (DEPS_DIR, ICU_VERSION),
"-DICU_LIBRARY_DIR=" "%s/install/icu-%s/lib" % (DEPS_DIR, ICU_VERSION),
"-DPCRE_LIBRARY_DIR=" "%s/install/pcre-%s/lib" % (DEPS_DIR, PCRE_VERSION),
"-DBUILD_IFCPYTHON=" "OFF",
"-DUSE_MMAP=" "OFF",
"-DCMAKE_INSTALL_PREFIX=" "%s/install/ifcopenshell" % (DEPS_DIR,)], cmake_dir=CMAKE_DIR, cwd=executables_dir)
logger.info("\rBuilding executables... ")
__check_call__([make, "-j%s" % (IFCOS_NUM_BUILD_PROCS,)], cwd=executables_dir)
__check_call__([make, "install/strip"], cwd=executables_dir)
# On OSX the actual Python library is not linked against.
ADDITIONAL_ARGS=""
if get_os() == "Darwin":
ADDITIONAL_ARGS="-Wl,-flat_namespace,-undefined,suppress"
os.environ["CXXFLAGS"]="%s %s" % (CXXFLAGS_MINIMAL, ADDITIONAL_ARGS)
os.environ["CFLAGS"]="%s %s" % (CFLAGS_MINIMAL, ADDITIONAL_ARGS)
os.environ["LDFLAGS"]="%s %s" % (LDFLAGS, ADDITIONAL_ARGS)
for PYTHON_VERSION, _, TAG in PYTHON_VERSION_CONFS():
logger.info("\rConfiguring python %s%s wrapper..." % (PYTHON_VERSION, TAG))
python_dir = os.path.join(IFCOS_DIR, "python-%s%s" % (PYTHON_VERSION, TAG))
if not os.path.exists(python_dir):
os.makedirs(python_dir)
PYTHON_LIBRARY=__check_output__([bash, "-c", "ls %s/install/python-%s%s/lib/libpython*.*" % (DEPS_DIR, PYTHON_VERSION, TAG)], cwd=None).strip()
PYTHON_INCLUDE=__check_output__([bash, "-c", "ls -d %s/install/python-%s%s/include/python*" % (DEPS_DIR, PYTHON_VERSION, TAG)], cwd=None).strip()
PYTHON_EXECUTABLE=os.path.join(DEPS_DIR, "install", "python-%s%s" % (PYTHON_VERSION, TAG), "bin", "python%s" % (PYTHON_VERSION[0],))
os.environ["PYTHON_LIBRARY_BASENAME"]=os.path.basename(PYTHON_LIBRARY)
run_cmake("", cmake_args=["-DBOOST_ROOT=%s/install/boost-%s" % (DEPS_DIR, BOOST_VERSION),
"-DOCC_INCLUDE_DIR="+occ_include_dir,
"-DOCC_LIBRARY_DIR="+occ_library_dir,
"-DOPENCOLLADA_INCLUDE_DIR=%s/install/OpenCOLLADA/include/opencollada" % (DEPS_DIR,),
"-DOPENCOLLADA_LIBRARY_DIR=%s/install/OpenCOLLADA/lib/opencollada" % (DEPS_DIR,),
"-DICU_INCLUDE_DIR=%s/install/icu-%s/include" % (DEPS_DIR, ICU_VERSION),
"-DICU_LIBRARY_DIR=%s/install/icu-%s/lib" % (DEPS_DIR, ICU_VERSION),
"-DPYTHON_LIBRARY=%s" % (PYTHON_LIBRARY,),
"-DPYTHON_EXECUTABLE=%s" % (PYTHON_EXECUTABLE,),
"-DPYTHON_INCLUDE_DIR=%s" % (PYTHON_INCLUDE,),
"-DSWIG_EXECUTABLE=%s/install/swig/bin/swig" % (DEPS_DIR,),
"-DCMAKE_INSTALL_PREFIX=%s/install/ifcopenshell/tmp" % (DEPS_DIR,),
"-DCOLLADA_SUPPORT=OFF"], cmake_dir=CMAKE_DIR, cwd=python_dir)
logger.info("\rBuilding python %s%s wrapper... " % (PYTHON_VERSION, TAG))
__check_call__([make, "-j%s" % (IFCOS_NUM_BUILD_PROCS,), "_ifcopenshell_wrapper"], cwd=python_dir)
__check_call__([make, "install/local"], cwd=os.path.join(python_dir, "ifcwrap"))
module_dir = os.path.dirname(__check_output__([PYTHON_EXECUTABLE, "-c", "from __future__ import print_function; import inspect, ifcopenshell; print(inspect.getfile(ifcopenshell))"]))
if get_os() != "Darwin":
# TODO: This symbol name depends on the Python version?
__check_call__([strip, "-s", "-K", "PyInit__ifcopenshell_wrapper", "_ifcopenshell_wrapper.so"], cwd=module_dir)
__check_call__([cp, "-R", module_dir, os.path.join(DEPS_DIR, "install", "ifcopenshell", "python-%s%s" % (PYTHON_VERSION, TAG))])
logger.info("\rBuilt IfcOpenShell...\n\n")
+32
View File
@@ -0,0 +1,32 @@
http://git.dev.opencascade.org/gitweb/?p=occt.git;a=commitdiff;h=0ab4e621833f4eae945a3762c9a29ee12e2eec53#patch1
diff --git a/src/HLRBRep/HLRBRep_InternalAlgo.cxx b/src/HLRBRep/HLRBRep_InternalAlgo.cxx
index ca885ca..c13cb06 100644 (file)
--- a/src/HLRBRep/HLRBRep_InternalAlgo.cxx
+++ b/src/HLRBRep/HLRBRep_InternalAlgo.cxx
@@ -165,7 +165,7 @@ void HLRBRep_InternalAlgo::Update ()
SB.Bounds(v1,v2,e1,e2,f1,f2);
for (Standard_Integer e = e1; e <= e2; e++) {
- HLRBRep_EdgeData ed = aEDataArray.ChangeValue(e);
+ HLRBRep_EdgeData& ed = aEDataArray.ChangeValue(e);
HLRAlgo::DecodeMinMax(ed.MinMax(), TheMin, TheMax);
if (FirstTime) {
FirstTime = Standard_False;
@@ -307,7 +307,7 @@ void HLRBRep_InternalAlgo::InitEdgeStatus ()
Standard_Integer nf = myDS->NbFaces();
for (Standard_Integer e = 1; e <= ne; e++) {
- HLRBRep_EdgeData ed = aEDataArray.ChangeValue(e);
+ HLRBRep_EdgeData& ed = aEDataArray.ChangeValue(e);
if (ed.Selected()) ed.Status().ShowAll();
}
// for (Standard_Integer f = 1; f <= nf; f++) {
@@ -368,7 +368,7 @@ void HLRBRep_InternalAlgo::Select ()
Standard_Integer nf = myDS->NbFaces();
for (Standard_Integer e = 1; e <= ne; e++) {
- HLRBRep_EdgeData ed = aEDataArray.ChangeValue(e);
+ HLRBRep_EdgeData& ed = aEDataArray.ChangeValue(e);
ed.Selected(Standard_True);
}
+27 -2
View File
@@ -1,5 +1,30 @@
################################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
################################################################################
ADD_EXECUTABLE(IfcParseExamples IfcParseExamples.cpp)
TARGET_LINK_LIBRARIES (IfcParseExamples IfcParse)
TARGET_LINK_LIBRARIES(IfcParseExamples IfcParse)
set_target_properties(IfcParseExamples PROPERTIES FOLDER Examples)
ADD_EXECUTABLE(IfcOpenHouse IfcOpenHouse.cpp)
TARGET_LINK_LIBRARIES (IfcOpenHouse IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKOffset)
TARGET_LINK_LIBRARIES(IfcOpenHouse ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES})
set_target_properties(IfcOpenHouse PROPERTIES FOLDER Examples)
ADD_EXECUTABLE(IfcAdvancedHouse IfcAdvancedHouse.cpp)
TARGET_LINK_LIBRARIES(IfcAdvancedHouse ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES})
set_target_properties(IfcAdvancedHouse PROPERTIES FOLDER Examples)
+182
View File
@@ -0,0 +1,182 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include <string>
#include <iostream>
#include <fstream>
#include <TColgp_Array2OfPnt.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <Geom_BSplineSurface.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepBuilderAPI_NurbsConvert.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <BRepAlgoAPI_Cut.hxx>
#include <Standard_Version.hxx>
#ifdef USE_IFC4
#include "../ifcparse/Ifc4.h"
#define IfcSchema Ifc4
#else
#include "../ifcparse/Ifc2x3.h"
#define IfcSchema Ifc2x3
#endif
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcHierarchyHelper.h"
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/Serialization.h"
#if USE_VLD
#include <vld.h>
#endif
// The creation of Nurbs-surface for the IfcSite mesh, to be implemented lateron
void createGroundShape(TopoDS_Shape& shape);
int main() {
// The IfcHierarchyHelper is a subclass of the regular IfcFile that provides several
// convenience functions for working with geometry in IFC files.
IfcHierarchyHelper<IfcSchema> file;
file.header().file_name().name("IfcAdvancedHouse.ifc");
IfcSchema::IfcBuilding* building = file.addBuilding();
// By adding a building, a hierarchy has been automatically created that consists of the following
// structure: IfcProject > IfcSite > IfcBuilding
// Lateron changing the name of the IfcProject can be done by obtaining a reference to the
// project, which has been created automatically.
file.getSingle<IfcSchema::IfcProject>()->setName("IfcOpenHouse");
// To demonstrate the ability to serialize arbitrary opencascade solids a building envelope is
// constructed by applying boolean operations. Naturally, in IFC, building elements should be
// modeled separately, with rich parametric and relational semantics. Creating geometry in this
// way does not preserve any history and is merely a demonstration of technical capabilities.
TopoDS_Shape outer = BRepPrimAPI_MakeBox(gp_Pnt(-5000., -180., -2000.), gp_Pnt(5000., 5180., 3000.)).Shape();
TopoDS_Shape inner = BRepPrimAPI_MakeBox(gp_Pnt(-4640., 180., 0.), gp_Pnt(4640., 4820., 3000.)).Shape();
TopoDS_Shape window1 = BRepPrimAPI_MakeBox(gp_Pnt(-5000., -180., 400.), gp_Pnt( 500., 1180., 2000.)).Shape();
TopoDS_Shape window2 = BRepPrimAPI_MakeBox(gp_Pnt( 2070., -180., 400.), gp_Pnt(3930., 180., 2000.)).Shape();
TopoDS_Shape building_shell = BRepAlgoAPI_Cut(
BRepAlgoAPI_Cut(
BRepAlgoAPI_Cut(outer, inner),
window1
),
window2
);
// Since the solid consists only of planar faces and straight edges it can be serialized as an
// IfcFacetedBRep. If it would not be a polyhedron, serialise() can only be successful when linked
// to the IFC4 model and with `advanced` set to `true` which introduces IfcAdvancedFace. It would
// return `0` otherwise.
IfcSchema::IfcProductDefinitionShape* building_shape = IfcGeom::serialise(STRINGIFY(IfcSchema), building_shell, false)->as<IfcSchema::IfcProductDefinitionShape>();
file.addEntity(building_shape);
IfcSchema::IfcRepresentation* rep = *building_shape->Representations()->begin();
rep->setContextOfItems(file.getRepresentationContext("model"));
building->setRepresentation(building_shape);
// A pale white colour is assigned to the building.
file.setSurfaceColour(
building_shape, 0.75, 0.73, 0.68);
// For the ground mesh of the IfcSite we will use a Nurbs surface created in Open Cascade. Only
// in IFC4 the surface can be directly serialized. In IFC2X3 the it will have to be tesselated.
TopoDS_Shape shape;
createGroundShape(shape);
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::serialise(STRINGIFY(IfcSchema), shape, true)->as<IfcSchema::IfcProductDefinitionShape>();
if (!ground_representation) {
ground_representation = IfcGeom::tesselate(STRINGIFY(IfcSchema), shape, 100.)->as<IfcSchema::IfcProductDefinitionShape>();
}
file.getSingle<IfcSchema::IfcSite>()->setRepresentation(ground_representation);
IfcSchema::IfcRepresentation::list::ptr ground_reps = file.getSingle<IfcSchema::IfcSite>()->Representation()->Representations();
for (IfcSchema::IfcRepresentation::list::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
(*it)->setContextOfItems(file.getRepresentationContext("Model"));
}
file.addEntity(ground_representation);
file.setSurfaceColour(ground_representation, 0.15, 0.25, 0.05);
/*
// Note that IFC lacks elementary surfaces that STEP does have, such as spherical_surface.
// BRepBuilderAPI_NurbsConvert can be used to serialize such surfaces as nurbs surfaces.
TopoDS_Shape sphere = BRepPrimAPI_MakeSphere(gp_Pnt(), 1000.).Shape();
IfcSchema::IfcProductDefinitionShape* sphere_representation = IfcGeom::serialise(sphere, true);
if (S(IfcSchema::Identifier) == "IFC4") {
sphere = BRepBuilderAPI_NurbsConvert(sphere, true).Shape();
sphere_representation = IfcGeom::serialise(sphere, true);
}
*/
// Finally create a file stream for our output and write the IFC file to it.
std::ofstream f("IfcAdvancedHouse.ifc");
f << file;
}
void createGroundShape(TopoDS_Shape& shape) {
TColgp_Array2OfPnt cv (0, 4, 0, 4);
cv.SetValue(0, 0, gp_Pnt(-10000, -10000, -4130));
cv.SetValue(0, 1, gp_Pnt(-10000, -4330, -4130));
cv.SetValue(0, 2, gp_Pnt(-10000, 0, -5130));
cv.SetValue(0, 3, gp_Pnt(-10000, 4330, -7130));
cv.SetValue(0, 4, gp_Pnt(-10000, 10000, -7130));
cv.SetValue(1, 0, gp_Pnt( -3330, -10000, -5130));
cv.SetValue(1, 1, gp_Pnt( -7670, -3670, 5000));
cv.SetValue(1, 2, gp_Pnt( -9000, 0, 1000));
cv.SetValue(1, 3, gp_Pnt( -7670, 7670, 6000));
cv.SetValue(1, 4, gp_Pnt( -3330, 10000, -4130));
cv.SetValue(2, 0, gp_Pnt( 0, -10000, -5530));
cv.SetValue(2, 1, gp_Pnt( 0, -3670, 3000));
cv.SetValue(2, 2, gp_Pnt( 0, 0, -12000));
cv.SetValue(2, 3, gp_Pnt( 0, 7670, 1500));
cv.SetValue(2, 4, gp_Pnt( 0, 10000, -4130));
cv.SetValue(3, 0, gp_Pnt( 3330, -10000, -6130));
cv.SetValue(3, 1, gp_Pnt( 7670, -3670, 6000));
cv.SetValue(3, 2, gp_Pnt( 9000, 0, 5000));
cv.SetValue(3, 3, gp_Pnt( 7670, 9000, 7000));
cv.SetValue(3, 4, gp_Pnt( 3330, 10000, -4130));
cv.SetValue(4, 0, gp_Pnt( 10000, -10000, -6130));
cv.SetValue(4, 1, gp_Pnt( 10000, -4330, -5130));
cv.SetValue(4, 2, gp_Pnt( 10000, 0, -4130));
cv.SetValue(4, 3, gp_Pnt( 10000, 4330, -4130));
cv.SetValue(4, 4, gp_Pnt( 10000, 10000, -8130));
TColStd_Array1OfReal knots(0, 1);
knots(0) = 0;
knots(1) = 1;
TColStd_Array1OfInteger mult(0, 1);
mult(0) = 5;
mult(1) = 5;
Handle(Geom_BSplineSurface) surf = new Geom_BSplineSurface(cv, knots, knots, mult, mult, 4, 4);
#if OCC_VERSION_HEX < 0x60502
shape = BRepBuilderAPI_MakeFace(surf);
#else
shape = BRepBuilderAPI_MakeFace(surf, Precision::Confusion());
#endif
}
+66 -34
View File
@@ -28,33 +28,42 @@
#include <Geom_BSplineSurface.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <Standard_Version.hxx>
#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 "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcHierarchyHelper.h"
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/Serialization.h"
#if USE_VLD
#include <vld.h>
#endif
// Some convenience typedefs and definitions.
typedef std::string S;
typedef IfcWrite::IfcGuidHelper guid;
typedef IfcParse::IfcGlobalId guid;
typedef std::pair<double, double> XY;
boost::none_t const null = (static_cast<boost::none_t>(0));
boost::none_t const null = boost::none;
// The creation of Nurbs-surface for the IfcSite mesh, to be implemented lateron
void createGroundShape(TopoDS_Shape& shape);
int main(int argc, char** argv) {
int main() {
// The IfcHierarchyHelper is a subclass of the regular IfcFile that provides several
// convenience functions for working with geometry in IFC files.
IfcHierarchyHelper file;
IfcHierarchyHelper<IfcSchema> file;
file.header().file_name().name("IfcOpenHouse.ifc");
// Start by adding a wall to the file, initially leaving most attributes blank.
@@ -195,43 +204,46 @@ int main(int argc, char** argv) {
file.addBuildingProduct(north_wall);
file.setSurfaceColour(north_wall->Representation(), wall_colour);
IfcSchema::IfcShapeRepresentation* clipped_wall_body_rep = file.addEmptyRepresentation();
file.addBox(clipped_wall_body_rep, 5000, 360, 6000);
// The east wall geometry is clipped using two IfcHalfSpaceSolids, created from an
// 'axis 3d placement' that specifies the plane against which the geometry is clipped.
file.clipRepresentation(clipped_wall_body_rep, file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false);
file.clipRepresentation(clipped_wall_body_rep, file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false);
// Two identical representations are created for the two remaining walls. Mapped items
// are not used, because it is not allowed by the standard for wall body representations.
// MappedItems are not allowed for Axis representations as per CV-2x3-161
IfcSchema::IfcProductDefinitionShape* clipped_wall_body_reps[2];
for (int i = 0; i < 2; ++i) {
IfcSchema::IfcShapeRepresentation* body = file.addEmptyRepresentation();
file.addBox(body, 5000, 360, 6000);
// The wall geometry is clipped using two IfcHalfSpaceSolids, created from an
// 'axis 3d placement' that specifies the plane against which the geometry is clipped.
file.clipRepresentation(body, file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false);
file.clipRepresentation(body, file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false);
file.setSurfaceColour(body, wall_colour);
IfcSchema::IfcShapeRepresentation* axis = file.addEmptyRepresentation("Axis", "Curve2D");
file.addAxis(axis, 5000);
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
reps->push(body);
reps->push(axis);
clipped_wall_body_reps[i] = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
}
// Now create a wall on the east of the building, again starting with just a box shape
IfcSchema::IfcWallStandardCase* east_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
S("East wall"), null, null, file.addLocalPlacement(storey_placement, 4820, 2500, 0, 0, 0, 1, 0, 1, 0), file.addMappedItem(clipped_wall_body_rep), null
S("East wall"), null, null, file.addLocalPlacement(storey_placement, 4820, 2500, 0, 0, 0, 1, 0, 1, 0), clipped_wall_body_reps[0], null
#ifdef USE_IFC4
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
#endif
);
file.addBuildingProduct(east_wall);
file.setSurfaceColour(clipped_wall_body_rep, wall_colour);
// The east wall is copied to the west location of the house
IfcSchema::IfcWallStandardCase* west_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
S("West wall"), null, null, file.addLocalPlacement(storey_placement, -4820, 2500, 0, 0, 0, 1, 0, -1, 0), file.addMappedItem(clipped_wall_body_rep), null
S("West wall"), null, null, file.addLocalPlacement(storey_placement, -4820, 2500, 0, 0, 0, 1, 0, -1, 0), clipped_wall_body_reps[1], null
#ifdef USE_IFC4
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
#endif
);
file.addBuildingProduct(west_wall);
for (int i = 0; i < 2; ++i) {
// CV-2x3-161: MappedItems are not allowed for Axis representations
IfcSchema::IfcWallStandardCase* wall = i == 0 ? east_wall : west_wall;
IfcSchema::IfcShapeRepresentation* wall_axis_rep = file.addEmptyRepresentation("Axis", "Curve2D");
file.addAxis(wall_axis_rep, 5000);
IfcSchema::IfcRepresentation::list::ptr reps = wall->Representation()->Representations();
reps->push(wall_axis_rep);
wall->Representation()->setRepresentations(reps);
}
// The west wall is assigned an opening element we created for the south wall, opening elements are
// not shared accross building elements, even if they share the same representation. Hence, the east
// wall will not feature this opening.
@@ -255,14 +267,30 @@ int main(int argc, char** argv) {
// will be tesselated using the deflection specified.
TopoDS_Shape shape;
createGroundShape(shape);
IfcEntityList::ptr geometrical_entities(new IfcEntityList);
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::tesselate(shape, 100., geometrical_entities);
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::tesselate(STRINGIFY(IfcSchema), shape, 100.)->as<IfcSchema::IfcProductDefinitionShape>();
file.getSingle<IfcSchema::IfcSite>()->setRepresentation(ground_representation);
file.addEntities(geometrical_entities);
IfcSchema::IfcShapeRepresentation::list::ptr ground_reps = geometrical_entities->as<IfcSchema::IfcShapeRepresentation>();
for (IfcSchema::IfcShapeRepresentation::list::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
GProp_GProps prop;
BRepGProp::SurfaceProperties(shape, prop);
const double site_area = prop.Mass() / 1000 / 1000;
IfcSchema::IfcProperty::list::ptr properties(new IfcSchema::IfcProperty::list);
properties->push(new IfcSchema::IfcPropertySingleValue("TotalArea", null, new IfcSchema::IfcAreaMeasure(site_area), 0));
IfcSchema::IfcPropertySet* pset = new IfcSchema::IfcPropertySet(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("Pset_SiteCommon"), null, properties);
#ifdef USE_IFC4
IfcSchema::IfcObjectDefinition::list::ptr related_objs(new IfcSchema::IfcObjectDefinition::list);
#else
IfcSchema::IfcObject::list::ptr related_objs(new IfcSchema::IfcObject::list);
#endif
related_objs->push(file.getSingle<IfcSchema::IfcSite>());
IfcSchema::IfcRelDefinesByProperties* site_prop = new IfcSchema::IfcRelDefinesByProperties(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, related_objs, pset);
file.addEntity(site_prop);
IfcSchema::IfcRepresentation::list::ptr ground_reps = file.getSingle<IfcSchema::IfcSite>()->Representation()->Representations();
for (IfcSchema::IfcRepresentation::list::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
(*it)->setContextOfItems(file.getRepresentationContext("Model"));
}
file.addEntity(ground_representation);
file.setSurfaceColour(ground_representation, 0.15, 0.25, 0.05);
// According to the Ifc2x3 schema an IfcWallStandardCase needs to have an IfcMaterialLayerSet
@@ -313,9 +341,9 @@ int main(int argc, char** argv) {
null,
null,
#ifdef USE_IFC4
file.entitiesByType<IfcSchema::IfcWallStandardCase>()->generalize(),
file.instances_by_type<IfcSchema::IfcWallStandardCase>()->generalize(),
#else
file.entitiesByType<IfcSchema::IfcWallStandardCase>()->as<IfcSchema::IfcRoot>(),
file.instances_by_type<IfcSchema::IfcWallStandardCase>()->as<IfcSchema::IfcRoot>(),
#endif
layer_usage);
@@ -370,7 +398,7 @@ int main(int argc, char** argv) {
IfcSchema::IfcShapeRepresentation* door_body = 0;
for (IfcSchema::IfcRepresentation::list::it i = door_representations->begin(); i != door_representations->end(); ++i) {
IfcSchema::IfcRepresentation* rep = *i;
if (rep->is(IfcSchema::Type::IfcShapeRepresentation) && rep->RepresentationIdentifier() == "Body") {
if (rep->declaration().is(IfcSchema::IfcShapeRepresentation::Class()) && rep->RepresentationIdentifier() == "Body") {
door_body = (IfcSchema::IfcShapeRepresentation*) rep;
}
}
@@ -381,6 +409,10 @@ int main(int argc, char** argv) {
file.setSurfaceColour(door->Representation(), 0.9, 0.9, 0.9);
file.addEntity(new IfcSchema::IfcRelFillsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, door_opening, door));
IfcSchema::IfcDoorStyle* door_style = new IfcSchema::IfcDoorStyle(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("Door type"), null, null, null, null, null,
IfcSchema::IfcDoorStyleOperationEnum::IfcDoorStyleOperation_SINGLE_SWING_LEFT, IfcSchema::IfcDoorStyleConstructionEnum::IfcDoorStyleConstruction_WOOD, false, false);
file.addRelatedObject<IfcSchema::IfcRelDefinesByType>(door_style, door);
// Surface styles are assigned to representation items, hence there is no real limitation to
// assign different colours within the same representation. However, some viewers have
// difficulties rendering products with representation items with different surface styles.
+17 -12
View File
@@ -17,9 +17,15 @@
* *
********************************************************************************/
#include "../ifcparse/IfcFile.h"
// TODO: Multiple schemas
#define IfcSchema Ifc2x3
using namespace IfcSchema;
#include "../ifcparse/IfcFile.h"
#include "../ifcparse/Ifc2x3.h"
#if USE_VLD
#include <vld.h>
#endif
int main(int argc, char** argv) {
@@ -32,8 +38,8 @@ int main(int argc, char** argv) {
Logger::SetOutput(&std::cout,&std::cout);
// Parse the IFC file provided in argv[1]
IfcParse::IfcFile file;
if ( ! file.Init(argv[1]) ) {
IfcParse::IfcFile file(argv[1]);
if (!file.good()) {
std::cout << "Unable to parse .ifc file" << std::endl;
return 1;
}
@@ -54,19 +60,18 @@ int main(int argc, char** argv) {
// we need to cast them to IfcWindows. Since these properties
// are optional we need to make sure the properties are
// defined for the window in question before accessing them.
IfcBuildingElement::list::ptr elements = file.entitiesByType<IfcBuildingElement>();
IfcSchema::IfcBuildingElement::list::ptr elements = file.instances_by_type<IfcSchema::IfcBuildingElement>();
std::cout << "Found " << elements->size() << " elements in " << argv[1] << ":" << std::endl;
for ( IfcBuildingElement::list::it it = elements->begin(); it != elements->end(); ++ it ) {
for (IfcSchema::IfcBuildingElement::list::it it = elements->begin(); it != elements->end(); ++it) {
const IfcBuildingElement* element = *it;
std::cout << element->entity->toString() << std::endl;
const IfcSchema::IfcBuildingElement* element = *it;
std::cout << element->data().toString() << std::endl;
if ( element->is(IfcWindow::Class()) ) {
const IfcWindow* window = (IfcWindow*)element;
if ( window->hasOverallWidth() && window->hasOverallHeight() ) {
const IfcSchema::IfcWindow* window;
if ((window = element->as<IfcSchema::IfcWindow>()) != 0) {
if (window->hasOverallWidth() && window->hasOverallHeight()) {
const double area = window->OverallWidth()*window->OverallHeight();
std::cout << "The area of this window is " << area << std::endl;
}
+11 -11
View File
@@ -33,8 +33,8 @@
#include "../ifcparse/IfcHierarchyHelper.h"
typedef std::string S;
typedef IfcWrite::IfcGuidHelper guid;
boost::none_t const null = (static_cast<boost::none_t>(0));
typedef IfcParse::IfcGlobalId guid;
boost::none_t const null = boost::none;
static int i = 0;
void create_product_from_item(IfcHierarchyHelper& file, IfcSchema::IfcRepresentationItem* item, const std::string& s) {
@@ -43,16 +43,16 @@ void create_product_from_item(IfcHierarchyHelper& file, IfcSchema::IfcRepresenta
file.addBuildingProduct(product);
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
product->setObjectPlacement(file.addLocalPlacement(120 * i++));
product->setObjectPlacement(file.addLocalPlacement(0, 120 * i++));
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
items->push(item);
if (s == "GeometricSet") {
IfcSchema::IfcGeometricSet* set = new IfcSchema::IfcGeometricSet(items->generalize());
file.addEntity(set);
items = IfcSchema::IfcRepresentationItem::list(new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
items = IfcSchema::IfcRepresentationItem::list::ptr(new IfcSchema::IfcRepresentationItem::list());
items->push(set);
}
@@ -60,7 +60,7 @@ void create_product_from_item(IfcHierarchyHelper& file, IfcSchema::IfcRepresenta
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), s, items);
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
file.addEntity(rep);
file.addEntity(shape);
@@ -109,11 +109,11 @@ void create_products_from_curve(IfcHierarchyHelper& file, IfcSchema::IfcBoundedC
int main(int argc, char** argv) {
const char filename[] = "IfcArbitraryOpenProfileDef.ifc";
IfcHierarchyHelper file;
file.filename(filename);
file.header().file_name().name(filename);
double coords1[] = {-50.0, 0.0};
double coords2[] = { 50.0, 0.0};
IfcSchema::IfcCartesianPoint::list points (new IfcTemplatedEntityList<IfcSchema::IfcCartesianPoint>());
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list());
points->push(new IfcSchema::IfcCartesianPoint(std::vector<double>(coords1, coords1+2)));
points->push(new IfcSchema::IfcCartesianPoint(std::vector<double>(coords2, coords2+2)));
file.addEntities(points->generalize());
@@ -126,8 +126,8 @@ int main(int argc, char** argv) {
file.addEntity(ellipse);
IfcEntityList::ptr trim1(new IfcEntityList);
IfcEntityList::ptr trim2(new IfcEntityList);
trim1->push(new IfcWrite::IfcSelectHelper( 0., Ifc2x3::Type::IfcParameterValue));
trim2->push(new IfcWrite::IfcSelectHelper(180., Ifc2x3::Type::IfcParameterValue));
trim1->push(new IfcSchema::IfcParameterValue( 0.));
trim2->push(new IfcSchema::IfcParameterValue(180.));
IfcSchema::IfcTrimmedCurve* trim = new IfcSchema::IfcTrimmedCurve(ellipse, trim1, trim2, true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
file.addEntity(trim);
+7 -7
View File
@@ -32,19 +32,19 @@
#include "../ifcparse/IfcHierarchyHelper.h"
typedef std::string S;
typedef IfcWrite::IfcGuidHelper guid;
boost::none_t const null = (static_cast<boost::none_t>(0));
typedef IfcParse::IfcGlobalId guid;
boost::none_t const null = boost::none;
int main(int argc, char** argv) {
const char filename[] = "IfcCompositeProfileDef.ifc";
IfcHierarchyHelper file;
file.filename(filename);
file.header().file_name().name(filename);
double coords1[] = {100.0, 0.0};
double coords2[] = {200.0, 0.0};
double coords3[] = {300.0, 0.0};
IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list());
IfcSchema::IfcCartesianTransformationOperator2D* transform1 = new IfcSchema::IfcCartesianTransformationOperator2D(file.addDoublet<IfcSchema::IfcDirection>(1, 0), file.addDoublet<IfcSchema::IfcDirection>(0, -1), file.addDoublet<IfcSchema::IfcCartesianPoint>(40, 0), null);
IfcSchema::IfcCartesianTransformationOperator2D* transform2 = new IfcSchema::IfcCartesianTransformationOperator2D(file.addDoublet<IfcSchema::IfcDirection>(0, -1), file.addDoublet<IfcSchema::IfcDirection>(1, 0), file.addDoublet<IfcSchema::IfcCartesianPoint>(40, 0), 0.3);
@@ -98,15 +98,15 @@ int main(int argc, char** argv) {
file.addEntity(composite);
file.addEntity(solid);
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
items->push(solid);
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("SweptSolid"), items);
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
file.addEntity(rep);
file.addEntity(shape);
+6 -6
View File
@@ -32,8 +32,8 @@
#include "../ifcparse/IfcHierarchyHelper.h"
typedef std::string S;
typedef IfcWrite::IfcGuidHelper guid;
boost::none_t const null = (static_cast<boost::none_t>(0));
typedef IfcParse::IfcGlobalId guid;
boost::none_t const null = boost::none;
class Node {
private:
@@ -135,7 +135,7 @@ public:
int main(int argc, char** argv) {
const char filename[] = "IfcCsgPrimitive.ifc";
IfcHierarchyHelper file;
file.filename(filename);
file.header().file_name().name(filename);
IfcSchema::IfcRepresentationItem* csg1 = Node::Box(8000.,6000.,3000.).subtract(
Node::Box(7600.,5600.,2800.).move(200.,200.,200.)
@@ -171,8 +171,8 @@ int main(int argc, char** argv) {
product->setObjectPlacement(file.addLocalPlacement());
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
items->push(csg1);
items->push(csg2);
@@ -180,7 +180,7 @@ int main(int argc, char** argv) {
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("CSG"), items);
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
file.addEntity(rep);
file.addEntity(shape);
+10 -10
View File
@@ -32,8 +32,8 @@
#include "../ifcparse/IfcHierarchyHelper.h"
typedef std::string S;
typedef IfcWrite::IfcGuidHelper guid;
boost::none_t const null = (static_cast<boost::none_t>(0));
typedef IfcParse::IfcGlobalId guid;
boost::none_t const null = boost::none;
typedef struct {
double r1;
@@ -58,7 +58,7 @@ void create_testcase_for(IfcHierarchyHelper& file, const EllipsePie& pie, Ifc2x3
Ifc2x3::IfcCartesianPoint* p2 = new Ifc2x3::IfcCartesianPoint(coords2);
Ifc2x3::IfcCartesianPoint* p3 = new Ifc2x3::IfcCartesianPoint(coords3);
Ifc2x3::IfcCartesianPoint::list points(new IfcTemplatedEntityList<Ifc2x3::IfcCartesianPoint>());
Ifc2x3::IfcCartesianPoint::list::ptr points(new Ifc2x3::IfcCartesianPoint::list());
points->push(p3);
points->push(p1);
points->push(p2);
@@ -70,8 +70,8 @@ void create_testcase_for(IfcHierarchyHelper& file, const EllipsePie& pie, Ifc2x3
IfcEntityList::ptr trim1(new IfcEntityList);
IfcEntityList::ptr trim2(new IfcEntityList);
if (pref == Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER) {
trim1->push(new IfcWrite::IfcSelectHelper(pie.t1, Ifc2x3::Type::IfcParameterValue));
trim2->push(new IfcWrite::IfcSelectHelper(pie.t2, Ifc2x3::Type::IfcParameterValue));
trim1->push(new Ifc2x3::IfcParameterValue(pie.t1));
trim2->push(new Ifc2x3::IfcParameterValue(pie.t2));
} else {
trim1->push(p2);
trim2->push(p3);
@@ -79,7 +79,7 @@ void create_testcase_for(IfcHierarchyHelper& file, const EllipsePie& pie, Ifc2x3
Ifc2x3::IfcTrimmedCurve* trim = new Ifc2x3::IfcTrimmedCurve(ellipse, trim1, trim2, true, pref);
file.addEntity(trim);
Ifc2x3::IfcCompositeCurveSegment::list segments(new IfcTemplatedEntityList<Ifc2x3::IfcCompositeCurveSegment>());
Ifc2x3::IfcCompositeCurveSegment::list::ptr segments(new Ifc2x3::IfcCompositeCurveSegment::list());
Ifc2x3::IfcCompositeCurveSegment* s2 = new Ifc2x3::IfcCompositeCurveSegment(Ifc2x3::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, trim);
Ifc2x3::IfcPolyline* poly = new Ifc2x3::IfcPolyline(points);
@@ -100,22 +100,22 @@ void create_testcase_for(IfcHierarchyHelper& file, const EllipsePie& pie, Ifc2x3
file.addBuildingProduct(product);
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
product->setObjectPlacement(file.addLocalPlacement(200 * i++));
product->setObjectPlacement(file.addLocalPlacement(0, 200 * i++));
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(profile,
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
file.addEntity(solid);
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
items->push(solid);
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("SweptSolid"), items);
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
file.addEntity(rep);
file.addEntity(shape);
+207
View File
@@ -0,0 +1,207 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* Example that generates various forms of IfcFace *
* *
********************************************************************************/
#include "../ifcparse/Ifc2x3.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcHierarchyHelper.h"
typedef std::string S;
typedef IfcParse::IfcGlobalId guid;
boost::none_t const null = (static_cast<boost::none_t>(0));
static int x = 0;
void create_testcase(IfcHierarchyHelper& file, IfcSchema::IfcFace* face, const std::string& name) {
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
faces->push(face);
IfcSchema::IfcOpenShell* shell = new IfcSchema::IfcOpenShell(faces);
IfcSchema::IfcConnectedFaceSet::list::ptr shells(new IfcSchema::IfcConnectedFaceSet::list);
shells->push(shell);
IfcSchema::IfcFaceBasedSurfaceModel* model = new IfcSchema::IfcFaceBasedSurfaceModel(shells);
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
guid(), 0, name, null, null, 0, 0, null, null);
file.addBuildingProduct(product);
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
product->setObjectPlacement(file.addLocalPlacement(0, 1000 * x++, 0));
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
items->push(model);
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
file.getRepresentationContext("Model"), S("Body"), S("SurfaceModel"), items);
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
file.addEntity(shape);
product->setRepresentation(shape);
}
int main(int argc, char** argv) {
IfcHierarchyHelper file;
{
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
bounds->push(bound);
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
create_testcase(file, face, "polyloop");
}
{
IfcSchema::IfcCartesianPoint* point1 = file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, 0., 0.);
IfcSchema::IfcCartesianPoint* point2 = file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, 0., 0.);
IfcSchema::IfcVertexPoint* vertex1 = new IfcSchema::IfcVertexPoint(point1);
IfcSchema::IfcVertexPoint* vertex2 = new IfcSchema::IfcVertexPoint(point2);
IfcSchema::IfcCircle* circle = new IfcSchema::IfcCircle(file.addPlacement2d(), 400.);
IfcSchema::IfcEdgeCurve* edge1 = new IfcSchema::IfcEdgeCurve(vertex1, vertex2, circle, true);
IfcSchema::IfcEdgeCurve* edge2 = new IfcSchema::IfcEdgeCurve(vertex2, vertex1, circle, true);
IfcSchema::IfcOrientedEdge* oriented_edge1 = new IfcSchema::IfcOrientedEdge(edge1, true);
IfcSchema::IfcOrientedEdge* oriented_edge2 = new IfcSchema::IfcOrientedEdge(edge2, true);
IfcSchema::IfcOrientedEdge::list::ptr edges(new IfcSchema::IfcOrientedEdge::list);
edges->push(oriented_edge1);
edges->push(oriented_edge2);
IfcSchema::IfcEdgeLoop* loop = new IfcSchema::IfcEdgeLoop(edges);
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
bounds->push(bound);
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
create_testcase(file, face, "circle");
}
{
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
IfcSchema::IfcFaceOuterBound* outer_bound = new IfcSchema::IfcFaceOuterBound(loop, true);
IfcSchema::IfcCartesianPoint::list::ptr points2 (new IfcSchema::IfcCartesianPoint::list);
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-300, -300, 0));
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, -300, 0));
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, +300, 0));
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-300, +300, 0));
IfcSchema::IfcPolyLoop* loop2 = new IfcSchema::IfcPolyLoop(points2);
IfcSchema::IfcFaceBound* inner_bound1 = new IfcSchema::IfcFaceBound(loop2, false);
IfcSchema::IfcCartesianPoint::list::ptr points3 (new IfcSchema::IfcCartesianPoint::list);
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, +300, 0));
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+300, +300, 0));
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+300, -300, 0));
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, -300, 0));
IfcSchema::IfcPolyLoop* loop3 = new IfcSchema::IfcPolyLoop(points3);
IfcSchema::IfcFaceBound* inner_bound2 = new IfcSchema::IfcFaceBound(loop3, true);
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
bounds->push(inner_bound1);
bounds->push(outer_bound);
bounds->push(inner_bound2);
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
create_testcase(file, face, "polyloop with holes");
}
{
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, -400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, +400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
IfcSchema::IfcFaceOuterBound* bound1 = new IfcSchema::IfcFaceOuterBound(loop, true);
IfcSchema::IfcCartesianPoint::list::ptr points2 (new IfcSchema::IfcCartesianPoint::list);
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, +400, 0));
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, -400, 0));
IfcSchema::IfcPolyLoop* loop2 = new IfcSchema::IfcPolyLoop(points2);
IfcSchema::IfcFaceOuterBound* bound2 = new IfcSchema::IfcFaceOuterBound(loop2, false);
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
bounds->push(bound1);
bounds->push(bound2);
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
create_testcase(file, face, "multiple outer boundaries (invalid)");
}
{
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 1e-6));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
bounds->push(bound);
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
create_testcase(file, face, "imprecise polyloop");
}
{
IfcSchema::IfcCartesianPoint* point1 = file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, 0., 0.);
IfcSchema::IfcCartesianPoint* point2 = file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, 0., 0.);
IfcSchema::IfcVertexPoint* vertex1 = new IfcSchema::IfcVertexPoint(point1);
IfcSchema::IfcVertexPoint* vertex2 = new IfcSchema::IfcVertexPoint(point2);
IfcSchema::IfcCircle* circle = new IfcSchema::IfcCircle(file.addPlacement2d(), 400.);
IfcSchema::IfcEdgeCurve* edge1 = new IfcSchema::IfcEdgeCurve(vertex1, vertex2, circle, true);
IfcSchema::IfcEdgeCurve* edge2 = new IfcSchema::IfcEdgeCurve(vertex2, vertex1, circle, true);
IfcSchema::IfcOrientedEdge* oriented_edge1 = new IfcSchema::IfcOrientedEdge(edge1, true);
IfcSchema::IfcOrientedEdge* oriented_edge2 = new IfcSchema::IfcOrientedEdge(edge2, true);
IfcSchema::IfcOrientedEdge::list::ptr edges(new IfcSchema::IfcOrientedEdge::list);
edges->push(oriented_edge1);
edges->push(oriented_edge2);
IfcSchema::IfcEdgeLoop* loop = new IfcSchema::IfcEdgeLoop(edges);
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
bounds->push(bound);
IfcSchema::IfcCartesianPoint::list::ptr trim1(new IfcSchema::IfcCartesianPoint::list);
IfcSchema::IfcCartesianPoint::list::ptr trim2(new IfcSchema::IfcCartesianPoint::list);
trim1->push(point1);
trim2->push(point2);
IfcSchema::IfcTrimmedCurve* trimmed_curve = new IfcSchema::IfcTrimmedCurve(circle, trim1->generalize(), trim2->generalize(), true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);
IfcSchema::IfcArbitraryOpenProfileDef* profile = new IfcSchema::IfcArbitraryOpenProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_CURVE, boost::none, trimmed_curve);
IfcSchema::IfcAxis1Placement* place = new IfcSchema::IfcAxis1Placement(file.addTriplet<IfcSchema::IfcCartesianPoint>(0., 0., 0.), file.addTriplet<IfcSchema::IfcDirection>(1., 0., 0.));
IfcSchema::IfcSurfaceOfRevolution* surface = new IfcSchema::IfcSurfaceOfRevolution(profile, file.addPlacement3d(), place);
IfcSchema::IfcFace* face = new IfcSchema::IfcFaceSurface(bounds, surface, true);
create_testcase(file, face, "face surface");
}
const std::string filename = "faces.ifc";
file.header().file_name().name(filename);
std::ofstream f(filename.c_str());
f << file;
}
+143
View File
@@ -0,0 +1,143 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* Example of curve rebar. *
* *
********************************************************************************/
#include <iostream>
#include <string>
#include <fstream>
#include "ifcparse\Ifc2x3.h"
#include "ifcparse\IfcUtil.h"
#include "ifcparse\IfcHierarchyHelper.h"
#include "ifcgeom\IfcGeom.h"
typedef std::string S;
typedef IfcParse::IfcGlobalId guid;
boost::none_t const null = boost::none;
void create_curve_rebar(IfcHierarchyHelper& file)
{
int dia = 24;
int R = 3 * dia;
int length = 12 * dia;
double crossSectionarea = M_PI * (dia / 2) * 2;
IfcSchema::IfcReinforcingBar* rebar = new IfcSchema::IfcReinforcingBar(
guid(), 0, S("test"), null,
null, 0, 0,
null, S("SR24"), //SteelGrade
dia, //diameter
crossSectionarea, //crossSectionarea = math.pi*(12.0/2)**2
0,
IfcSchema::IfcReinforcingBarRoleEnum::IfcReinforcingBarRoleEnum::IfcReinforcingBarRole_LIGATURE,
IfcSchema::IfcReinforcingBarSurfaceEnum::IfcReinforcingBarSurfaceEnum::IfcReinforcingBarSurface_PLAIN //PLAIN or TEXTURED
);
file.addBuildingProduct(rebar);
rebar->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
IfcSchema::IfcCompositeCurveSegment::list::ptr segments(new IfcSchema::IfcCompositeCurveSegment::list());
IfcSchema::IfcCartesianPoint* p1 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, 0, 1000.);
IfcSchema::IfcCartesianPoint* p2 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, 0, 0);
IfcSchema::IfcCartesianPoint* p3 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, R, 0);
IfcSchema::IfcCartesianPoint* p4 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, R, -R);
IfcSchema::IfcCartesianPoint* p5 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, R + length, -R);
/*first segment - line */
IfcSchema::IfcCartesianPoint::list::ptr points1(new IfcSchema::IfcCartesianPoint::list());
points1->push(p1);
points1->push(p2);
file.addEntities(points1->generalize());
IfcSchema::IfcPolyline* poly1 = new IfcSchema::IfcPolyline(points1);
file.addEntity(poly1);
IfcSchema::IfcCompositeCurveSegment* segment1 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, poly1);
file.addEntity(segment1);
segments->push(segment1);
/*second segment - arc */
IfcSchema::IfcAxis2Placement3D* axis1 = new IfcSchema::IfcAxis2Placement3D(p3, file.addTriplet<IfcSchema::IfcDirection>(1, 0, 0), file.addTriplet<IfcSchema::IfcDirection>(0, 1, 0));
file.addEntity(axis1);
IfcSchema::IfcCircle* circle = new IfcSchema::IfcCircle(axis1, R);
file.addEntity(circle);
IfcEntityList::ptr trim1(new IfcEntityList);
IfcEntityList::ptr trim2(new IfcEntityList);
trim1->push(new IfcSchema::IfcParameterValue(180));
trim1->push(p2);
trim2->push(new IfcSchema::IfcParameterValue(270));
trim2->push(p4);
IfcSchema::IfcTrimmedCurve* trimmed_curve = new IfcSchema::IfcTrimmedCurve(circle, trim1, trim2, false, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
file.addEntity(trimmed_curve);
IfcSchema::IfcCompositeCurveSegment* segment2 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT, false, trimmed_curve);
file.addEntity(segment2);
segments->push(segment2);
/*third segment - line */
IfcSchema::IfcCartesianPoint::list::ptr points2(new IfcSchema::IfcCartesianPoint::list());
points2->push(p4);
points2->push(p5);
file.addEntities(points2->generalize());
IfcSchema::IfcPolyline* poly2 = new IfcSchema::IfcPolyline(points2);
file.addEntity(poly2);
IfcSchema::IfcCompositeCurveSegment* segment3 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, poly2);
file.addEntity(segment3);
segments->push(segment3);
IfcSchema::IfcCompositeCurve* curve = new IfcSchema::IfcCompositeCurve(segments, false);
file.addEntity(curve);
IfcSchema::IfcSweptDiskSolid* solid = new IfcSchema::IfcSweptDiskSolid(curve, dia / 2, null, 0, 1);
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list());
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list());
items->push(solid);
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("AdvancedSweptSolid"), items);
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
file.addEntity(shape);
rebar->setRepresentation(shape);
IfcSchema::IfcObjectPlacement* storey_placement = file.getSingle<IfcSchema::IfcBuildingStorey>()->ObjectPlacement();
rebar->setObjectPlacement(file.addLocalPlacement(storey_placement, 0, 0, 0));
}
int main()
{
IfcHierarchyHelper file;
file.header().file_name().name("ifc_curve_rebar.ifc");
create_curve_rebar(file);
std::ofstream f("ifc_curve_rebar.ifc");
f << file;
return 0;
}
File diff suppressed because it is too large Load Diff
+85
View File
@@ -0,0 +1,85 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* Example that generates an IfcTriangulatedFaceSet *
* *
********************************************************************************/
#include "../ifcparse/Ifc4.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcHierarchyHelper.h"
#include "suzanne_geometry.h"
typedef std::string S;
typedef IfcParse::IfcGlobalId guid;
boost::none_t const null = (static_cast<boost::none_t>(0));
template <typename T>
std::vector< std::vector<T> > create_vector_from_array(const T* arr, unsigned size) {
std::vector< std::vector<T> > result;
result.reserve(size);
for (unsigned i = 0; i < size; ) {
std::vector<T> ts; ts.reserve(3);
for (unsigned j = 0; j < 3; ++i, ++j) {
ts.push_back(arr[i]);
}
result.push_back(ts);
}
return result;
}
int main(int argc, char** argv) {
IfcHierarchyHelper file;
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
guid(), 0, S("Blender's Suzanne"), null, null, 0, 0, null, null);
file.addBuildingProduct(product);
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
product->setObjectPlacement(file.addLocalPlacement());
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
std::vector< std::vector< double > > vertices_vector = create_vector_from_array(vertices, sizeof(vertices) / sizeof(vertices[0]));
std::vector< std::vector< int > > indices_vector = create_vector_from_array(indices, sizeof(indices) / sizeof(indices[0]));
IfcSchema::IfcCartesianPointList3D* coordinates = new IfcSchema::IfcCartesianPointList3D(vertices_vector);
IfcSchema::IfcTriangulatedFaceSet* faceset = new IfcSchema::IfcTriangulatedFaceSet(coordinates, null, null, indices_vector, null);
items->push(faceset);
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
file.getRepresentationContext("Model"), S("Body"), S("SurfaceModel"), items);
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
file.addEntity(shape);
product->setRepresentation(shape);
const std::string filename = "tesselated_faceset.ifc";
file.header().file_name().name(filename);
std::ofstream f(filename.c_str());
f << file;
}
@@ -66,7 +66,7 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
settings = ifcopenshell_geom.settings()
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, blender_booleans)
iterator = ifcopenshell_geom.iterator(settings, filename)
valid_file = iterator.findContext()
valid_file = iterator.initialize()
if not valid_file:
return False
print("Done reading file")
@@ -92,8 +92,10 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
faces = [[f[i], f[i + 1], f[i + 2]] \
for i in range(0, len(f), 3)]
me = bpy.data.meshes.new('mesh%d' % ob.geometry.id)
# Depending on version, geometry.id will be either int or str
me = bpy.data.meshes.new('mesh-%r' % ob.geometry.id)
me.from_pydata(verts, [], faces)
me.validate()
def add_material(mname, props):
if mname in bpy.data.materials:
-278
View File
@@ -1,278 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifdef WITH_OPENCOLLADA
#include <string>
#include "ColladaSerializer.h"
std::string collada_id(const std::string& s) {
std::string id;
id.reserve(s.size());
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
const std::string::value_type c = *it;
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_')) {
id.push_back(c);
}
}
return id;
}
void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<double>& floats, const char* coords /* = "XYZ" */) {
COLLADASW::FloatSource source(mSW);
source.setId(mesh_id + suffix);
source.setArrayId(mesh_id + suffix + COLLADASW::LibraryGeometries::ARRAY_ID_SUFFIX);
source.setAccessorStride(strlen(coords));
source.setAccessorCount(floats.size() / 3);
for (unsigned int i = 0; i < source.getAccessorStride(); ++i) {
source.getParameterNameList().push_back(std::string(1, coords[i]));
}
source.prepareToAppendValues();
for (std::vector<double>::const_iterator it = floats.begin(); it != floats.end(); ++it) {
source.appendValues(*it);
}
source.finish();
}
void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials) {
// The goal of the IfcGeom::Iterator is to filter out empty geometries, but
// since this function would crash trying to deference the material_ids in
// that case, a hard return statement is added just in case.
if (indices.empty()) return;
openMesh(mesh_id);
// The normals vector can be empty for example when the WELD_VERTICES setting is used.
// IfcOpenShell does not provide them with multiple face normals collapsed into a single vertex.
const bool has_normals = !normals.empty();
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX, positions);
if (has_normals) {
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, normals);
}
COLLADASW::VerticesElement vertices(mSW);
vertices.setId(mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX );
vertices.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::POSITION, "#" + mesh_id + COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX));
vertices.add();
std::vector<int>::const_iterator index_range_start = indices.begin();
std::vector<int>::const_iterator material_it = material_ids.begin();
int previous_material_id = -1;
for (std::vector<int>::const_iterator it = indices.begin(); ; it += 3) {
const int current_material_id = *(material_it++);
const int num_triangles = std::distance(index_range_start, it) / 3;
if ((previous_material_id != current_material_id && num_triangles > 0) || (it == indices.end())) {
COLLADASW::Triangles triangles(mSW);
triangles.setMaterial(materials[previous_material_id].name());
triangles.setCount(num_triangles);
int offset = 0;
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX,"#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++ ) );
if (has_normals) {
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::NORMAL,"#" + mesh_id + COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, offset++ ) );
}
triangles.prepareToAppendValues();
for (std::vector<int>::const_iterator jt = index_range_start; jt != it; ++jt) {
const int idx = *jt;
if (has_normals) {
triangles.appendValues(idx, idx);
} else {
triangles.appendValues(idx);
}
}
triangles.finish();
index_range_start = it;
}
previous_material_id = current_material_id;
if (it == indices.end()) {
break;
}
}
closeMesh();
closeGeometry();
}
void ColladaSerializer::ColladaExporter::ColladaGeometries::close() {
closeLibrary();
}
void ColladaSerializer::ColladaExporter::ColladaScene::add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<double>& matrix) {
if (!scene_opened) {
openVisualScene(scene_id);
scene_opened = true;
}
COLLADASW::Node node(mSW);
node.setNodeId(node_id);
node.setNodeName(node_name);
node.setType(COLLADASW::Node::NODE);
// The matrix attribute of an entity is basically a 4x3 representation of its ObjectPlacement.
// Note that this placement is absolute, ie it is multiplied with all parent placements.
double matrix_array[4][4] = {
{matrix[0], matrix[3], matrix[6], matrix[ 9]},
{matrix[1], matrix[4], matrix[7], matrix[10]},
{matrix[2], matrix[5], matrix[8], matrix[11]},
{ 0, 0, 0, 1}
};
node.start();
node.addMatrix(matrix_array);
COLLADASW::InstanceGeometry instanceGeometry(mSW);
instanceGeometry.setUrl ("#" + geom_name);
for (std::vector<std::string>::const_iterator it = material_ids.begin(); it != material_ids.end(); ++it) {
COLLADASW::InstanceMaterial material (*it, "#" + *it);
instanceGeometry.getBindMaterial().getInstanceMaterialList().push_back(material);
}
instanceGeometry.add();
node.end();
}
void ColladaSerializer::ColladaExporter::ColladaScene::write() {
if (scene_opened) {
closeVisualScene();
closeLibrary();
COLLADASW::Scene scene (mSW, COLLADASW::URI ("#" + scene_id));
scene.add();
}
}
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeom::Material& material) {
openEffect(collada_id(material.name()) + "-fx");
COLLADASW::EffectProfile effect(mSW);
effect.setShaderType(COLLADASW::EffectProfile::LAMBERT);
if (material.hasDiffuse()) {
const double* diffuse = material.diffuse();
effect.setDiffuse(COLLADASW::ColorOrTexture(COLLADASW::Color(diffuse[0],diffuse[1],diffuse[2])));
}
if (material.hasSpecular()) {
const double* specular = material.specular();
effect.setSpecular(COLLADASW::ColorOrTexture(COLLADASW::Color(specular[0],specular[1],specular[2])));
}
if (material.hasSpecularity()) {
effect.setShininess(material.specularity());
}
if (material.hasTransparency()) {
const double transparency = material.transparency();
if (transparency > 0) {
// The default opacity mode for Collada is A_ONE, which apparently indicates a
// transparency value of 1 to be fully opaque. Hence transparency is inverted.
effect.setTransparency(1.0 - transparency);
}
}
addEffectProfile(effect);
closeEffect();
}
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::close() {
closeLibrary();
}
void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const IfcGeom::Material& material) {
if (!contains(material)) {
effects.write(material);
materials.push_back(material);
}
}
bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeom::Material& material) {
return std::find(materials.begin(), materials.end(), material) != materials.end();
}
void ColladaSerializer::ColladaExporter::ColladaMaterials::write() {
effects.close();
for (std::vector<IfcGeom::Material>::const_iterator it = materials.begin(); it != materials.end(); ++it) {
const std::string& material_name = collada_id((*it).name());
openMaterial(material_name);
addInstanceEffect("#" + material_name + "-fx");
closeMaterial();
}
closeLibrary();
}
void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_name, float unit_magnitude) {
stream.startDocument();
COLLADASW::Asset asset(&stream);
asset.getContributor().mAuthoringTool = std::string("IfcOpenShell ") + IFCOPENSHELL_VERSION;
asset.setUnit(unit_name, unit_magnitude);
asset.setUpAxisType(COLLADASW::Asset::Z_UP);
asset.add();
}
void ColladaSerializer::ColladaExporter::write(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& _materials) {
std::vector<std::string> material_references;
for (std::vector<IfcGeom::Material>::const_iterator it = _materials.begin(); it != _materials.end(); ++it) {
const IfcGeom::Material& material = *it;
if (!materials.contains(material)) {
materials.add(material);
}
material_references.push_back(collada_id(material.name()));
}
deferreds.push_back(DeferredObject(guid, name, type, obj_id, matrix, vertices, normals, indices, material_ids, _materials, material_references));
}
const std::string ColladaSerializer::ColladaExporter::DeferredObject::Name() const {
std::stringstream ss;
if (!this->name.empty()) {
ss << this->obj_id << "_" << this->name;
} else {
ss << this->guid;
}
return collada_id(ss.str());
}
void ColladaSerializer::ColladaExporter::endDocument() {
// In fact due the XML based nature of Collada and its dependency on library nodes,
// only at this point all objects are written to the stream.
materials.write();
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
const std::string object_name = it->Name();
geometries.write(object_name, it->type, it->vertices, it->normals, it->indices, it->material_ids, it->materials);
}
geometries.close();
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
const std::string object_name = it->Name();
scene.add(object_name + "-instance", object_name, object_name, it->material_references, it->matrix);
}
scene.write();
stream.endDocument();
}
bool ColladaSerializer::ready() {
return true;
}
void ColladaSerializer::writeHeader() {
exporter.startDocument(unit_name, unit_magnitude);
}
void ColladaSerializer::write(const IfcGeom::TriangulationElement<double>* o) {
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
exporter.write(o->guid(), o->name(), o->type(), o->id(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.material_ids(), mesh.materials());
}
void ColladaSerializer::finalize() {
exporter.endDocument();
}
#endif
-165
View File
@@ -1,165 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifdef WITH_OPENCOLLADA
#ifndef COLLADASERIALIZER_H
#define COLLADASERIALIZER_H
#include <COLLADASWStreamWriter.h>
#include <COLLADASWPrimitves.h>
#include <COLLADASWLibraryGeometries.h>
#include <COLLADASWSource.h>
#include <COLLADASWScene.h>
#include <COLLADASWNode.h>
#include <COLLADASWInstanceGeometry.h>
#include <COLLADASWLibraryVisualScenes.h>
#include <COLLADASWLibraryEffects.h>
#include <COLLADASWLibraryMaterials.h>
#include <COLLADASWBaseInputElement.h>
#include <COLLADASWAsset.h>
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcconvert/GeometrySerializer.h"
class ColladaSerializer : public GeometrySerializer
{
private:
class ColladaExporter
{
private:
class ColladaGeometries : public COLLADASW::LibraryGeometries
{
public:
explicit ColladaGeometries(COLLADASW::StreamWriter& stream)
: COLLADASW::LibraryGeometries(&stream)
{}
void addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<double>& floats, const char* coords = "XYZ");
void write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials);
void close();
};
class ColladaScene : public COLLADASW::LibraryVisualScenes
{
private:
const std::string scene_id;
bool scene_opened;
public:
ColladaScene(const std::string& scene_id, COLLADASW::StreamWriter& stream)
: COLLADASW::LibraryVisualScenes(&stream)
, scene_id(scene_id)
, scene_opened(false)
{}
void add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<double>& matrix);
void write();
};
class ColladaMaterials : public COLLADASW::LibraryMaterials
{
private:
class ColladaEffects : public COLLADASW::LibraryEffects
{
public:
explicit ColladaEffects(COLLADASW::StreamWriter& stream)
: COLLADASW::LibraryEffects(&stream)
{}
void write(const IfcGeom::Material& material);
void close();
};
std::vector<IfcGeom::Material> materials;
ColladaEffects effects;
public:
explicit ColladaMaterials(COLLADASW::StreamWriter& stream)
: COLLADASW::LibraryMaterials(&stream)
, effects(stream)
{}
void add(const IfcGeom::Material& material);
bool contains(const IfcGeom::Material& material);
void write();
};
class DeferredObject {
public:
std::string guid, name, type;
int obj_id;
std::vector<double> matrix;
std::vector<double> vertices;
std::vector<double> normals;
std::vector<int> indices;
std::vector<int> material_ids;
std::vector<IfcGeom::Material> materials;
std::vector<std::string> material_references;
DeferredObject(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<double>& matrix, const std::vector<double>& vertices,
const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids,
const std::vector<IfcGeom::Material>& materials, const std::vector<std::string>& material_references)
: guid(guid)
, name(name)
, type(type)
, obj_id(obj_id)
, matrix(matrix)
, vertices(vertices)
, normals(normals)
, indices(indices)
, material_ids(material_ids)
, materials(materials)
, material_references(material_references)
{}
const std::string Name() const;
};
COLLADABU::NativeString filename;
COLLADASW::StreamWriter stream;
ColladaGeometries geometries;
ColladaScene scene;
ColladaMaterials materials;
public:
ColladaExporter(const std::string& scene_name, const std::string& fn)
: filename(fn.c_str())
, stream(filename)
, geometries(stream)
, scene(scene_name, stream)
, materials(stream)
{}
std::vector<DeferredObject> deferreds;
virtual ~ColladaExporter() {}
void startDocument(const std::string& unit_name, float unit_magnitude);
void write(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& materials);
void endDocument();
};
ColladaExporter exporter;
std::string unit_name;
float unit_magnitude;
public:
ColladaSerializer(const std::string& dae_filename)
: GeometrySerializer()
, exporter("IfcOpenShell", dae_filename)
{}
bool ready();
void writeHeader();
void write(const IfcGeom::TriangulationElement<double>* o);
void write(const IfcGeom::BRepElement<double>* o) {}
void finalize();
bool isTesselated() const { return true; }
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
unit_name = name;
unit_magnitude = magnitude;
}
void setFile(IfcParse::IfcFile*) {}
};
#endif
#endif
File diff suppressed because it is too large Load Diff
-78
View File
@@ -1,78 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* This file defines default materials for several IFC datatypes *
* *
********************************************************************************/
#ifndef SURFACESTYLE_H
#define SURFACESTYLE_H
#include <string>
#include <sstream>
#include <array>
class SurfaceStyle {
public:
class ColorComponent {
private:
std::array<double, 3> data;
public:
ColorComponent(double r, double g, double b) {
data[0] = r; data[1] = g; data[2] = b;
}
const double& R() const { return data[0]; }
const double& G() const { return data[1]; }
const double& B() const { return data[2]; }
double& R() { return data[0]; }
double& G() { return data[1]; }
double& B() { return data[2]; }
};
private:
std::string name;
ColorComponent diffuse, specular, ambient;
double transparency;
double specularity;
public:
SurfaceStyle(const std::string& name,
double dr = 0.7, double dg = 0.7, double db = 0.7,
double sr = 0.2, double sg = 0.2, double sb = 0.2,
double ar = 0.1, double ag = 0.1, double ab = 0.1,
double Ns = 10.0, double Tr = 1.0)
: name(name)
, diffuse(dr, dg, db)
, specular(sr, sg, sb)
, ambient(ar, ag, ab)
, transparency(Tr)
, specularity(Ns)
{}
const std::string& Name() const { return name; }
const ColorComponent& Diffuse() const { return diffuse; }
const ColorComponent& Specular() const { return specular; }
const ColorComponent& Ambient() const { return ambient; }
double Transparency() const { return transparency; }
double Specularity() const { return specularity; }
};
SurfaceStyle GetDefaultMaterial(const std::string& s);
#endif
-257
View File
@@ -1,257 +0,0 @@
#include <map>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/foreach.hpp>
#include <boost/version.hpp>
#include "XmlSerializer.h"
using boost::property_tree::ptree;
using namespace IfcSchema;
static std::map<std::string, std::string> argument_name_map;
// Format an IFC attribute and maybe returns as string. Only literal scalar
// values are converted. Things like entity instances and lists are omitted.
boost::optional<std::string> format_attribute(const Argument* argument, IfcUtil::ArgumentType argument_type) {
boost::optional<std::string> value;
switch(argument_type) {
case IfcUtil::Argument_BOOL: {
const bool b = *argument;
value = b ? "true" : "false";
break; }
case IfcUtil::Argument_DOUBLE: {
const double d = *argument;
std::stringstream stream;
stream << d;
value = stream.str();
break; }
case IfcUtil::Argument_STRING:
case IfcUtil::Argument_ENUMERATION: {
value = static_cast<std::string>(*argument);
break; }
case IfcUtil::Argument_INT: {
const int v = *argument;
std::stringstream stream;
stream << v;
value = stream.str();
break; }
case IfcUtil::Argument_ENTITY: {
IfcUtil::IfcBaseClass* e = *argument;
if (Type::IsSimple(e->type())) {
IfcUtil::IfcBaseType* f = (IfcUtil::IfcBaseType*) e;
value = format_attribute(f->getArgument(0), f->getArgumentType(0));
} else if (e->is(IfcSchema::Type::IfcSIUnit) || e->is(IfcSchema::Type::IfcConversionBasedUnit)) {
// Some string concatenation to have a unit name as a XML attribute.
std::string unit_name;
if (e->is(IfcSchema::Type::IfcSIUnit)) {
IfcSchema::IfcSIUnit* unit = (IfcSchema::IfcSIUnit*) e;
unit_name = IfcSchema::IfcSIUnitName::ToString(unit->Name());
if (unit->hasPrefix()) {
unit_name = IfcSchema::IfcSIPrefix::ToString(unit->Prefix()) + unit_name;
}
} else {
IfcSchema::IfcConversionBasedUnit* unit = (IfcSchema::IfcConversionBasedUnit*) e;
unit_name = unit->Name();
}
for (std::string::iterator c = unit_name.begin(); c != unit_name.end(); ++c) *c = tolower(*c);
value = unit_name;
}
break; }
}
return value;
}
// Formats an entity instances as a ptree node, and insert into the DOM. Recurses
// over the entity attributes and writes them as xml attributes of the node.
ptree& format_entity_instance(IfcUtil::IfcBaseEntity* instance, ptree& tree, bool as_link = false) {
ptree child;
const unsigned n = instance->getArgumentCount();
for (unsigned i = 0; i < n; ++i) {
const Argument* argument = instance->getArgument(i);
if (argument->isNull()) continue;
std::string argument_name = instance->getArgumentName(i);
std::map<std::string, std::string>::const_iterator argument_name_it;
argument_name_it = argument_name_map.find(argument_name);
if (argument_name_it != argument_name_map.end()) {
argument_name = argument_name_it->second;
}
const IfcUtil::ArgumentType argument_type = instance->getArgumentType(i);
boost::optional<std::string> value;
try {
value = format_attribute(argument, argument_type);
} catch (...) {}
if (value) {
if (as_link) {
if (argument_name == "id") {
child.put("<xmlattr>.xlink:href", std::string("#") + *value);
}
} else {
std::stringstream stream;
stream << "<xmlattr>." << argument_name;
child.put(stream.str(), *value);
}
}
}
return tree.add_child(Type::ToString(instance->type()), child);
}
// A function to be called recursively. Template specialization is used
// to descend into decomposition, containment and property relationships.
template <typename A>
void descend(A* instance, ptree& tree) {
format_entity_instance(instance, tree);
}
// Returns related entity instances using IFC's objectified relationship
// model. The second and third argument require a member function pointer.
template <typename T, typename U, typename V, typename F, typename G>
typename V::list::ptr get_related(T* t, F f, G g) {
typename U::list::ptr li = (*t.*f)()->template as<U>();
typename V::list::ptr acc(new typename V::list);
for (typename U::list::it it = li->begin(); it != li->end(); ++it) {
U* u = *it;
acc->push((*u.*g)());
}
return acc;
}
// Descends into the tree by recursing into IfcRelContainedInSpatialStructure,
// IfcRelDecomposes and IfcRelDefinesByProperties relations.
template <>
void descend(IfcProduct* product, ptree& tree) {
ptree& child = format_entity_instance(product, tree);
if (product->is(Type::IfcSpatialStructureElement)) {
IfcSpatialStructureElement* structure = (IfcSpatialStructureElement*) product;
IfcProduct::list::ptr elements = get_related
<IfcSpatialStructureElement, IfcRelContainedInSpatialStructure, IfcProduct>
(structure, &IfcSpatialStructureElement::ContainsElements, &IfcRelContainedInSpatialStructure::RelatedElements);
for (IfcProduct::list::it it = elements->begin(); it != elements->end(); ++it) {
descend(*it, child);
}
}
IfcObjectDefinition::list::ptr structures = get_related
<IfcProduct, IfcRelDecomposes, IfcObjectDefinition>
(product, &IfcProduct::IsDecomposedBy, &IfcRelDecomposes::RelatedObjects);
for (IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
IfcObjectDefinition* ob = *it;
if (ob->is(Type::IfcSpatialStructureElement)) {
descend((IfcProduct*)ob, child);
} else {
descend(ob, child);
}
}
IfcPropertySetDefinition::list::ptr property_sets = get_related
<IfcProduct, IfcRelDefinesByProperties, IfcPropertySetDefinition>
(product, &IfcProduct::IsDefinedBy, &IfcRelDefinesByProperties::RelatingPropertyDefinition);
for (IfcPropertySetDefinition::list::it it = property_sets->begin(); it != property_sets->end(); ++it) {
IfcPropertySetDefinition* pset = *it;
if (pset->is(Type::IfcPropertySet)) {
format_entity_instance(pset, child, true);
}
}
}
// Descends into the tree by recursing into IfcRelDecomposes relations.
template <>
void descend(IfcProject* project, ptree& tree) {
ptree& child = format_entity_instance(project, tree);
IfcObjectDefinition::list::ptr structures = get_related
<IfcProject, IfcRelDecomposes, IfcObjectDefinition>
(project, &IfcProject::IsDecomposedBy, &IfcRelDecomposes::RelatedObjects);
for (IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
IfcObjectDefinition* ob = *it;
if (ob->is(Type::IfcSpatialStructureElement)) {
descend((IfcProduct*)ob, child);
} else {
descend(ob, child);
}
}
}
// Format IfcProperty instances and insert into the DOM. IfcComplexProperties are flattened out.
void format_properties(IfcProperty::list::ptr properties, ptree& node) {
for (IfcProperty::list::it it = properties->begin(); it != properties->end(); ++it) {
IfcProperty* p = *it;
if (p->is(Type::IfcComplexProperty)) {
IfcComplexProperty* complex = (IfcComplexProperty*) p;
format_properties(complex->HasProperties(), node);
} else {
format_entity_instance(p, node);
}
}
}
void XmlSerializer::finalize() {
argument_name_map.insert(std::make_pair("GlobalId", "id"));
IfcProject::list::ptr projects = file->entitiesByType<IfcProject>();
if (projects->size() != 1) {
Logger::Message(Logger::LOG_ERROR, "Expected a single IfcProject");
return;
}
IfcProject* project = *projects->begin();
ptree root, header, decomposition, properties;
// Write the SPF header as XML nodes.
BOOST_FOREACH(const std::string& s, file->header().file_description().description()) {
header.add_child("file_description.description", ptree(s));
}
BOOST_FOREACH(const std::string& s, file->header().file_name().author()) {
header.add_child("file_name.author", ptree(s));
}
BOOST_FOREACH(const std::string& s, file->header().file_name().organization()) {
header.add_child("file_name.organization", ptree(s));
}
BOOST_FOREACH(const std::string& s, file->header().file_schema().schema_identifiers()) {
header.add_child("file_schema.schema_identifiers", ptree(s));
}
header.put("file_description.implementation_level", file->header().file_description().implementation_level());
header.put("file_name.name", file->header().file_name().name());
header.put("file_name.time_stamp", file->header().file_name().time_stamp());
header.put("file_name.preprocessor_version", file->header().file_name().preprocessor_version());
header.put("file_name.originating_system", file->header().file_name().originating_system());
header.put("file_name.authorization", file->header().file_name().authorization());
// Descend into the decomposition structure of the IFC file.
descend(project, decomposition);
// Write all property sets and values as XML nodes.
IfcPropertySet::list::ptr psets = file->entitiesByType<IfcPropertySet>();
for (IfcPropertySet::list::it it = psets->begin(); it != psets->end(); ++it) {
IfcPropertySet* pset = *it;
ptree& node = format_entity_instance(pset, properties);
format_properties(pset->HasProperties(), node);
}
root.add_child("ifc.header", header);
root.add_child("ifc.properties", properties);
root.add_child("ifc.decomposition", decomposition);
root.put("ifc.<xmlattr>.xmlns:xlink", "http://www.w3.org/1999/xlink");
#if BOOST_VERSION >= 105600
boost::property_tree::xml_writer_settings<ptree::key_type> settings = boost::property_tree::xml_writer_make_settings<ptree::key_type>('\t', 1);
#else
boost::property_tree::xml_writer_settings<char> settings('\t', 1);
#endif
boost::property_tree::write_xml(xml_filename, root, std::locale(), settings);
}
+3 -1
View File
@@ -4,6 +4,8 @@ the IFC schema and will most likely fail on any other Express schema.
The code can be invoked in the following way and results in two header files
and a single implementation file named according to the schema name in the
Express file. A python 3 interpreter with the pyparsing library is required.
Express file. A python 3 interpreter with the pyparsing [1] library is required.
$ python bootstrap.py express.bnf > express_parser.py && python express_parser.py IFC2X3_TC1.exp
[1] http://pyparsing.wikispaces.com/Download+and+Installation
+52 -28
View File
@@ -19,8 +19,14 @@
import sys
import string
import operator
import itertools
from pyparsing import *
try: from functools import reduce
except: pass
class Expression:
def __init__(self, contents):
self.contents = contents[0]
@@ -56,12 +62,12 @@ class Keyword:
class Terminal:
def __init__(self, contents):
self.contents = contents[0]
def __repr__(self):
s = self.contents
is_keyword = len(s) >= 4 and s[0::len(s)-1] == '""' and \
self.is_keyword = len(s) >= 4 and s[0::len(s)-1] == '""' and \
all(c in alphanums+"_" for c in s[1:-1])
ty = "CaselessKeyword" if is_keyword else "CaselessLiteral"
return "%s(%s)" % (ty, s)
def __repr__(self):
ty = "CaselessKeyword" if self.is_keyword else "CaselessLiteral"
return "%s(%s)" % (ty, self.contents)
LPAREN = Suppress("(")
@@ -94,16 +100,16 @@ grammar.ignore(HASH + restOfLine)
express = grammar.parseFile(sys.argv[1])
def find_keywords(expr, li = None):
def find_bytype(expr, ty, li = None):
if li is None: li = []
if isinstance(expr, Term):
expr = expr.contents
if isinstance(expr, Keyword):
li.append(repr(expr))
return li
if isinstance(expr, ty):
li.append(expr)
return set(li)
elif isinstance(expr, Expression):
for term in expr:
find_keywords(term, li)
find_bytype(term, ty, li)
return set(li)
actions = {
@@ -115,13 +121,15 @@ actions = {
'general_aggregation_types' : "lambda t: AggregationType(t)",
'select_type' : "lambda t: SelectType(t)",
'binary_type' : "lambda t: BinaryType(t)",
'subtype_declaration' : "lambda t: SubtypeExpression(t)",
'subtype_declaration' : "lambda t: SubTypeExpression(t)",
'derive_clause' : "lambda t: AttributeList('derive', t)",
'derived_attr' : "lambda t: DerivedAttribute(t)",
'inverse_clause' : "lambda t: AttributeList('inverse', t)",
'inverse_attr' : "lambda t: InverseAttribute(t)",
'bound_spec' : "lambda t: BoundSpecification(t)",
'explicit_attr' : "lambda t: ExplicitAttribute(t)",
'width_spec' : "lambda t: WidthSpec(t)",
'string_type' : "lambda t: StringType(t)",
}
to_emit = set(id for id, expr in express)
@@ -129,18 +137,22 @@ emitted = set()
to_combine = set(["simple_id"])
to_ignore = set(["where_clause", "supertype_constraint", "unique_clause"])
statements = []
terminals = reduce(lambda x,y: x | y, (find_bytype(e, Terminal) for id, e in express))
keywords = list(filter(operator.attrgetter('is_keyword'), terminals))
negated_keywords = map(lambda s: "~%s" % s, keywords)
while True:
emitted_in_loop = set()
for id, expr in express:
kws = find_keywords(expr)
kws = map(repr, find_bytype(expr, Keyword))
found = [k in emitted for k in kws]
if id in to_emit and all(found):
emitted_in_loop.add(id)
emitted.add(id)
stmt = "(%s)" % expr
if id in to_combine:
stmt = "originalTextFor(Combine%s)" % stmt
stmt = " + ".join(itertools.chain(negated_keywords, ("originalTextFor(Combine%s)" % stmt,)))
if id in actions:
stmt = "%s.setParseAction(%s)" % (stmt, actions[id])
statements.append("%s = %s" % (id, stmt))
@@ -158,29 +170,41 @@ for id in to_emit:
stmt = "Suppress%s" % stmt
statements.append("%s << %s" % (id, stmt))
print ("""import sys
from pyparsing import *
from nodes import *
print ("""import os
import sys
import pickle
%s
cache_file = sys.argv[1] + ".cache.dat"
if os.path.exists(cache_file):
with open(cache_file, "rb") as f:
mapping = pickle.load(f)
else:
from pyparsing import *
from nodes import *
import schema
import mapping
%s
import schema
import mapping
syntax.ignore("--" + restOfLine)
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
ast = syntax.parseFile(sys.argv[1])
schema = schema.Schema(ast)
mapping = mapping.Mapping(schema)
with open(cache_file, "wb") as f:
pickle.dump(mapping, f, protocol=0)
import header
import enum_header
import implementation
import latebound_header
import latebound_implementation
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
ast = syntax.parseFile(sys.argv[1])
schema = schema.Schema(ast)
mapping = mapping.Mapping(schema)
import schema_class
header.Header(mapping).emit()
enum_header.EnumHeader(mapping).emit()
implementation.Implementation(mapping).emit()
latebound_header.LateBoundHeader(mapping).emit()
latebound_implementation.LateBoundImplementation(mapping).emit()
"""%('\n'.join(statements)))
schema_class.SchemaClass(mapping).emit()
sys.stdout.write(schema.name)
"""%('\n '.join(statements)))
+35
View File
@@ -0,0 +1,35 @@
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
class Base(object):
"""
A base class for all code generation classes. Currently only working around
some python 2/3 incompatibilities in terms of unicode file handling.
"""
def emit(self):
import platform
if tuple(map(int, platform.python_version_tuple())) < (2, 8):
from io import open as unicode_open
unicode_type = unicode
else:
unicode_open = open
unicode_type = lambda x, *args, **kwargs: x
f = unicode_open(self.file_name, 'w', encoding='utf-8')
f.write(unicode_type(repr(self), encoding='utf-8', errors='ignore'))
f.close()
+12 -5
View File
@@ -27,18 +27,25 @@
# #
###############################################################################
import re,csv
import re
import os
import csv
from schema import OrderedCaseInsensitiveDict
try: from html.entities import entitydefs
except: from htmlentitydefs import entitydefs
name_to_oid = {}
make_absolute = lambda fn: os.path.join(os.path.dirname(os.path.realpath(__file__)), fn)
name_to_oid = OrderedCaseInsensitiveDict()
oid_to_desc = {}
oid_to_name = {}
oid_to_pid = {}
regices = list(zip([re.compile(s,re.M) for s in [r'<[\w\n=" \-/\.;_\t:%#,\?\(\)]+>',r'(\n[\t ]*){2,}',r'^[\t ]+']],['','\n\n',' ']))
definition_files = ['DocEntity.csv', 'DocEnumeration.csv', 'DocDefined.csv', 'DocSelect.csv']
definition_files = map(make_absolute, definition_files)
for fn in definition_files:
with open(fn) as f:
for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'):
@@ -46,15 +53,15 @@ for fn in definition_files:
oid_to_name[oid] = name
oid_to_desc[oid] = desc
with open('DocEntityAttributes.csv') as f:
with open(make_absolute('DocEntityAttributes.csv')) as f:
for pid, x, oid in csv.reader(f, delimiter=';', quotechar='"'):
oid_to_pid[oid] = pid
with open('DocAttribute.csv') as f:
with open(make_absolute('DocAttribute.csv')) as f:
for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'):
pid = oid_to_pid[oid]
pname = oid_to_name[pid]
name_to_oid[(pname, name)] = oid
name_to_oid[".".join((pname, name))] = oid
oid_to_desc[oid] = desc
def description(item):
+6 -5
View File
@@ -18,8 +18,9 @@
###############################################################################
import templates
import codegen
class EnumHeader:
class EnumHeader(codegen.Base):
def __init__(self, mapping):
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]))
@@ -30,9 +31,9 @@ class EnumHeader:
}
self.schema_name = mapping.schema.name.capitalize()
self.file_name = '%senum.h'%self.schema_name
def __repr__(self):
return self.str
def emit(self):
f = open('%senum.h'%self.schema_name, 'w', encoding='utf-8')
f.write(str(self))
f.close()
+2 -4
View File
@@ -1,5 +1,3 @@
# Taken from http://sourceforge.net/p/exp-engine/expresso/ci/master/tree/docs/iso-10303-11--2004.bnf
ABS = "abs" .
ABSTRACT = "abstract" .
ACOS = "acos" .
@@ -202,7 +200,7 @@ constructed_types = enumeration_type | select_type .
declaration = entity_decl | function_decl | procedure_decl | subtype_constraint_decl | type_decl .
derived_attr = attribute_decl ":" parameter_type ":=" expression ";" .
derive_clause = DERIVE derived_attr { derived_attr } .
domain_rule = rule_label_id ":" expression .
domain_rule = [ rule_label_id ":" ] expression .
element = expression [ ":" repetition ] .
entity_body = { explicit_attr } [ derive_clause ] [ inverse_clause ] [ unique_clause ] [ where_clause ] .
entity_constructor = entity_ref "(" [ expression { "," expression } ] ")" .
@@ -334,7 +332,7 @@ type_label_id = simple_id .
unary_op = "+" | "-" | NOT .
underlying_type = constructed_types | concrete_types .
unique_clause = UNIQUE unique_rule ";" { unique_rule ";" } .
unique_rule = rule_label_id ":" referenced_attribute { "," referenced_attribute } .
unique_rule = [ rule_label_id ":" ] referenced_attribute { "," referenced_attribute } .
until_control = UNTIL logical_expression .
use_clause = USE FROM schema_ref [ "(" named_type_or_rename { "," named_type_or_rename } ")" ] ";" .
variable_id = simple_id .
+33 -18
View File
@@ -17,10 +17,13 @@
# #
###############################################################################
import operator
import codegen
import templates
import documentation
class Header:
class Header(codegen.Base):
def __init__(self, mapping):
declarations = []
@@ -40,15 +43,18 @@ class Header:
emitted_simpletypes = set()
while len(emitted_simpletypes) < len(mapping.schema.simpletypes):
for name, type in mapping.schema.simpletypes.items():
if name in emitted_simpletypes: continue
if name.lower() in emitted_simpletypes: continue
type_str = mapping.make_type_string(mapping.flatten_type_string(type))
attr_type = mapping.make_argument_type(type)
superclass = mapping.simple_type_parent(name)
if superclass is None:
superclass = "IfcUtil::IfcBaseType"
elif superclass not in emitted_simpletypes:
elif superclass.lower() not in emitted_simpletypes:
continue
emitted_simpletypes.add(name)
else:
# Case normalize
superclass = [k for k in mapping.schema.simpletypes.keys() if k.lower() == superclass.lower()][0]
emitted_simpletypes.add(name.lower())
write(templates.simpletype, name=name, type=type_str, attr_type=attr_type, superclass=superclass)
class_definitions = []
@@ -59,14 +65,14 @@ class Header:
emitted_entities = set()
while len(emitted_entities) < len(mapping.schema.entities):
for name, type in mapping.schema.entities.items():
if name in emitted_entities: continue
if len(type.supertypes) == 0 or set(type.supertypes) < emitted_entities:
if name.lower() in emitted_entities: continue
if len(type.supertypes) == 0 or set(map(str.lower, type.supertypes)) <= emitted_entities:
attr_lines = []
def write_method(attr):
if attr.optional:
attr_lines.append(templates.optional_attribute_description % (attr.name, name))
attr_lines.append("bool has%s() const;"%(attr.name))
attr_lines.extend(["/// %s"%d for d in documentation.description((name, attr.name))])
attr_lines.extend(["/// %s"%d for d in documentation.description(".".join((name, attr.name)))])
type_str = mapping.get_parameter_type(attr, allow_optional=False, allow_entities=False)
if mapping.make_argument_type(attr) != "IfcUtil::Argument_UNKNOWN":
attr_lines.append("%s %s() const;"%(type_str, attr.name))
@@ -87,7 +93,11 @@ class Header:
inverse = "\n".join(["%s%s"%(' '*4, a) for a in inv_lines])
if len(inverse): inverse += '\n'
supertypes = type.supertypes if len(type.supertypes) else ['IfcUtil::IfcBaseEntity']
def case_norm(n):
n = n.lower()
return [k for k in mapping.schema.entities.keys() if k.lower() == n][0]
supertypes = map(case_norm, type.supertypes) if len(type.supertypes) else ['IfcUtil::IfcBaseEntity']
superclass = ": %s "%(", ".join(["public %s"%c for c in supertypes]))
argument_count = mapping.argument_count(type)
@@ -95,17 +105,23 @@ class Header:
argument_start = argument_count - len(type.attributes)
argument_name_function_body_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return "%s"; '%(i+argument_start, attr.name) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
argument_name_function_body_tail = (" return %s::getArgumentName(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcException("argument out of range"); '
argument_name_function_body_tail = (" return %s::getArgumentName(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' (void)i; throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
argument_name_function_body = argument_name_function_body_switch_stmt + argument_name_function_body_tail
argument_type_function_body_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return %s; '%(i+argument_start, mapping.make_argument_type(attr)) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
argument_type_function_body_tail = (" return %s::getArgumentType(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcException("argument out of range"); '
derived = mapping.derived_in_supertype(type)
attribute_names = list(map(operator.attrgetter('name'), mapping.arguments(type)))
derived_in_supertype = set(derived) & set(attribute_names)
derived_in_supertype_indices = sorted(attribute_names.index(nm) for nm in derived_in_supertype)
attribute_type_cases = ['case %d: return IfcUtil::Argument_DERIVED; ' % idx for idx in derived_in_supertype_indices]
attribute_type_cases += ['case %d: return %s; '%(i+argument_start, mapping.make_argument_type(attr)) for i, attr in enumerate(type.attributes)]
argument_type_function_body_switch_stmt = " switch (i) {%s}"%("".join(attribute_type_cases)) if len(type.attributes) else ""
argument_type_function_body_tail = (" return %s::getArgumentType(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' (void)i; throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
argument_type_function_body = argument_type_function_body_switch_stmt + argument_type_function_body_tail
argument_entity_function_body_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return %s; '%(i+argument_start, mapping.make_argument_entity(attr)) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
argument_entity_function_body_tail = (" return %s::getArgumentEntity(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcException("argument out of range"); '
argument_entity_function_body_tail = (" return %s::getArgumentEntity(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' (void)i; throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
argument_entity_function_body = argument_entity_function_body_switch_stmt + argument_entity_function_body_tail
@@ -123,10 +139,9 @@ class Header:
}
self.schema_name = mapping.schema.name.capitalize()
self.file_name = '%s.h'%self.schema_name
def __repr__(self):
return self.str
def emit(self):
f = open('%s.h'%self.schema_name, 'w', encoding='utf-8')
f.write(str(self))
f.close()
+65 -38
View File
@@ -17,15 +17,19 @@
# #
###############################################################################
import codegen
import templates
class Implementation:
from schema import OrderedCaseInsensitiveDict
class Implementation(codegen.Base):
def __init__(self, mapping):
enumeration_functions = []
entity_implementations = []
schema_entity_statements = []
schema_name = mapping.schema.name.capitalize()
schema_name_upper = mapping.schema.name.upper()
stringify = lambda s: '"%s"'%s
cat = lambda vs: "".join(vs)
@@ -43,6 +47,8 @@ class Implementation:
templates.enumeration_function,
max_id = len(enum.values),
name = name,
schema_name = schema_name,
schema_name_upper = schema_name_upper,
values = catc(map(stringify, enum.values)),
from_string_statements = catnl(templates.enum_from_string_stmt%dict(context,**locals()) for value in enum.values)
)
@@ -52,6 +58,7 @@ class Implementation:
for name, type in mapping.schema.entities.items():
parent_type_test = "" if not type.supertypes or len(type.supertypes) != 1 \
else templates.parent_type_test%(type.supertypes[0])
constructor_arguments = mapping.get_assignable_arguments(type, include_derived = True)
constructor_arguments_str = catc("%(full_type)s v%(index)d_%(name)s"%a for a in constructor_arguments if not a['is_derived'])
attributes = []
@@ -63,6 +70,8 @@ class Implementation:
write_attr(
templates.const_function,
class_name = name,
schema_name = schema_name,
schema_name_upper = schema_name_upper,
name = 'has%s'%arg['name'],
arguments = '',
return_type = 'bool',
@@ -72,10 +81,10 @@ class Implementation:
def find_template(arg):
simple = mapping.schema.is_simpletype(arg['list_instance_type'])
select = arg['list_instance_type'] == "IfcUtil::IfcBaseClass"
express = arg['list_instance_type'] in mapping.express_to_cpp_typemapping
express = mapping.flatten_type_string(arg['list_instance_type']) in mapping.express_to_cpp_typemapping
if arg['is_enum']: return templates.get_attr_stmt_enum
elif arg['is_nested']: return templates.get_attr_stmt_nested_array
elif arg['is_array'] and not (select or simple or express): return templates.get_attr_stmt_array
elif arg['is_nested'] and arg['is_templated_list']: return templates.get_attr_stmt_nested_array
elif arg['is_templated_list'] and not (select or simple or express): return templates.get_attr_stmt_array
elif arg['non_optional_type'].endswith('*'): return templates.get_attr_stmt_entity
else: return templates.get_attr_stmt
@@ -85,9 +94,11 @@ class Implementation:
class_name = name,
name = arg['name'],
arguments = '',
schema_name = schema_name,
schema_name_upper = schema_name_upper,
return_type = arg['non_optional_type'],
body = tmpl % {'index': arg['index']-1,
'type' : arg['non_optional_type'].split('::')[0],
'type' : arg['non_optional_type'].replace('::Value', ''),
'list_instance_type' : arg['list_instance_type']}
)
@@ -96,7 +107,7 @@ class Implementation:
select = arg['list_instance_type'] == "IfcUtil::IfcBaseClass"
express = arg['list_instance_type'] in mapping.express_to_cpp_typemapping
if arg['is_enum']: return templates.set_attr_stmt_enum
elif arg['is_array'] and not (select or simple or express): return templates.set_attr_stmt_array
elif arg['is_templated_list'] and not (select or simple or express): return templates.set_attr_stmt_array
else: return templates.set_attr_stmt
tmpl = find_template(arg)
@@ -106,8 +117,10 @@ class Implementation:
name = 'set%s'%arg['name'],
arguments = '%s v'%arg['non_optional_type'],
return_type = 'void',
schema_name = schema_name,
schema_name_upper = schema_name_upper,
body = tmpl % {'index': arg['index']-1,
'type' : arg['non_optional_type'].split('::')[0]}
'type' : arg['non_optional_type'].replace('::Value', '')}
)
if arg['is_derived']:
@@ -122,7 +135,7 @@ class Implementation:
else templates.constructor_stmt
impl = tmpl % {'name' : deref_name,
'index' : arg['index']-1,
'type' : arg['non_optional_type'].split('::')[0]}
'type' : arg['non_optional_type'].replace('::Value', '')}
if is_optional_non_naked_ptr:
impl = templates.constructor_stmt_optional%{'name' : arg_name,
'index' : arg['index']-1,
@@ -131,17 +144,19 @@ class Implementation:
def get_attribute_index(entity, attr_name):
related_entity = mapping.schema.entities[entity]
return [a['name'] for a in mapping.get_assignable_arguments(related_entity, include_derived=True)].index(attr_name)
return [a['name'].lower() for a in mapping.get_assignable_arguments(related_entity, include_derived=True)].index(attr_name.lower())
inverse = [templates.const_function % {
'class_name' : name,
'schema_name' : schema_name,
'schema_name_upper' : schema_name_upper,
'name' : i.name,
'arguments' : '',
'return_type' : '%s::list::ptr' % i.entity,
'body' : templates.get_inverse % {'type': i.entity, 'index':get_attribute_index(i.entity, i.attribute)}
'return_type' : '::%s::%s::list::ptr' % (schema_name, i.entity),
'body' : templates.get_inverse % {'type': i.entity, 'index':get_attribute_index(i.entity, i.attribute), 'schema_name' : schema_name, 'schema_name_upper': schema_name_upper}
} for i in (type.inverse.elements if type.inverse else [])]
superclass = "%s((IfcAbstractEntity*)0)" % type.supertypes[0] if len(type.supertypes) == 1 else 'IfcUtil::IfcBaseEntity()'
superclass = "%s((IfcEntityInstanceData*)0)" % type.supertypes[0] if len(type.supertypes) == 1 else 'IfcUtil::IfcBaseEntity()'
write(
templates.entity_implementation,
@@ -151,10 +166,12 @@ class Implementation:
constructor_implementation = cat(constructor_implementations),
attributes = nl(catnl(attributes)),
inverse = nl(catnl(inverse)),
superclass = superclass
superclass = superclass,
schema_name = schema_name,
schema_name_upper = schema_name_upper
)
selectable_simple_types = sorted(set(sum([b.values for a,b in mapping.schema.selects.items()], [])) & set(mapping.schema.types.keys()))
selectable_simple_types = sorted(set(sum([b.values for a,b in mapping.schema.selects.items()], [])) & set(map(str, mapping.schema.types.keys())))
schema_entity_statements += [templates.schema_entity_stmt%locals() for name, type in mapping.schema.simpletypes.items()]
schema_entity_statements += [templates.schema_entity_stmt%locals() for name, type in mapping.schema.entities.items()]
@@ -166,12 +183,15 @@ class Implementation:
'name' : name,
'padding' : ' ' * (max_len - len(name))
} for name in enumerable_types]
enumeration_index_by_str = OrderedCaseInsensitiveDict((j,i) for i,j in enumerate(enumerable_types))
def get_parent_id(s):
e = mapping.schema.entities.get(s)
if e and e.supertypes:
return enumeration_index_by_str[e.supertypes[0]]
else: return -1
parent_type_statements = [templates.parent_type_stmt % {
'name' : name,
'parent' : type.supertypes[0],
'padding' : ' ' * (max_len - len(name))
} for name, type in mapping.schema.entities.items() if type.supertypes and len(type.supertypes) == 1]
parent_type_statements = ",".join(map(str, map(get_parent_id, enumerable_types)))
max_id = len(enumerable_types)
@@ -189,44 +209,51 @@ class Implementation:
constructor = templates.constructor_single_initlist if superclass \
else templates.constructor
def compose(params):
simpletype_impl_cast = templates.simpletype_impl_cast_templated if mapping.is_templated_list(type) \
else templates.simpletype_impl_cast
simpletype_impl_constructor = templates.simpletype_impl_constructor_templated if mapping.is_templated_list(type) \
else templates.simpletype_impl_constructor
def compose(params, schema_name=schema_name, schema_name_upper=schema_name_upper):
class_name, attr_type, superclass, superclass_init, name, tmpl, return_type, args, body = params
underlying_type = mapping.list_instance_type(type)
arguments = ",".join(args)
body = body % locals()
return tmpl % locals()
simple_type_impl.append(templates.simpletype_impl_comment % {'name': class_name})
simple_type_impl.extend(map(compose, map(lambda x: (class_name, attr_type, superclass, "(IfcAbstractEntity*)0")+x, (
('getArgumentType', templates.const_function, 'IfcUtil::ArgumentType', ('unsigned int i',), templates.simpletype_impl_argument_type ),
('getArgument', templates.const_function, 'Argument*', ('unsigned int i',), templates.simpletype_impl_argument ),
('is', templates.const_function, 'bool', ('Type::Enum v',), simpletype_impl_is ),
('type', templates.const_function, 'Type::Enum', (), templates.simpletype_impl_type ),
('Class', templates.function, 'Type::Enum', (), templates.simpletype_impl_class ),
('', constructor, '', ('IfcAbstractEntity* e',), templates.simpletype_impl_explicit_constructor),
('', constructor, '', ("%s v" % type_str,), templates.simpletype_impl_constructor ),
('', templates.cast_function, type_str, (), templates.simpletype_impl_cast )
simple_type_impl.extend(map(compose, map(lambda x: (class_name, attr_type, superclass, "(IfcEntityInstanceData*)0")+x, (
('Class', templates.function, 'const IfcParse::type_declaration&', (), templates.simpletype_impl_class ),
('declaration', templates.const_function, 'const IfcParse::type_declaration&', (), templates.simpletype_impl_declaration ),
('', constructor, '', ('IfcEntityInstanceData* e',), templates.simpletype_impl_explicit_constructor),
('', constructor, '', ("%s v" % type_str,), simpletype_impl_constructor ),
('', templates.cast_function, type_str, (), simpletype_impl_cast )
))))
simple_type_impl.append('')
external_definitions = [("extern entity* %s_%%s_type;" % schema_name_upper) % n for n in mapping.schema.entities.keys() ] + \
[("extern type_declaration* %s_%%s_type;" % schema_name_upper) % n for n in mapping.schema.simpletypes.keys()]
self.str = templates.implementation % {
'schema_name_upper' : mapping.schema.name.upper(),
'schema_name' : mapping.schema.name.capitalize(),
'schema_name_upper' : schema_name_upper,
'schema_name' : schema_name,
'max_id' : max_id,
'enumeration_functions' : cat(enumeration_functions),
'schema_entity_statements' : catnl(schema_entity_statements),
'type_name_strings' : type_name_strings,
'string_map_statements' : catnl(string_map_statements),
'simple_type_statement' : simple_type_statements,
'parent_type_statements' : catnl(parent_type_statements),
'parent_type_statements' : parent_type_statements,
'entity_implementations' : catnl(entity_implementations),
'simple_type_impl' : catnl(simple_type_impl)
'simple_type_impl' : catnl(simple_type_impl),
'external_definitions' : catnl(external_definitions)
}
self.schema_name = mapping.schema.name.capitalize()
self.file_name = '%s.cpp'%self.schema_name
def __repr__(self):
return self.str
def emit(self):
f = open('%s.cpp'%self.schema_name, 'w', encoding='utf-8')
f.write(str(self))
f.close()
@@ -1,119 +0,0 @@
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
import templates
class LateBoundImplementation:
def __init__(self, mapping):
schema_name = mapping.schema.name.capitalize()
entity_descriptors = []
enumeration_descriptors = []
derived_field_statements = []
inverse_implementations = []
for name, type in mapping.schema.simpletypes.items():
entity_descriptors.append(templates.entity_descriptor % {
'type' : name,
'parent_statement' : '0',
'entity_descriptor_attributes' : templates.entity_descriptor_attribute_without_entity % {
'name' : 'wrappedValue',
'optional' : 'false',
'type' : mapping.make_argument_type(mapping.schema.types[name].type)
}
})
emitted_entities = set()
entities_to_emit = mapping.schema.entities.keys()
while len(emitted_entities) < len(mapping.schema.entities):
for name, type in mapping.schema.entities.items():
if name in emitted_entities: continue
if len(type.supertypes) == 0 or set(type.supertypes) < emitted_entities:
constructor_arguments = mapping.get_assignable_arguments(type, include_derived = True)
entity_descriptor_attributes = []
for arg in constructor_arguments:
if not arg['is_inherited']:
is_enumeration = arg['argument_type_enum'] == 'IfcUtil::Argument_ENUMERATION'
tmpl = templates.entity_descriptor_attribute_with_entity
entity_name = arg['argument_type'] if is_enumeration else arg['argument_entity'].split('::')[1]
entity_descriptor_attributes.append(tmpl % {
'name' : arg['name'],
'optional' : 'true' if arg['is_optional'] else 'false',
'type' : arg['argument_type_enum'],
'entity_name': entity_name
})
emitted_entities.add(name)
parent_statement = '0' if len(type.supertypes) != 1 else templates.entity_descriptor_parent % {
'type' : type.supertypes[0]
}
entity_descriptors.append(templates.entity_descriptor % {
'type' : name,
'parent_statement' : parent_statement,
'entity_descriptor_attributes' : '\n'.join(entity_descriptor_attributes)
})
for name, enum in mapping.schema.enumerations.items():
enumeration_descriptor_values = '\n'.join([templates.enumeration_descriptor_value % {
'name' : v
} for v in enum.values])
enumeration_descriptors.append(templates.enumeration_descriptor % {
'type' : name,
'enumeration_descriptor_values' : enumeration_descriptor_values
})
for name, type in mapping.schema.entities.items():
constructor_arguments = mapping.get_assignable_arguments(type, include_derived = True)
statements = ''.join(templates.derived_field_statement_attrs % (a['index']-1) for a in constructor_arguments if a['is_derived'])
if len(statements):
derived_field_statements.append(templates.derived_field_statement % {
'type' : name,
'statements' : statements
})
for name, type in mapping.schema.entities.items():
if type.inverse:
for attr in type.inverse.elements:
related_entity = mapping.schema.entities[attr.entity]
related_attrs = [a['name'] for a in mapping.get_assignable_arguments(related_entity, include_derived=True)]
inverse_implementations.append(templates.inverse_implementation % {
'type' : name,
'name' : attr.name,
'related_type' : attr.entity,
'index' : related_attrs.index(attr.attribute)
})
self.str = templates.lb_implementation % {
'schema_name_upper' : mapping.schema.name.upper(),
'schema_name' : mapping.schema.name.capitalize(),
'entity_descriptors' : '\n'.join(entity_descriptors),
'enumeration_descriptors' : '\n'.join(enumeration_descriptors),
'derived_field_statements' : '\n'.join(derived_field_statements),
'inverse_implementations' : '\n'.join(inverse_implementations)
}
self.schema_name = mapping.schema.name.capitalize()
def __repr__(self):
return self.str
def emit(self):
f = open('%s-latebound.cpp'%self.schema_name, 'w', encoding='utf-8')
f.write(str(self))
f.close()
+66 -40
View File
@@ -17,6 +17,9 @@
# #
###############################################################################
from __future__ import print_function
import sys
import nodes
import templates
@@ -28,8 +31,15 @@ class Mapping:
'integer' : 'int',
'real' : 'double',
'number' : 'double',
'string' : 'std::string'
'string' : 'std::string',
'binary' : 'boost::dynamic_bitset<>'
}
supported_argument_types = set([
'INT', 'BOOL', 'DOUBLE', 'STRING', 'BINARY', 'ENUMERATION', 'ENTITY_INSTANCE',
'AGGREGATE_OF_INT', 'AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_STRING', 'AGGREGATE_OF_BINARY', 'AGGREGATE_OF_ENTITY_INSTANCE',
'AGGREGATE_OF_AGGREGATE_OF_INT', 'AGGREGATE_OF_AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE',
])
def __init__(self, schema):
self.schema = schema
@@ -44,17 +54,17 @@ class Mapping:
def simple_type_parent(self, type):
parent = self.schema.types[type].type.type
if isinstance(parent, nodes.AggregationType): parent = None
return None if parent in self.express_to_cpp_typemapping else parent
return None if str(parent) in self.express_to_cpp_typemapping else parent
def make_type_string(self, type):
if isinstance(type, str):
return self.express_to_cpp_typemapping.get(type, type)
if isinstance(type, (str, nodes.BinaryType, nodes.StringType)):
return self.express_to_cpp_typemapping.get(str(type), "::%s::%s" % (self.schema.name.capitalize(), type))
else:
is_list = self.schema.is_entity(type.type)
is_nested_list = isinstance(type.type, nodes.AggregationType)
tmpl = templates.list_list_type if is_nested_list else templates.list_type if is_list else templates.array_type
return tmpl % {
'instance_type' : self.make_type_string(type.type),
'instance_type' : self.make_type_string(self.flatten_type_string(type.type)),
'lower' : type.bounds.lower,
'upper' : type.bounds.upper,
}
@@ -70,66 +80,71 @@ class Mapping:
def make_argument_entity(self, attr):
type = attr.type if hasattr(attr, 'type') else attr
while isinstance(type, nodes.AggregationType): type = type.type
if type in self.express_to_cpp_typemapping or isinstance(type, nodes.BinaryType): return "Type::UNDEFINED"
if str(type) in self.express_to_cpp_typemapping: return "Type::UNDEFINED"
else: return "Type::%s" % type
def make_argument_type(self, attr):
def _make_argument_type(type):
if type in self.express_to_cpp_typemapping:
return self.express_to_cpp_typemapping.get(type, type).split('::')[-1].upper()
elif self.schema.is_entity(type):
return "ENTITY"
elif self.schema.is_type(type):
return _make_argument_type(self.schema.types[type].type.type)
if self.schema.is_entity(type) or isinstance(type, nodes.SelectType):
return "ENTITY_INSTANCE"
elif isinstance(type, nodes.BinaryType):
return "UNKNOWN"
return "BINARY"
elif isinstance(type, nodes.StringType):
return "STRING"
elif isinstance(type, nodes.EnumerationType):
return "ENUMERATION"
elif isinstance(type, nodes.SelectType):
return "ENTITY"
elif isinstance(type, nodes.AggregationType):
ty = _make_argument_type(type.type)
if ty == "UNKNOWN": return "UNKNOWN"
return "%s_LIST"%ty if ty.startswith("ENTITY") else ("VECTOR_%s"%ty)
else: raise ValueError
supported = {'INT', 'BOOL', 'DOUBLE', 'STRING', 'VECTOR_INT', 'VECTOR_DOUBLE', 'VECTOR_STRING', 'ENTITY', 'ENTITY_LIST', 'ENTITY_LIST_LIST', 'ENUMERATION'}
return "AGGREGATE_OF_" + ty
elif str(type) in self.express_to_cpp_typemapping:
return self.express_to_cpp_typemapping.get(str(type), type).split('::')[-1].upper()
elif self.schema.is_type(type):
return _make_argument_type(self.schema.types[type].type.type)
else:
raise ValueError("Unable to map type %r for attribute %r" % (type, attr))
ty = _make_argument_type(attr.type if hasattr(attr, 'type') else attr)
if ty not in supported: ty = 'UNKNOWN'
if ty not in self.supported_argument_types:
print("Attribute %r mapped as 'unknown'" % (attr), file=sys.stderr)
ty = 'UNKNOWN'
return "IfcUtil::Argument_%s" % ty
def get_type_dep(self, type):
if isinstance(type, str):
return self.express_to_cpp_typemapping.get(type, type)
return self.express_to_cpp_typemapping.get(str(type), type)
else:
return self.get_type_dep(type.type)
def get_parameter_type(self, attr, allow_optional, allow_entities, allow_pointer = True):
attr_type = self.flatten_type(attr.type)
type_str = self.express_to_cpp_typemapping.get(str(attr_type), attr_type)
is_ptr = False
if self.schema.is_enumeration(attr_type):
type_str = '%s::%s'%(attr_type, attr_type)
type_str = '::%s::%s::Value' % (self.schema.name.capitalize(), attr_type)
elif isinstance(type_str, nodes.AggregationType):
is_nested_list = isinstance(attr_type.type, nodes.AggregationType)
ty = self.get_parameter_type(attr_type.type if is_nested_list else attr_type, False, allow_entities, False)
if True and self.schema.is_select(attr_type.type):
if self.schema.is_select(attr_type.type):
type_str = templates.untyped_list
elif self.schema.is_simpletype(ty) or ty in self.express_to_cpp_typemapping.values():
type_str = templates.array_type % {
elif self.schema.is_simpletype(ty) or str(ty) in self.express_to_cpp_typemapping.values():
tmpl = templates.nested_array_type if is_nested_list else templates.array_type
bounds = (attr_type.bounds.lower, attr_type.bounds.upper) if attr_type.bounds else (-1, -1)
type_str = tmpl % {
'instance_type' : ty,
'lower' : attr_type.bounds.lower,
'upper' : attr_type.bounds.upper
'lower' : bounds[0],
'upper' : bounds[1]
}
else:
tmpl = templates.list_list_type if is_nested_list else templates.list_type
type_str = tmpl % {
'instance_type': ty
}
elif allow_pointer and (self.schema.is_entity(type_str) or self.schema.is_select(type_str)):
type_str += '*'
elif (self.schema.is_entity(type_str) or self.schema.is_select(type_str)):
type_str = '::%s::%s' % (self.schema.name.capitalize(), attr_type)
if allow_pointer:
type_str += "*"
is_ptr = True
elif not allow_pointer and self.schema.is_select(type_str):
type_str = "IfcUtil::IfcBaseClass*"
@@ -151,23 +166,34 @@ class Mapping:
return c + ([str(s) for s in t.derive.elements] if t.derive else [])
def list_instance_type(self, attr):
f = lambda v : 'IfcUtil::IfcBaseClass' if self.schema.is_select(v) else v
if self.is_array(attr.type):
if not isinstance(attr.type, str) and self.is_array(attr.type.type):
if isinstance(attr.type.type, str):
return f(attr.type.type)
else: return f(attr.type.type.type)
attr_type = attr.type if isinstance(attr, nodes.ExplicitAttribute) else attr
if isinstance(attr_type, str): return None
def f(v):
v = self.flatten_type(v)
if self.schema.is_select(v):
return 'IfcUtil::IfcBaseClass'
elif str(v) in self.schema.types or str(v) in self.schema.entities:
return "::%s::%s" % (self.schema.name.capitalize(), v)
else: return str(v)
if self.is_array(attr_type):
if not isinstance(attr_type, str) and self.is_array(attr_type.type):
if isinstance(attr_type.type, str):
return f(attr_type.type)
else: return f(attr_type.type.type)
else:
if isinstance(attr.type, str):
return f(attr.type)
else: return f(attr.type.type)
if isinstance(attr_type, str):
return f(attr_type)
else: return f(attr_type.type)
return None
def is_templated_list(self, attr):
attr_type = attr.type if isinstance(attr, nodes.ExplicitAttribute) else attr
if isinstance(attr, str): return False
ty = self.list_instance_type(attr)
arr = self.is_array(attr.type)
if ty is None: return False
arr = self.is_array(attr_type)
simple = self.schema.is_simpletype(ty)
express = ty in self.express_to_cpp_typemapping
express = self.flatten_type_string(ty) in self.express_to_cpp_typemapping
select = ty == 'IfcUtil::IfcBaseClass'
return arr and not simple and not express and not select
+37 -10
View File
@@ -21,8 +21,8 @@ import string
import collections
class Node:
def __init__(self, tokens):
self.tokens = tokens
def __init__(self, tokens = None):
self.tokens = tokens or []
self.init()
def tokens_of_type(self, cls):
return [t for t in self.tokens if isinstance(t, cls)]
@@ -44,15 +44,17 @@ class TypeDeclaration(Node):
class EntityDeclaration(Node):
name = property(lambda self: self.tokens[1])
attributes = property(lambda self: self.tokens_of_type(ExplicitAttribute))
abstract = property(lambda self: self.single_token_of_type(SuperTypeExpression) is not None and \
self.single_token_of_type(SuperTypeExpression).abstract)
def init(self):
assert self.tokens[0] == 'entity'
s = self.single_token_of_type(SubtypeExpression)
s = self.single_token_of_type(SubTypeExpression)
self.inverse = self.single_token_of_type(AttributeList, 'type', 'inverse')
self.derive = self.single_token_of_type(AttributeList, 'type', 'derive')
self.supertypes = s.types if s else []
def __repr__(self):
builder = ""
builder += "Entity(%s)" % (self.name)
builder += "%sEntity(%s)" % ("Abstract " if self.abstract else "", self.name)
if len(self.supertypes):
builder += "\n Supertypes: %s"%(",".join(self.supertypes))
if len(self.attributes):
@@ -106,12 +108,20 @@ class SelectType(Node):
class SubSuperTypeExpression(Node):
type = property(lambda self: self.tokens[0])
types = property(lambda self: self.tokens[3::2])
abstract = False
def init(self):
assert self.type == self.class_type
if self.tokens[0] == 'abstract':
self.tokens = self.tokens[1:]
self.abstract = True
assert self.type == self.type_relationship
class SubtypeExpression(SubSuperTypeExpression):
class_type = 'subtype'
class SubTypeExpression(SubSuperTypeExpression):
type_relationship = 'subtype'
class SuperTypeExpression(SubSuperTypeExpression):
type_relationship = 'supertype'
class AttributeList(Node):
@@ -127,8 +137,8 @@ class AttributeList(Node):
class InverseAttribute(Node):
name = property(lambda self: self.tokens[0])
type = property(lambda self: self.tokens[2])
bounds = property(lambda self: None if len(self.tokens) == 6 else self.tokens[3])
type = property(lambda self: self.tokens[2] if self.tokens[2] != self.tokens[-4] else None)
bounds = property(lambda self: None if len(self.tokens) != 9 else self.tokens[3])
entity = property(lambda self: self.tokens[-4])
attribute = property(lambda self: self.tokens[-2])
def init(self):
@@ -149,7 +159,7 @@ class BinaryType(Node):
def init(self):
pass
def __repr__(self):
return "BINARY"
return "binary"
class BoundSpecification(Node):
@@ -170,6 +180,23 @@ class ExplicitAttribute(Node):
def init(self):
# NB: This assumes a single name per attribute
# definition, which is not necessarily the case.
if self.tokens[0] == "self":
i = list(self.tokens).index(":")
self.tokens = self.tokens[i-1:]
assert self.tokens[1] == ':'
def __repr__(self):
return "%s : %s%s" % (self.name, self.type, " ?" if self.optional else "")
class WidthSpec(Node):
def init(self):
if self.tokens[-1] == "fixed":
self.tokens[-1:] = []
assert (self.tokens[0], self.tokens[-1]) == ("(", ")")
self.width = int("".join(self.tokens[1:-1]))
class StringType(Node):
def init(self):
pass
def __repr__(self):
return "string"
+48 -10
View File
@@ -18,29 +18,67 @@
###############################################################################
import nodes
import platform
import collections
if tuple(map(int, platform.python_version_tuple())) < (2, 7):
import ordereddict
collections.OrderedDict = ordereddict.OrderedDict
# According to ISO 10303-11 7.1.2: Letters: "... The case of
# letters is significant only within explicit string literals."
class OrderedCaseInsensitiveDict_KeyObject(str):
def __eq__(self, other):
return self.lower() == other.lower()
def __hash__(self):
return hash(self.lower())
class OrderedCaseInsensitiveDict(collections.OrderedDict):
def __init__(self, *args, **kwargs):
collections.OrderedDict.__init__(self)
for key, value in collections.OrderedDict(*args, **kwargs).items():
self[OrderedCaseInsensitiveDict_KeyObject(key)] = value
def __setitem__(self, key, value):
return collections.OrderedDict.__setitem__(self, OrderedCaseInsensitiveDict_KeyObject(key), value)
def __getitem__(self, key):
return collections.OrderedDict.__getitem__(self, OrderedCaseInsensitiveDict_KeyObject(key))
def get(self, key, *args, **kwargs):
return collections.OrderedDict.get(self, OrderedCaseInsensitiveDict_KeyObject(key), *args, **kwargs)
def __contains__(self, key):
return collections.OrderedDict.__contains__(self, OrderedCaseInsensitiveDict_KeyObject(key))
class Schema:
def is_enumeration(self, v):
return v in self.enumerations
return str(v) in self.enumerations
def is_select(self, v):
return v in self.selects
return str(v) in self.selects
def is_simpletype(self, v):
return v in self.simpletypes
return str(v) in self.simpletypes
def is_type(self, v):
return v in self.types
return str(v) in self.types
def is_entity(self, v):
return v in self.entities
return str(v) in self.entities
def __len__(self):
return len(self.types) + len(self.entities)
def __iter__(self):
return iter(self.keys)
def __getitem__(self, key):
return self.types_entities[key]
def __init__(self, parsetree):
self.name = parsetree[1]
sort = lambda d: collections.OrderedDict(sorted(d.items()))
sort = lambda d: OrderedCaseInsensitiveDict(sorted(d))
self.types = sort({t.name:t for t in parsetree if isinstance(t, nodes.TypeDeclaration)})
self.entities = sort({t.name:t for t in parsetree if isinstance(t, nodes.EntityDeclaration)})
self.types = sort([(t.name,t) for t in parsetree if isinstance(t, nodes.TypeDeclaration)])
self.entities = sort([(t.name,t) for t in parsetree if isinstance(t, nodes.EntityDeclaration)])
self.keys = list(self.types.keys()) + list(self.entities.keys())
self.types_entities = {k: v for d in (self.types, self.entities) for k, v in d.items()}
of_type = lambda *types: sort({a: b.type.type for a,b in self.types.items() if any(isinstance(b.type.type, ty) for ty in types)})
of_type = lambda *types: sort([(a, b.type.type) for a,b in self.types.items() if any(isinstance(b.type.type, ty) for ty in types)])
self.enumerations = of_type(nodes.EnumerationType)
self.selects = of_type(nodes.SelectType)
self.simpletypes = of_type(str, nodes.AggregationType)
self.simpletypes = of_type(str, nodes.AggregationType, nodes.BinaryType, nodes.StringType)
+250
View File
@@ -0,0 +1,250 @@
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
import operator
import nodes
import codegen
import templates
class SchemaClass(codegen.Base):
def __init__(self, mapping):
class UnmetDependenciesException(Exception): pass
schema_name = mapping.schema.name
self.schema_name = schema_name_title = schema_name.capitalize()
declared_types = []
def get_declared_type(type, emitted_names=None):
if isinstance(type, nodes.AggregationType):
aggr_type = type.aggregate_type
make_bound = lambda b: -1 if b == '?' else int(b)
bound1, bound2 = map(make_bound, (type.bounds.lower, type.bounds.upper))
decl_type = get_declared_type(type.type, emitted_names)
return "new aggregation_type(aggregation_type::%(aggr_type)s_type, %(bound1)d, %(bound2)d, %(decl_type)s)" % locals()
elif isinstance(type, nodes.BinaryType):
return "new simple_type(simple_type::binary_type)"
elif isinstance(type, nodes.StringType):
return "new simple_type(simple_type::string_type)"
elif isinstance(type, str):
if mapping.schema.is_type(type) or mapping.schema.is_entity(type):
if emitted_names is None or type.lower() in emitted_names:
return "new named_type(%s_%s_type)" % (schema_name, type)
else:
raise UnmetDependenciesException(type)
else:
return "new simple_type(simple_type::%s_type)" % type
def find_inverse_name_and_index(entity_name, attribute_name):
attributes_per_subtype = []
while True:
entity = mapping.schema.entities[entity_name]
attr_names = list(map(operator.attrgetter('name'), entity.attributes))
if len(attr_names):
attributes_per_subtype.append((entity_name, attr_names))
if len(entity.supertypes) != 1: break
entity_name = entity.supertypes[0]
index = 0
for et, attrs in attributes_per_subtype[::-1]:
try: return et, attrs.index(attribute_name)
except: pass
else:
raise Exception("No declared type for <%r>" % type)
statements = ['',
'#include "../ifcparse/IfcSchema.h"',
'#include "../ifcparse/%(schema_name_title)s.h"' % locals(),
'',
'using namespace IfcParse;',
'']
collections_by_type = (('entity', mapping.schema.entities ),
('type_declaration', mapping.schema.simpletypes ),
('select_type', mapping.schema.selects ),
('enumeration_type', mapping.schema.enumerations))
for cpp_type, collection in collections_by_type:
for name in collection.keys():
statements.append('%(cpp_type)s* %(schema_name)s_%(name)s_type = 0;' % locals())
declarations_by_index = []
statements.append("{factory_placeholder}")
statements.append("""
#if defined(__clang__)
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC push_options
#pragma GCC optimize ("O0")
#elif defined(_MSC_VER)
#pragma optimize("", off)
#endif
""")
statements.append('IfcParse::schema_definition* %(schema_name)s_populate_schema() {' % locals())
emitted = set()
len_to_emit = len(mapping.schema)
def write_simpletype(schema_name, name, type):
try:
declared_type = get_declared_type(type, emitted)
except UnmetDependenciesException:
print("Unmet", repr(name))
return False
statements.append(' %(schema_name)s_%(name)s_type = new type_declaration("%(name)s", %%(index_in_schema_%(name)s)d, %(declared_type)s);' % locals())
def write_enumeration(schema_name, name, enum):
statements.append(' {')
statements.append(' std::vector<std::string> items; items.reserve(%d);' % len(enum.values))
statements.extend(map(lambda v: ' items.push_back("%s");' % v, sorted(enum.values)))
statements.append(' %(schema_name)s_%(name)s_type = new enumeration_type("%(name)s", %%(index_in_schema_%(name)s)d, items);' % locals())
statements.append(' }')
def write_entity(schema_name, name, type):
if len(type.supertypes) == 0 or set(map(lambda s: s.lower(), type.supertypes)) < emitted:
supertype = '0' if len(type.supertypes) == 0 else '%s_%s_type' % (schema_name, type.supertypes[0])
statements.append(' %(schema_name)s_%(name)s_type = new entity("%(name)s", %%(index_in_schema_%(name)s)d, %(supertype)s);' % locals())
else: return False
def write_select(schema_name, name, type):
if set(map(lambda s: s.lower(),type.values)) < emitted:
statements.append(' {')
statements.append(' std::vector<const declaration*> items; items.reserve(%d);' % len(type.values))
statements.extend(map(lambda v: ' items.push_back(%s_%s_type);' % (schema_name, v), sorted(type.values)))
statements.append(' %(schema_name)s_%(name)s_type = new select_type("%(name)s", %%(index_in_schema_%(name)s)d, items);' % locals())
statements.append(' }')
else: return False
def write(name):
if mapping.schema.is_simpletype(name):
fn = write_simpletype
elif mapping.schema.is_enumeration(name):
fn = write_enumeration
elif mapping.schema.is_entity(name):
fn = write_entity
elif mapping.schema.is_select(name):
fn = write_select
decl = mapping.schema[name]
if isinstance(decl, nodes.TypeDeclaration):
decl = decl.type.type
return fn(schema_name, name, decl) is not False
while len(emitted) < len_to_emit:
for name in mapping.schema:
if name.lower() in emitted: continue
if write(name):
emitted.add(name.lower())
declarations_by_index.append(name)
declared_types.append('%(schema_name)s_%(name)s_type' % locals())
num_declarations = len(declared_types)
for name, type in mapping.schema.entities.items():
derived = set(mapping.derived_in_supertype(type))
attribute_names = list(map(operator.attrgetter('name'), mapping.arguments(type)))
statements.append(' {')
statements.append(' std::vector<const entity::attribute*> attributes; attributes.reserve(%d);' % len(type.attributes))
for attr in type.attributes:
attr_name, optional = attr.name, str(attr.optional).lower()
decl_type = get_declared_type(attr.type)
statements.append(' attributes.push_back(new entity::attribute("%(attr_name)s", %(decl_type)s, %(optional)s));' % locals())
statements.append(' std::vector<bool> derived; derived.reserve(%d);' % len(attribute_names))
statements.append(' ' + " ".join(map(lambda b: 'derived.push_back(%s);' % str(b in derived).lower(), attribute_names)))
statements.append(' %(schema_name)s_%(name)s_type->set_attributes(attributes, derived);' % locals())
statements.append(' }')
for name, type in mapping.schema.entities.items():
if type.inverse:
statements.append(' {')
statements.append(' std::vector<const entity::inverse_attribute*> attributes; attributes.reserve(%d);' % len(type.inverse.elements))
for attr in type.inverse.elements:
if attr.bounds:
make_bound = lambda b: -1 if b == '?' else int(b)
bound1, bound2 = map(make_bound, (attr.bounds.lower, attr.bounds.upper))
else:
bound1, bound2 = -1, -1
attr_name, aggr_type, entity_ref = attr.name, attr.type, attr.entity
if aggr_type is None: aggr_type = 'unspecified'
attribute_entity, attribute_entity_index = find_inverse_name_and_index(entity_ref, attr.attribute)
statements.append(' attributes.push_back(new entity::inverse_attribute("%(attr_name)s", entity::inverse_attribute::%(aggr_type)s_type, %(bound1)d, %(bound2)d, %(schema_name)s_%(entity_ref)s_type, %(schema_name)s_%(attribute_entity)s_type->attributes()[%(attribute_entity_index)d]));' % locals())
statements.append(' %(schema_name)s_%(name)s_type->set_inverse_attributes(attributes);' % locals())
statements.append(' }')
statements.append('')
statements.append(' std::vector<const declaration*> declarations; declarations.reserve(%(num_declarations)d);' % locals())
for type_name in declared_types:
statements.append(' declarations.push_back(%(type_name)s);' % locals())
statements.append(' return new schema_definition("%(schema_name)s", declarations, new %(schema_name)s_instance_factory());' % locals())
statements.extend(('}',''))
statements.append("""
#if defined(__clang__)
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC pop_options
#elif defined(_MSC_VER)
#pragma optimize("", on)
#endif
""")
statements.extend(('const schema_definition& %s::get_schema() {' % schema_name_title,
'',
' static const schema_definition* s = %(schema_name)s_populate_schema();' % locals(),
' return *s;',
'}','',''))
declarations_by_index.sort(key=str.lower)
declarations_by_index_map = dict(("index_in_schema_%s" % j,i) for i,j in enumerate(declarations_by_index))
def bind(s):
if "%" in s: return s % declarations_by_index_map
else: return s
can_be_instantiated_set = set(list(mapping.schema.entities.keys()) + list(mapping.schema.simpletypes.keys()))
def can_be_instantiated(idx_name):
name = idx_name[1]
return name in can_be_instantiated_set
instance_mapping = """switch(data->type()->index_in_schema()) {
%s
default: throw IfcParse::IfcException(data->type()->name() + " cannot be instantiated");
}
""" % "\n ".join(map(lambda tup: ("case %%d: return new ::%s::%%s(data);" % schema_name_title) % tup, filter(can_be_instantiated, enumerate(declarations_by_index))))
statements[statements.index("{factory_placeholder}")] = """
class %(schema_name)s_instance_factory : public IfcParse::instance_factory {
virtual IfcUtil::IfcBaseClass* operator()(IfcEntityInstanceData* data) const {
%(instance_mapping)s
}
};
""" % locals()
self.str = "\n".join(map(bind, statements))
self.file_name = '%s-schema.cpp'%self.schema_name
def __repr__(self):
return self.str
+79 -289
View File
@@ -23,19 +23,24 @@ header = """
#include <string>
#include <vector>
#include <map>
#include <boost/optional.hpp>
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/ifc_parse_api.h"
#include "../ifcparse/IfcEntityList.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcSchema.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/Argument.h"
#include "../ifcparse/%(schema_name)senum.h"
#define IfcSchema %(schema_name)s
struct %(schema_name)s {
namespace %(schema_name)s {
static const IfcParse::schema_definition& get_schema();
const char* const Identifier = "%(schema_name_upper)s";
static const char* const Identifier;
// Forward definitions
%(forward_definitions)s
@@ -43,9 +48,7 @@ const char* const Identifier = "%(schema_name_upper)s";
%(declarations)s
%(class_definitions)s
void InitStringMap();
IfcUtil::IfcBaseClass* SchemaEntity(IfcAbstractEntity* e = 0);
}
};
#endif
"""
@@ -54,97 +57,31 @@ enum_header = """
#ifndef %(schema_name_upper)sENUM_H
#define %(schema_name_upper)sENUM_H
#define IfcSchema %(schema_name)s
#include "../ifcparse/ifc_parse_api.h"
namespace %(schema_name)s {
namespace Type {
typedef enum {
%(types)s, UNDEFINED
} Enum;
Enum Parent(Enum v);
Enum FromString(const std::string& s);
std::string ToString(Enum v);
bool IsSimple(Enum v);
}
}
#include <string>
#include <boost/optional.hpp>
#endif
"""
lb_header = """
#ifndef %(schema_name_upper)sRT_H
#define %(schema_name_upper)sRT_H
#define IfcSchema %(schema_name)s
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcEntityDescriptor.h"
#include "../ifcparse/IfcWritableEntity.h"
namespace %(schema_name)s {
namespace Type {
int GetAttributeCount(Enum t);
int GetAttributeIndex(Enum t, const std::string& a);
IfcUtil::ArgumentType GetAttributeType(Enum t, unsigned char a);
Enum GetAttributeEntity(Enum t, unsigned char a);
const std::string& GetAttributeName(Enum t, unsigned char a);
bool GetAttributeOptional(Enum t, unsigned char a);
bool GetAttributeDerived(Enum t, unsigned char a);
std::pair<const char*, int> GetEnumerationIndex(Enum t, const std::string& a);
std::pair<Enum, unsigned> GetInverseAttribute(Enum t, const std::string& a);
std::set<std::string> GetInverseAttributeNames(Enum t);
void PopulateDerivedFields(IfcWrite::IfcWritableEntity* e);
}}
#endif
"""
lb_header = """"""
implementation= """
#include "../ifcparse/%(schema_name)s.h"
#include "../ifcparse/IfcSchema.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcWrite.h"
#include "../ifcparse/IfcWritableEntity.h"
using namespace %(schema_name)s;
#include <map>
const char* const %(schema_name)s::Identifier = "%(schema_name_upper)s";
using namespace IfcParse;
using namespace IfcWrite;
IfcUtil::IfcBaseClass* %(schema_name)s::SchemaEntity(IfcAbstractEntity* e) {
switch(e->type()) {
%(schema_entity_statements)s
default: throw IfcException("Unable to find find keyword in schema"); break;
}
}
std::string Type::ToString(Enum v) {
if (v < 0 || v >= %(max_id)d) throw IfcException("Unable to find find keyword in schema");
const char* names[] = { %(type_name_strings)s };
return names[v];
}
static std::map<std::string,Type::Enum> string_map;
void %(schema_name)s::InitStringMap() {
%(string_map_statements)s
}
Type::Enum Type::FromString(const std::string& s) {
if (string_map.empty()) InitStringMap();
std::map<std::string,Type::Enum>::const_iterator it = string_map.find(s);
if ( it == string_map.end() ) throw IfcException("Unable to find find keyword in schema");
else return it->second;
}
Type::Enum Type::Parent(Enum v){
if (v < 0 || v >= %(max_id)d) return (Enum)-1;
%(parent_type_statements)s
return (Enum)-1;
}
bool Type::IsSimple(Enum v) {
return %(simple_type_statement)s;
}
// External definitions
%(external_definitions)s
%(enumeration_functions)s
@@ -153,150 +90,7 @@ bool Type::IsSimple(Enum v) {
%(entity_implementations)s
"""
lb_implementation = """
#include <set>
#include "../ifcparse/%(schema_name)s.h"
#include "../ifcparse/%(schema_name)s-latebound.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcWrite.h"
#include "../ifcparse/IfcWritableEntity.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcEntityDescriptor.h"
using namespace %(schema_name)s;
using namespace IfcParse;
using namespace IfcWrite;
using namespace IfcUtil;
typedef std::map<Type::Enum,IfcEntityDescriptor*> entity_descriptor_map_t;
typedef std::map<Type::Enum,IfcEnumerationDescriptor*> enumeration_descriptor_map_t;
typedef std::map<Type::Enum, std::map<std::string, std::pair<Type::Enum, int> > > inverse_map_t;
typedef std::map<Type::Enum,std::set<int> > derived_map_t;
entity_descriptor_map_t entity_descriptor_map;
enumeration_descriptor_map_t enumeration_descriptor_map;
inverse_map_t inverse_map;
derived_map_t derived_map;
void InitDescriptorMap() {
IfcEntityDescriptor* current;
%(entity_descriptors)s
// Enumerations
IfcEnumerationDescriptor* current_enum;
std::vector<std::string> values;
%(enumeration_descriptors)s
}
void InitInverseMap() {
%(inverse_implementations)s
}
void InitDerivedMap() {
%(derived_field_statements)s
}
int Type::GetAttributeIndex(Enum t, const std::string& a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentIndex(a);
}
int Type::GetAttributeCount(Enum t) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentCount();
}
ArgumentType Type::GetAttributeType(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentType(a);
}
Type::Enum Type::GetAttributeEntity(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentEntity(a);
}
const std::string& Type::GetAttributeName(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentName(a);
}
bool Type::GetAttributeOptional(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentOptional(a);
}
bool Type::GetAttributeDerived(Enum t, unsigned char a) {
if (derived_map.empty()) ::InitDerivedMap();
std::map<Type::Enum,std::set<int> >::const_iterator i = derived_map.find(t);
return i != derived_map.end() && i->second.find(a) != i->second.end();
}
std::pair<const char*, int> Type::GetEnumerationIndex(Enum t, const std::string& a) {
if (enumeration_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEnumerationDescriptor*>::const_iterator i = enumeration_descriptor_map.find(t);
if ( i == enumeration_descriptor_map.end() ) throw IfcException("Value not found");
else return i->second->getIndex(a);
}
std::pair<Type::Enum, unsigned> Type::GetInverseAttribute(Enum t, const std::string& a) {
if (inverse_map.empty()) ::InitInverseMap();
inverse_map_t::const_iterator it;
inverse_map_t::mapped_type::const_iterator jt;
while (true) {
it = inverse_map.find(t);
if (it != inverse_map.end()) {
jt = it->second.find(a);
if (jt != it->second.end()) {
return jt->second;
}
}
if ((t = Parent(t)) == -1) break;
}
throw IfcException("Attribute not found");
}
std::set<std::string> Type::GetInverseAttributeNames(Enum t) {
if (inverse_map.empty()) ::InitInverseMap();
inverse_map_t::const_iterator it;
inverse_map_t::mapped_type::const_iterator jt;
std::set<std::string> return_value;
while (true) {
it = inverse_map.find(t);
if (it != inverse_map.end()) {
for (jt = it->second.begin(); jt != it->second.end(); ++jt) {
return_value.insert(jt->first);
}
}
if ((t = Parent(t)) == -1) break;
}
return return_value;
}
void Type::PopulateDerivedFields(IfcWrite::IfcWritableEntity* e) {
std::map<Type::Enum, std::set<int> >::const_iterator i = derived_map.find(e->type());
if (i != derived_map.end()) {
for (std::set<int>::const_iterator it = i->second.begin(); it != i->second.end(); ++it) {
e->setArgumentDerived(*it);
}
}
}
"""
lb_implementation = """"""
entity_descriptor = """ current = entity_descriptor_map[Type::%(type)s] = new IfcEntityDescriptor(Type::%(type)s,%(parent_statement)s);
%(entity_descriptor_attributes)s"""
@@ -307,7 +101,7 @@ entity_descriptor_attribute_with_entity = ' current->add("%(name)s",%(optiona
enumeration_descriptor = """ values.clear(); values.reserve(128);
%(enumeration_descriptor_values)s
current_enum = enumeration_descriptor_map[Type::%(type)s] = new IfcEnumerationDescriptor(Type::%(type)s, values);"""
enumeration_descriptor_map[Type::%(type)s] = new IfcEnumerationDescriptor(Type::%(type)s, values);"""
enumeration_descriptor_value = ' values.push_back("%(name)s");'
@@ -315,89 +109,85 @@ derived_field_statement = ' {std::set<int> idxs; %(statements)sderived_map[Ty
derived_field_statement_attrs = 'idxs.insert(%d); '
simpletype = """%(documentation)s
class %(name)s : public %(superclass)s {
class IFC_PARSE_API %(name)s : public %(superclass)s {
public:
virtual IfcUtil::ArgumentType getArgumentType(unsigned int i) const;
virtual Argument* getArgument(unsigned int i) const;
bool is(Type::Enum v) const;
Type::Enum type() const;
static Type::Enum Class();
explicit %(name)s (IfcAbstractEntity* e);
virtual const IfcParse::type_declaration& declaration() const;
static const IfcParse::type_declaration& Class();
explicit %(name)s (IfcEntityInstanceData* e);
%(name)s (%(type)s v);
operator %(type)s() const;
};
"""
simpletype_impl_comment = "// Function implementations for %(name)s"
simpletype_impl_argument_type = "if (i == 0) { return %(attr_type)s; } else { throw IfcParse::IfcException(\"argument out of range\"); }"
simpletype_impl_argument = "return entity->getArgument(i);"
simpletype_impl_is_with_supertype = "return v == Type::%(class_name)s || %(superclass)s::is(v);"
simpletype_impl_is_without_supertype = "return v == %(class_name)s::Class();"
simpletype_impl_type = "return Type::%(class_name)s;"
simpletype_impl_class = "return Type::%(class_name)s;"
simpletype_impl_explicit_constructor = "entity = e;"
simpletype_impl_constructor = "IfcWritableEntity* e = new IfcWritableEntity(Type::%(class_name)s); e->setArgument(0, v); entity = e;"
simpletype_impl_cast = "return *entity->getArgument(0);"
simpletype_impl_argument_type = "if (i == 0) { return %(attr_type)s; } else { throw IfcParse::IfcAttributeOutOfRangeException(\"Argument index out of range\"); }"
simpletype_impl_argument = "return data_->getArgument(i);"
simpletype_impl_is_with_supertype = "return v == %(class_name)s_type || %(superclass)s::is(v);"
simpletype_impl_is_without_supertype = "return v == %(class_name)s_type;"
simpletype_impl_type = "return *%(schema_name_upper)s_%(class_name)s_type;"
simpletype_impl_class = "return *%(schema_name_upper)s_%(class_name)s_type;"
simpletype_impl_explicit_constructor = "data_ = e;"
simpletype_impl_constructor = "data_ = new IfcEntityInstanceData(%(schema_name_upper)s_%(class_name)s_type); {IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument(); attr->set(v" +"); data_->setArgument(0, attr);}"
simpletype_impl_constructor_templated = "data_ = new IfcEntityInstanceData(%(schema_name_upper)s_%(class_name)s_type); {IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument(); attr->set(v->generalize()); data_->setArgument(0, attr);}"
simpletype_impl_cast = "return *data_->getArgument(0);"
simpletype_impl_cast_templated = "IfcEntityList::ptr es = *data_->getArgument(0); return es->as< %(underlying_type)s >();"
simpletype_impl_declaration = "return *%(schema_name_upper)s_%(class_name)s_type;"
select = """%(documentation)s
typedef IfcUtil::IfcBaseClass %(name)s;
"""
enumeration = """namespace %(name)s {
enumeration = """struct %(name)s {
%(documentation)s
typedef enum {%(values)s} %(name)s;
const char* ToString(%(name)s v);
%(name)s FromString(const std::string& s);
}
typedef enum {%(values)s} Value;
IFC_PARSE_API static const char* ToString(Value v);
IFC_PARSE_API static Value FromString(const std::string& s);
};
"""
entity = """%(documentation)s
class %(name)s %(superclass)s{
class IFC_PARSE_API %(name)s %(superclass)s{
public:
%(attributes)s virtual unsigned int getArgumentCount() const { return %(argument_count)d; }
virtual IfcUtil::ArgumentType getArgumentType(unsigned int i) const {%(argument_type_function_body)s}
virtual Type::Enum getArgumentEntity(unsigned int i) const {%(argument_entity_function_body)s}
virtual const char* getArgumentName(unsigned int i) const {%(argument_name_function_body)s}
virtual Argument* getArgument(unsigned int i) const { return entity->getArgument(i); }
%(inverse)s bool is(Type::Enum v) const;
Type::Enum type() const;
static Type::Enum Class();
%(name)s (IfcAbstractEntity* e);
%(attributes)s %(inverse)s virtual const IfcParse::entity& declaration() const;
static const IfcParse::entity& Class();
%(name)s (IfcEntityInstanceData* e);
%(name)s (%(constructor_arguments)s);
typedef IfcTemplatedEntityList< %(name)s > list;
};
"""
enumeration_function="""
const char* %(name)s::ToString(%(name)s v) {
const char* %(schema_name)s::%(name)s::ToString(Value v) {
if ( v < 0 || v >= %(max_id)d ) throw IfcException("Unable to find find keyword in schema");
const char* names[] = { %(values)s };
return names[v];
}
%(name)s::%(name)s %(name)s::FromString(const std::string& s) {
%(schema_name)s::%(name)s::Value %(schema_name)s::%(name)s::FromString(const std::string& s) {
%(from_string_statements)s
throw IfcException("Unable to find find keyword in schema");
}
"""
entity_implementation = """// Function implementations for %(name)s
%(attributes)s%(inverse)sbool %(name)s::is(Type::Enum v) const { return v == Type::%(name)s%(parent_type_test)s; }
Type::Enum %(name)s::type() const { return Type::%(name)s; }
Type::Enum %(name)s::Class() { return Type::%(name)s; }
%(name)s::%(name)s(IfcAbstractEntity* e) : %(superclass)s { if (!e) return; if (!e->is(Type::%(name)s)) throw IfcException("Unable to find find keyword in schema"); entity = e; }
%(name)s::%(name)s(%(constructor_arguments)s) : %(superclass)s { IfcWritableEntity* e = new IfcWritableEntity(Class());%(constructor_implementation)s entity = e; EntityBuffer::Add(this); }
%(attributes)s
%(inverse)s
const IfcParse::entity& %(schema_name)s::%(name)s::declaration() const { return *%(schema_name_upper)s_%(name)s_type; }
const IfcParse::entity& %(schema_name)s::%(name)s::Class() { return *%(schema_name_upper)s_%(name)s_type; }
%(schema_name)s::%(name)s::%(name)s(IfcEntityInstanceData* e) : %(superclass)s { if (!e) return; if (e->type() != %(schema_name_upper)s_%(name)s_type) throw IfcException("Unable to find find keyword in schema"); data_ = e; }
%(schema_name)s::%(name)s::%(name)s(%(constructor_arguments)s) : %(superclass)s {data_ = new IfcEntityInstanceData(%(schema_name_upper)s_%(name)s_type); %(constructor_implementation)s }
"""
optional_attribute_description = "/// Whether the optional attribute %s is defined for this %s"
function = "%(return_type)s %(class_name)s::%(name)s(%(arguments)s) { %(body)s }"
const_function = "%(return_type)s %(class_name)s::%(name)s(%(arguments)s) const { %(body)s }"
constructor = "%(class_name)s::%(class_name)s(%(arguments)s) { %(body)s }"
constructor_single_initlist = "%(class_name)s::%(class_name)s(%(arguments)s) : %(superclass)s(%(superclass_init)s) { %(body)s }"
cast_function = "%(class_name)s::operator %(return_type)s() const { %(body)s }"
function = "%(return_type)s %(schema_name)s::%(class_name)s::%(name)s(%(arguments)s) { %(body)s }"
const_function = "%(return_type)s %(schema_name)s::%(class_name)s::%(name)s(%(arguments)s) const { %(body)s }"
constructor = "%(schema_name)s::%(class_name)s::%(class_name)s(%(arguments)s) { %(body)s }"
constructor_single_initlist = "%(schema_name)s::%(class_name)s::%(class_name)s(%(arguments)s) : %(superclass)s(%(superclass_init)s) { %(body)s }"
cast_function = "%(schema_name)s::%(class_name)s::operator %(return_type)s() const { %(body)s }"
array_type = "std::vector< %(instance_type)s > /*[%(lower)s:%(upper)s]*/"
nested_array_type = "std::vector< std::vector< %(instance_type)s > >"
list_type = "IfcTemplatedEntityList< %(instance_type)s >::ptr"
list_list_type = "IfcTemplatedEntityListList< %(instance_type)s >::ptr"
untyped_list = "IfcEntityList::ptr"
@@ -406,31 +196,31 @@ inverse_attr = "IfcTemplatedEntityList< %(entity)s >::ptr %(name)s() const; // I
enum_from_string_stmt = ' if (s == "%(value)s") return ::%(schema_name)s::%(name)s::%(short_name)s_%(value)s;'
schema_entity_stmt = ' case Type::%(name)s: return new %(name)s(e); break;'
schema_simple_stmt = ' case Type::%(name)s: return new IfcUtil::IfcEntitySelect(e); break;'
string_map_statement = ' string_map["%(uppercase_name)s"%(padding)s] = Type::%(name)s;'
parent_type_stmt = ' if(v==%(name)s%(padding)s) { return %(parent)s; }'
parent_type_test = " || %s::is(v)"
optional_attr_stmt = "return !entity->getArgument(%(index)d)->isNull();"
optional_attr_stmt = "return !data_->getArgument(%(index)d)->isNull();"
get_attr_stmt = "return *entity->getArgument(%(index)d);"
get_attr_stmt_enum = "return %(type)s::FromString(*entity->getArgument(%(index)d));"
get_attr_stmt_entity = "return (%(type)s)((IfcUtil::IfcBaseClass*)(*entity->getArgument(%(index)d)));"
get_attr_stmt_array = "IfcEntityList::ptr es = *entity->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
get_attr_stmt_nested_array = "IfcEntityListList::ptr es = *entity->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
get_attr_stmt = "return *data_->getArgument(%(index)d);"
get_attr_stmt_enum = "return %(type)s::FromString(*data_->getArgument(%(index)d));"
get_attr_stmt_entity = "return (%(type)s)((IfcUtil::IfcBaseClass*)(*data_->getArgument(%(index)d)));"
get_attr_stmt_array = "IfcEntityList::ptr es = *data_->getArgument(%(index)d); return es->as< %(list_instance_type)s >();"
get_attr_stmt_nested_array = "IfcEntityListList::ptr es = *data_->getArgument(%(index)d); return es->as< %(list_instance_type)s >();"
get_inverse = "return entity->getInverse(Type::%(type)s, %(index)d)->as<%(type)s>();"
get_inverse = "return data_->getInverse(%(schema_name_upper)s_%(type)s_type, %(index)d)->as<%(type)s>();"
set_attr_stmt = "if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%(index)d,v);"
set_attr_stmt_enum = "if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%(index)d,v,%(type)s::ToString(v));"
set_attr_stmt_array = "if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%(index)d,v->generalize());"
set_attr_stmt = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set(v" +");data_->setArgument(%(index)d,attr);}"
set_attr_stmt_enum = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set(IfcWrite::IfcWriteArgument::EnumerationReference(v,%(type)s::ToString(v)));data_->setArgument(%(index)d,attr);}"
set_attr_stmt_array = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set(v->generalize()" +");data_->setArgument(%(index)d,attr);}"
constructor_stmt = " e->setArgument(%(index)d,(%(name)s));"
constructor_stmt_enum = " e->setArgument(%(index)d,%(name)s,%(type)s::ToString(%(name)s));"
constructor_stmt_array = " e->setArgument(%(index)d,(%(name)s)->generalize());"
constructor_stmt_optional = " if (%(name)s) {%(stmt)s } else { e->setArgument(%(index)d); }"
constructor_stmt_derived = " e->setArgumentDerived(%(index)d);"
constructor_stmt = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set((%(name)s)" +");data_->setArgument(%(index)d,attr);}"
constructor_stmt_enum = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set((IfcWrite::IfcWriteArgument::EnumerationReference(%(name)s,%(type)s::ToString(%(name)s)))" +");data_->setArgument(%(index)d,attr);}"
constructor_stmt_array = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set((%(name)s)->generalize()" +");data_->setArgument(%(index)d,attr);}"
constructor_stmt_derived = "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();attr->set(IfcWrite::IfcWriteArgument::Derived()" +");data_->setArgument(%(index)d,attr);}"
constructor_stmt_optional = " if (%(name)s) {%(stmt)s } else { IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument(); attr->set(boost::blank()); data_->setArgument(%(index)d, attr); }"
inverse_implementation = " inverse_map[Type::%(type)s].insert(std::make_pair(\"%(name)s\", std::make_pair(Type::%(related_type)s, %(index)d)));"
+222 -81
View File
@@ -20,8 +20,14 @@
#ifndef IFCGEOM_H
#define IFCGEOM_H
#define ALMOST_ZERO (1e-9)
#define ALMOST_THE_SAME(a,b) (fabs(a-b) < ALMOST_ZERO)
#include <cmath>
static const double ALMOST_ZERO = 1.e-9;
template <typename T>
inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMOST_ZERO) {
return fabs(a-b) < tolerance;
}
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
@@ -37,70 +43,108 @@
#include <Geom_Curve.hxx>
#include <gp_Pln.hxx>
#include <TColgp_SequenceOfPnt.hxx>
#include <TopTools_ListOfShape.hxx>
#include <BOPAlgo_Operation.hxx>
#include "../ifcparse/macros.h"
#include "../ifcparse/IfcParse.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcgeom/IfcGeomElement.h"
#include "../ifcgeom/IfcGeomRepresentation.h"
#include "../ifcgeom/IfcRepresentationShapeItem.h"
#include "../ifcgeom/IfcGeomShapeType.h"
#define IN_CACHE(T,E,t,e) std::map<int,t>::const_iterator it = cache.T.find(E->entity->id());\
#include "../ifcgeom_schema_agnostic/Kernel.h"
#include "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
// #define NO_CACHE
#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->data().id());\
if ( it != cache.T.end() ) { e = it->second; return true; }
#define CACHE(T,E,e) cache.T[E->entity->id()] = e;
#define CACHE(T,E,e) cache.T[E->data().id()] = e;
#endif
#define INCLUDE_PARENT_DIR(x) STRINGIFY(../ifcparse/x.h)
#include INCLUDE_PARENT_DIR(IfcSchema)
namespace IfcGeom {
class Cache {
class IFC_GEOM_API MAKE_TYPE_NAME(Cache) {
public:
#include "IfcRegisterCreateCache.h"
std::map<int, SurfaceStyle> Style;
std::map<int, TopoDS_Shape> Shape;
};
class Kernel {
class IFC_GEOM_API MAKE_TYPE_NAME(Kernel) : public IfcGeom::Kernel {
private:
Cache cache;
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;
#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;
public:
// Tolerances and settings for various geometrical operations:
enum GeomValue {
// Specifies the deflection of the mesher
// Default: 0.001m / 1mm
GV_DEFLECTION_TOLERANCE,
// Specifies the tolerance of the wire builder, most notably for trimmed curves
// Defailt: 0.0001m / 0.1mm
GV_WIRE_CREATION_TOLERANCE,
// Specifies the minimal area of a face to be included in an IfcConnectedFaceset
// Default: 0.000001m 0.01cm2
GV_MINIMAL_FACE_AREA,
// Specifies the treshold distance under which cartesian points are deemed equal
// Default: 0.00001m / 0.01mm
GV_POINT_EQUALITY_TOLERANCE,
// Specifies maximum number of faces for a shell to be sewed. Sewing shells
// that consist of many faces is really detrimental for the performance.
// Default: 1000
GV_MAX_FACES_TO_SEW,
// By default singular faces have no explicitly defined orientation, to
// force faces to be defined CounterClockWise, set this value greater than zero.
GV_FORCE_CCW_FACE_ORIENTATION,
// The length unit used the creation of TopoDS_Shapes, primarily affects the
// interpretation of IfcCartesianPoints and IfcVector magnitudes
// DefaultL 1.0
GV_LENGTH_UNIT,
// The plane angle unit used for the creation of TopoDS_Shapes, primarily affects
// the interpretation of IfcParamaterValues of IfcTrimmedCurves
// Default: -1.0 (= not set, fist try degrees, then radians)
GV_PLANEANGLE_UNIT,
// The precision used in boolean operations, setting this value too low results
// in artefacts and potentially modelling failures
// Default: 0.00001 (obtained from IfcGeometricRepresentationContext if available)
GV_PRECISION
};
MAKE_TYPE_NAME(Kernel)()
: IfcGeom::Kernel(0)
, 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)
{}
MAKE_TYPE_NAME(Kernel)(const MAKE_TYPE_NAME(Kernel)& other) : IfcGeom::Kernel(0) {
*this = other;
}
MAKE_TYPE_NAME(Kernel)& operator=(const MAKE_TYPE_NAME(Kernel)& other) {
setValue(GV_DEFLECTION_TOLERANCE, other.getValue(GV_DEFLECTION_TOLERANCE));
setValue(GV_WIRE_CREATION_TOLERANCE, other.getValue(GV_WIRE_CREATION_TOLERANCE));
setValue(GV_POINT_EQUALITY_TOLERANCE, other.getValue(GV_POINT_EQUALITY_TOLERANCE));
setValue(GV_MAX_FACES_TO_SEW, other.getValue(GV_MAX_FACES_TO_SEW));
setValue(GV_LENGTH_UNIT, other.getValue(GV_LENGTH_UNIT));
setValue(GV_PLANEANGLE_UNIT, other.getValue(GV_PLANEANGLE_UNIT));
setValue(GV_PRECISION, other.getValue(GV_PRECISION));
setValue(GV_DIMENSIONALITY, other.getValue(GV_DIMENSIONALITY));
setValue(GV_DEFLECTION_TOLERANCE, other.getValue(GV_DEFLECTION_TOLERANCE));
return *this;
}
bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face);
bool convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire);
bool convert_shapes(const IfcUtil::IfcBaseClass* L, IfcRepresentationShapeItems& result);
bool is_shape_collection(const IfcUtil::IfcBaseClass* L);
IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseClass* L);
bool convert_shape(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
bool flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse);
bool convert_wire(const IfcUtil::IfcBaseClass* L, TopoDS_Wire& result);
@@ -108,8 +152,40 @@ public:
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_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 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&);
#if OCC_VERSION_HEX < 0x60900
bool boolean_operation(const TopoDS_Shape&, const TopTools_ListOfShape&, BOPAlgo_Operation, TopoDS_Shape&);
bool boolean_operation(const TopoDS_Shape&, const TopoDS_Shape&, BOPAlgo_Operation, TopoDS_Shape&);
#else
bool boolean_operation(const TopoDS_Shape&, const TopTools_ListOfShape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
bool boolean_operation(const TopoDS_Shape&, const TopoDS_Shape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
#endif
const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const Handle_Geom_Surface&);
const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const TopoDS_Face&);
const Handle_Geom_Curve intersect(const TopoDS_Face&, const Handle_Geom_Surface&);
bool intersect(const Handle_Geom_Curve&, const Handle_Geom_Surface&, gp_Pnt&);
bool intersect(const Handle_Geom_Curve&, const TopoDS_Face&, gp_Pnt&);
bool intersect(const Handle_Geom_Curve&, const TopoDS_Shape&, std::vector<gp_Pnt>&);
bool intersect(const Handle_Geom_Surface&, const TopoDS_Shape&, std::vector< std::pair<Handle_Geom_Surface, Handle_Geom_Curve> >&);
bool closest(const gp_Pnt&, const std::vector<gp_Pnt>&, gp_Pnt&);
bool project(const Handle_Geom_Curve&, const gp_Pnt&, gp_Pnt& p, double& u, double& d);
bool project(const Handle_Geom_Surface&, const TopoDS_Shape&, double& u1, double& v1, double& u2, double& v2, double widen=0.1);
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);
bool is_convex(const TopoDS_Wire& wire);
TopoDS_Shape halfspace_from_plane(const gp_Pln& pln,const gp_Pnt& cent);
@@ -117,68 +193,133 @@ public:
gp_Pnt point_above_plane(const gp_Pln& pln, bool agree=true);
const TopoDS_Shape& ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid);
bool profile_helper(int numVerts, double* verts, int numFillets, int* filletIndices, double* filletRadii, gp_Trsf2d trsf, TopoDS_Shape& face);
double shape_volume(const TopoDS_Shape& s);
double face_area(const TopoDS_Face& f);
void apply_tolerance(TopoDS_Shape& s, double t);
void setValue(GeomValue var, double value);
double getValue(GeomValue var);
bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape);
void remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
void remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
void remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
bool wire_to_sequence_of_point(const TopoDS_Wire&, TColgp_SequenceOfPnt&);
void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed);
bool approximate_plane_through_wire(const TopoDS_Wire&, gp_Pln&);
bool flatten_wire(TopoDS_Wire&);
bool triangulate_wire(const TopoDS_Wire&, TopTools_ListOfShape&);
bool wire_intersections(const TopoDS_Wire & wire, TopTools_ListOfShape & wires);
void select_largest(const TopTools_ListOfShape& shapes, TopoDS_Shape& largest);
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 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);
IfcSchema::IfcRepresentation* find_representation(const IfcSchema::IfcProduct*, const std::string&);
std::pair<std::string, double> initializeUnits(IfcSchema::IfcUnitAssignment*);
IfcSchema::IfcObjectDefinition* get_decomposing_entity(IfcSchema::IfcProduct*);
static IfcSchema::IfcObjectDefinition* get_decomposing_entity(IfcSchema::IfcProduct*);
template <typename P>
IfcGeom::BRepElement<P>* create_brep_for_representation_and_product(const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*);
template <typename P, typename PP>
IfcGeom::BRepElement<P, PP>* create_brep_for_representation_and_product(
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*);
const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem* representation_item);
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::IfcRepresentationItem* representation_item) {
IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem();
for (IfcSchema::IfcStyledItem::list::it jt = styled_items->begin(); jt != styled_items->end(); ++jt) {
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> _get_surface_style(const IfcSchema::IfcStyledItem* si) {
#ifdef USE_IFC4
IfcUtil::IfcAbstractSelect::list::ptr style_assignments = (*jt)->Styles();
for (IfcUtil::IfcAbstractSelect::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
if (!(*kt)->is(IfcSchema::Type::IfcPresentationStyleAssignment)) {
continue;
}
IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt;
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 = (*jt)->Styles();
for (IfcSchema::IfcPresentationStyleAssignment::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
IfcSchema::IfcPresentationStyleAssignment* style_assignment = *kt;
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->is(IfcSchema::Type::IfcSurfaceStyle)) {
IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style;
if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) {
IfcEntityList::ptr styles_elements = surface_style->Styles();
for (IfcEntityList::it mt = styles_elements->begin(); mt != styles_elements->end(); ++mt) {
if ((*mt)->is(T::Class())) {
return std::make_pair(surface_style, (T*) *mt);
}
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);
}
}
}
}
}
// StyledByItem is a SET [0:1] OF IfcStyledItem, so we
// break after encountering the first IfcStyledItem
break;
}
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0,0);
}
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() {
// 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(
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;
bool success = convert_shapes(item, items);
if (!success) {
throw IfcParse::IfcException("Failed to process representation item");
}
return items;
}
};
IfcSchema::IfcProductDefinitionShape* tesselate(TopoDS_Shape& shape, double deflection, IfcEntityList::ptr es);
IfcUtil::IfcBaseClass* MAKE_TYPE_NAME(tesselate_)(const TopoDS_Shape& shape, double deflection);
IfcUtil::IfcBaseClass* MAKE_TYPE_NAME(serialise_)(const TopoDS_Shape& shape, bool advanced);
}
#endif
+65 -5
View File
@@ -77,17 +77,23 @@
#include <TopLoc_Location.hxx>
#ifdef USE_IFC4
#include <Geom_BSplineCurve.hxx>
#endif
#include "../ifcgeom/IfcGeom.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircle* l, Handle(Geom_Curve)& curve) {
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
if ( r < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l);
return false;
}
gp_Trsf trsf;
IfcSchema::IfcAxis2Placement* placement = l->Position();
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
if (placement->declaration().is(IfcSchema::IfcAxis2Placement3D::Class())) {
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
} else {
gp_Trsf2d trsf2d;
@@ -102,7 +108,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipse* l, Handle(Geom_Curve)
double x = l->SemiAxis1() * getValue(GV_LENGTH_UNIT);
double y = l->SemiAxis2() * getValue(GV_LENGTH_UNIT);
if (x < ALMOST_ZERO || y < ALMOST_ZERO) {
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l);
return false;
}
// Open Cascade does not allow ellipses of which the minor radius
@@ -112,7 +118,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipse* l, Handle(Geom_Curve)
const bool rotated = y > x;
gp_Trsf trsf;
IfcSchema::IfcAxis2Placement* placement = l->Position();
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
if (placement->declaration().is(IfcSchema::IfcAxis2Placement3D::Class())) {
convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
} else {
gp_Trsf2d trsf2d;
@@ -135,4 +141,58 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLine* l, Handle(Geom_Curve)& c
// See note at IfcGeomWires.cpp:237
curve = new Geom_Line(pnt,vec);
return true;
}
}
#ifdef USE_IFC4
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineCurveWithKnots* l, Handle(Geom_Curve)& curve) {
const bool is_rational = l->declaration().is(IfcSchema::IfcRationalBSplineCurveWithKnots::Class());
const IfcSchema::IfcCartesianPoint::list::ptr cps = l->ControlPointsList();
const std::vector<int> mults = l->KnotMultiplicities();
const std::vector<double> knots = l->Knots();
TColgp_Array1OfPnt Poles(0, cps->size() - 1);
TColStd_Array1OfReal Weights(0, cps->size() - 1);
TColStd_Array1OfReal Knots(0, (int)knots.size() - 1);
TColStd_Array1OfInteger Mults(0, (int)mults.size() - 1);
Standard_Integer Degree = l->Degree();
Standard_Boolean Periodic = l->ClosedCurve();
int i;
if (is_rational) {
IfcSchema::IfcRationalBSplineCurveWithKnots* rl = (IfcSchema::IfcRationalBSplineCurveWithKnots*)l;
std::vector<double> weights = rl->WeightsData();
i = 0;
for (std::vector<double>::const_iterator it = weights.begin(); it != weights.end(); ++it, ++i) {
Weights(i) = *it;
}
}
i = 0;
for (IfcSchema::IfcCartesianPoint::list::it it = cps->begin(); it != cps->end(); ++it, ++i) {
gp_Pnt pnt;
if (!convert(*it, pnt)) return false;
Poles(i) = pnt;
}
i = 0;
for (std::vector<int>::const_iterator it = mults.begin(); it != mults.end(); ++it, ++i) {
Mults(i) = *it;
}
i = 0;
for (std::vector<double>::const_iterator it = knots.begin(); it != knots.end(); ++it, ++i) {
Knots(i) = *it;
}
if (is_rational) {
curve = new Geom_BSplineCurve(Poles, Weights, Knots, Mults, Degree, Periodic);
} else {
curve = new Geom_BSplineCurve(Poles, Knots, Mults, Degree, Periodic);
}
return true;
}
#endif
+110 -36
View File
@@ -20,9 +20,14 @@
#ifndef IFCGEOMELEMENT_H
#define IFCGEOMELEMENT_H
#include <string>
#include <algorithm>
#include "../ifcparse/IfcGlobalId.h"
#include "../ifcgeom/IfcGeomRepresentation.h"
#include "../ifcgeom/IfcGeomIteratorSettings.h"
#include "ifc_geom_api.h"
namespace IfcGeom {
@@ -40,7 +45,7 @@ namespace IfcGeom {
for(int i = 1; i < 5; ++i) {
for (int j = 1; j < 4; ++j) {
const double trsf_value = trsf.Value(j,i);
const double matrix_value = i == 4 && settings.convert_back_units()
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));
@@ -53,18 +58,28 @@ namespace IfcGeom {
template <typename P>
class Transformation {
private:
gp_Trsf trsf;
Matrix<P> _matrix;
ElementSettings settings_;
gp_Trsf trsf_;
Matrix<P> matrix_;
public:
Transformation(const ElementSettings& settings, const gp_Trsf& trsf)
: trsf(trsf)
, _matrix(settings, trsf)
: settings_(settings)
, trsf_(trsf)
, matrix_(settings, trsf)
{}
const gp_Trsf& data() const { return trsf; }
const Matrix<P>& matrix() const { return _matrix; }
const gp_Trsf& data() const { return trsf_; }
const Matrix<P>& matrix() const { return matrix_; }
Transformation inverted() const {
return Transformation(settings_, trsf_.Inverted());
}
Transformation multiplied(const Transformation& other) const {
return Transformation(settings_, trsf_.Multiplied(other.data()));
}
};
template <typename P>
template <typename P = double, typename PP = P>
class Element {
private:
int _id;
@@ -72,64 +87,123 @@ namespace IfcGeom {
std::string _name;
std::string _type;
std::string _guid;
Transformation<P> _transformation;
std::string _context;
std::string _unique_id;
Transformation<PP> _transformation;
IfcUtil::IfcBaseEntity* product_;
std::vector<const IfcGeom::Element<P, PP>*> _parents;
public:
friend bool operator == (const Element<P, PP> & element1, const Element<P, PP> & element2) {
return element1.id() == element2.id();
}
// Use the id to compare, or the elevation is the elements are IfcBuildingStoreys and the elevation is set
friend bool operator < (const Element<P, PP> & element1, const Element<P, PP> & element2) {
if (element1.type() == "IfcBuildingStorey" && element2.type() == "IfcBuildingStorey") {
size_t attr_index = element1.product()->declaration().attribute_index("Elevation");
Argument* elev_attr1 = element1.product()->data().getArgument(attr_index);
Argument* elev_attr2 = element2.product()->data().getArgument(attr_index);
if (!elev_attr1->isNull() && !elev_attr2->isNull()) {
double elev1 = *elev_attr1;
double elev2 = *elev_attr2;
return elev1 < elev2;
}
}
return element1.id() < element2.id();
}
int id() const { return _id; }
int parent_id() const { return _parent_id; }
const std::string& name() const { return _name; }
const std::string& type() const { return _type; }
const std::string& guid() const { return _guid; }
const Transformation<P>& transformation() const { return _transformation; }
Element(const ElementSettings& settings, int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf)
: _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _transformation(settings, trsf)
{}
const std::string& context() const { return _context; }
const std::string& unique_id() const { return _unique_id; }
const Transformation<PP>& transformation() const { return _transformation; }
IfcUtil::IfcBaseEntity* product() const { return product_; }
const std::vector<const IfcGeom::Element<P, PP>*> parents() const { return _parents; }
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)
: _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _context(context), _transformation(settings, trsf)
, product_(product)
{
std::ostringstream oss;
if (type == "IfcProject") {
oss << "project";
} else {
try {
oss << "product-" << IfcParse::IfcGlobalId(guid).formatted();
} catch (const std::exception& e) {
oss << "product";
Logger::Error(e);
}
}
if (!_context.empty()) {
std::string ctx = _context;
boost::to_lower(ctx);
boost::replace_all(ctx, " ", "-");
oss << "-" << ctx;
}
_unique_id = oss.str();
}
virtual ~Element() {}
};
template <typename P>
class BRepElement : public Element<P> {
template <typename P = double, typename PP = P>
class BRepElement : public Element<P, PP> {
private:
Representation::BRep* _geometry;
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 gp_Trsf& trsf, Representation::BRep* geometry)
: Element<P>(geometry->settings(),id,parent_id,name,type,guid,trsf)
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,
IfcUtil::IfcBaseEntity* product)
: Element<P, PP>(geometry->settings() ,id, parent_id, name, type, guid, context, trsf, product)
, _geometry(geometry)
{}
virtual ~BRepElement() {
delete _geometry;
}
private:
BRepElement(const BRepElement& other);
BRepElement& operator=(const BRepElement& other);
};
template <typename P>
class TriangulationElement : public Element<P> {
template <typename P = double, typename PP = P>
class TriangulationElement : public Element<P, PP> {
private:
Representation::Triangulation<P>* _geometry;
boost::shared_ptr< Representation::Triangulation<P> > _geometry;
public:
const Representation::Triangulation<P>& geometry() const { return *_geometry; }
TriangulationElement(const BRepElement<P>& shape_model)
: Element<P>(shape_model)
, _geometry(new Representation::Triangulation<P>(shape_model.geometry()))
const boost::shared_ptr< Representation::Triangulation<P> >& geometry_pointer() const { return _geometry; }
TriangulationElement(const BRepElement<P, PP>& shape_model)
: Element<P, PP>(shape_model)
, _geometry(boost::shared_ptr<Representation::Triangulation<P> >(new Representation::Triangulation<P>(shape_model.geometry())))
{}
TriangulationElement(const Element<P, PP>& element, const boost::shared_ptr<Representation::Triangulation<P> >& geometry)
: Element<P, PP>(element)
, _geometry(geometry)
{}
virtual ~TriangulationElement() {
delete _geometry;
}
private:
TriangulationElement(const TriangulationElement& other);
TriangulationElement& operator=(const TriangulationElement& other);
};
template <typename P>
class SerializedElement : public Element<P> {
template <typename P = double, typename PP = P>
class SerializedElement : public Element<P, PP> {
private:
Representation::Serialization* _geometry;
public:
const Representation::Serialization& geometry() const { return *_geometry; }
SerializedElement(const BRepElement<P>& shape_model)
: Element<P>(shape_model)
SerializedElement(const BRepElement<P, PP>& shape_model)
: Element<P, PP>(shape_model)
, _geometry(new Representation::Serialization(shape_model.geometry()))
{}
virtual ~SerializedElement() {
@@ -141,4 +215,4 @@ namespace IfcGeom {
};
}
#endif
#endif
+424 -191
View File
@@ -47,6 +47,7 @@
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <Geom_Line.hxx>
#include <Geom_Plane.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Ellipse.hxx>
#include <Geom_TrimmedCurve.hxx>
@@ -70,9 +71,11 @@
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS_Iterator.hxx>
#include <BRepAlgoAPI_Cut.hxx>
#include <ShapeFix_Edge.hxx>
#include <ShapeFix_Shape.hxx>
#include <ShapeFix_ShapeTolerance.hxx>
#include <ShapeFix_Solid.hxx>
@@ -83,127 +86,297 @@
#include <Standard_Failure.hxx>
#include <BRep_Tool.hxx>
#include <BRepCheck_Face.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <Standard_Version.hxx>
#include <TopTools_DataMapOfShapeInteger.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#ifdef USE_IFC4
#include <Geom_BSplineSurface.hxx>
#include <TColgp_Array2OfPnt.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <Geom_Plane.hxx>
#include <BRepCheck_Face.hxx>
#endif
#include "../ifcgeom/IfcGeom.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
IfcSchema::IfcFaceBound::list::it it = bounds->begin();
IfcSchema::IfcLoop* loop = (*it)->Bound();
TopoDS_Wire outer_wire;
if ( ! convert_wire(loop,outer_wire) ) return false;
BRepBuilderAPI_MakeFace mf (outer_wire);
BRepBuilderAPI_FaceError er = mf.Error();
if ( er == BRepBuilderAPI_NotPlanar ) {
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(outer_wire, 0.01, TopAbs_WIRE);
mf.~BRepBuilderAPI_MakeFace();
new (&mf) BRepBuilderAPI_MakeFace(outer_wire);
er = mf.Error();
}
if ( er != BRepBuilderAPI_FaceDone ) return false;
if ( bounds->size() == 1 ) {
face = mf.Face();
} else {
for( ++it; it != bounds->end(); ++ it) {
IfcSchema::IfcLoop* loop = (*it)->Bound();
TopoDS_Wire wire;
if ( ! convert_wire(loop,wire) ) return false;
mf.Add(wire);
}
if ( mf.IsDone() ) {
ShapeFix_Shape sfs(mf.Face());
sfs.Perform();
TopoDS_Shape sfs_shape = sfs.Shape();
bool is_face = sfs_shape.ShapeType() == TopAbs_FACE;
if ( is_face ) {
face = TopoDS::Face(sfs_shape);
} else {
return false;
}
} else {
return false;
}
}
if ( getValue(GV_FORCE_CCW_FACE_ORIENTATION)>0 ) {
// Check the orientation of the face by comparing the
// normal of the topological surface to the Newell's Method's
// normal. Newell's Method is used for the normal calculation
// as a simple edge cross product can give opposite results
// for a concave face boundary.
// Reference: Graphics Gems III p. 231
BRepGProp_Face prop(TopoDS::Face(face));
gp_Vec normal_direction;
gp_Pnt center;
double u1,u2,v1,v2;
prop.Bounds(u1,u2,v1,v2);
prop.Normal((u1+u2)/2.0,(v1+v2)/2.0,center,normal_direction);
gp_Dir face_normal1 = gp_Dir(normal_direction.XYZ());
Handle(Geom_Surface) face_surface;
const bool is_face_surface = l->declaration().is(IfcSchema::IfcFaceSurface::Class());
double x = 0, y = 0, z = 0;
gp_Pnt current, previous, first;
int n = 0;
// Iterate over the vertices of the outer wire (discarding
// any potential holes)
for ( TopExp_Explorer exp(outer_wire,TopAbs_VERTEX);; exp.Next()) {
unsigned has_more = exp.More();
if ( has_more ) {
const TopoDS_Vertex& v = TopoDS::Vertex(exp.Current());
current = BRep_Tool::Pnt(v);
} else {
current = first;
}
if ( n ) {
const double& xn = previous.X();
const double& yn = previous.Y();
const double& zn = previous.Z();
const double& xn1 = current.X();
const double& yn1 = current.Y();
const double& zn1 = current.Z();
x += (yn-yn1)*(zn+zn1);
y += (xn+xn1)*(zn-zn1);
z += (xn-xn1)*(yn+yn1);
} else {
first = current;
}
if ( !has_more ) {
break;
}
previous = current;
++n;
}
if (is_face_surface) {
IfcSchema::IfcFaceSurface* fs = (IfcSchema::IfcFaceSurface*) l;
fs->FaceSurface();
// FIXME: Surfaces are interpreted as a TopoDS_Shape
TopoDS_Shape surface_shape;
if (!convert_shape(fs->FaceSurface(), surface_shape)) return false;
// If Newell's normal does not point in the same direction
// as the topological face normal the face orientation is
// reversed
gp_Vec face_normal2(x,y,z);
// FIXME: Assert this obtaines the only face
TopExp_Explorer exp(surface_shape, TopAbs_FACE);
if (!exp.More()) return false;
if (face_normal2.Magnitude() > ALMOST_ZERO) {
if ( face_normal1.Dot(face_normal2) < 0 ) {
TopAbs_Orientation o = face.Orientation();
face.Orientation(o == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD);
}
}
TopoDS_Face surface = TopoDS::Face(exp.Current());
face_surface = BRep_Tool::Surface(surface);
}
// It might be a good idea to globally discard faces
// smaller than a certain treshold value. But for now
// only when processing IfcConnectedFacesets the small
// faces are skipped.
// return face_area(face) > 0.0001;
return true;
const int num_bounds = bounds->size();
int num_outer_bounds = 0;
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
IfcSchema::IfcFaceBound* bound = *it;
if (bound->declaration().is(IfcSchema::IfcFaceOuterBound::Class())) num_outer_bounds ++;
}
// The number of outer bounds should be one according to the schema. Also Open Cascade
// expects this, but it is not strictly checked. Regardless, if the number is greater,
// the face will still be processed as long as there are no holes. A compound of faces
// is returned in that case.
if (num_bounds > 1 && num_outer_bounds > 1 && num_bounds != num_outer_bounds) {
Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l);
return false;
}
TopoDS_Compound compound;
BRep_Builder builder;
if (num_outer_bounds > 1) {
builder.MakeCompound(compound);
}
TopTools_DataMapOfShapeInteger wire_senses;
// The builder is initialized on the heap because of the various different moments
// of initialization depending on the configuration of surfaces and boundaries.
BRepBuilderAPI_MakeFace* mf = 0;
bool success = false;
int processed = 0;
for (int process_interior = 0; process_interior <= 1; ++process_interior) {
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
IfcSchema::IfcFaceBound* bound = *it;
IfcSchema::IfcLoop* loop = bound->Bound();
bool same_sense = bound->Orientation();
const bool is_interior =
!bound->declaration().is(IfcSchema::IfcFaceOuterBound::Class()) &&
(num_bounds > 1) &&
(num_outer_bounds < num_bounds);
// The exterior face boundary is processed first
if (is_interior == !process_interior) continue;
TopoDS_Wire wire;
if (!convert_wire(loop, wire)) {
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop);
delete mf;
return false;
}
/*
The approach below does not result in a significant speed-up
if (loop->declaration().is(IfcSchema::IfcPolyLoop::Class()) && processed == 0 && face_surface.IsNull()) {
IfcSchema::IfcPolyLoop* polyloop = (IfcSchema::IfcPolyLoop*) loop;
IfcSchema::IfcCartesianPoint::list::ptr points = polyloop->Polygon();
if (points->size() == 3) {
// Help Open Cascade by finding the plane more efficiently
IfcSchema::IfcCartesianPoint::list::it point_iterator = points->begin();
gp_Pnt a, b, c;
convert(*point_iterator++, a);
convert(*point_iterator++, b);
convert(*point_iterator++, c);
const gp_XYZ ab = (b.XYZ() - a.XYZ());
const gp_XYZ ac = (c.XYZ() - a.XYZ());
const gp_Vec cross = ab.Crossed(ac);
if (cross.SquareMagnitude() > ALMOST_ZERO) {
const gp_Dir n = cross;
face_surface = new Geom_Plane(a, n);
}
}
}
*/
if (!same_sense) {
wire.Reverse();
}
wire_senses.Bind(wire.Oriented(TopAbs_FORWARD), same_sense ? TopAbs_FORWARD : TopAbs_REVERSED);
bool flattened_wire = false;
if (!mf) {
process_wire:
if (face_surface.IsNull()) {
if (count(wire, TopAbs_EDGE) > 128) {
// tfk: optimization find the underlying surface ourselves since it's going
// to be planar in IFC if no explicit surface is given. Should we always do this?
gp_Pln pln;
approximate_plane_through_wire(wire, pln);
mf = new BRepBuilderAPI_MakeFace(pln, wire, true);
} else {
mf = new BRepBuilderAPI_MakeFace(wire);
}
} else {
/// @todo check necessity of false here
mf = new BRepBuilderAPI_MakeFace(face_surface, wire, false);
}
/* BRepBuilderAPI_FaceError er = mf->Error();
if (er == BRepBuilderAPI_NotPlanar) {
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(wire, getValue(GV_PRECISION), TopAbs_WIRE);
delete mf;
mf = new BRepBuilderAPI_MakeFace(wire);
} */
if (mf->IsDone()) {
TopoDS_Face outer_face_bound = mf->Face();
// In case of (non-planar) face surface, p-curves need to be computed.
// For planar faces, Open Cascade generates p-curves on the fly.
if (!face_surface.IsNull()) {
TopExp_Explorer exp(outer_face_bound, TopAbs_EDGE);
for (; exp.More(); exp.Next()) {
const TopoDS_Edge& edge = TopoDS::Edge(exp.Current());
ShapeFix_Edge fix_edge;
fix_edge.FixAddPCurve(edge, outer_face_bound, false, getValue(GV_PRECISION));
}
}
if (BRepCheck_Face(outer_face_bound).OrientationOfWires() == BRepCheck_BadOrientationOfSubshape) {
wire.Reverse();
same_sense = !same_sense;
delete mf;
if (face_surface.IsNull()) {
mf = new BRepBuilderAPI_MakeFace(wire);
} else {
mf = new BRepBuilderAPI_MakeFace(face_surface, wire);
}
ShapeFix_Face fix(mf->Face());
fix.FixOrientation();
outer_face_bound = fix.Face();
}
if (num_outer_bounds > 1) {
builder.Add(compound, outer_face_bound);
delete mf; mf = 0;
} else if (num_bounds > 1) {
// Reinitialize the builder to the outer face
// bound in order to add holes more robustly.
delete mf;
// TODO: What about the face_surface?
mf = new BRepBuilderAPI_MakeFace(outer_face_bound);
} else {
face = outer_face_bound;
success = true;
}
} else {
const bool non_planar = mf->Error() == BRepBuilderAPI_NotPlanar;
delete mf;
const bool sewing_shells = getValue(GV_MAX_FACES_TO_SEW) > -1;
if (non_planar && sewing_shells && bounds->size() == 1 && face_surface.IsNull()) {
Logger::Message(Logger::LOG_ERROR, "Triangulating face boundary", bound);
// When creating a solid, flatting the boundary only postpones the issue to
// creating a topological manifold out of the individual faces.
TopTools_ListOfShape face_list;
triangulate_wire(wire, face_list);
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
TopTools_ListIteratorOfListOfShape face_iterator;
for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) {
builder.Add(compound, face_iterator.Value());
}
face = compound;
return true;
}
if (!non_planar || flattened_wire || !flatten_wire(wire)) {
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary", bound);
return false;
} else {
Logger::Message(Logger::LOG_ERROR, "Flattening face boundary", bound);
flattened_wire = true;
goto process_wire;
}
}
} else {
mf->Add(wire);
}
processed ++;
}
}
if (!success) {
success = processed == num_bounds;
if (success) {
if (num_outer_bounds > 1) {
face = compound;
} else {
success = success && mf->IsDone();
if (success) {
face = mf->Face();
}
ShapeFix_Face sfs(TopoDS::Face(face));
TopTools_DataMapOfShapeListOfShape wire_map;
sfs.FixOrientation(wire_map);
TopoDS_Iterator jt(face, false);
for (; jt.More(); jt.Next()) {
const TopoDS_Wire& w = TopoDS::Wire(jt.Value());
if (wire_map.IsBound(w)) {
const TopTools_ListOfShape& shapes = wire_map.Find(w);
TopTools_ListIteratorOfListOfShape it(shapes);
for (; it.More(); it.Next()) {
// Apparently the wire got reversed, so register it with opposite orientation in the map
wire_senses.Bind(it.Value(), wire_senses.Find(w) == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD);
}
}
}
face = TopoDS::Face(sfs.Face());
}
}
}
if (success) {
// If the wires are reversed the face needs to be reversed as well in order
// to maintain the counter-clock-wise ordering of the bounding wire's vertices.
if (num_bounds == 1 || true) {
bool all_reversed = true;
TopoDS_Iterator jt(face, false);
for (; jt.More(); jt.Next()) {
const TopoDS_Wire& w = TopoDS::Wire(jt.Value());
if (!wire_senses.IsBound(w.Oriented(TopAbs_FORWARD)) || (w.Orientation() == wire_senses.Find(w.Oriented(TopAbs_FORWARD)))) {
all_reversed = false;
}
}
if (all_reversed) {
face.Reverse();
}
}
}
delete mf;
return success;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, TopoDS_Shape& face) {
@@ -235,15 +408,22 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids*
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleProfileDef* l, TopoDS_Shape& face) {
const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
gp_Trsf2d trsf2d;
IfcGeom::Kernel::convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
double coords[8] = {-x,-y,x,-y,x,y,-x,y};
return profile_helper(4,coords,0,0,0,trsf2d,face);
}
@@ -254,12 +434,19 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef* l,
const double r = l->RoundingRadius() * getValue(GV_LENGTH_UNIT);
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || r < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
gp_Trsf2d trsf2d;
IfcGeom::Kernel::convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
double coords[8] = {-x,-y, x,-y, x,y, -x,y};
int fillets[4] = {0,1,2,3};
double radii[4] = {r,r,r,r};
@@ -278,7 +465,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l,
const double r2 = fr2 ? l->InnerFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.;
if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
@@ -286,7 +473,14 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l,
TopoDS_Face f2;
gp_Trsf2d trsf2d;
IfcGeom::Kernel::convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
double coords1[8] = {-x ,-y, x ,-y, x, y, -x, y };
double coords2[8] = {-x+d,-y+d, x-d,-y+d, x-d,y-d, -x+d,y-d};
double radii1[4] = {r1,r1,r1,r1};
@@ -320,12 +514,19 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrapeziumProfileDef* l, TopoDS
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
if ( x1 < ALMOST_ZERO || w < ALMOST_ZERO || y < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
gp_Trsf2d trsf2d;
IfcGeom::Kernel::convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
double coords[8] = {-x1,-y, x1,-y, dx+w-x1,y, dx-x1,y};
return profile_helper(4,coords,0,0,0,trsf2d,face);
}
@@ -345,7 +546,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcIShapeProfileDef* l, TopoDS_Sh
bool doFillet2 = doFillet1;
double x2 = x1, dy2 = dy1, f2 = f1;
if (l->is(IfcSchema::Type::IfcAsymmetricIShapeProfileDef)) {
if (l->declaration().is(IfcSchema::IfcAsymmetricIShapeProfileDef::Class())) {
IfcSchema::IfcAsymmetricIShapeProfileDef* assym = (IfcSchema::IfcAsymmetricIShapeProfileDef*) l;
x2 = assym->TopFlangeWidth() / 2. * getValue(GV_LENGTH_UNIT);
doFillet2 = assym->hasTopFlangeFilletRadius();
@@ -358,12 +559,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcIShapeProfileDef* l, TopoDS_Sh
}
if ( x1 < ALMOST_ZERO || x2 < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || dy1 < ALMOST_ZERO || dy2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
gp_Trsf2d trsf2d;
convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
double coords[24] = {-x1,-y, x1,-y, x1,-y+dy1, d1,-y+dy1, d1,y-dy2, x2,y-dy2, x2,y, -x2,y, -x2,y-dy2, -d1,y-dy2, -d1,-y+dy1, -x1,-y+dy1};
int fillets[4] = {3,4,9,10};
@@ -391,12 +598,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcZShapeProfileDef* l, TopoDS_Sh
}
if ( x == 0.0f || y == 0.0f || dx == 0.0f || dy == 0.0f ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
gp_Trsf2d trsf2d;
IfcGeom::Kernel::convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
double coords[16] = {-dx,-y, x,-y, x,-y+dy, dx,-y+dy, dx,y, -x,y, -x,y-dy, -dx,y-dy};
int fillets[4] = {2,3,6,7};
@@ -418,12 +631,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCShapeProfileDef* l, TopoDS_Sh
}
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
gp_Trsf2d trsf2d;
IfcGeom::Kernel::convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
double coords[24] = {-x,-y,x,-y,x,-y+d2,x-d1,-y+d2,x-d1,-y+d1,-x+d1,-y+d1,-x+d1,y-d1,x-d1,y-d1,x-d1,y-d2,x,y-d2,x,y,-x,y};
int fillets[8] = {0,1,4,5,6,7,10,11};
@@ -451,7 +670,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Sh
}
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
@@ -483,7 +702,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Sh
const double det = a1*b2 - a2*b1;
if (ALMOST_THE_SAME(det, 0.)) {
Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:",l->entity);
Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:",l);
return false;
}
@@ -492,7 +711,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Sh
}
gp_Trsf2d trsf2d;
convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
double coords[12] = {-x,-y, x,-y, x,-y+d-dy1, xx, xy, -x+d-dx1,y, -x,y};
int fillets[3] = {2,3,4};
@@ -529,12 +754,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcUShapeProfileDef* l, TopoDS_Sh
}
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
gp_Trsf2d trsf2d;
convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
double coords[16] = {-x,-y, x,-y, x,-y+d2-dy2, -x+d1,-y+d2+dy1, -x+d1,y-d2-dy1, x,y-d2+dy2, x,y, -x,y};
int fillets[4] = {2,3,4,5};
@@ -557,7 +788,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
const double webSlope = hasWebSlope ? (l->WebSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
@@ -605,7 +836,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
const double det = a1*b2 - a2*b1;
if (ALMOST_THE_SAME(det, 0.)) {
Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:",l->entity);
Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:",l);
return false;
}
@@ -617,7 +848,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
}
gp_Trsf2d trsf2d;
convert(l->Position(),trsf2d);
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
double coords[16] = {d1/2.-dx2,-y, xx,xy, x,y-d2+dy2, x,y, -x,y, -x,y-d2+dy2, -xx,xy, -d1/2.+dx2,-y};
int fillets[6] = {0,1,2,5,6,7};
@@ -628,17 +865,25 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleProfileDef* l, TopoDS_Shape& face) {
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
if ( r == 0.0f ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
gp_Trsf2d trsf;
convert(l->Position(),trsf);
gp_Trsf2d trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
gp_Ax2 ax = gp_Ax2().Transformed(trsf2d);
BRepBuilderAPI_MakeWire w;
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
Handle(Geom_Circle) circle = new Geom_Circle(ax, r);
TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(circle);
BRepBuilderAPI_MakeWire w;
w.Add(edge);
TopoDS_Face f;
@@ -652,13 +897,20 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, Top
const double t = l->WallThickness() * getValue(GV_LENGTH_UNIT);
if ( r == 0.0f || t == 0.0f ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
gp_Trsf2d trsf;
convert(l->Position(),trsf);
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
gp_Trsf2d trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
gp_Ax2 ax = gp_Ax2().Transformed(trsf2d);
BRepBuilderAPI_MakeWire outer;
Handle(Geom_Circle) outerCircle = new Geom_Circle(ax, r);
@@ -681,20 +933,27 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipseProfileDef* l, TopoDS_S
double ry = l->SemiAxis2() * getValue(GV_LENGTH_UNIT);
if ( rx < ALMOST_ZERO || ry < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
return false;
}
const bool rotated = ry > rx;
gp_Trsf2d trsf;
convert(l->Position(),trsf);
gp_Trsf2d trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
gp_Ax2 ax = gp_Ax2();
if (rotated) {
ax.Rotate(ax.Axis(), M_PI / 2.);
std::swap(rx, ry);
}
ax.Transform(trsf);
ax.Transform(trsf2d);
BRepBuilderAPI_MakeWire w;
Handle(Geom_Ellipse) ellipse = new Geom_Ellipse(ax, rx, ry);
@@ -764,7 +1023,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeProfileDef* l, TopoDS
builder.MakeCompound(compound);
IfcSchema::IfcProfileDef::list::ptr profiles = l->Profiles();
bool first = true;
//bool first = true;
for (IfcSchema::IfcProfileDef::list::it it = profiles->begin(); it != profiles->end(); ++it) {
TopoDS_Face f;
if (convert_face(*it, f)) {
@@ -798,20 +1057,32 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcDerivedProfileDef* l, TopoDS_S
}
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPlane* l, TopoDS_Shape& face) {
gp_Pln pln;
convert(l, pln);
Handle_Geom_Surface surf = new Geom_Plane(pln);
#if OCC_VERSION_HEX < 0x60502
face = BRepBuilderAPI_MakeFace(surf);
#else
face = BRepBuilderAPI_MakeFace(surf, getValue(GV_PRECISION));
#endif
return true;
}
#ifdef USE_IFC4
bool convert_surf(IfcSchema::IfcBSplineSurfaceWithKnots* l, Handle_Geom_Surface& surf) {
SHARED_PTR< IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint> > cps = l->ControlPointsList();
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineSurfaceWithKnots* l, TopoDS_Shape& face) {
boost::shared_ptr< IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint> > cps = l->ControlPointsList();
std::vector<double> uknots = l->UKnots();
std::vector<double> vknots = l->VKnots();
std::vector<int> umults = l->UMultiplicities();
std::vector<int> vmults = l->VMultiplicities();
TColgp_Array2OfPnt Poles (0, cps->size() - 1, 0, (*cps->begin()).size() - 1);
TColStd_Array1OfReal UKnots(0, uknots.size() - 1);
TColStd_Array1OfReal VKnots(0, vknots.size() - 1);
TColStd_Array1OfInteger UMults(0, umults.size() - 1);
TColStd_Array1OfInteger VMults(0, vmults.size() - 1);
TColgp_Array2OfPnt Poles (0, (int)cps->size() - 1, 0, (int)(*cps->begin()).size() - 1);
TColStd_Array1OfReal UKnots(0, (int)uknots.size() - 1);
TColStd_Array1OfReal VKnots(0, (int)vknots.size() - 1);
TColStd_Array1OfInteger UMults(0, (int)umults.size() - 1);
TColStd_Array1OfInteger VMults(0, (int)vmults.size() - 1);
Standard_Integer UDegree = l->UDegree();
Standard_Integer VDegree = l->VDegree();
@@ -841,51 +1112,13 @@ bool convert_surf(IfcSchema::IfcBSplineSurfaceWithKnots* l, Handle_Geom_Surface&
for (std::vector<int>::const_iterator it = vmults.begin(); it != vmults.end(); ++it, ++i) {
VMults(i) = *it;
}
surf = new Geom_BSplineSurface(Poles, UKnots, VKnots, UMults, VMults, UDegree, VDegree);
return true;
}
Handle_Geom_Surface surf = new Geom_BSplineSurface(Poles, UKnots, VKnots, UMults, VMults, UDegree, VDegree);
bool convert_surf(IfcSchema::IfcPlane* l, Handle_Geom_Surface& surf) {
gp_Pln pln;
convert(l, pln);
surf = new Geom_Plane(pln);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAdvancedFace* l, TopoDS_Shape& face) {
IfcSchema::IfcSurface* s = l->FaceSurface();
Handle_Geom_Surface surf(0);
if (s->is(IfcSchema::Type::IfcBSplineSurfaceWithKnots)) {
convert_surf((IfcSchema::IfcBSplineSurfaceWithKnots*)s, surf);
} else if (s->is(IfcSchema::Type::IfcPlane)) {
convert_surf((IfcSchema::IfcPlane*)s, surf);
} else {
return false;
}
BRepBuilderAPI_MakeFace mf(surf, Precision::Confusion());
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
IfcSchema::IfcLoop* loop = (*it)->Bound();
TopoDS_Wire outer_wire;
if (!convert_wire(loop, outer_wire)) return false;
TopoDS_Face temp = BRepBuilderAPI_MakeFace(surf, outer_wire);
if (BRepCheck_Face(temp).OrientationOfWires() == BRepCheck_BadOrientationOfSubshape) {
outer_wire.Reverse();
ShapeFix_Face fix(BRepBuilderAPI_MakeFace(surf, outer_wire).Face());
fix.FixOrientation();
fix.Perform();
TopoDS_Face temp = fix.Face();
TopExp_Explorer exp(temp, TopAbs_WIRE);
outer_wire = TopoDS::Wire(exp.Current());
}
mf.Add(outer_wire);
}
face = mf.Face();
#if OCC_VERSION_HEX < 0x60502
face = BRepBuilderAPI_MakeFace(surf);
#else
face = BRepBuilderAPI_MakeFace(surf, getValue(GV_PRECISION));
#endif
return true;
}
+319
View File
@@ -0,0 +1,319 @@
/********************************************************************************
* *
* 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/>. *
* *
********************************************************************************/
/** @file IfcGeomFilter.h
@brief A set of predefined product filters for IfcGeom::Iterator */
#ifndef IFCGEOMFILTER_H
#define IFCGEOMFILTER_H
#include "IfcGeom.h"
#include <boost/foreach.hpp>
#include <boost/function.hpp>
#include <boost/regex.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <functional>
namespace IfcGeom
{
/// The filter function (free or member function) or function object (use boost::ref() to reference to it)
/// should return true if the geometry for the product is wanted to be included in the output.
/// http://www.boost.org/doc/libs/1_62_0/doc/html/function/tutorial.html
typedef boost::function<bool(IfcSchema::IfcProduct*)> filter_t;
struct filter
{
filter() : include(false), traverse(false) {}
filter(bool incl, bool trav) : include(incl), traverse(trav) {}
/// Should the product be included (true) or excluded (false).
bool include;
/// If traversal requested, traverse to the parents to see if they satisfy the criteria. E.g. we might be looking for
/// children of a storey named "Level 20", or children of entities that have no representation, e.g. IfcCurtainWall.
bool traverse;
/// Optional description for the filtering criteria of this filter.
std::string description;
bool match(IfcSchema::IfcProduct* prod, const filter_t& pred) const
{
bool is_match = pred(prod);
if (!is_match && traverse) {
is_match = traverse_match(prod, pred);
}
return is_match == include;
}
static bool traverse_match(IfcSchema::IfcProduct* prod, const filter_t& pred)
{
throw std::runtime_error("todo");
/*
IfcSchema::IfcProduct* parent, *current = prod;
while ((parent = dynamic_cast<IfcSchema::IfcProduct*>(IfcGeom::Kernel::get_decomposing_entity(current))) != 0) {
if (pred(parent)) {
return true;
}
current = parent;
}
*/
return false;
}
};
struct wildcard_filter : public filter
{
wildcard_filter() : filter(false, false) {}
wildcard_filter(bool include, bool traverse, const std::set<std::string>& patterns)
: filter(include, traverse)
{
populate(patterns);
}
std::set<boost::regex> values;
void populate(const std::set<std::string>& patterns)
{
values.clear();
BOOST_FOREACH(const std::string &pattern, patterns) {
values.insert(wildcard_string_to_regex(pattern));
}
}
bool match(const std::string &str) const { return match_values(values, str); }
static bool match_values(const std::set<boost::regex>& values, const std::string &str)
{
BOOST_FOREACH(const boost::regex& r, values) {
if (boost::regex_match(str, r)) {
return true;
}
}
return false;
}
static boost::regex wildcard_string_to_regex(std::string str)
{
// Escape all non-"*?" regex special chars
static const std::string special_chars = "\\^.$|()[]+/";
BOOST_FOREACH(char c, special_chars) {
std::string char_str(1, c);
boost::replace_all(str, char_str, "\\" + char_str);
}
// Convert "*?" to their regex equivalents
boost::replace_all(str, "?", ".");
boost::replace_all(str, "*", ".*");
return boost::regex(str);
}
};
/// @note supports only string arguments for now
struct string_arg_filter : public wildcard_filter
{
// Using this for now in order to overcome the fact that different classes have the argument at different indices.
typedef std::map<const IfcParse::declaration*, unsigned short> arg_map_t;
arg_map_t args;
/// @todo Take only attribute name when IfcBaseClass and IfcLateBoundEntity are merged.
string_arg_filter(arg_map_t args) : args(args) { assert_arguments(); }
string_arg_filter(const IfcParse::declaration* type, unsigned short index) { args[type] = index; assert_arguments(); }
string_arg_filter(
const IfcParse::declaration* type1, unsigned short index1,
const IfcParse::declaration* type2, unsigned short index2)
{
args[type1] = index1;
args[type2] = index2;
assert_arguments();
}
/// @todo this won't be needed when we have the generic argument name access
void assert_arguments()
{
// TODO
#if 0
for (arg_map_t::const_iterator it = args.begin(); it != args.end(); ++it) {
IfcEntityInstanceData dummy(it->first);
IfcUtil::IfcBaseClass* base = IfcSchema::SchemaEntity(&dummy);
assert(it->second < base->getArgumentCount() && "Argument index out of bounds");
assert(base->getArgumentType(it->second) == IfcUtil::Argument_STRING && "Argument type not string");
delete base;
}
#endif
}
std::string value(IfcSchema::IfcProduct* prod) const
{
for (arg_map_t::const_iterator it = args.begin(); it != args.end(); ++it) {
if (prod->declaration().is(*it->first) && it->second < prod->data().getArgumentCount() &&
prod->data().getArgument(it->second)->type() == IfcUtil::Argument_STRING) {
Argument *arg = prod->data().getArgument(it->second);
if (!arg->isNull()) {
return *arg;
}
}
}
return "";
}
bool match(IfcSchema::IfcProduct* prod) const { return wildcard_filter::match(value(prod)); }
bool operator()(IfcSchema::IfcProduct* prod) const
{
// @note bind1st() and mem_fun() deprecated in C++11, use bind() and mem_fn() when migrating to C++11.
return filter::match(prod, std::bind1st(std::mem_fun(&string_arg_filter::match), this));
}
void update_description()
{
std::stringstream ss;
ss << (traverse ? "traverse " : "") << (include ? "include" : "exclude");
std::vector<std::string> patterns;
BOOST_FOREACH(const boost::regex& r, values) {
patterns.push_back("\"" + r.str() + "\"");
}
// TODO
#if 0
for (arg_map_t::const_iterator it = args.begin(); it != args.end(); ++it) {
IfcEntityInstanceData dummy(it->first);
IfcUtil::IfcBaseClass* base = IfcSchema::SchemaEntity(&dummy);
try {
ss << " " << IfcSchema::ToString::Class()(it->first) << "." << base->declaration().as_entity()->all_attributes()[it->second]->name();
} catch (const std::exception& e) {
Logger::Error(e);
}
delete base;
}
#endif
ss << " values " << boost::algorithm::join(patterns, " ");
description = ss.str();
}
};
struct layer_filter : public wildcard_filter
{
typedef std::map<std::string, IfcSchema::IfcPresentationLayerAssignment*> layer_map_t;
layer_filter() {}
layer_filter(bool include, bool traverse, const std::set<std::string>& patterns)
: wildcard_filter(include, traverse, patterns)
{
}
bool match(IfcSchema::IfcProduct* prod) const
{
throw std::runtime_error("todo");
/*
layer_map_t layers = IfcGeom::Kernel::get_layers(prod);
return std::find_if(layers.begin(), layers.end(), wildcards_match(values)) != layers.end();
*/
}
bool operator()(IfcSchema::IfcProduct* prod) const
{
return filter::match(prod, std::bind1st(std::mem_fun(&layer_filter::match), this));
}
struct wildcards_match
{
wildcards_match(const std::set<boost::regex>& patterns) : patterns(patterns) {}
bool operator()(const layer_map_t::value_type& layer_map_value) const
{
return wildcard_filter::match_values(patterns, layer_map_value.first);
}
std::set<boost::regex> patterns;
};
void update_description()
{
std::stringstream ss;
ss << (traverse ? "traverse " : "") << (include ? "include" : "exclude") << " layers";
std::vector<std::string> str_values;
BOOST_FOREACH(const boost::regex& r, values) {
str_values.push_back(" \"" + r.str() + "\"");
}
ss << boost::algorithm::join(str_values, " ");
description = ss.str();
}
};
struct entity_filter : public filter
{
entity_filter() {}
entity_filter(bool include, bool traverse/*, const std::set<std::string>& types*/)
: filter(include, traverse)
{
//populate(types);
}
std::set<const IfcParse::declaration*> values;
void populate(const std::set<std::string>&)
{
// TODO
#if 0
values.clear();
BOOST_FOREACH(const std::string& type, types) {
const IfcParse::declaration* ty;
try {
ty = IfcSchema::FromString::Class()(boost::to_upper_copy(type));
} catch (const IfcParse::IfcException&) {
throw IfcParse::IfcException("'" + type + "' does not name a valid IFC entity");
}
values.insert(ty);
/// @todo Add child classes so that containment in set can be in O(log n)
}
#endif
}
bool match(IfcSchema::IfcProduct* prod) const
{
// The set is iterated over to able to filter on subtypes.
BOOST_FOREACH(const IfcParse::declaration* type, values) {
if (prod->declaration().is(*type)) {
return true;
}
}
return false;
}
bool operator()(IfcSchema::IfcProduct* prod) const
{
return filter::match(prod, std::bind1st(std::mem_fun(&entity_filter::match), this));
}
void update_description()
{
// TODO
#if 0
std::stringstream ss;
ss << (traverse ? "traverse " : "") << (include ? "include" : "exclude") << " entities";
BOOST_FOREACH(IfcSchema::Enum::Class() type, values) {
ss << " " << IfcSchema::ToString::Class()(type);
}
description = ss.str();
#endif
}
};
}
#endif
File diff suppressed because it is too large Load Diff
+109 -15
View File
@@ -77,6 +77,58 @@
#include "../ifcgeom/IfcGeom.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
namespace {
// Helper functions (re)set gp_(G)Trsf(2d) forms explicitly to 'Identity'
// so that it can be easily identified in the IfcMappedItem processing
// For axis placements detect equality early in order for the
// relatively computionaly expensive gp_Trsf calculation to be skipped
template <typename T>
bool axis_equal(const T& a, const T& b, double tolerance);
template <>
bool axis_equal(const gp_Ax3& a, const gp_Ax3& b, double tolerance) {
if (!a.Location().IsEqual(b.Location(), tolerance)) return false;
// Note that the tolerance below is angular, above is linear. Since architectural
// objects are about 1m'ish in scale, it should be somewhat equivalent. Besides,
// this is mostly a filter for NULL or default values in the placements.
if (!a.Direction().IsEqual(b.Direction(), tolerance)) return false;
if (!a.XDirection().IsEqual(b.XDirection(), tolerance)) return false;
if (!a.YDirection().IsEqual(b.YDirection(), tolerance)) return false;
return true;
}
bool axis_equal(const gp_Ax2d& a, const gp_Ax2d& b, double tolerance) {
if (!a.Location().IsEqual(b.Location(), tolerance)) return false;
if (!a.Direction().IsEqual(b.Direction(), tolerance)) return false;
return true;
}
template <typename T> struct dimension_count {};
template <> struct dimension_count <gp_Trsf2d > { static const int n = 2; };
template <> struct dimension_count <gp_GTrsf2d> { static const int n = 2; };
template <> struct dimension_count < gp_Trsf > { static const int n = 3; };
template <> struct dimension_count < gp_GTrsf > { static const int n = 3; };
template <typename T>
bool is_identity(const T& t, double tolerance) {
// Note the {1, n+1} range due to Open Cascade's 1-based indexing
// Note the {1, n+2} range due to the translation part of the matrix
for (int i = 1; i < dimension_count<T>::n + 2; ++i) {
for (int j = 1; j < dimension_count<T>::n + 1; ++j) {
const double iden_value = i == j ? 1. : 0.;
const double trsf_value = t.Value(j, i);
if (fabs(trsf_value - iden_value) > tolerance) {
return false;
}
}
}
return true;
}
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianPoint* l, gp_Pnt& point) {
IN_CACHE(IfcCartesianPoint,l,gp_Pnt,point)
std::vector<double> xyz = l->Coordinates();
@@ -120,7 +172,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement3D* l, gp_Trsf&
gp_Ax3 ax3;
if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection);
else ax3 = gp_Ax3(o,axis);
trsf.SetTransformation(ax3, gp_Ax3(gp_Pnt(),gp_Dir(0,0,1),gp_Dir(1,0,0)));
if (!axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) {
trsf.SetTransformation(ax3, gp::XOY());
}
CACHE(IfcAxis2Placement3D,l,trsf)
return true;
}
@@ -147,9 +203,16 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
if ( l->hasAxis3() ) IfcGeom::Kernel::convert(l->Axis3(),axis3);
gp_Ax3 ax3 (origin,axis3,axis1);
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
trsf.SetTransformation(ax3);
trsf.Invert();
if ( l->hasScale() ) trsf.SetScaleFactor(l->Scale());
if (!axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) {
trsf.SetTransformation(ax3);
trsf.Invert();
}
if (l->hasScale() && !ALMOST_THE_SAME(l->Scale(), 1.)) {
trsf.SetScaleFactor(l->Scale());
}
CACHE(IfcCartesianTransformationOperator3D,l,trsf)
return true;
}
@@ -183,7 +246,12 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
}
trsf.Invert();
if ( l->hasScale() ) trsf.SetScaleFactor(l->Scale());
if ( l->hasScale() && !ALMOST_THE_SAME(l->Scale(), 1.) ) trsf.SetScaleFactor(l->Scale());
if (is_identity(trsf, getValue(GV_PRECISION))) {
trsf = gp_Trsf2d();
}
CACHE(IfcCartesianTransformationOperator2D,l,trsf)
return true;
}
@@ -211,6 +279,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
gtrsf.SetValue(2,2,scale2);
gtrsf.SetValue(3,3,scale3);
gtrsf.PreMultiply(trsf);
if (is_identity(gtrsf, getValue(GV_PRECISION))) {
gtrsf = gp_GTrsf();
}
CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gtrsf)
return true;
}
@@ -247,6 +320,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
gtrsf.SetValue(1,1,scale1);
gtrsf.SetValue(2,2,scale2);
gtrsf.Multiply(trsf);
if (is_identity(gtrsf, getValue(GV_PRECISION))) {
gtrsf = gp_GTrsf2d();
}
CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gtrsf)
return true;
}
@@ -274,33 +352,49 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d
if ( l->hasRefDirection() )
IfcGeom::Kernel::convert(l->RefDirection(),V);
gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()),gp_Dir2d(V.X(),V.Y()));
trsf.SetTransformation(axis,gp_Ax2d());
gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()), gp_Dir2d(V.X(),V.Y()));
if (!axis_equal(axis, gp_Ax2d(), getValue(GV_PRECISION))) {
trsf.SetTransformation(axis, gp_Ax2d());
}
CACHE(IfcAxis2Placement2D,l,trsf)
return true;
}
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->is(IfcSchema::Type::IfcLocalPlacement) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity);
if ( ! l->declaration().is(IfcSchema::IfcLocalPlacement::Class()) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l);
return false;
}
IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l;
while (1) {
for (;;) {
gp_Trsf trsf2;
IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement();
if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) {
if ( relplacement->declaration().is(IfcSchema::IfcAxis2Placement3D::Class()) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2);
trsf.PreMultiply(trsf2);
}
if ( current->hasPlacementRelTo() ) {
IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo();
if ( relto->is(IfcSchema::Type::IfcLocalPlacement) )
IfcSchema::IfcObjectPlacement* parent = current->PlacementRelTo();
IfcSchema::IfcProduct::list::ptr parentPlaces = parent->PlacesObject();
bool parentPlacesType = false;
for ( IfcSchema::IfcProduct::list::it iter = parentPlaces->begin();
iter != parentPlaces->end(); ++iter) {
if ( (*iter)->declaration().is(*placement_rel_to) ) parentPlacesType = true;
}
if ( parentPlacesType ) break;
else if ( parent->declaration().is(IfcSchema::IfcLocalPlacement::Class()) )
current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo();
else break;
else break;
} else break;
}
CACHE(IfcObjectPlacement,l,trsf)
return true;
}
}
-493
View File
@@ -1,493 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) *
* and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). *
* *
* IfcGeom::Representation::Triangulation is a class that represents a *
* triangulated IfcShapeRepresentation. *
* Triangulation.verts is a 1 dimensional vector of float defining the *
* cartesian coordinates of the vertices of the triangulated shape in the *
* format of [x1,y1,z1,..,xn,yn,zn] *
* Triangulation.faces is a 1 dimensional vector of int containing the *
* indices of the triangles referencing positions in Triangulation.verts *
* Triangulation.edges is a 1 dimensional vector of int in {0,1} that dictates*
* the visibility of the edges that span the faces in Triangulation.faces *
* *
* IfcGeom::Element represents the actual IfcBuildingElements. *
* IfcGeomObject.name is the GUID of the element *
* IfcGeomObject.type is the datatype of the element e.g. IfcWindow *
* IfcGeomObject.mesh is a pointer to an IfcMesh *
* IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the *
* orientation and translation of the mesh in relation to the world origin *
* *
* IfcGeom::Iterator::findContext() *
* finds the most suitable representation contexts. Returns true iff *
* at least a single representation will process successfully *
* *
* IfcGeom::Iterator::get() *
* returns a pointer to the current IfcGeom::Element *
* *
* IfcGeom::Iterator::next() *
* returns true iff a following entity is available for a successive call to *
* IfcGeom::Iterator::get() *
* *
* IfcGeom::Iterator::progress() *
* returns an int in [0..100] that indicates the overall progress *
* *
********************************************************************************/
#ifndef IFCGEOMITERATOR_H
#define IFCGEOMITERATOR_H
#include <map>
#include <set>
#include <vector>
#include <limits>
#include <algorithm>
#include <gp_Mat.hxx>
#include <gp_Mat2d.hxx>
#include <gp_GTrsf.hxx>
#include <gp_GTrsf2d.hxx>
#include <gp_Trsf.hxx>
#include <gp_Trsf2d.hxx>
#include "../ifcparse/IfcFile.h"
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom/IfcGeomElement.h"
#include "../ifcgeom/IfcGeomMaterial.h"
#include "../ifcgeom/IfcGeomIteratorSettings.h"
#include "../ifcgeom/IfcRepresentationShapeItem.h"
namespace IfcGeom {
template <typename P>
class Iterator {
private:
Kernel kernel;
IteratorSettings settings;
IfcParse::IfcFile* ifc_file;
// A container and iterator for IfcRepresentations
IfcSchema::IfcRepresentation::list::ptr representations;
IfcSchema::IfcRepresentation::list::it representation_iterator;
// The object is fetched beforehand to be sure that get() returns a valid element
TriangulationElement<P>* current_triangulation;
BRepElement<P>* current_shape_model;
SerializedElement<P>* current_serialization;
// A container and iterator for IfcBuildingElements for the current IfcRepresentation referenced by *representation_iterator
IfcSchema::IfcProduct::list::ptr ifcproducts;
IfcSchema::IfcProduct::list::it ifcproduct_iterator;
int done;
int total;
std::string unit_name;
// double?
P unit_magnitude;
void initUnits() {
IfcSchema::IfcProject::list::ptr projects = ifc_file->entitiesByType<IfcSchema::IfcProject>();
if (projects->size() == 1) {
IfcSchema::IfcProject* project = *projects->begin();
std::pair<std::string, double> length_unit = kernel.initializeUnits(project->UnitsInContext());
unit_name = length_unit.first;
unit_magnitude = static_cast<P>(length_unit.second);
}
}
std::set<IfcSchema::Type::Enum> entities_to_include_or_exclude;
bool include_entities_in_processing;
void populate_set(const std::set<std::string>& include_or_ignore) {
entities_to_include_or_exclude.clear();
for (std::set<std::string>::const_iterator it = include_or_ignore.begin(); it != include_or_ignore.end(); ++it) {
std::string uppercase_type = *it;
for (std::string::iterator c = uppercase_type.begin(); c != uppercase_type.end(); ++c) {
*c = toupper(*c);
}
IfcSchema::Type::Enum ty;
try {
ty = IfcSchema::Type::FromString(uppercase_type);
} catch (const IfcParse::IfcException&) {
std::stringstream ss;
ss << "'" << *it << "' does not name a valid IFC entity";
throw IfcParse::IfcException(ss.str());
}
entities_to_include_or_exclude.insert(ty);
// TODO: Add child classes so that containment in set can be in O(log n)
}
}
public:
bool findContext() {
try {
initUnits();
} catch (...) {}
// Really this should only be 'Model', as per
// the standard 'Design' is deprecated. So,
// just for backwards compatibility:
std::set<std::string> context_types;
context_types.insert("model");
context_types.insert("design");
// DDS likes to output 'model view'
context_types.insert("model view");
double lowest_precision_encountered = std::numeric_limits<double>::infinity();
bool any_precision_encountered = false;
representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
IfcSchema::IfcGeometricRepresentationContext::list::it it;
IfcSchema::IfcGeometricRepresentationSubContext::list::it jt;
IfcSchema::IfcGeometricRepresentationContext::list::ptr contexts =
ifc_file->entitiesByType<IfcSchema::IfcGeometricRepresentationContext>();
IfcSchema::IfcGeometricRepresentationContext::list::ptr filtered_contexts (new IfcSchema::IfcGeometricRepresentationContext::list);
for (it = contexts->begin(); it != contexts->end(); ++it) {
IfcSchema::IfcGeometricRepresentationContext* context = *it;
if (context->is(IfcSchema::Type::IfcGeometricRepresentationSubContext)) {
// Continue, as the list of subcontexts will be considered
// by the parent's context inverse attributes.
continue;
}
if (context->hasContextType()) {
std::string context_type_lc = context->ContextType();
for (std::string::iterator c = context_type_lc.begin(); c != context_type_lc.end(); ++c) {
*c = tolower(*c);
}
if (context_types.find(context_type_lc) != context_types.end()) {
filtered_contexts->push(context);
}
}
}
if (filtered_contexts->size() == 0) {
filtered_contexts = contexts;
}
for (it = filtered_contexts->begin(); it != filtered_contexts->end(); ++it) {
IfcSchema::IfcGeometricRepresentationContext* context = *it;
representations->push(context->RepresentationsInContext());
if (context->hasPrecision() && context->Precision() < lowest_precision_encountered) {
lowest_precision_encountered = context->Precision();
any_precision_encountered = true;
}
IfcSchema::IfcGeometricRepresentationSubContext::list::ptr sub_contexts = context->HasSubContexts();
for (jt = sub_contexts->begin(); jt != sub_contexts->end(); ++jt) {
representations->push((*jt)->RepresentationsInContext());
}
// There is no need for full recursion as the following is governed by the schema:
// WR31: The parent context shall not be another geometric representation sub context.
}
if (any_precision_encountered) {
// Some arbitrary factor that has proven to work better for the models in the set of test files.
lowest_precision_encountered *= 10.;
lowest_precision_encountered *= unit_magnitude;
if (lowest_precision_encountered < 1.e-7) {
Logger::Message(Logger::LOG_WARNING, "Precision lower than 0.0000001 meter not enforced");
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-7);
} else {
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, lowest_precision_encountered);
}
} else {
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-5);
}
if (representations->size() == 0) return false;
representation_iterator = representations->begin();
ifcproducts.reset();
if (!create()) {
return false;
}
done = 0;
total = representations->size();
return true;
}
int progress() {
return 100 * done / total;
}
const std::string& getUnitName() {
return unit_name;
}
const P getUnitMagnitude() {
return unit_magnitude;
}
const std::string getLog() {
return Logger::GetLog();
}
IfcParse::IfcFile* getFile() {
return ifc_file;
}
void includeEntities(const std::set<std::string>& entities) {
populate_set(entities);
include_entities_in_processing = true;
}
void excludeEntities(const std::set<std::string>& entities) {
populate_set(entities);
include_entities_in_processing = false;
}
private:
// Move to the next IfcRepresentation
void _nextShape() {
ifcproducts.reset();
++ representation_iterator;
++ done;
}
BRepElement<P>* create_shape_model_for_next_entity() {
while ( true ) {
IfcSchema::IfcRepresentation* representation;
// Have we reached the end of our list of representations?
if ( representation_iterator == representations->end() ) {
representations.reset();
return 0;
}
representation = *representation_iterator;
// Has the list of IfcProducts for this representation been initialized?
if (!ifcproducts) {
IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation();
ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list);
IfcSchema::IfcProduct::list::ptr unfiltered_products(new IfcSchema::IfcProduct::list);
for ( IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it ) {
if ( (*it)->is(IfcSchema::Type::IfcProductDefinitionShape) ) {
IfcSchema::IfcProductDefinitionShape* pds = (IfcSchema::IfcProductDefinitionShape*)*it;
unfiltered_products->push(pds->ShapeOfProduct());
} else {
// http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm
// IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards.
// It will be changed into an ABSTRACT supertype in future releases of IFC.
// IfcProductRepresentation also lacks the INVERSE relation to IfcProduct
// Let's find the IfcProducts that reference the IfcProductRepresentation anyway
unfiltered_products->push((*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>());
}
// Filter the products based on the set of entities being included or excluded for
// processing. The set is iterated over te able to filter on subtypes.
for ( IfcSchema::IfcProduct::list::it it = unfiltered_products->begin(); it != unfiltered_products->end(); ++it ) {
bool found = false;
for (std::set<IfcSchema::Type::Enum>::const_iterator jt = entities_to_include_or_exclude.begin(); jt != entities_to_include_or_exclude.end(); ++jt) {
if ((*it)->is(*jt)) {
found = true;
break;
}
}
if (found == include_entities_in_processing) {
ifcproducts->push(*it);
}
}
}
// Does this representation have any IfcProducts?
if (!ifcproducts->size()) {
_nextShape();
continue;
}
ifcproduct_iterator = ifcproducts->begin();
}
// Have we reached the end of our list of IfcProducts?
if ( ifcproduct_iterator == ifcproducts->end() ) {
_nextShape();
continue;
}
IfcSchema::IfcProduct* product = *ifcproduct_iterator;
BRepElement<P>* element = kernel.create_brep_for_representation_and_product<P>(settings, representation, product);
if ( !element ) {
_nextShape();
continue;
}
return element;
}
}
public:
bool next() {
// Free all possible representations of the current geometrical entity
delete current_triangulation;
current_triangulation = 0;
delete current_serialization;
current_serialization = 0;
delete current_shape_model;
current_shape_model = 0;
// Increment the iterator over the list of products using the current
// shape representation
if (ifcproducts) {
++ifcproduct_iterator;
}
return create();
}
Element<P>* get() {
// TODO: Test settings and throw
if (current_triangulation) return current_triangulation;
else if (current_serialization) return current_serialization;
else if (current_shape_model) return current_shape_model;
else return 0;
}
const Element<P>* getObject(int id) {
gp_Trsf trsf;
int parent_id = -1;
std::string instance_type, product_name, product_guid;
try {
const IfcUtil::IfcBaseClass* ifc_entity = ifc_file->entityById(id);
instance_type = IfcSchema::Type::ToString(ifc_entity->type());
if ( ifc_entity->is(IfcSchema::Type::IfcProduct) ) {
IfcSchema::IfcProduct* ifc_product = (IfcSchema::IfcProduct*)ifc_entity;
product_guid = ifc_product->GlobalId();
product_name = ifc_product->hasName() ? ifc_product->Name() : "";
parent_id = -1;
try {
IfcSchema::IfcObjectDefinition* parent_object = kernel.get_decomposing_entity(ifc_product);
if (parent_object) {
parent_id = parent_object->entity->id();
}
} catch (...) {}
try {
kernel.convert(ifc_product->ObjectPlacement(), trsf);
} catch (...) {}
}
} catch(...) {}
ElementSettings element_settings(settings, unit_magnitude, instance_type);
Element<P>* ifc_object = new Element<P>(element_settings, id, parent_id, product_name, instance_type, product_guid, trsf);
return ifc_object;
}
bool create() {
try {
current_shape_model = create_shape_model_for_next_entity();
} catch (...) {}
if (!current_shape_model) return false;
if (settings.use_brep_data()) {
try {
current_serialization = new SerializedElement<P>(*current_shape_model);
} catch (...) {}
return !!current_serialization;
} else if (!settings.disable_triangulation()) {
try {
current_triangulation = new TriangulationElement<P>(*current_shape_model);
} catch (...) {}
return !!current_triangulation;
} else {
return true;
}
}
private:
void initialize() {
current_triangulation = 0;
current_shape_model = 0;
current_serialization = 0;
// Upon initialisation, the (empty) set of entity names,
// should be excluded, or no products would be processed.
include_entities_in_processing = false;
unit_name = "METER";
unit_magnitude = 1.f;
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.sew_shells() ? 1000 : -1);
kernel.setValue(IfcGeom::Kernel::GV_FORCE_CCW_FACE_ORIENTATION, settings.force_ccw_face_orientation() ? 1 : -1);
}
public:
Iterator(const IteratorSettings& settings, IfcParse::IfcFile* file)
: settings(settings)
, ifc_file(file)
{
initialize();
}
Iterator(const IteratorSettings& settings, const std::string& filename)
: settings(settings)
, ifc_file(new IfcParse::IfcFile)
{
ifc_file->Init(filename);
initialize();
}
Iterator(const IteratorSettings& settings, void* data, int length)
: settings(settings)
, ifc_file(new IfcParse::IfcFile)
{
ifc_file->Init(data, length);
initialize();
}
Iterator(const IteratorSettings& settings, std::istream& filestream, int length)
: settings(settings)
, ifc_file(new IfcParse::IfcFile)
{
ifc_file->Init(filestream, length);
initialize();
}
~Iterator() {
// TODO: Correctly implement destructor for IfcFile
delete ifc_file;
delete current_triangulation;
current_triangulation = 0;
delete current_serialization;
current_serialization = 0;
delete current_shape_model;
current_shape_model = 0;
}
};
}
#endif
@@ -0,0 +1,32 @@
#include "IfcGeomIteratorImplementation.h"
#include "../ifcgeom_schema_agnostic/IteratorImplementation.h"
namespace IfcGeom {
template class MAKE_TYPE_NAME(IteratorImplementation_)<float, float>;
template class MAKE_TYPE_NAME(IteratorImplementation_)<float, double>;
template class MAKE_TYPE_NAME(IteratorImplementation_)<double, double>;
}
#define MAKE_INIT_FN__(a, b) init_ ## a ## b
#define MAKE_INIT_FN_(a, b) MAKE_INIT_FN__(a, b)
#define MAKE_INIT_FN(t) MAKE_INIT_FN_(t, IfcSchema)
namespace {
template <typename P, typename PP>
struct factory_t {
IfcGeom::IteratorImplementation<P, PP>* operator()(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file) const {
return new IfcGeom::MAKE_TYPE_NAME(IteratorImplementation_)<P, PP>(settings, file);
}
};
}
template <typename P, typename PP>
void MAKE_INIT_FN(IteratorImplementation_)(IteratorFactoryImplementation<P, PP>* mapping) {
static const std::string schema_name = STRINGIFY(IfcSchema);
factory_t<P, PP> factory;
mapping->bind(schema_name, factory);
}
template void MAKE_INIT_FN(IteratorImplementation_)<float, float>(IteratorFactoryImplementation<float, float>*);
template void MAKE_INIT_FN(IteratorImplementation_)<float, double>(IteratorFactoryImplementation<float, double>*);
template void MAKE_INIT_FN(IteratorImplementation_)<double, double>(IteratorFactoryImplementation<double, double>*);
+758
View File
@@ -0,0 +1,758 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) *
* and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). *
* *
* IfcGeom::Representation::Triangulation is a class that represents a *
* triangulated IfcShapeRepresentation. *
* Triangulation.verts is a 1 dimensional vector of float defining the *
* cartesian coordinates of the vertices of the triangulated shape in the *
* format of [x1,y1,z1,..,xn,yn,zn] *
* Triangulation.faces is a 1 dimensional vector of int containing the *
* indices of the triangles referencing positions in Triangulation.verts *
* Triangulation.edges is a 1 dimensional vector of int in {0,1} that dictates*
* the visibility of the edges that span the faces in Triangulation.faces *
* *
* IfcGeom::Element represents the actual IfcBuildingElements. *
* IfcGeomObject.name is the GUID of the element *
* IfcGeomObject.type is the datatype of the element e.g. IfcWindow *
* IfcGeomObject.mesh is a pointer to an IfcMesh *
* IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the *
* orientation and translation of the mesh in relation to the world origin *
* *
* IfcGeom::Iterator::initialize() *
* finds the most suitable representation contexts. Returns true iff *
* at least a single representation will process successfully *
* *
* IfcGeom::Iterator::get() *
* returns a pointer to the current IfcGeom::Element *
* *
* IfcGeom::Iterator::next() *
* returns true iff a following entity is available for a successive call to *
* IfcGeom::Iterator::get() *
* *
* IfcGeom::Iterator::progress() *
* returns an int in [0..100] that indicates the overall progress *
* *
********************************************************************************/
#ifndef IFCGEOMITERATOR_H
#define IFCGEOMITERATOR_H
#include <map>
#include <set>
#include <vector>
#include <limits>
#include <algorithm>
#include <boost/algorithm/string.hpp>
#include <gp_Mat.hxx>
#include <gp_Mat2d.hxx>
#include <gp_GTrsf.hxx>
#include <gp_GTrsf2d.hxx>
#include <gp_Trsf.hxx>
#include <gp_Trsf2d.hxx>
#include "../ifcparse/IfcFile.h"
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom/IfcGeomElement.h"
#include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h"
#include "../ifcgeom/IfcGeomIteratorSettings.h"
#include "../ifcgeom/IfcRepresentationShapeItem.h"
#include "../ifcgeom/IfcGeomFilter.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
#undef min
#endif
#ifdef max
#undef max
#endif
namespace IfcGeom {
template <typename P, typename PP>
class MAKE_TYPE_NAME(IteratorImplementation_) : public IteratorImplementation<P, PP> {
private:
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;
IteratorSettings settings;
IfcParse::IfcFile* ifc_file;
// A container and iterator for IfcRepresentations
IfcSchema::IfcRepresentation::list::ptr representations;
IfcSchema::IfcRepresentation::list::it representation_iterator;
// The object is fetched beforehand to be sure that get() returns a valid element
TriangulationElement<P, PP>* current_triangulation;
BRepElement<P, PP>* current_shape_model;
SerializedElement<P, PP>* current_serialization;
// A container and iterator for IfcBuildingElements for the current IfcRepresentation referenced by *representation_iterator
IfcSchema::IfcProduct::list::ptr ifcproducts;
IfcSchema::IfcProduct::list::it ifcproduct_iterator;
IfcSchema::IfcRepresentation::list::ptr ok_mapped_representations;
int done;
int total;
std::string unit_name;
double unit_magnitude;
gp_XYZ bounds_min_;
gp_XYZ bounds_max_;
std::vector<filter_t> filters_;
struct filter_match
{
filter_match(IfcSchema::IfcProduct *prod) : product(prod) {}
bool operator()(const filter_t& filter) const { return filter(product); }
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;
}
}
/// @todo public/private sections all over the place: move all public to the beginning of the class
public:
typedef P Precision;
typedef PP PlacementPrecision;
MAKE_TYPE_NAME(IteratorImplementation_)(const IteratorSettings& settings, IfcParse::IfcFile* file, std::vector<IfcGeom::filter_t>& filters)
: settings(settings)
, ifc_file(file)
, owns_ifc_file(false)
, filters_(filters)
{
_initialize();
}
bool initialize() {
try {
initUnits();
} catch (const std::exception& e) {
Logger::Error(e);
}
std::set<std::string> allowed_context_types;
allowed_context_types.insert("model");
allowed_context_types.insert("plan");
allowed_context_types.insert("notdefined");
std::set<std::string> context_types;
if (!settings.get(IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES)) {
// Really this should only be 'Model', as per
// the standard 'Design' is deprecated. So,
// just for backwards compatibility:
context_types.insert("model");
context_types.insert("design");
// Some earlier (?) versions DDS-CAD output their own ContextTypes
context_types.insert("model view");
context_types.insert("detail view");
}
if (settings.get(IteratorSettings::INCLUDE_CURVES)) {
context_types.insert("plan");
}
double lowest_precision_encountered = std::numeric_limits<double>::infinity();
bool any_precision_encountered = false;
representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
ok_mapped_representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
IfcSchema::IfcGeometricRepresentationContext::list::it it;
IfcSchema::IfcGeometricRepresentationSubContext::list::it jt;
IfcSchema::IfcGeometricRepresentationContext::list::ptr contexts =
ifc_file->instances_by_type<IfcSchema::IfcGeometricRepresentationContext>();
IfcSchema::IfcGeometricRepresentationContext::list::ptr filtered_contexts (new IfcSchema::IfcGeometricRepresentationContext::list);
for (it = contexts->begin(); it != contexts->end(); ++it) {
IfcSchema::IfcGeometricRepresentationContext* context = *it;
if (context->declaration().is(IfcSchema::IfcGeometricRepresentationSubContext::Class())) {
// Continue, as the list of subcontexts will be considered
// by the parent's context inverse attributes.
continue;
}
try {
if (context->hasContextType()) {
std::string context_type = context->ContextType();
boost::to_lower(context_type);
if (allowed_context_types.find(context_type) == allowed_context_types.end()) {
Logger::Message(Logger::LOG_ERROR, std::string("ContextType '") + context->ContextType() + "' not allowed:", context);
}
if (context_types.find(context_type) != context_types.end()) {
filtered_contexts->push(context);
}
}
} catch (const std::exception& e) {
Logger::Error(e);
}
}
// In case no contexts are identified based on their ContextType, all contexts are
// considered. Note that sub contexts are excluded as they are considered later on.
if (filtered_contexts->size() == 0) {
for (it = contexts->begin(); it != contexts->end(); ++it) {
IfcSchema::IfcGeometricRepresentationContext* context = *it;
if (!context->declaration().is(IfcSchema::IfcGeometricRepresentationSubContext::Class())) {
filtered_contexts->push(context);
}
}
}
for (it = filtered_contexts->begin(); it != filtered_contexts->end(); ++it) {
IfcSchema::IfcGeometricRepresentationContext* context = *it;
representations->push(context->RepresentationsInContext());
try {
if (context->hasPrecision() && context->Precision() < lowest_precision_encountered) {
lowest_precision_encountered = context->Precision();
any_precision_encountered = true;
}
} catch (const 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());
}
// There is no need for full recursion as the following is governed by the schema:
// WR31: The parent context shall not be another geometric representation sub context.
}
if (any_precision_encountered) {
// Some arbitrary factor that has proven to work better for the models in the set of test files.
lowest_precision_encountered *= 10.;
lowest_precision_encountered *= unit_magnitude;
if (lowest_precision_encountered < 1.e-7) {
Logger::Message(Logger::LOG_WARNING, "Precision lower than 0.0000001 meter not enforced");
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-7);
} else {
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, lowest_precision_encountered);
}
} else {
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-5);
}
if (representations->size() == 0) {
Logger::Message(Logger::LOG_ERROR, "No geometries found");
return false;
}
representation_iterator = representations->begin();
ifcproducts.reset();
if (!create()) {
return false;
}
done = 0;
total = representations->size();
for (int i = 1; i < 4; ++i) {
bounds_min_.SetCoord(i, std::numeric_limits<double>::infinity());
bounds_max_.SetCoord(i, -std::numeric_limits<double>::infinity());
}
IfcSchema::IfcProduct::list::ptr products = ifc_file->instances_by_type<IfcSchema::IfcProduct>();
for (IfcSchema::IfcProduct::list::it iter = products->begin(); iter != products->end(); ++iter) {
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;
bool success = false;
try {
success = kernel.convert(product->ObjectPlacement(), trsf);
} catch (const std::exception& e) {
Logger::Error(e);
} catch (...) {
Logger::Error("Failed to construct placement");
}
if (!success) {
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()));
}
}
return true;
}
int progress() const { return 100 * done / total; }
const std::string& getUnitName() const { return unit_name; }
/// @note Double always as per IFC specification.
double getUnitMagnitude() const { return unit_magnitude; }
std::string getLog() const { return Logger::GetLog(); }
IfcParse::IfcFile* file() const { return ifc_file; }
const std::vector<IfcGeom::filter_t>& filters() const { return filters_; }
std::vector<IfcGeom::filter_t>& filters() { return filters_; }
const gp_XYZ& bounds_min() const { return bounds_min_; }
const gp_XYZ& bounds_max() const { return bounds_max_; }
private:
// Move to the next IfcRepresentation
void _nextShape() {
// In order to conserve memory and reduce cache insertion times, the cache is
// cleared after an arbitary 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;
}
bool geometry_reuse_ok_for_current_representation_;
bool reuse_ok_(const IfcSchema::IfcProduct::list::ptr& products) {
// With world coords enabled, object transformations are directly applied to
// the BRep. There is no way to re-use the geometry for multiple products.
if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
return false;
}
std::set<const IfcSchema::IfcMaterial*> associated_single_materials;
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()) {
return false;
}
if (settings.get(IteratorSettings::APPLY_LAYERSETS)) {
IfcSchema::IfcRelAssociates::list::ptr associations = product->HasAssociations();
for (IfcSchema::IfcRelAssociates::list::it jt = associations->begin(); jt != associations->end(); ++jt) {
IfcSchema::IfcRelAssociatesMaterial* assoc = (*jt)->as<IfcSchema::IfcRelAssociatesMaterial>();
if (assoc) {
if (assoc->RelatingMaterial()->declaration().is(IfcSchema::IfcMaterialLayerSetUsage::Class())) {
// TODO: Check whether single layer?
return false;
}
}
}
}
// 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));
if (associated_single_materials.size() > 1) return false;
}
return associated_single_materials.size() == 1;
}
BRepElement<P, PP>* create_shape_model_for_next_entity() {
for (;;) {
IfcSchema::IfcRepresentation* representation;
// Have we reached the end of our list of representations?
if ( representation_iterator == representations->end() ) {
representations.reset();
return 0;
}
representation = *representation_iterator;
// Has the list of IfcProducts for this representation been initialized?
if (!ifcproducts) {
ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list);
IfcSchema::IfcProduct::list::ptr unfiltered_products = kernel.products_represented_by(representation);
geometry_reuse_ok_for_current_representation_ = reuse_ok_(unfiltered_products);
IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap();
if (!geometry_reuse_ok_for_current_representation_ && maps->size() == 1) {
// unfiltered_products contains products represented by this representation by means of mapped items.
// For example because of openings applied to products, reuse might not be acceptable and then the
// products will be processed by means of their immediate representation and not the mapped representation.
// IfcRepresentationMaps are also used for IfcTypeProducts, so an additional check is performed whether the map
// is indeed used by IfcMappedItems.
IfcSchema::IfcRepresentationMap* map = *maps->begin();
if (map->MapUsage()->size() > 0) {
_nextShape();
continue;
}
}
bool representation_processed_as_mapped_item = false;
IfcSchema::IfcRepresentation* representation_mapped_to = kernel.representation_mapped_to(representation);
if (representation_mapped_to) {
// Check if this represenation has (or will be) processed as part its mapped representation
representation_processed_as_mapped_item = ok_mapped_representations->contains(representation_mapped_to) ||
reuse_ok_(kernel.products_represented_by(representation_mapped_to));
}
if (representation_processed_as_mapped_item) {
ok_mapped_representations->push(representation_mapped_to);
_nextShape();
continue;
}
// Filter the products based on the set of entities and/or names being included or excluded 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);
}
}
ifcproduct_iterator = ifcproducts->begin();
}
// Have we reached the end of our list of IfcProducts?
if ( ifcproduct_iterator == ifcproducts->end() ) {
_nextShape();
continue;
}
IfcSchema::IfcProduct* product = *ifcproduct_iterator;
Logger::SetProduct(product);
BRepElement<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);
} else {
element = kernel.create_brep_for_processed_representation(settings, representation, product, current_shape_model);
}
Logger::SetProduct(boost::none);
if (!element) {
_nextShape();
continue;
}
return element;
}
}
void free_shapes() {
// Free all possible representations of the current geometrical entity
delete current_triangulation;
current_triangulation = 0;
delete current_serialization;
current_serialization = 0;
delete current_shape_model;
current_shape_model = 0;
}
public:
/// Returns what would be the product for the next shape representation
/// @todo Double-check and test the impl.
//IfcSchema::IfcProduct* peek_next() const
//{
// if (ifcproducts && ifcproduct_iterator + 1 != ifcproducts->end()){
// return *(ifcproduct_iterator + 1);
// } else {
// return 0;
// }
//}
/// @todo Would this be as simple as the following code?
//void skip_next() { if (ifcproducts) { ++ifcproduct_iterator; } }
/// Moves to the next shape representation, create its geometry, and returns the associated product.
/// Use get() to retrieve the created geometry.
IfcUtil::IfcBaseClass* next() {
// Increment the iterator over the list of products using the current
// shape representation
if (ifcproducts) {
++ifcproduct_iterator;
}
return create();
}
/// Gets the representation of the current geometrical entity.
Element<P, PP>* get()
{
// TODO: Test settings and throw
Element<P, PP>* ret = 0;
if (current_triangulation) { ret = current_triangulation; }
else if (current_serialization) { ret = current_serialization; }
else if (current_shape_model) { ret = current_shape_model; }
// If we want to organize the element considering their hierarchy
if (settings.get(IteratorSettings::SEARCH_FLOOR))
{
// We are going to build a vector with the element parents.
// First, create the parent vector
std::vector<const IfcGeom::Element<P, PP>*> parents;
// if the element has a parent
if (ret->parent_id() != -1)
{
const IfcGeom::Element<P, PP>* parent_object = NULL;
bool hasParent = true;
// get the parent
try {
parent_object = get_object(ret->parent_id());
} catch (const std::exception& e) {
Logger::Error(e);
hasParent = false;
}
// Add the previously found parent to the vector
if (hasParent) parents.insert(parents.begin(), parent_object);
// We need to find all the parents
while (parent_object != NULL && hasParent && parent_object->parent_id() != -1)
{
// Find the next parent
try {
parent_object = get_object(parent_object->parent_id());
} catch (const std::exception& e) {
Logger::Error(e);
hasParent = false;
}
// Add the previously found parent to the vector
if (hasParent) parents.insert(parents.begin(), parent_object);
hasParent = hasParent && parent_object->parent_id() != -1;
}
// when done push the parent list in the Element object
ret->SetParents(parents);
}
}
return ret;
}
/// Gets the native (Open Cascade) representation of the current geometrical entity.
BRepElement<P, PP>* get_native()
{
// TODO: Test settings and throw
return current_shape_model;
}
const Element<P, PP>* get_object(int id) {
gp_Trsf trsf;
int parent_id = -1;
std::string instance_type, product_name, product_guid;
IfcSchema::IfcProduct* ifc_product = 0;
try {
IfcUtil::IfcBaseClass* ifc_entity = ifc_file->instance_by_id(id);
instance_type = ifc_entity->declaration().name();
if (ifc_entity->declaration().is(IfcSchema::IfcRoot::Class())) {
IfcSchema::IfcRoot* ifc_root = ifc_entity->as<IfcSchema::IfcRoot>();
product_guid = ifc_root->GlobalId();
product_name = ifc_root->hasName() ? ifc_root->Name() : "";
}
if (ifc_entity->declaration().is(IfcSchema::IfcProduct::Class())) {
ifc_product = ifc_entity->as<IfcSchema::IfcProduct>();
parent_id = -1;
try {
IfcSchema::IfcObjectDefinition* parent_object = kernel.get_decomposing_entity(ifc_product);
if (parent_object) {
parent_id = parent_object->data().id();
}
} catch (const std::exception& e) {
Logger::Error(e);
} catch (...) {
Logger::Error("Failed to find decomposing entity");
}
try {
kernel.convert(ifc_product->ObjectPlacement(), trsf);
} catch (const std::exception& e) {
Logger::Error(e);
} catch (...) {
Logger::Error("Failed to construct placement");
}
}
} catch (const std::exception& e) {
Logger::Error(e);
} catch (const Standard_Failure& e) {
if (e.GetMessageString() && strlen(e.GetMessageString())) {
Logger::Error(e.GetMessageString());
} else {
Logger::Error("Unknown error returning product");
}
} catch (...) {
Logger::Error("Unknown error returning product");
}
ElementSettings element_settings(settings, unit_magnitude, instance_type);
Element<P, PP>* ifc_object = new Element<P, PP>(element_settings, id, parent_id, product_name, instance_type, product_guid, "", trsf, ifc_product);
return ifc_object;
}
IfcUtil::IfcBaseClass* create() {
IfcGeom::BRepElement<P, PP>* next_shape_model = 0;
IfcGeom::SerializedElement<P, PP>* next_serialization = 0;
IfcGeom::TriangulationElement<P, PP>* next_triangulation = 0;
try {
next_shape_model = create_shape_model_for_next_entity();
} catch (const std::exception& e) {
Logger::Error(e);
} catch (const Standard_Failure& e) {
if (e.GetMessageString() && strlen(e.GetMessageString())) {
Logger::Error(e.GetMessageString());
} else {
Logger::Error("Unknown error creating geometry");
}
} catch (...) {
Logger::Error("Unknown error creating geometry");
}
if (next_shape_model) {
if (settings.get(IteratorSettings::USE_BREP_DATA)) {
try {
next_serialization = new SerializedElement<P, PP>(*next_shape_model);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Getting a serialized element from model failed.");
}
} else if (!settings.get(IteratorSettings::DISABLE_TRIANGULATION)) {
try {
if (ifcproduct_iterator == ifcproducts->begin() || !geometry_reuse_ok_for_current_representation_) {
next_triangulation = new TriangulationElement<P, PP>(*next_shape_model);
} else {
next_triangulation = new TriangulationElement<P, PP>(*next_shape_model, current_triangulation->geometry_pointer());
}
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed.");
}
}
}
free_shapes();
current_shape_model = next_shape_model;
current_serialization = next_serialization;
current_triangulation = next_triangulation;
return next_shape_model ? next_shape_model->product() : 0;
}
private:
void _initialize() {
current_triangulation = 0;
current_shape_model = 0;
current_serialization = 0;
unit_name = "METER";
unit_magnitude = 1.f;
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.get(IteratorSettings::SEW_SHELLS) ? 1000 : -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());
} else if (settings.get(IteratorSettings::SITE_LOCAL_PLACEMENT)) {
kernel.set_conversion_placement_rel_to(&IfcSchema::IfcSite::Class());
}
}
bool owns_ifc_file;
public:
MAKE_TYPE_NAME(IteratorImplementation_)(const IteratorSettings& settings, IfcParse::IfcFile* file)
: settings(settings)
, ifc_file(file)
, owns_ifc_file(false)
{
_initialize();
}
MAKE_TYPE_NAME(IteratorImplementation_)(const IteratorSettings& settings, const std::string& filename)
: settings(settings)
, ifc_file(new IfcParse::IfcFile(filename))
, owns_ifc_file(true)
{
_initialize();
}
MAKE_TYPE_NAME(IteratorImplementation_)(const IteratorSettings& settings, void* data, int length)
: settings(settings)
, ifc_file(new IfcParse::IfcFile(data, length))
, owns_ifc_file(true)
{
_initialize();
}
MAKE_TYPE_NAME(IteratorImplementation_)(const IteratorSettings& settings, std::istream& filestream, int length)
: settings(settings)
, ifc_file(new IfcParse::IfcFile(filestream, length))
, owns_ifc_file(true)
{
_initialize();
}
~MAKE_TYPE_NAME(IteratorImplementation_)() {
if (owns_ifc_file) {
delete ifc_file;
}
free_shapes();
}
};
}
#endif
+124 -139
View File
@@ -20,153 +20,138 @@
#ifndef IFCGEOMITERATORSETTINGS_H
#define IFCGEOMITERATORSETTINGS_H
#include <string>
#include "ifc_geom_api.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcBaseClass.h"
namespace IfcGeom {
namespace IfcGeom
{
class IFC_GEOM_API IteratorSettings
{
public:
/// Enumeration of setting identifiers. These settings define the
/// behaviour of various aspects of IfcOpenShell.
enum Setting
{
/// Specifies whether vertices are welded, meaning that the coordinates
/// vector will only contain unique xyz-triplets. This results in a
/// manifold mesh which is useful for modelling applications, but might
/// result in unwanted shading artifacts in rendering applications.
WELD_VERTICES = 1,
/// Specifies whether to apply the local placements of building elements
/// directly to the coordinates of the representation mesh rather than
/// to represent the local placement in the 4x3 matrix, which will in that
/// case be the identity matrix.
USE_WORLD_COORDS = 1 << 1,
/// Internally IfcOpenShell measures everything in meters. This settings
/// specifies whether to convert IfcGeomObjects back to the units in which
/// the geometry in the IFC file is specified.
CONVERT_BACK_UNITS = 1 << 2,
/// Specifies whether to use the Open Cascade BREP format for representation
/// items rather than to create triangle meshes. This is useful is IfcOpenShell
/// is used as a library in an application that is also built on Open Cascade.
USE_BREP_DATA = 1 << 3,
/// Specifies whether to sew IfcConnectedFaceSets (open and closed shells) to
/// TopoDS_Shells or whether to keep them as a loose collection of faces.
SEW_SHELLS = 1 << 4,
/// Specifies whether to compose IfcOpeningElements into a single compound
/// in order to speed up the processing of opening subtractions.
FASTER_BOOLEANS = 1 << 5,
/// Disables the subtraction of IfcOpeningElement representations from
/// the related building element representations.
DISABLE_OPENING_SUBTRACTIONS = 1 << 6,
/// Disables the triangulation of the topological representations. Useful if
/// the client application understands Open Cascade's native format.
DISABLE_TRIANGULATION = 1 << 7,
/// Applies default materials to entity instances without a surface style.
APPLY_DEFAULT_MATERIALS = 1 << 8,
/// Specifies whether to include subtypes of IfcCurve.
INCLUDE_CURVES = 1 << 9,
/// Specifies whether to exclude subtypes of IfcSolidModel and IfcSurface.
EXCLUDE_SOLIDS_AND_SURFACES = 1 << 10,
/// Disables computation of normals. Saves time and file size and is useful
/// in instances where you're going to recompute normals for the exported
/// model in other modelling application in any case.
NO_NORMALS = 1 << 11,
/// Generates UVs by using simple box projection. Requires normals.
/// Applicable for OBJ and DAE output.
GENERATE_UVS = 1 << 12,
/// Specifies whether to slice representations according to associated IfcLayerSets.
APPLY_LAYERSETS = 1 << 13,
/// Search for a parent of type IfcBuildingStorey for each representation
SEARCH_FLOOR = 1 << 14,
///
SITE_LOCAL_PLACEMENT = 1 << 15,
///
BUILDING_LOCAL_PLACEMENT = 1 << 16,
/// Number of different setting flags.
NUM_SETTINGS = 16
};
/// Used to store logical OR combination of setting flags.
typedef unsigned SettingField;
class IteratorSettings {
public:
// Enumeration of setting identifiers. These settings define the
// behaviour of various aspects of IfcOpenShell.
IteratorSettings()
: settings_(WELD_VERTICES) // OR options that default to true here
, deflection_tolerance_(1.e-3)
{
}
// Specifies whether vertices are welded, meaning that the coordinates
// vector will only contain unique xyz-triplets. This results in a
// manifold mesh which is useful for modelling applications, but might
// result in unwanted shading artifacts in rendering applications.
static const int WELD_VERTICES = 1;
// Specifies whether to apply the local placements of building elements
// directly to the coordinates of the representation mesh rather than
// to represent the local placement in the 4x3 matrix, which will in that
// case be the identity matrix.
static const int USE_WORLD_COORDS = 2;
// Internally IfcOpenShell measures everything in meters. This settings
// specifies whether to convert IfcGeomObjects back to the units in which
// the geometry in the IFC file is specified.
static const int CONVERT_BACK_UNITS = 3;
// Specifies whether to use the Open Cascade BREP format for representation
// items rather than to create triangle meshes. This is useful is IfcOpenShell
// is used as a library in an application that is also built on Open Cascade.
static const int USE_BREP_DATA = 4;
// Specifies whether to sew IfcConnectedFaceSets (open and closed shells) to
// TopoDS_Shells or whether to keep them as a loose collection of faces.
static const int SEW_SHELLS = 5;
// Specifies whether to compose IfcOpeningElements into a single compound
// in order to speed up the processing of opening subtractions.
static const int FASTER_BOOLEANS = 6;
// By default singular faces have no explicitly defined orientation, to
// force faces to be defined CounterClockWise set this to true.
static const int FORCE_CCW_FACE_ORIENTATION = 7;
// Disables the subtraction of IfcOpeningElement representations from
// the related building element representations.
static const int DISABLE_OPENING_SUBTRACTIONS = 8;
// Disables the triangulation of the topological representations. Useful if
// the client application understands Open Cascade's native format.
static const int DISABLE_TRIANGULATION = 9;
// Applies default materials to entity instances without a surface style.
static const int APPLY_DEFAULT_MATERIALS = 10;
/// Note that this is independent of the IFC length unit, one millimeter by default.
double deflection_tolerance() const { return deflection_tolerance_; }
// End of settings enumeration.
void set_deflection_tolerance(double value)
{
/// @todo Using deflection tolerance of 1e-6 or smaller hangs the conversion, research more in-depth.
/// This bug can be reproduced e.g. with the Duplex model that can be found from http://www.nibs.org/?page=bsa_commonbimfiles#project1
deflection_tolerance_ = value;
if (deflection_tolerance_ <= 1e-6) {
Logger::Message(Logger::LOG_WARNING, "Deflection tolerance cannot be set to <= 1e-6; using the default value 1e-3");
deflection_tolerance_ = 1e-3;
}
}
private:
bool _weld_vertices, _use_world_coords, _convert_back_units, _use_brep_data, _sew_shells, _faster_booleans, _force_ccw_face_orientation, _disable_opening_subtractions, _disable_triangulation, _apply_default_materials;
double _deflection_tolerance;
public:
IteratorSettings()
: _weld_vertices(true)
, _use_world_coords(false)
, _convert_back_units(false)
, _use_brep_data(false)
, _sew_shells(false)
, _faster_booleans(false)
, _force_ccw_face_orientation(false)
, _disable_opening_subtractions(false)
, _disable_triangulation(false)
, _apply_default_materials(false)
// TODO: Make deflection tolerance into a command line argument
// For now, stick to one millimeter. Note that this is independent of the IFC length unit.
, _deflection_tolerance(1.e-3)
{}
/// Get boolean value for a single settings or for a combination of settings.
bool get(SettingField setting) const
{
/// @todo If unknown setting value/combination: throw IfcParse::IfcException("Invalid IteratorSetting")?
return (settings_ & setting) != 0;
}
const bool& weld_vertices() const { return _weld_vertices; }
bool& weld_vertices() { return _weld_vertices; }
const bool& use_world_coords() const { return _use_world_coords; }
bool& use_world_coords() { return _use_world_coords; }
const bool& convert_back_units() const { return _convert_back_units; }
bool& convert_back_units() { return _convert_back_units; }
const bool& use_brep_data() const { return _use_brep_data; }
bool& use_brep_data() { return _use_brep_data; }
const bool& sew_shells() const { return _sew_shells; }
bool& sew_shells() { return _sew_shells; }
const bool& faster_booleans() const { return _faster_booleans; }
bool& faster_booleans() { return _faster_booleans; }
const bool& force_ccw_face_orientation() const { return _force_ccw_face_orientation; }
bool& force_ccw_face_orientation() { return _force_ccw_face_orientation; }
const bool& disable_opening_subtractions() const { return _disable_opening_subtractions; }
bool& disable_opening_subtractions() { return _disable_opening_subtractions; }
const bool& disable_triangulation() const { return _disable_triangulation; }
bool& disable_triangulation() { return _disable_triangulation; }
const bool& apply_default_materials() const { return _apply_default_materials; }
bool& apply_default_materials() { return _apply_default_materials; }
const double& deflection_tolerance() const { return _deflection_tolerance; }
double& deflection_tolerance() { return _deflection_tolerance; }
void set(int setting, bool value) {
switch (setting) {
case USE_WORLD_COORDS:
_use_world_coords = value;
break;
case WELD_VERTICES:
_weld_vertices = value;
break;
case CONVERT_BACK_UNITS:
_convert_back_units = value;
break;
case USE_BREP_DATA:
_use_brep_data = value;
break;
case FASTER_BOOLEANS:
_faster_booleans = value;
break;
case SEW_SHELLS:
_sew_shells = value;
break;
case FORCE_CCW_FACE_ORIENTATION:
_force_ccw_face_orientation = value;
break;
case DISABLE_OPENING_SUBTRACTIONS:
_disable_opening_subtractions = value;
break;
case DISABLE_TRIANGULATION:
_disable_triangulation = value;
break;
case APPLY_DEFAULT_MATERIALS:
_apply_default_materials = value;
break;
default: throw IfcParse::IfcException("Invalid IteratorSetting");
}
}
};
class ElementSettings : public IteratorSettings {
private:
double _unit_magnitude;
std::string _element_type;
public:
ElementSettings(const IteratorSettings& settings,
double unit_magnitude,
const std::string& element_type)
: IteratorSettings(settings)
, _unit_magnitude(unit_magnitude)
, _element_type(element_type)
{}
/// Set boolean value for a single settings or for a combination of settings.
void set(SettingField setting, bool value)
{
/// @todo If unknown setting value/combination: throw IfcParse::IfcException("Invalid IteratorSetting")?
if (value) {
settings_ |= setting;
} else {
settings_ &= ~setting;
}
}
const double& unit_magnitude() const { return _unit_magnitude; }
const std::string& element_type() const { return _element_type; }
};
protected:
SettingField settings_;
double deflection_tolerance_;
};
class IFC_GEOM_API ElementSettings : public IteratorSettings
{
public:
ElementSettings(const IteratorSettings& settings,
double unit_magnitude,
const std::string& element_type)
: IteratorSettings(settings)
, unit_magnitude_(unit_magnitude)
, element_type_(element_type)
{
}
double unit_magnitude() const { return unit_magnitude_; }
const std::string& element_type() const { return element_type_; }
private:
double unit_magnitude_;
std::string element_type_;
};
}
#endif
#endif
+64 -87
View File
@@ -21,56 +21,65 @@
#include "IfcGeom.h"
bool process_colour(IfcSchema::IfcColourRgb* colour, std::tr1::array<double, 3>& rgb) {
if (colour != 0) {
rgb[0] = colour->Red();
rgb[1] = colour->Green();
rgb[2] = colour->Blue();
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;
}
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;
}
}
}
bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, std::tr1::array<double, 3>& rgb) {
if (factor != 0) {
const double f = *factor;
rgb[0] = rgb[1] = rgb[2] = f;
}
return factor != 0;
}
#define Kernel MAKE_TYPE_NAME(Kernel)
bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, std::tr1::array<double, 3>& rgb) {
if (colour_or_factor == 0) {
return false;
} else if (colour_or_factor->is(IfcSchema::Type::IfcColourRgb)) {
return process_colour(static_cast<IfcSchema::IfcColourRgb*>(colour_or_factor), rgb);
} else if (colour_or_factor->is(IfcSchema::Type::IfcNormalisedRatioMeasure)) {
return process_colour(static_cast<IfcSchema::IfcNormalisedRatioMeasure*>(colour_or_factor), rgb);
} else {
return false;
}
}
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepresentationItem* item) {
std::pair<IfcSchema::IfcSurfaceStyle*, IfcSchema::IfcSurfaceStyleShading*> shading_styles = get_surface_style<IfcSchema::IfcSurfaceStyleShading>(item);
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->entity->id();
std::map<int,SurfaceStyle>::const_iterator it = cache.Style.find(surface_style_id);
if (it != cache.Style.end()) {
int surface_style_id = shading_styles.first->data().id();
std::map<int,SurfaceStyle>::const_iterator it = style_cache.find(surface_style_id);
if (it != style_cache.end()) {
return &(it->second);
}
SurfaceStyle surface_style;
if (shading_styles.first->hasName()) {
surface_style = SurfaceStyle(surface_style_id, shading_styles.first->Name());
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);
}
std::tr1::array<double, 3> rgb;
if (process_colour(shading_styles.second->SurfaceColour(), rgb)) {
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->is(IfcSchema::Type::IfcSurfaceStyleRendering)) {
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));
@@ -87,12 +96,12 @@ const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepr
}
if (rendering_style->hasSpecularHighlight()) {
IfcSchema::IfcSpecularHighlightSelect* highlight = rendering_style->SpecularHighlight();
if (highlight->is(IfcSchema::Type::IfcSpecularRoughness)) {
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->is(IfcSchema::Type::IfcSpecularExponent)) {
} else if (highlight->declaration().is(IfcSchema::IfcSpecularExponent::Class())) {
surface_style.Specularity().reset(*((IfcSchema::IfcSpecularExponent*)highlight));
}
}
@@ -104,59 +113,27 @@ const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepr
surface_style.Transparency().reset(d);
}
}
return &(cache.Style[surface_style_id] = surface_style);
return &(style_cache[surface_style_id] = surface_style);
}
static std::map<std::string, IfcGeom::SurfaceStyle> default_materials;
static IfcGeom::SurfaceStyle default_material;
static bool default_materials_initialized = false;
void InitDefaultMaterials() {
default_materials.insert(std::make_pair("IfcSite", IfcGeom::SurfaceStyle("IfcSite")));
default_materials["IfcSite" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.8, 0.65));
default_materials.insert(std::make_pair("IfcSlab", IfcGeom::SurfaceStyle("IfcSlab")));
default_materials["IfcSlab" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.4 , 0.4, 0.4 ));
default_materials.insert(std::make_pair("IfcWallStandardCase", IfcGeom::SurfaceStyle("IfcWallStandardCase")));
default_materials["IfcWallStandardCase"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.9 , 0.9, 0.9 ));
default_materials.insert(std::make_pair("IfcWall", IfcGeom::SurfaceStyle("IfcWall")));
default_materials["IfcWall" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.9 , 0.9, 0.9 ));
default_materials.insert(std::make_pair("IfcWindow", IfcGeom::SurfaceStyle("IfcWindow")));
default_materials["IfcWindow" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.8, 0.75));
default_materials["IfcWindow" ].Transparency().reset(0.3);
default_materials.insert(std::make_pair("IfcDoor", IfcGeom::SurfaceStyle("IfcDoor")));
default_materials["IfcDoor" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.55, 0.3, 0.15));
default_materials.insert(std::make_pair("IfcBeam", IfcGeom::SurfaceStyle("IfcBeam")));
default_materials["IfcBeam" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.7, 0.7 ));
default_materials.insert(std::make_pair("IfcRailing", IfcGeom::SurfaceStyle("IfcRailing")));
default_materials["IfcRailing" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.65, 0.6, 0.6 ));
default_materials.insert(std::make_pair("IfcMember", IfcGeom::SurfaceStyle("IfcMember")));
default_materials["IfcMember" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.65, 0.6, 0.6 ));
default_materials.insert(std::make_pair("IfcPlate", IfcGeom::SurfaceStyle("IfcPlate")));
default_materials["IfcPlate" ].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.8 , 0.8, 0.8 ));
default_material = IfcGeom::SurfaceStyle("DefaultMaterial");
default_material.Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.7, 0.7, 0.7));
default_materials_initialized = true;
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepresentationItem* item) {
return internalize_surface_style(get_surface_style<IfcSchema::IfcSurfaceStyleShading>(item));
}
const IfcGeom::SurfaceStyle* IfcGeom::get_default_style(const std::string& s) {
if (!default_materials_initialized) InitDefaultMaterials();
std::map<std::string, IfcGeom::SurfaceStyle>::const_iterator it = default_materials.find(s);
if (it == default_materials.end()) {
default_materials.insert(std::make_pair(s, IfcGeom::SurfaceStyle(s)));
default_materials[s].Diffuse().reset(*default_material.Diffuse());
it = default_materials.find(s);
const IfcGeom::SurfaceStyle* 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);
}
}
}
const IfcGeom::SurfaceStyle& surface_style = it->second;
return &surface_style;
return 0;
}
+57 -16
View File
@@ -22,7 +22,6 @@
#include <BRep_Builder.hxx>
#include <TopoDS_Compound.hxx>
#include <BRepBuilderAPI_GTransform.hxx>
#include "../ifcgeom/IfcGeom.h"
@@ -30,30 +29,72 @@
IfcGeom::Representation::Serialization::Serialization(const BRep& brep)
: Representation(brep.settings())
, _id(brep.getId())
, id_(brep.id())
{
TopoDS_Compound compound = brep.as_compound();
for (IfcGeom::IfcRepresentationShapeItems::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());
surface_styles_.push_back(clr.G());
surface_styles_.push_back(clr.B());
} else {
surface_styles_.push_back(-1.);
surface_styles_.push_back(-1.);
surface_styles_.push_back(-1.);
}
if (it->hasStyle() && it->Style().Transparency()) {
surface_styles_.push_back(1. - *it->Style().Transparency());
} else {
surface_styles_.push_back(1.);
}
}
std::stringstream sstream;
BRepTools::Write(compound,sstream);
brep_data_ = sstream.str();
}
// todo copied from kernel
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepBuilderAPI_GTransform.hxx>
TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const gp_Trsf& t) {
if (t.Form() == gp_Identity) {
return s;
} else {
/// @todo set to 1. and exactly 1. or use epsilon?
if (t.ScaleFactor() != 1.) {
return BRepBuilderAPI_Transform(s, t, true);
} else {
return s.Moved(t);
}
}
}
TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const gp_GTrsf& t) {
if (t.Form() == gp_Other) {
return BRepBuilderAPI_GTransform(s, t, true);
} else {
return apply_transformation(s, t.Trsf());
}
}
TopoDS_Compound IfcGeom::Representation::BRep::as_compound() const {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++ it) {
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) {
const TopoDS_Shape& s = it->Shape();
gp_GTrsf trsf = it->Placement();
if (settings().convert_back_units()) {
if (settings().get(IteratorSettings::CONVERT_BACK_UNITS)) {
gp_Trsf scale;
scale.SetScaleFactor(1.0 / settings().unit_magnitude());
trsf.PreMultiply(scale);
}
bool trsf_valid = false;
gp_Trsf _trsf;
try {
_trsf = trsf.Trsf();
trsf_valid = true;
} catch (...) {}
const TopoDS_Shape moved_shape = trsf_valid ? s.Moved(_trsf) :
BRepBuilderAPI_GTransform(s,trsf,true).Shape();
builder.Add(compound,moved_shape);
const TopoDS_Shape moved_shape = apply_transformation(s, trsf);
builder.Add(compound, moved_shape);
}
std::stringstream sstream;
BRepTools::Write(compound,sstream);
_brep_data = sstream.str();
return compound;
}
+195 -56
View File
@@ -27,54 +27,68 @@
#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/IfcGeomMaterial.h"
#include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h"
#include "../ifcgeom/IfcRepresentationShapeItem.h"
#include <TopoDS_Compound.hxx>
namespace IfcGeom {
namespace Representation {
class Representation {
class IFC_GEOM_API Representation {
Representation(const Representation&); //N/A
Representation& operator =(const Representation&); //N/A
protected:
const ElementSettings _settings;
const ElementSettings settings_;
public:
explicit Representation(const ElementSettings& settings)
: _settings(settings)
: settings_(settings)
{}
const ElementSettings& settings() const { return _settings; }
const ElementSettings& settings() const { return settings_; }
virtual ~Representation() {}
};
class BRep : public Representation {
class IFC_GEOM_API BRep : public Representation {
private:
unsigned int id;
const IfcGeom::IfcRepresentationShapeItems shapes;
std::string id_;
const IfcGeom::IfcRepresentationShapeItems shapes_;
BRep(const BRep& other);
BRep& operator=(const BRep& other);
public:
BRep(const ElementSettings& settings, unsigned int id, const IfcGeom::IfcRepresentationShapeItems& shapes)
BRep(const ElementSettings& settings, const std::string& id, const IfcGeom::IfcRepresentationShapeItems& shapes)
: Representation(settings)
, id(id)
, shapes(shapes)
, id_(id)
, shapes_(shapes)
{}
virtual ~BRep() {}
IfcGeom::IfcRepresentationShapeItems::const_iterator begin() const { return shapes.begin(); }
IfcGeom::IfcRepresentationShapeItems::const_iterator end() const { return shapes.end(); }
const unsigned int& getId() const { return id; }
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() const;
};
class Serialization : public Representation {
class IFC_GEOM_API Serialization : public Representation {
private:
int _id;
std::string _brep_data;
std::string id_;
std::string brep_data_;
std::vector<double> surface_styles_;
public:
int id() const { return _id; }
const std::string& brep_data() const { return _brep_data; }
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&);
@@ -91,69 +105,70 @@ namespace IfcGeom {
typedef std::map<VertexKey, int> VertexKeyMap;
typedef std::pair<int, int> Edge;
int _id;
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:
int id() const { return _id; }
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.getId())
, id_(shape_model.id())
{
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it = shape_model.begin(); it != shape_model.end(); ++ it ) {
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++ iit ) {
int surface_style_id = -1;
if (it->hasStyle()) {
Material adapter(&it->Style());
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 = _materials.size();
surface_style_id = (int)_materials.size();
_materials.push_back(adapter);
} else {
surface_style_id = jt - _materials.begin();
surface_style_id = (int)(jt - _materials.begin());
}
}
if (settings().apply_default_materials() && surface_style_id == -1) {
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 it = std::find(_materials.begin(), _materials.end(), material);
if (it == _materials.end()) {
surface_style_id = _materials.size();
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 = it - _materials.begin();
surface_style_id = (int)(mit - _materials.begin());
}
}
const TopoDS_Shape& s = it->Shape();
const gp_GTrsf& trsf = it->Placement();
const TopoDS_Shape& s = iit->Shape();
const gp_GTrsf& trsf = iit->Placement();
// Triangulate the shape
try {
BRepMesh_IncrementalMesh(s, settings().deflection_tolerance());
} catch(...) {
// TODO: Catch outside
// Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape:",ifc_file->entityById(_id)->entity);
Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape");
Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape");
continue;
}
TopExp_Explorer exp;
// Iterates over the faces of the shape
for ( exp.Init(s,TopAbs_FACE); exp.More(); exp.Next() ) {
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);
@@ -174,8 +189,9 @@ namespace IfcGeom {
BRepGProp_Face prop(face);
std::map<int,int> dict;
// Vertex normals are only calculated if vertices are not welded
const bool calculate_normals = !settings().weld_vertices();
// 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());
@@ -188,12 +204,24 @@ namespace IfcGeom {
gp_Vec normal_direction;
prop.Normal(uv.X(),uv.Y(),p,normal_direction);
gp_Vec normal(0., 0., 0.);
if (normal_direction.Magnitude() > ALMOST_ZERO) {
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((float)normal.X());
_normals.push_back((float)normal.Y());
_normals.push_back((float)normal.Z());
_normals.push_back(static_cast<P>(normal.X()));
_normals.push_back(static_cast<P>(normal.Y()));
_normals.push_back(static_cast<P>(normal.Z()));
}
}
@@ -224,26 +252,137 @@ namespace IfcGeom {
_material_ids.push_back(surface_style_id);
addEdge(n1,n2,edgecount,edges_temp);
addEdge(n2,n3,edgecount,edges_temp);
addEdge(n3,n1,edgecount,edges_temp);
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 it = edges_temp.begin(); it != edges_temp.end(); ++it ) {
_edges.push_back(edgecount[*it]==1);
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 P X = static_cast<P>(settings().convert_back_units() ? (p.X() / settings().unit_magnitude()) : p.X());
const P Y = static_cast<P>(settings().convert_back_units() ? (p.Y() / settings().unit_magnitude()) : p.Y());
const P Z = static_cast<P>(settings().convert_back_units() ? (p.Z() / settings().unit_magnitude()) : p.Z());
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().weld_vertices()) {
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;
@@ -269,4 +408,4 @@ namespace IfcGeom {
}
}
#endif
#endif
+660
View File
@@ -0,0 +1,660 @@
#include <Geom_Line.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Ellipse.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Geom_Plane.hxx>
#include <Geom_BSplineSurface.hxx>
#include <Geom_CylindricalSurface.hxx>
#include <BRepTools_WireExplorer.hxx>
#include <TColgp_Array2OfPnt.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array2OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include "IfcGeom.h"
template <typename T, typename U>
int convert_to_ifc(const T& t, U*& u, bool /*advanced*/) {
std::vector<double> coords(3);
coords[0] = t.X(); coords[1] = t.Y(); coords[2] = t.Z();
u = new U(coords);
return 1;
}
template <>
int convert_to_ifc(const TopoDS_Vertex& v, IfcSchema::IfcCartesianPoint*& p, bool advanced) {
gp_Pnt pnt = BRep_Tool::Pnt(v);
return convert_to_ifc(pnt, p, advanced);
}
template <>
int convert_to_ifc(const TopoDS_Vertex& v, IfcSchema::IfcVertex*& vertex, bool advanced) {
IfcSchema::IfcCartesianPoint* p;
convert_to_ifc(v, p, advanced);
vertex = new IfcSchema::IfcVertexPoint(p);
return 1;
}
template <>
int convert_to_ifc(const gp_Ax2& a, IfcSchema::IfcAxis2Placement3D*& ax, bool advanced) {
IfcSchema::IfcCartesianPoint* p;
IfcSchema::IfcDirection *x, *z;
if (!(convert_to_ifc(a.Location(), p, advanced) && convert_to_ifc(a.Direction(), z, advanced) && convert_to_ifc(a.XDirection(), x, advanced))) {
ax = 0;
return 0;
}
ax = new IfcSchema::IfcAxis2Placement3D(p, z, x);
return 1;
}
template <typename T, typename U>
void opencascade_array_to_vector(T& t, std::vector<U>& u) {
u.reserve(t.Length());
for (int i = t.Lower(); i <= t.Upper(); ++i) {
u.push_back(t.Value(i));
}
}
template <typename T, typename U>
void opencascade_array_to_vector2(T& t, std::vector< std::vector<U> >& u) {
u.reserve(t.RowLength());
for (int j = t.LowerRow(); j <= t.UpperRow(); ++j) {
std::vector<U> v;
v.reserve(t.ColLength());
for (int i = t.LowerCol(); i <= t.UpperCol(); ++i) {
v.push_back(t.Value(j, i));
}
u.push_back(v);
}
}
#ifdef USE_IFC4
IfcSchema::IfcKnotType::Value opencascade_knotspec_to_ifc(GeomAbs_BSplKnotDistribution bspline_knot_spec) {
IfcSchema::IfcKnotType::Value knot_spec = IfcSchema::IfcKnotType::IfcKnotType_UNSPECIFIED;
if (bspline_knot_spec == GeomAbs_Uniform) {
knot_spec = IfcSchema::IfcKnotType::IfcKnotType_UNIFORM_KNOTS;
} else if (bspline_knot_spec == GeomAbs_QuasiUniform) {
knot_spec = IfcSchema::IfcKnotType::IfcKnotType_QUASI_UNIFORM_KNOTS;
} else if (bspline_knot_spec == GeomAbs_PiecewiseBezier) {
knot_spec = IfcSchema::IfcKnotType::IfcKnotType_PIECEWISE_BEZIER_KNOTS;
}
return knot_spec;
}
#endif
template <>
int convert_to_ifc(const Handle_Geom_Curve& c, IfcSchema::IfcCurve*& curve, bool advanced) {
if (c->DynamicType() == STANDARD_TYPE(Geom_Line)) {
IfcSchema::IfcDirection* d;
IfcSchema::IfcCartesianPoint* p;
Handle_Geom_Line line = Handle_Geom_Line::DownCast(c);
if (!convert_to_ifc(line->Position().Location(), p, advanced)) {
return 0;
}
if (!convert_to_ifc(line->Position().Direction(), d, advanced)) {
return 0;
}
IfcSchema::IfcVector* v = new IfcSchema::IfcVector(d, 1.);
curve = new IfcSchema::IfcLine(p, v);
return 1;
} else if (c->DynamicType() == STANDARD_TYPE(Geom_Circle)) {
IfcSchema::IfcAxis2Placement3D* ax;
Handle_Geom_Circle circle = Handle_Geom_Circle::DownCast(c);
convert_to_ifc(circle->Position(), ax, advanced);
curve = new IfcSchema::IfcCircle(ax, circle->Radius());
return 1;
} else if (c->DynamicType() == STANDARD_TYPE(Geom_Ellipse)) {
IfcSchema::IfcAxis2Placement3D* ax;
Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(c);
convert_to_ifc(ellipse->Position(), ax, advanced);
curve = new IfcSchema::IfcEllipse(ax, ellipse->MajorRadius(), ellipse->MinorRadius());
return 1;
}
#ifdef USE_IFC4
else if (c->DynamicType() == STANDARD_TYPE(Geom_BSplineCurve)) {
Handle_Geom_BSplineCurve bspline = Handle_Geom_BSplineCurve::DownCast(c);
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
TColgp_Array1OfPnt poles(1, bspline->NbPoles());
bspline->Poles(poles);
for (int i = 1; i <= bspline->NbPoles(); ++i) {
IfcSchema::IfcCartesianPoint* p;
if (!convert_to_ifc(poles.Value(i), p, advanced)) {
return 0;
}
points->push(p);
}
IfcSchema::IfcKnotType::Value knot_spec = opencascade_knotspec_to_ifc(bspline->KnotDistribution());
std::vector<int> mults;
std::vector<double> knots;
std::vector<double> weights;
TColStd_Array1OfInteger bspline_mults(1, bspline->NbKnots());
TColStd_Array1OfReal bspline_knots(1, bspline->NbKnots());
TColStd_Array1OfReal bspline_weights(1, bspline->NbPoles());
bspline->Multiplicities(bspline_mults);
bspline->Knots(bspline_knots);
bspline->Weights(bspline_weights);
opencascade_array_to_vector(bspline_mults, mults);
opencascade_array_to_vector(bspline_knots, knots);
opencascade_array_to_vector(bspline_weights, weights);
bool rational = false;
for (std::vector<double>::const_iterator it = weights.begin(); it != weights.end(); ++it) {
if ((*it) != 1.) {
rational = true;
break;
}
}
if (rational) {
curve = new IfcSchema::IfcRationalBSplineCurveWithKnots(
bspline->Degree(),
points,
IfcSchema::IfcBSplineCurveForm::IfcBSplineCurveForm_UNSPECIFIED,
bspline->IsClosed() != 0,
false,
mults,
knots,
knot_spec,
weights
);
} else {
curve = new IfcSchema::IfcBSplineCurveWithKnots(
bspline->Degree(),
points,
IfcSchema::IfcBSplineCurveForm::IfcBSplineCurveForm_UNSPECIFIED,
bspline->IsClosed() != 0,
false,
mults,
knots,
knot_spec
);
}
return 1;
}
#endif
return 0;
}
template <>
int convert_to_ifc(const Handle_Geom_Surface& s, IfcSchema::IfcSurface*& surface, bool advanced) {
if (s->DynamicType() == STANDARD_TYPE(Geom_Plane)) {
Handle_Geom_Plane plane = Handle_Geom_Plane::DownCast(s);
IfcSchema::IfcAxis2Placement3D* place;
/// @todo: Note that the Ax3 is converted to an Ax2 here
if (!convert_to_ifc(plane->Position().Ax2(), place, advanced)) {
return 0;
}
surface = new IfcSchema::IfcPlane(place);
return 1;
}
#ifdef USE_IFC4
else if (s->DynamicType() == STANDARD_TYPE(Geom_CylindricalSurface)) {
Handle_Geom_CylindricalSurface cyl = Handle_Geom_CylindricalSurface::DownCast(s);
IfcSchema::IfcAxis2Placement3D* place;
/// @todo: Note that the Ax3 is converted to an Ax2 here
if (!convert_to_ifc(cyl->Position().Ax2(), place, advanced)) {
return 0;
}
surface = new IfcSchema::IfcCylindricalSurface(place, cyl->Radius());
return 1;
} else if (s->DynamicType() == STANDARD_TYPE(Geom_BSplineSurface)) {
typedef IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint> points_t;
Handle_Geom_BSplineSurface bspline = Handle_Geom_BSplineSurface::DownCast(s);
points_t::ptr points(new points_t);
TColgp_Array2OfPnt poles(1, bspline->NbUPoles(), 1, bspline->NbVPoles());
bspline->Poles(poles);
for (int i = 1; i <= bspline->NbUPoles(); ++i) {
std::vector<IfcSchema::IfcCartesianPoint*> ps;
ps.reserve(bspline->NbVPoles());
for (int j = 1; j <= bspline->NbVPoles(); ++j) {
IfcSchema::IfcCartesianPoint* p;
if (!convert_to_ifc(poles.Value(i, j), p, advanced)) {
return 0;
}
ps.push_back(p);
}
points->push(ps);
}
IfcSchema::IfcKnotType::Value knot_spec_u = opencascade_knotspec_to_ifc(bspline->UKnotDistribution());
IfcSchema::IfcKnotType::Value knot_spec_v = opencascade_knotspec_to_ifc(bspline->VKnotDistribution());
if (knot_spec_u != knot_spec_v) {
knot_spec_u = IfcSchema::IfcKnotType::IfcKnotType_UNSPECIFIED;
}
std::vector<int> umults;
std::vector<int> vmults;
std::vector<double> uknots;
std::vector<double> vknots;
std::vector< std::vector<double> > weights;
TColStd_Array1OfInteger bspline_umults(1, bspline->NbUKnots());
TColStd_Array1OfInteger bspline_vmults(1, bspline->NbVKnots());
TColStd_Array1OfReal bspline_uknots(1, bspline->NbUKnots());
TColStd_Array1OfReal bspline_vknots(1, bspline->NbVKnots());
TColStd_Array2OfReal bspline_weights(1, bspline->NbUPoles(), 1, bspline->NbVPoles());
bspline->UMultiplicities(bspline_umults);
bspline->VMultiplicities(bspline_vmults);
bspline->UKnots(bspline_uknots);
bspline->VKnots(bspline_vknots);
bspline->Weights(bspline_weights);
opencascade_array_to_vector(bspline_umults, umults);
opencascade_array_to_vector(bspline_vmults, vmults);
opencascade_array_to_vector(bspline_uknots, uknots);
opencascade_array_to_vector(bspline_vknots, vknots);
opencascade_array_to_vector2(bspline_weights, weights);
bool rational = false;
for (std::vector< std::vector<double> >::const_iterator it = weights.begin(); it != weights.end(); ++it) {
for (std::vector<double>::const_iterator jt = it->begin(); jt != it->end(); ++jt) {
if ((*jt) != 1.) {
rational = true;
break;
}
}
}
if (rational) {
surface = new IfcSchema::IfcRationalBSplineSurfaceWithKnots(
bspline->UDegree(),
bspline->VDegree(),
points,
IfcSchema::IfcBSplineSurfaceForm::IfcBSplineSurfaceForm_UNSPECIFIED,
bspline->IsUClosed() != 0,
bspline->IsVClosed() != 0,
false,
umults,
vmults,
uknots,
vknots,
knot_spec_u,
weights
);
} else {
surface = new IfcSchema::IfcBSplineSurfaceWithKnots(
bspline->UDegree(),
bspline->VDegree(),
points,
IfcSchema::IfcBSplineSurfaceForm::IfcBSplineSurfaceForm_UNSPECIFIED,
bspline->IsUClosed() != 0,
bspline->IsVClosed() != 0,
false,
umults,
vmults,
uknots,
vknots,
knot_spec_u
);
}
return 1;
}
#endif
return 0;
}
template <>
int convert_to_ifc(const TopoDS_Edge& e, IfcSchema::IfcCurve*& c, bool advanced) {
double a, b;
IfcSchema::IfcCurve* base;
Handle_Geom_Curve crv = BRep_Tool::Curve(e, a, b);
if (!convert_to_ifc(crv, base, advanced)) {
return 0;
}
IfcEntityList::ptr trim1(new IfcEntityList);
IfcEntityList::ptr trim2(new IfcEntityList);
trim1->push(new IfcSchema::IfcParameterValue(a));
trim2->push(new IfcSchema::IfcParameterValue(b));
c = new IfcSchema::IfcTrimmedCurve(base, trim1, trim2, true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
return 1;
}
template <>
int convert_to_ifc(const TopoDS_Edge& e, IfcSchema::IfcEdge*& edge, bool advanced) {
double a, b;
TopExp_Explorer exp(e, TopAbs_VERTEX);
if (!exp.More()) return 0;
TopoDS_Vertex v1 = TopoDS::Vertex(exp.Current());
exp.Next();
if (!exp.More()) return 0;
TopoDS_Vertex v2 = TopoDS::Vertex(exp.Current());
IfcSchema::IfcVertex *vertex1, *vertex2;
if (!(convert_to_ifc(v1, vertex1, advanced) && convert_to_ifc(v2, vertex2, advanced))) {
return 0;
}
Handle_Geom_Curve crv = BRep_Tool::Curve(e, a, b);
if (crv.IsNull()) {
return 0;
}
if (crv->DynamicType() == STANDARD_TYPE(Geom_Line) && !advanced) {
IfcSchema::IfcEdge* edge2 = new IfcSchema::IfcEdge(vertex1, vertex2);
edge = new IfcSchema::IfcOrientedEdge(edge2, true);
return 1;
} else {
IfcSchema::IfcCurve* curve;
if (!convert_to_ifc(crv, curve, advanced)) {
return 0;
}
/// @todo probably not correct
const bool sense = e.Orientation() == TopAbs_FORWARD;
IfcSchema::IfcEdge* edge2 = new IfcSchema::IfcEdgeCurve(vertex1, vertex2, curve, true);
edge = new IfcSchema::IfcOrientedEdge(edge2, sense);
return 1;
}
}
template <>
int convert_to_ifc(const TopoDS_Wire& wire, IfcSchema::IfcLoop*& loop, bool advanced) {
bool polygonal = true;
for (TopExp_Explorer exp(wire, TopAbs_EDGE); exp.More(); exp.Next()) {
double a, b;
Handle_Geom_Curve crv = BRep_Tool::Curve(TopoDS::Edge(exp.Current()), a, b);
if (crv.IsNull()) {
continue;
}
if (crv->DynamicType() != STANDARD_TYPE(Geom_Line)) {
polygonal = false;
break;
}
}
if (!polygonal && !advanced) {
return 0;
} else if (polygonal && !advanced) {
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
BRepTools_WireExplorer exp(wire);
IfcSchema::IfcCartesianPoint* p;
for (; exp.More(); exp.Next()) {
if (convert_to_ifc(exp.CurrentVertex(), p, advanced)) {
points->push(p);
} else {
return 0;
}
}
loop = new IfcSchema::IfcPolyLoop(points);
return 1;
} else {
IfcSchema::IfcOrientedEdge::list::ptr edges(new IfcSchema::IfcOrientedEdge::list);
BRepTools_WireExplorer exp(wire);
for (; exp.More(); exp.Next()) {
IfcSchema::IfcEdge* edge;
// With advanced set to true convert_to_ifc(TopoDS_Edge&) will always create an IfcOrientedEdge
if (!convert_to_ifc(exp.Current(), edge, true)) {
double a, b;
if (BRep_Tool::Curve(TopoDS::Edge(exp.Current()), a, b).IsNull()) {
continue;
} else {
return 0;
}
}
edges->push(edge->as<IfcSchema::IfcOrientedEdge>());
}
loop = new IfcSchema::IfcEdgeLoop(edges);
return 1;
}
}
template <>
int convert_to_ifc(const TopoDS_Face& f, IfcSchema::IfcFace*& face, bool advanced) {
Handle_Geom_Surface surf = BRep_Tool::Surface(f);
TopExp_Explorer exp(f, TopAbs_WIRE);
IfcSchema::IfcFaceBound::list::ptr bounds(new IfcSchema::IfcFaceBound::list);
int index = 0;
for (; exp.More(); exp.Next(), ++index) {
IfcSchema::IfcLoop* loop;
if (!convert_to_ifc(TopoDS::Wire(exp.Current()), loop, advanced)) {
return 0;
}
IfcSchema::IfcFaceBound* bnd;
if (index == 0) {
bnd = new IfcSchema::IfcFaceOuterBound(loop, true);
} else {
bnd = new IfcSchema::IfcFaceBound(loop, true);
}
bounds->push(bnd);
}
const bool is_planar = surf->DynamicType() == STANDARD_TYPE(Geom_Plane);
if (!is_planar && !advanced) {
return 0;
}
if (is_planar && !advanced) {
face = new IfcSchema::IfcFace(bounds);
return 1;
} else {
#ifdef USE_IFC4
IfcSchema::IfcSurface* surface;
if (!convert_to_ifc(surf, surface, advanced)) {
return 0;
}
face = new IfcSchema::IfcAdvancedFace(bounds, surface, f.Orientation() == TopAbs_FORWARD);
return 1;
#else
// No IfcAdvancedFace in Ifc2x3
return 0;
#endif
}
}
template <typename U>
int convert_to_ifc(const TopoDS_Shape& s, U*& item, bool advanced) {
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
IfcSchema::IfcFace* f;
for (TopExp_Explorer exp(s, TopAbs_FACE); exp.More(); exp.Next()) {
if (convert_to_ifc(TopoDS::Face(exp.Current()), f, advanced)) {
faces->push(f);
} else {
/// Cleanup:
for (IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++it) {
IfcEntityList::ptr data = IfcParse::traverse(*it)->unique();
for (IfcEntityList::it jt = data->begin(); jt != data->end(); ++jt) {
delete *jt;
}
}
return 0;
}
}
item = new U(faces);
return faces->size();
}
IfcUtil::IfcBaseClass* IfcGeom::MAKE_TYPE_NAME(serialise_)(const TopoDS_Shape& shape, bool advanced) {
#ifndef USE_IFC4
advanced = false;
#endif
for (TopExp_Explorer exp(shape, TopAbs_COMPSOLID); exp.More();) {
/// @todo CompSolids are not supported
return 0;
}
IfcSchema::IfcRepresentation* rep = 0;
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
// First check if there is a solid with one or more shells
for (TopExp_Explorer exp(shape, TopAbs_SOLID); exp.More(); exp.Next()) {
IfcSchema::IfcClosedShell* outer = 0;
IfcSchema::IfcClosedShell::list::ptr inner(new IfcSchema::IfcClosedShell::list);
for (TopExp_Explorer exp2(exp.Current(), TopAbs_SHELL); exp2.More(); exp2.Next()) {
IfcSchema::IfcClosedShell* shell;
if (!convert_to_ifc(exp2.Current(), shell, advanced)) {
return 0;
}
/// @todo Are shells always in this order or does Orientation() needs to be checked?
if (outer) {
inner->push(shell);
} else {
outer = shell;
}
}
#ifdef USE_IFC4
if (advanced) {
if (inner->size()) {
items->push(new IfcSchema::IfcAdvancedBrepWithVoids(outer, inner));
} else {
items->push(new IfcSchema::IfcAdvancedBrep(outer));
}
} else
#endif
/// @todo this is not necessarily correct as the shell is not necessarily facetted.
if (inner->size()) {
items->push(new IfcSchema::IfcFacetedBrepWithVoids(outer, inner));
} else {
items->push(new IfcSchema::IfcFacetedBrep(outer));
}
}
if (items->size() > 0) {
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Body"), std::string("Brep"), items);
} else {
// If not, see if there is a shell
IfcSchema::IfcOpenShell::list::ptr shells(new IfcSchema::IfcOpenShell::list);
for (TopExp_Explorer exp(shape, TopAbs_SHELL); exp.More(); exp.Next()) {
IfcSchema::IfcOpenShell* shell;
if (!convert_to_ifc(exp.Current(), shell, advanced)) {
return 0;
}
shells->push(shell);
}
if (shells->size() > 0) {
items->push(new IfcSchema::IfcShellBasedSurfaceModel(shells->generalize()));
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Body"), std::string("Brep"), items);
} else {
// If not, see if there is are one of more faces. Note that they will be grouped into a shell.
IfcSchema::IfcOpenShell* shell;
int face_count = convert_to_ifc(shape, shell, advanced);
if (face_count > 0) {
items->push(shell);
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Body"), std::string("Brep"), items);
} else {
// If not, see if there are any edges. Note that wires are skipped as
// they are not commonly top-level geometrical descriptions in IFC.
// Also note that edges are written as trimmed curves rather than edges.
IfcEntityList::ptr edges(new IfcEntityList);
for (TopExp_Explorer exp(shape, TopAbs_EDGE); exp.More(); exp.Next()) {
IfcSchema::IfcCurve* c;
if (!convert_to_ifc(TopoDS::Edge(exp.Current()), c, advanced)) {
return 0;
}
edges->push(c);
}
if (edges->size() == 0) {
return 0;
} else if (edges->size() == 1) {
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Axis"), std::string("Curve2D"), edges->as<IfcSchema::IfcRepresentationItem>());
} else {
// A geometric set is created as that probably (?) makes more sense in IFC
IfcSchema::IfcGeometricCurveSet* curves = new IfcSchema::IfcGeometricCurveSet(edges);
items->push(curves);
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Axis"), std::string("GeometricCurveSet"), items->as<IfcSchema::IfcRepresentationItem>());
}
}
}
}
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
reps->push(rep);
return new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
}
IfcUtil::IfcBaseClass* IfcGeom::MAKE_TYPE_NAME(tesselate_)(const TopoDS_Shape& shape, double deflection) {
BRepMesh_IncrementalMesh(shape, deflection);
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
for (TopExp_Explorer exp(shape, TopAbs_FACE); exp.More(); exp.Next()) {
const TopoDS_Face& face = TopoDS::Face(exp.Current());
TopLoc_Location loc;
Handle(Poly_Triangulation) tri = BRep_Tool::Triangulation(face, loc);
if (!tri.IsNull()) {
const TColgp_Array1OfPnt& nodes = tri->Nodes();
std::vector<IfcSchema::IfcCartesianPoint*> vertices;
for (int i = 1; i <= nodes.Length(); ++i) {
gp_Pnt pnt = nodes(i).Transformed(loc);
std::vector<double> xyz; xyz.push_back(pnt.X()); xyz.push_back(pnt.Y()); xyz.push_back(pnt.Z());
IfcSchema::IfcCartesianPoint* cpnt = new IfcSchema::IfcCartesianPoint(xyz);
vertices.push_back(cpnt);
}
const Poly_Array1OfTriangle& triangles = tri->Triangles();
for (int i = 1; i <= triangles.Length(); ++i) {
int n1, n2, n3;
triangles(i).Get(n1, n2, n3);
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
points->push(vertices[n1 - 1]);
points->push(vertices[n2 - 1]);
points->push(vertices[n3 - 1]);
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, face.Orientation() != TopAbs_REVERSED);
IfcSchema::IfcFaceBound::list::ptr bounds(new IfcSchema::IfcFaceBound::list);
bounds->push(bound);
IfcSchema::IfcFace* face2 = new IfcSchema::IfcFace(bounds);
faces->push(face2);
}
}
}
IfcSchema::IfcOpenShell* shell = new IfcSchema::IfcOpenShell(faces);
IfcSchema::IfcConnectedFaceSet::list::ptr shells(new IfcSchema::IfcConnectedFaceSet::list);
shells->push(shell);
IfcSchema::IfcFaceBasedSurfaceModel* surface_model = new IfcSchema::IfcFaceBasedSurfaceModel(shells);
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
items->push(surface_model);
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
0, std::string("Facetation"), std::string("SurfaceModel"), items);
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shapedef = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
return shapedef;
}
+38
View File
@@ -0,0 +1,38 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef IFCGEOMSHAPETYPE_H
#define IFCGEOMSHAPETYPE_H
namespace IfcGeom {
enum ShapeType {
ST_SHAPELIST,
ST_SHAPE,
ST_FACE,
ST_WIRE,
ST_CURVE,
ST_EDGE,
ST_VERTEX,
ST_OTHER
};
}
#endif
+513 -173
View File
@@ -65,6 +65,9 @@
#include <TopoDS.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_CompSolid.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepPrimAPI_MakePrism.hxx>
@@ -74,6 +77,7 @@
#include <BRepPrimAPI_MakeCylinder.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <BRepPrimAPI_MakeWedge.hxx>
#include <BRepBuilderAPI_MakePolygon.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepBuilderAPI_MakeShell.hxx>
@@ -95,15 +99,30 @@
#include <Standard_Version.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include "../ifcgeom/IfcGeom.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_Shape& shape) {
const double height = l->Depth() * getValue(GV_LENGTH_UNIT);
if (height < getValue(GV_PRECISION)) {
Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l);
return false;
}
TopoDS_Shape face;
if ( !convert_face(l->SweptArea(),face) ) return false;
const double height = l->Depth() * getValue(GV_LENGTH_UNIT);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf);
}
gp_Dir dir;
convert(l->ExtrudedDirection(),dir);
@@ -136,10 +155,117 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_S
shape = BRepPrimAPI_MakePrism(face, height*dir);
}
shape.Move(trsf);
return ! shape.IsNull();
if (has_position && !shape.IsNull()) {
// IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D
// and therefore has a unit scale factor
shape.Move(trsf);
}
return !shape.IsNull();
}
#ifdef USE_IFC4
bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* l, TopoDS_Shape& shape) {
const double height = l->Depth() * getValue(GV_LENGTH_UNIT);
if (height < getValue(GV_PRECISION)) {
Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l);
return false;
}
TopoDS_Shape face1, face2;
if (!convert_face(l->SweptArea(), face1)) return false;
if (!convert_face(l->EndSweptArea(), face2)) return false;
gp_Trsf trsf;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf);
}
gp_Dir dir;
convert(l->ExtrudedDirection(), dir);
gp_Trsf end_profile;
end_profile.SetTranslation(height * dir);
TopoDS_Edge spine_edge = BRepBuilderAPI_MakeEdge(gp_Pnt(), gp_Pnt((height * dir).XYZ())).Edge();
TopoDS_Wire wire = BRepBuilderAPI_MakeWire(spine_edge).Wire();
shape.Nullify();
TopExp_Explorer exp1(face1, TopAbs_WIRE);
TopExp_Explorer exp2(face2, TopAbs_WIRE);
TopoDS_Vertex v1, v2;
TopExp::Vertices(wire, v1, v2);
TopoDS_Shape shell;
TopoDS_Compound compound;
BRep_Builder compound_builder;
for (; exp1.More() && exp2.More(); exp1.Next(), exp2.Next()) {
const TopoDS_Wire& w1 = TopoDS::Wire(exp1.Current());
const TopoDS_Wire& w2 = TopoDS::Wire(exp2.Current());
BRepOffsetAPI_MakePipeShell builder(wire);
builder.Add(w1, v1);
builder.Add(w2.Moved(end_profile), v2);
TopoDS_Shape result = builder.Shape();
BRepOffsetAPI_Sewing sewer;
sewer.SetTolerance(getValue(GV_PRECISION));
sewer.SetMaxTolerance(getValue(GV_PRECISION));
sewer.SetMinTolerance(getValue(GV_PRECISION));
sewer.Add(result);
sewer.Add(BRepBuilderAPI_MakeFace(w1).Face());
sewer.Add(BRepBuilderAPI_MakeFace(w2).Face().Moved(end_profile));
sewer.Perform();
result = sewer.SewedShape();
if (shell.IsNull()) {
shell = result;
} else if (l->SweptArea()->declaration().is(IfcSchema::IfcCircleHollowProfileDef::Class()) ||
l->SweptArea()->declaration().is(IfcSchema::IfcRectangleHollowProfileDef::Class()))
{
/// @todo a bit of of a hack, should be sufficient
shell = BRepAlgoAPI_Cut(shell, result).Shape();
break;
} else {
if (compound.IsNull()) {
compound_builder.MakeCompound(compound);
compound_builder.Add(compound, shell);
}
compound_builder.Add(compound, result);
}
}
if (!compound.IsNull()) {
shell = compound;
}
shape = shell;
if (exp1.More() != exp2.More()) {
Logger::Message(Logger::LOG_ERROR, "Inconsistent profiles encountered for:", l);
}
if (has_position && !shape.IsNull()) {
// IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D
// and therefore has a unit scale factor
shape.Move(trsf);
}
return !shape.IsNull();
}
#endif
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion* l, TopoDS_Shape& shape) {
TopoDS_Wire wire;
if ( !convert_wire(l->SweptCurve(), wire) ) {
@@ -149,14 +275,27 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion* l, T
wire = TopoDS::Wire(exp.Current());
}
const double height = l->Depth() * getValue(GV_LENGTH_UNIT);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf);
}
gp_Dir dir;
convert(l->ExtrudedDirection(),dir);
shape = BRepPrimAPI_MakePrism(wire, height*dir);
shape.Move(trsf);
if (has_position) {
// IfcSweptSurface.Position (trsf) is an IfcAxis2Placement3D
// and therefore has a unit scale factor
shape.Move(trsf);
}
return !shape.IsNull();
}
@@ -173,11 +312,22 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfRevolution* l, TopoDS
IfcGeom::Kernel::convert(l->AxisPosition(), ax1);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf);
}
shape = BRepPrimAPI_MakeRevol(wire, ax1);
shape.Move(trsf);
if (has_position) {
// IfcSweptSurface.Position (trsf) is an IfcAxis2Placement3D
// and therefore has a unit scale factor
shape.Move(trsf);
}
return !shape.IsNull();
}
@@ -191,7 +341,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRevolvedAreaSolid* l, TopoDS_S
IfcGeom::Kernel::convert(l->Axis(), ax1);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf);
}
if (ang >= M_PI * 2. - ALMOST_ZERO) {
shape = BRepPrimAPI_MakeRevol(face, ax1);
@@ -199,15 +355,40 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRevolvedAreaSolid* l, TopoDS_S
shape = BRepPrimAPI_MakeRevol(face, ax1, ang);
}
shape.Move(trsf);
if (has_position) {
// IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D
// and therefore has a unit scale factor
shape.Move(trsf);
}
return !shape.IsNull();
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFacetedBrep* l, IfcRepresentationShapeItems& shape) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, IfcRepresentationShapeItems& shape) {
TopoDS_Shape s;
const SurfaceStyle* collective_style = get_style(l);
if (convert_shape(l->Outer(),s) ) {
const SurfaceStyle* indiv_style = get_style(l->Outer());
IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list);
if (l->declaration().is(IfcSchema::IfcFacetedBrepWithVoids::Class())) {
voids = l->as<IfcSchema::IfcFacetedBrepWithVoids>()->Voids();
}
#ifdef USE_IFC4
if (l->declaration().is(IfcSchema::IfcAdvancedBrepWithVoids::Class())) {
voids = l->as<IfcSchema::IfcAdvancedBrepWithVoids>()->Voids();
}
#endif
for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) {
TopoDS_Shape s2;
/// @todo No extensive shapefixing since shells should be disjoint.
/// @todo Awaiting generalized boolean ops module with appropriate checking
if (convert_shape(l->Outer(), s2)) {
s = BRepAlgoAPI_Cut(s, s2).Shape();
}
}
shape.push_back(IfcRepresentationShapeItem(s, indiv_style ? indiv_style : collective_style));
return true;
}
@@ -215,6 +396,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFacetedBrep* l, IfcRepresentat
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFaceBasedSurfaceModel* l, IfcRepresentationShapeItems& 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 ) {
@@ -222,15 +404,16 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFaceBasedSurfaceModel* l, IfcR
const SurfaceStyle* shell_style = get_style(*it);
if (convert_shape(*it,s)) {
shapes.push_back(IfcRepresentationShapeItem(s, shell_style ? shell_style : collective_style));
part_success |= true;
}
}
return true;
return part_success;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, TopoDS_Shape& shape) {
IfcSchema::IfcSurface* surface = l->BaseSurface();
if ( ! surface->is(IfcSchema::Type::IfcPlane) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface->entity);
if ( ! surface->declaration().is(IfcSchema::IfcPlane::Class()) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface);
return false;
}
gp_Pln pln;
@@ -243,13 +426,33 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, TopoDS_Shap
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l, TopoDS_Shape& shape) {
TopoDS_Shape halfspace;
if ( ! IfcGeom::Kernel::convert((IfcSchema::IfcHalfSpaceSolid*)l,halfspace) ) return false;
TopoDS_Wire wire;
if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false;
if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false;
gp_Trsf trsf;
convert(l->Position(),trsf);
if ( ! convert(l->Position(),trsf) ) return false;
TColgp_SequenceOfPnt points;
if (wire_to_sequence_of_point(wire, points)) {
// Boolean subtractions not very robust for narrow operands,
// increase minimal point spacing to eliminate such shapes.
const double t = getValue(GV_PRECISION) * 10.;
remove_duplicate_points_from_loop(points, wire.Closed() != 0, t); // Note: wire always closed, as per if statement above
remove_collinear_points_from_loop(points, wire.Closed() != 0, t);
if (points.Length() < 3) {
Logger::Message(Logger::LOG_ERROR, "Not enough points retained from:", l->PolygonalBoundary());
return false;
}
sequence_of_point_to_wire(points, wire, wire.Closed() != 0);
}
TopoDS_Shape prism = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,200));
gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-100.0));
prism.Move(trsf*down);
// `trsf` and `down` both have a unit scale factor
prism.Move(trsf*down);
shape = BRepAlgoAPI_Common(halfspace,prism);
return true;
}
@@ -260,7 +463,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, Ifc
for( IfcEntityList::it it = shells->begin(); it != shells->end(); ++ it ) {
TopoDS_Shape s;
const SurfaceStyle* shell_style = 0;
if ((*it)->is(IfcSchema::Type::IfcRepresentationItem)) {
if ((*it)->declaration().is(IfcSchema::IfcRepresentationItem::Class())) {
shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it);
}
if (convert_shape(*it,s)) {
@@ -271,206 +474,189 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, Ifc
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) {
TopoDS_Shape s1, s2;
IfcRepresentationShapeItems items1, items2;
TopoDS_Wire boundary_wire;
IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand();
IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand();
bool is_halfspace = operand2->is(IfcSchema::Type::IfcHalfSpaceSolid);
bool is_halfspace = operand2->declaration().is(IfcSchema::IfcHalfSpaceSolid::Class());
if ( is_shape_collection(operand1) ) {
if ( shape_type(operand1) == ST_SHAPELIST ) {
if (!(convert_shapes(operand1, items1) && flatten_shape_list(items1, s1, true))) {
return false;
}
} else {
} else if ( shape_type(operand1) == ST_SHAPE ) {
if ( ! convert_shape(operand1, s1) ) {
return false;
}
{ TopoDS_Solid temp_solid;
s1 = ensure_fit_for_subtraction(s1, temp_solid); }
} else {
Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", operand1);
return false;
}
const double first_operand_volume = shape_volume(s1);
if ( first_operand_volume <= ALMOST_ZERO )
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand()->entity);
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand());
bool shape2_processed = false;
if ( is_shape_collection(operand2) ) {
if ( shape_type(operand2) == ST_SHAPELIST ) {
shape2_processed = convert_shapes(operand2, items2) && flatten_shape_list(items2, s2, true);
} else {
} else if ( shape_type(operand2) == ST_SHAPE ) {
shape2_processed = convert_shape(operand2,s2);
if (shape2_processed && !is_halfspace) {
TopoDS_Solid temp_solid;
s2 = ensure_fit_for_subtraction(s2, temp_solid);
}
} else {
Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", operand2);
}
if (!shape2_processed) {
shape = s1;
Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l->entity);
Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l);
return true;
}
if (!is_halfspace) {
const double second_operand_volume = shape_volume(s2);
if ( second_operand_volume <= ALMOST_ZERO )
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2->entity);
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2);
}
const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator();
const IfcSchema::IfcBooleanOperator::Value op = l->Operator();
/*
// TK: A little debugging trick to output both operands for visual inspection
BRep_Builder builder;
TopoDS_Compound compound;
builder.MakeCompound(compound);
builder.Add(compound, s1);
builder.Add(compound, s2);
shape = compound;
return true;
*/
BOPAlgo_Operation occ_op;
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
occ_op = BOPAlgo_CUT;
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) {
occ_op = BOPAlgo_COMMON;
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) {
occ_op = BOPAlgo_FUSE;
} else {
return false;
}
#if OCC_VERSION_HEX < 0x60900
bool valid_result = boolean_operation(s1, s2, occ_op, shape);
#else
const double fuzz = is_halfspace ? getValue(GV_PRECISION) * 10. : -1.;
bool valid_result = boolean_operation(s1, s2, occ_op, shape, fuzz);
#endif
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
bool valid_cut = false;
BRepAlgoAPI_Cut brep_cut(s1,s2);
if ( brep_cut.IsDone() ) {
TopoDS_Shape result = brep_cut;
ShapeFix_Shape fix(result);
try {
fix.Perform();
result = fix.Shape();
} catch (...) {
Logger::Message(Logger::LOG_WARNING, "Shape healing failed on boolean result", l->entity);
}
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if ( is_valid ) {
shape = result;
valid_cut = true;
}
}
if ( valid_cut ) {
// In case of a subtraction, a check on volume is performed.
if (valid_result) {
const double volume_after_subtraction = shape_volume(shape);
if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) )
Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",l->entity);
Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",l);
} else {
Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",l->entity);
Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",l);
shape = s1;
}
// NB: After issuing error the first operand is returned!
return true;
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) {
BRepAlgoAPI_Fuse brep_fuse(s1,s2);
if ( brep_fuse.IsDone() ) {
TopoDS_Shape result = brep_fuse;
ShapeFix_Shape fix(result);
fix.Perform();
result = fix.Shape();
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if ( is_valid ) {
shape = result;
return true;
}
}
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) {
BRepAlgoAPI_Common brep_common(s1,s2);
if ( brep_common.IsDone() ) {
TopoDS_Shape result = brep_common;
ShapeFix_Shape fix(result);
fix.Perform();
result = fix.Shape();
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if ( is_valid ) {
shape = result;
return true;
}
}
} else {
return valid_result;
}
return false;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Shape& shape) {
IfcSchema::IfcFace::list::ptr faces = l->CfsFaces();
bool facesAdded = false;
const unsigned int num_faces = faces->size();
bool valid_shell = false;
if ( num_faces < getValue(GV_MAX_FACES_TO_SEW) ) {
BRepOffsetAPI_Sewing builder;
builder.SetTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMaxTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMinTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
for( IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++ it ) {
TopoDS_Face face;
bool converted_face = false;
try {
converted_face = convert_face(*it,face);
} catch (...) {}
if ( converted_face && face_area(face) > getValue(GV_MINIMAL_FACE_AREA) ) {
builder.Add(face);
facesAdded = true;
TopTools_ListOfShape face_list;
for (IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++it) {
bool success = false;
TopoDS_Face face;
try {
success = convert_face(*it, face);
} catch (const std::exception& e) {
Logger::Error(e);
} catch (const Standard_Failure& e) {
if (e.GetMessageString() && strlen(e.GetMessageString())) {
Logger::Error(e.GetMessageString());
} else {
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
Logger::Error("Unknown error creating face");
}
} catch (...) {
Logger::Error("Unknown error creating face");
}
if (!success) {
Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", (*it));
continue;
}
if (face.ShapeType() == TopAbs_COMPOUND) {
TopoDS_Iterator face_it(face, false);
for (; face_it.More(); face_it.Next()) {
if (face_it.Value().ShapeType() == TopAbs_FACE) {
// This should really be the case. This is not asserted.
const TopoDS_Face& triangle = TopoDS::Face(face_it.Value());
if (face_area(triangle) > getValue(GV_MINIMAL_FACE_AREA)) {
face_list.Append(triangle);
} else {
Logger::Message(Logger::LOG_WARNING, "Invalid face:", (*it));
}
}
}
} else {
if (face_area(face) > getValue(GV_MINIMAL_FACE_AREA)) {
face_list.Append(face);
} else {
Logger::Message(Logger::LOG_WARNING, "Invalid face:", (*it));
}
}
if ( ! facesAdded ) return false;
try {
builder.Perform();
shape = builder.SewedShape();
valid_shell = BRepCheck_Analyzer(shape).IsValid();
} catch(...) {}
if (valid_shell) {
try {
ShapeFix_Solid solid;
solid.LimitTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
TopoDS_Solid solid_shape = solid.SolidFromShell(TopoDS::Shell(shape));
if (!solid_shape.IsNull()) {
try {
BRepClass3d_SolidClassifier classifier(solid_shape);
shape = solid_shape;
} catch (...) {}
}
} catch(...) {}
} else {
Logger::Message(Logger::LOG_WARNING,"Failed to sew faceset:",l->entity);
}
}
if (!valid_shell) {
if (face_list.Extent() == 0) {
return false;
}
if (face_list.Extent() > getValue(GV_MAX_FACES_TO_SEW) || !create_solid_from_faces(face_list, shape)) {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
for( IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++ it ) {
TopoDS_Face face;
bool converted_face = false;
try {
converted_face = convert_face(*it,face);
} catch (...) {}
if ( converted_face && face_area(face) > getValue(GV_MINIMAL_FACE_AREA) ) {
builder.Add(compound,face);
facesAdded = true;
} else {
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
}
TopTools_ListIteratorOfListOfShape face_iterator;
for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) {
builder.Add(compound, face_iterator.Value());
}
if ( ! facesAdded ) return false;
shape = compound;
}
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentationShapeItems& shapes) {
gp_GTrsf gtrsf;
IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget();
if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) {
if ( transform->declaration().is(IfcSchema::IfcCartesianTransformationOperator3DnonUniform::Class()) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf);
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity);
} else if ( transform->declaration().is(IfcSchema::IfcCartesianTransformationOperator2DnonUniform::Class()) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform);
return false;
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) {
} else if ( transform->declaration().is(IfcSchema::IfcCartesianTransformationOperator3D::Class()) ) {
gp_Trsf trsf;
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf);
gtrsf = trsf;
} else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) {
} else if ( transform->declaration().is(IfcSchema::IfcCartesianTransformationOperator2D::Class()) ) {
gp_Trsf2d trsf_2d;
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,trsf_2d);
gtrsf = (gp_Trsf) trsf_2d;
@@ -478,7 +664,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentati
IfcSchema::IfcRepresentationMap* map = l->MappingSource();
IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin();
gp_Trsf trsf;
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
if (placement->declaration().is(IfcSchema::IfcAxis2Placement3D::Class())) {
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
} else {
gp_Trsf2d trsf_2d;
@@ -486,21 +672,32 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentati
trsf = trsf_2d;
}
gtrsf.Multiply(trsf);
const unsigned int previous_size = (const unsigned int) shapes.size();
bool b = convert_shapes(map->MappedRepresentation(),shapes);
for ( unsigned int i = previous_size; i < shapes.size(); ++ i ) {
shapes[i].append(gtrsf);
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 ) {
shapes[i].prepend(gtrsf);
// Apply styles assigned to the mapped item only if on
// a more granular level no styles have been applied
if (!shapes[i].hasStyle()) {
shapes[i].setStyle(mapped_item_style);
}
}
return b;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcShapeRepresentation* l, IfcRepresentationShapeItems& shapes) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRepresentation* l, IfcRepresentationShapeItems& shapes) {
IfcSchema::IfcRepresentationItem::list::ptr items = l->Items();
bool part_succes = false;
if ( items->size() ) {
for ( IfcSchema::IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++ it ) {
IfcSchema::IfcRepresentationItem* representation_item = *it;
if ( is_shape_collection(representation_item) ) {
if ( shape_type(representation_item) == ST_SHAPELIST ) {
part_succes |= convert_shapes(*it, shapes);
} else {
TopoDS_Shape s;
@@ -521,14 +718,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcGeometricSet* l, IfcRepresenta
const IfcGeom::SurfaceStyle* parent_style = get_style(l);
for ( IfcEntityList::it it = elements->begin(); it != elements->end(); ++ it ) {
IfcSchema::IfcGeometricSetSelect* element = *it;
if (element->is(IfcSchema::Type::IfcSurface)) {
IfcSchema::IfcSurface* surface = (IfcSchema::IfcSurface*) element;
TopoDS_Shape s;
if (convert_shape(surface, s)) {
part_succes = true;
const IfcGeom::SurfaceStyle* style = get_style(surface);
shapes.push_back(IfcRepresentationShapeItem(s, style ? style : parent_style));
TopoDS_Shape s;
if (convert_shape(element, s)) {
part_succes = true;
const IfcGeom::SurfaceStyle* style = 0;
if (element->declaration().is(IfcSchema::IfcPoint::Class())) {
style = get_style((IfcSchema::IfcPoint*) element);
} else if (element->declaration().is(IfcSchema::IfcCurve::Class())) {
style = get_style((IfcSchema::IfcCurve*) element);
} else if (element->declaration().is(IfcSchema::IfcSurface::Class())) {
style = get_style((IfcSchema::IfcSurface*) element);
}
shapes.push_back(IfcRepresentationShapeItem(s, style ? style : parent_style));
}
}
return part_succes;
@@ -542,7 +743,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBlock* l, TopoDS_Shape& shape)
BRepPrimAPI_MakeBox builder(dx, dy, dz);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
// IfcCsgPrimitive3D.Position has unit scale factor
shape = builder.Solid().Moved(trsf);
return true;
}
@@ -575,7 +779,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRightCircularCylinder* l, Topo
BRepPrimAPI_MakeCylinder builder(r, h);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
// IfcCsgPrimitive3D.Position has unit scale factor
shape = builder.Solid().Moved(trsf);
return true;
}
@@ -586,7 +793,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRightCircularCone* l, TopoDS_S
BRepPrimAPI_MakeCone builder(r, 0., h);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
// IfcCsgPrimitive3D.Position has unit scale factor
shape = builder.Solid().Moved(trsf);
return true;
}
@@ -596,7 +806,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSphere* l, TopoDS_Shape& shape
BRepPrimAPI_MakeSphere builder(r);
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
// IfcCsgPrimitive3D.Position has unit scale factor
shape = builder.Solid().Moved(trsf);
return true;
}
@@ -609,7 +822,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_S
IfcGeom::Kernel::convert(l->BasisSurface(), pln);
gp_Trsf trsf;
trsf.SetTransformation(pln.Position());
trsf.SetTransformation(pln.Position(), gp::XOY());
TopoDS_Wire outer;
convert_wire(l->OuterBoundary(), outer);
@@ -617,9 +830,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_S
BRepBuilderAPI_MakeFace mf (outer);
mf.Add(outer);
IfcSchema::IfcCurve::list::ptr inner = l->InnerBoundaries();
IfcSchema::IfcCurve::list::ptr boundaries = l->InnerBoundaries();
for (IfcSchema::IfcCurve::list::it it = inner->begin(); it != inner->end(); ++it) {
for (IfcSchema::IfcCurve::list::it it = boundaries->begin(); it != boundaries->end(); ++it) {
TopoDS_Wire inner;
convert_wire(*it, inner);
@@ -628,14 +841,16 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_S
ShapeFix_Shape sfs(mf.Face());
sfs.Perform();
// `trsf` consitutes the placement of the plane and therefore has unit scale factor
face = TopoDS::Face(sfs.Shape()).Moved(trsf);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularTrimmedSurface* l, TopoDS_Shape& face) {
if (!l->BasisSurface()->is(IfcSchema::Type::IfcPlane)) {
Logger::Message(Logger::LOG_ERROR, "Unsupported BasisSurface:", l->BasisSurface()->entity);
if (!l->BasisSurface()->declaration().is(IfcSchema::IfcPlane::Class())) {
Logger::Message(Logger::LOG_ERROR, "Unsupported BasisSurface:", l->BasisSurface());
return false;
}
gp_Pln pln;
@@ -653,13 +868,21 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l,
TopoDS_Shape face;
TopoDS_Wire wire, section;
if (!l->ReferenceSurface()->is(IfcSchema::Type::IfcPlane)) {
Logger::Message(Logger::LOG_WARNING, "Reference surface not supported", l->ReferenceSurface()->entity);
if (!l->ReferenceSurface()->declaration().is(IfcSchema::IfcPlane::Class())) {
Logger::Message(Logger::LOG_WARNING, "Reference surface not supported", l->ReferenceSurface());
return false;
}
if (!IfcGeom::Kernel::convert(l->Position(), position) ||
!convert_face(l->SweptArea(), face) ||
gp_Trsf trsf;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf);
}
if (!convert_face(l->SweptArea(), face) ||
!convert_wire(l->Directrix(), wire) ) {
return false;
}
@@ -679,7 +902,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l,
for (TopExp_Explorer exp(wire, TopAbs_VERTEX); exp.More(); exp.Next()) {
if (pln.Distance(BRep_Tool::Pnt(TopoDS::Vertex(exp.Current()))) > ALMOST_ZERO) {
directrix_on_plane = false;
Logger::Message(Logger::LOG_WARNING, "The Directrix does not lie on the ReferenceSurface", l->entity);
Logger::Message(Logger::LOG_WARNING, "The Directrix does not lie on the ReferenceSurface", l);
break;
}
}
@@ -716,7 +939,12 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l,
builder.Build();
builder.MakeSolid();
shape = builder.Shape();
shape.Move(position);
if (has_position) {
// IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D
// and therefore has a unit scale factor
shape.Move(position);
}
return true;
}
@@ -752,8 +980,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shap
// Subtraction of pipes with small radii is unstable.
hasInnerRadius = false;
} else {
Handle(Geom_Circle) circle = new Geom_Circle(directrix, r2);
section2 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle));
Handle(Geom_Circle) circle2 = new Geom_Circle(directrix, r2);
section2 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle2));
}
}
@@ -794,7 +1022,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shap
}
if (!is_valid) {
Logger::Message(Logger::LOG_WARNING, "Failed to subtract inner radius void for:", l->entity);
Logger::Message(Logger::LOG_WARNING, "Failed to subtract inner radius void for:", l);
}
}
@@ -807,7 +1035,12 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCylindricalSurface* l, TopoDS_
gp_Trsf trsf;
IfcGeom::Kernel::convert(l->Position(),trsf);
// IfcElementarySurface.Position has unit scale factor
#if OCC_VERSION_HEX < 0x60502
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius())).Face().Moved(trsf);
#else
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius()), getValue(GV_PRECISION)).Face().Moved(trsf);
#endif
return true;
}
@@ -815,4 +1048,111 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAdvancedBrep* l, TopoDS_Shape&
return convert(l->Outer(), shape);
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, TopoDS_Shape& shape) {
IfcSchema::IfcCartesianPointList3D* point_list = l->Coordinates();
const std::vector< std::vector<double> > coordinates = point_list->CoordList();
std::vector<gp_Pnt> points;
points.reserve(coordinates.size());
for (std::vector< std::vector<double> >::const_iterator it = coordinates.begin(); it != coordinates.end(); ++it) {
const std::vector<double>& coords = *it;
if (coords.size() != 3) {
Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on Coordinates", l);
return false;
}
points.push_back(gp_Pnt(coords[0] * getValue(GV_LENGTH_UNIT),
coords[1] * getValue(GV_LENGTH_UNIT),
coords[2] * getValue(GV_LENGTH_UNIT)));
}
std::vector< std::vector<int> > indices = l->CoordIndex();
std::vector<TopoDS_Face> faces;
faces.reserve(indices.size());
for(std::vector< std::vector<int> >::const_iterator it = indices.begin(); it != indices.end(); ++ it) {
const std::vector<int>& tri = *it;
if (tri.size() != 3) {
Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on CoordIndex", l);
return false;
}
const int min_index = *std::min_element(tri.begin(), tri.end());
const int max_index = *std::max_element(tri.begin(), tri.end());
if (min_index < 1 || max_index > (int) points.size()) {
Logger::Message(Logger::LOG_ERROR, "Contents of CoordIndex out of bounds", l);
return false;
}
const gp_Pnt& a = points[tri[0] - 1]; // account for zero- vs
const gp_Pnt& b = points[tri[1] - 1]; // one-based indices in
const gp_Pnt& c = points[tri[2] - 1]; // c++ and express
TopoDS_Wire wire = BRepBuilderAPI_MakePolygon(a, b, c, true).Wire();
TopoDS_Face face = BRepBuilderAPI_MakeFace(wire).Face();
TopoDS_Iterator face_it(face, false);
const TopoDS_Wire& w = TopoDS::Wire(face_it.Value());
const bool reversed = w.Orientation() == TopAbs_REVERSED;
if (reversed) {
face.Reverse();
}
if (face_area(face) > getValue(GV_MINIMAL_FACE_AREA)) {
faces.push_back(face);
}
}
if (faces.empty()) return false;
bool valid_shell = false;
if (faces.size() < getValue(GV_MAX_FACES_TO_SEW)) {
BRepOffsetAPI_Sewing builder;
builder.SetTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMaxTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMinTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
for (std::vector<TopoDS_Face>::const_iterator it = faces.begin(); it != faces.end(); ++it) {
builder.Add(*it);
}
try {
builder.Perform();
shape = builder.SewedShape();
valid_shell = BRepCheck_Analyzer(shape).IsValid();
} catch(...) {}
if (valid_shell) {
try {
ShapeFix_Solid solid;
solid.LimitTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
TopoDS_Solid solid_shape = solid.SolidFromShell(TopoDS::Shell(shape));
if (!solid_shape.IsNull()) {
try {
BRepClass3d_SolidClassifier classifier(solid_shape);
shape = solid_shape;
} catch (...) {}
}
} catch(...) {}
} else {
Logger::Message(Logger::LOG_WARNING, "Failed to sew faceset:", l);
}
}
if (!valid_shell) {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
for (std::vector<TopoDS_Face>::const_iterator it = faces.begin(); it != faces.end(); ++it) {
builder.Add(compound, *it);
}
shape = compound;
}
return true;
}
#endif
+280
View File
@@ -0,0 +1,280 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef IFCGEOMTREE_H
#define IFCGEOMTREE_H
#include "../ifcparse/IfcFile.h"
#include "../ifcgeom/IfcGeomElement.h"
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
#include "../ifcgeom_schema_agnostic/Kernel.h"
#include <NCollection_UBTree.hxx>
#include <BRepBndLib.hxx>
#include <Bnd_Box.hxx>
#include <BRepAlgoAPI_Common.hxx>
#include <BRepAlgoAPI_Cut.hxx>
#include <BRepClass3d_SolidClassifier.hxx>
namespace IfcGeom {
namespace impl {
template <typename T>
class tree {
public:
void add(const T& t, const Bnd_Box& b) {
tree_.Add(t, b);
}
void add(const T& t, const TopoDS_Shape& s) {
Bnd_Box b;
BRepBndLib::AddClose(s, b);
add(t, b);
shapes_[t] = s;
}
std::vector<T> select_box(const T& t, bool completely_within = false, double extend=-1.e-5) const {
typename map_t::const_iterator it = shapes_.find(t);
if (it == shapes_.end()) {
return std::vector<T>();
}
Bnd_Box b;
BRepBndLib::AddClose(it->second, b);
// Gap is assumed to be positive throughout the codebase,
// but at least for IsOut() in the selector a negative
// Gap should work as well.
b.SetGap(b.GetGap() + extend);
return select_box(b, completely_within);
}
std::vector<T> select_box(const gp_Pnt& p) const {
Bnd_Box b;
b.Add(p);
return select_box(b);
}
std::vector<T> select_box(const Bnd_Box& b, bool completely_within = false) const {
selector s(b);
tree_.Select(s);
if (completely_within) {
std::vector<T> ts = s.results();
std::vector<T> ts_filtered;
ts_filtered.reserve(ts.size());
typename std::vector<T>::const_iterator it = ts.begin();
for (; it != ts.end(); ++it) {
const TopoDS_Shape& shp = shapes_.find(*it)->second;
Bnd_Box B;
BRepBndLib::AddClose(shp, B);
// BndBox::CornerMin() /-Max() introduced in OCCT 6.8
double x1, y1, z1, x2, y2, z2;
b.Get(x1, y1, z1, x2, y2, z2);
double gap = B.GetGap();
gp_Pnt p1(x1 - gap, y1 - gap, z1 - gap);
gp_Pnt p2(x2 + gap, y2 + gap, z2 + gap);
if (!b.IsOut(p1) && !b.IsOut(p2)) {
ts_filtered.push_back(*it);
}
}
return ts_filtered;
} else {
return s.results();
}
}
std::vector<T> select(const T& t, bool completely_within = false) const {
std::vector<T> ts = select_box(t);
if (ts.empty()) {
return ts;
}
std::vector<T> ts_filtered;
const TopoDS_Shape& A = shapes_.find(t)->second;
if (IfcGeom::Kernel::count(A, TopAbs_SHELL) == 0) {
return ts_filtered;
}
ts_filtered.reserve(ts.size());
typename std::vector<T>::const_iterator it = ts.begin();
for (it = ts.begin(); it != ts.end(); ++it) {
const TopoDS_Shape& B = shapes_.find(*it)->second;
if (IfcGeom::Kernel::count(B, TopAbs_SHELL) == 0) {
continue;
}
if (completely_within) {
BRepAlgoAPI_Cut cut(B, A);
if (cut.IsDone()) {
if (IfcGeom::Kernel::count(cut.Shape(), 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) {
ts_filtered.push_back(*it);
}
}
}
}
return ts_filtered;
}
std::vector<T> select(const TopoDS_Shape& s) const {
Bnd_Box bb;
BRepBndLib::AddClose(s, bb);
std::vector<T> ts;
if (IfcGeom::Kernel::count(s, TopAbs_SHELL) == 0) {
return ts;
}
ts = select_box(bb);
if (ts.empty()) {
return ts;
}
std::vector<T> ts_filtered;
ts_filtered.reserve(ts.size());
typename std::vector<T>::const_iterator it = ts.begin();
for (it = ts.begin(); it != ts.end(); ++it) {
const TopoDS_Shape& B = shapes_.find(*it)->second;
if (IfcGeom::Kernel::count(B, TopAbs_SHELL) == 0) {
continue;
}
BRepAlgoAPI_Common common(s, B);
if (common.IsDone()) {
if (IfcGeom::Kernel::count(common.Shape(), TopAbs_SHELL) > 0) {
ts_filtered.push_back(*it);
}
}
}
return ts_filtered;
}
std::vector<T> select(const gp_Pnt& p) const {
std::vector<T> ts = select_box(p);
if (ts.empty()) {
return ts;
}
std::vector<T> ts_filtered;
ts_filtered.reserve(ts.size());
typename std::vector<T>::const_iterator it = ts.begin();
for (it = ts.begin(); it != ts.end(); ++it) {
const TopoDS_Shape& B = shapes_.find(*it)->second;
TopExp_Explorer exp(B, TopAbs_SOLID);
for (; exp.More(); exp.Next()) {
BRepClass3d_SolidClassifier cls(exp.Current(), p, 1e-5);
if (cls.State() != TopAbs_OUT) {
ts_filtered.push_back(*it);
break;
}
}
}
return ts_filtered;
}
protected:
typedef NCollection_UBTree<T, Bnd_Box> tree_t;
typedef std::map<T, TopoDS_Shape> map_t;
tree_t tree_;
map_t shapes_;
class selector : public tree_t::Selector
{
public:
selector(const Bnd_Box& b)
: tree_t::Selector()
, bounds_(b)
{}
Standard_Boolean Reject(const Bnd_Box& b) const {
return bounds_.IsOut(b);
}
Standard_Boolean Accept(const T& o) {
results_.push_back(o);
return Standard_True;
}
const std::vector<T>& results() const {
return results_;
}
private:
std::vector<T> results_;
const Bnd_Box& bounds_;
};
};
}
class tree : public impl::tree<IfcUtil::IfcBaseEntity*> {
public:
tree() {};
tree(IfcParse::IfcFile& f) {
add_file(f, IfcGeom::IteratorSettings());
}
tree(IfcParse::IfcFile& f, const IfcGeom::IteratorSettings& settings) {
add_file(f, settings);
}
void add_file(IfcParse::IfcFile& f, const IfcGeom::IteratorSettings& settings) {
IfcGeom::IteratorSettings settings_ = settings;
settings_.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
settings_.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true);
settings_.set(IfcGeom::IteratorSettings::SEW_SHELLS, true);
IfcGeom::Iterator<double> it(settings_, &f);
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());
} while (it.next());
}
}
};
}
#endif
+441 -87
View File
@@ -65,6 +65,8 @@
#include <TopoDS.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopLoc_Location.hxx>
#include <TopTools_ListOfShape.hxx>
@@ -81,11 +83,174 @@
#include <ShapeFix_ShapeTolerance.hxx>
#include <ShapeFix_Solid.hxx>
#include <Geom_BSplineCurve.hxx>
#include <BRepTools_WireExplorer.hxx>
#include <ShapeBuild_ReShape.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include "../ifcgeom/IfcGeom.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
namespace {
// Returns the other vertex of an edge
TopoDS_Vertex other(const TopoDS_Edge& e, const TopoDS_Vertex& v) {
TopoDS_Vertex a, b;
TopExp::Vertices(e, a, b);
return v.IsSame(b) ? a : b;
}
TopoDS_Edge first_edge(const TopoDS_Wire& w) {
TopoDS_Vertex v1, v2;
TopExp::Vertices(w, v1, v2);
TopTools_IndexedDataMapOfShapeListOfShape wm;
TopExp::MapShapesAndAncestors(w, TopAbs_VERTEX, TopAbs_EDGE, wm);
return TopoDS::Edge(wm.FindFromKey(v1).First());
}
// Returns new wire with the edge replaced by a linear edge with the vertex v moved to p
TopoDS_Wire adjust(const TopoDS_Wire& w, const TopoDS_Vertex& v, const gp_Pnt& p) {
BRep_Builder b;
TopoDS_Vertex v2;
b.MakeVertex(v2, p, BRep_Tool::Tolerance(v));
ShapeBuild_ReShape reshape;
reshape.Replace(v.Oriented(TopAbs_FORWARD), v2);
return TopoDS::Wire(reshape.Apply(w));
}
// A wrapper around BRepBuilderAPI_MakeWire that makes sure segments are connected either by moving end points or by adding intermediate segments
class wire_builder {
private:
BRepBuilderAPI_MakeWire mw_;
double p_;
bool override_next_;
gp_Pnt next_override_;
const IfcUtil::IfcBaseClass* inst_;
public:
wire_builder(double p, const IfcUtil::IfcBaseClass* inst = 0) : p_(p), override_next_(false), inst_(inst) {}
void operator()(const TopoDS_Shape& a) {
const TopoDS_Wire& w = TopoDS::Wire(a);
if (override_next_) {
override_next_ = false;
TopoDS_Edge e = first_edge(w);
mw_.Add(adjust(w, TopExp::FirstVertex(e, true), next_override_));
} else {
mw_.Add(w);
}
}
void operator()(const TopoDS_Shape& a, const TopoDS_Shape& b, bool last) {
TopoDS_Wire w1 = TopoDS::Wire(a);
const TopoDS_Wire& w2 = TopoDS::Wire(b);
if (override_next_) {
override_next_ = false;
TopoDS_Edge e = first_edge(w1);
w1 = adjust(w1, TopExp::FirstVertex(e, true), next_override_);
}
TopoDS_Vertex w11, w12, w21, w22;
TopExp::Vertices(w1, w11, w12);
TopExp::Vertices(w2, w21, w22);
gp_Pnt p1 = BRep_Tool::Pnt(w12);
gp_Pnt p2 = BRep_Tool::Pnt(w21);
double dist = p1.Distance(p2);
// Distance is within 2p, this is fine
if (dist < p_) {
mw_.Add(w1);
goto check;
}
// Distance is too large for attempting to move end points, add intermediate edge
if (dist > 1000. * p_) {
mw_.Add(w1);
mw_.Add(BRepBuilderAPI_MakeEdge(p1, p2));
Logger::Message(Logger::LOG_ERROR, "Added additional segment to close gap with length " + boost::lexical_cast<std::string>(dist) + " to:", inst_);
goto check;
}
{
TopTools_IndexedDataMapOfShapeListOfShape wmap1, wmap2;
// Find edges connected to end- and begin vertex
TopExp::MapShapesAndAncestors(w1, TopAbs_VERTEX, TopAbs_EDGE, wmap1);
TopExp::MapShapesAndAncestors(w2, TopAbs_VERTEX, TopAbs_EDGE, wmap2);
const TopTools_ListOfShape& last_edges = wmap1.FindFromKey(w12);
const TopTools_ListOfShape& first_edges = wmap2.FindFromKey(w21);
double _, __;
if (last_edges.Extent() == 1 && first_edges.Extent() == 1) {
Handle(Geom_Curve) c1 = BRep_Tool::Curve(TopoDS::Edge(last_edges.First()), _, __);
Handle(Geom_Curve) c2 = BRep_Tool::Curve(TopoDS::Edge(first_edges.First()), _, __);
const bool is_line1 = c1->DynamicType() == STANDARD_TYPE(Geom_Line);
const bool is_line2 = c2->DynamicType() == STANDARD_TYPE(Geom_Line);
// Adjust the segment that is linear
if (is_line1) {
mw_.Add(adjust(w1, w12, p2));
Logger::Message(Logger::LOG_ERROR, "Adjusted edge end-point with distance " + boost::lexical_cast<std::string>(dist) + " on:", inst_);
} else if (is_line2 && !last) {
mw_.Add(w1);
override_next_ = true;
next_override_ = p1;
Logger::Message(Logger::LOG_ERROR, "Adjusted edge end-point with distance " + boost::lexical_cast<std::string>(dist) + " on:", inst_);
} else {
// If both aren't linear an edge is added
mw_.Add(w1);
mw_.Add(BRepBuilderAPI_MakeEdge(p1, p2));
Logger::Message(Logger::LOG_ERROR, "Added additional segment to close gap with length " + boost::lexical_cast<std::string>(dist) + " to:", inst_);
}
} else {
Logger::Error("Internal error, inconsistent wire segments", inst_);
mw_.Add(w1);
}
}
check:
if (mw_.Error() == BRepBuilderAPI_NonManifoldWire) {
Logger::Error("Non-manifold curve segments:", inst_);
} else if (mw_.Error() == BRepBuilderAPI_DisconnectedWire) {
Logger::Error("Failed to join curve segments:", inst_);
}
}
const TopoDS_Wire& wire() { return mw_.Wire(); }
};
template <typename Fn>
void shape_pair_enumerate(TopTools_ListIteratorOfListOfShape& it, Fn& fn, bool closed) {
bool is_first = true;
TopoDS_Shape first, previous, current;
for (; it.More(); it.Next(), is_first = false) {
current = it.Value();
if (is_first) {
first = current;
} else {
fn(previous, current, false);
}
previous = current;
}
if (closed) {
fn(current, first, true);
} else {
fn(current);
}
}
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire& wire) {
if ( getValue(GV_PLANEANGLE_UNIT)<0 ) {
Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l->entity);
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);
@@ -99,13 +264,33 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
TopoDS_Wire wire_radians, wire_degrees;
try {
succes_radians = IfcGeom::Kernel::convert(l,wire_radians);
} catch (...) {}
} catch (const std::exception& e) {
Logger::Notice(e);
} catch (const Standard_Failure& e) {
if (e.GetMessageString() && strlen(e.GetMessageString())) {
Logger::Notice(e.GetMessageString());
} else {
Logger::Notice("Unknown error using radians");
}
} catch (...) {
Logger::Notice("Unknown error using radians");
}
// Now try degrees
setValue(GV_PLANEANGLE_UNIT,0.0174532925199433);
try {
succes_degrees = IfcGeom::Kernel::convert(l,wire_degrees);
} catch (...) {}
} catch (const std::exception& e) {
Logger::Notice(e);
} catch (const Standard_Failure& e) {
if (e.GetMessageString() && strlen(e.GetMessageString())) {
Logger::Notice(e.GetMessageString());
} else {
Logger::Notice("Unknown error using degrees");
}
} catch (...) {
Logger::Notice("Unknown error using degrees");
}
// Restore to unknown unit state
setValue(GV_PLANEANGLE_UNIT,-1.0);
@@ -139,113 +324,128 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
return use_radians || use_degrees;
}
IfcSchema::IfcCompositeCurveSegment::list::ptr segments = l->Segments();
BRepBuilderAPI_MakeWire w;
//TopoDS_Vertex last_vertex;
for( IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++ it ) {
TopTools_ListOfShape converted_segments;
for (IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++it) {
IfcSchema::IfcCurve* curve = (*it)->ParentCurve();
TopoDS_Wire wire2;
if ( !convert_wire(curve,wire2) ) {
Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve->entity);
TopoDS_Wire segment;
if (!convert_wire(curve, segment)) {
Logger::Message(Logger::LOG_ERROR, "Failed to convert curve:", curve);
continue;
}
if ( ! (*it)->SameSense() ) wire2.Reverse();
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(wire2, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_WIRE);
/*if ( it != segments->begin() ) {
TopExp_Explorer exp (wire2,TopAbs_VERTEX);
const TopoDS_Vertex& first_vertex = TopoDS::Vertex(exp.Current());
gp_Pnt first = BRep_Tool::Pnt(first_vertex);
gp_Pnt last = BRep_Tool::Pnt(last_vertex);
Standard_Real distance = first.Distance(last);
if ( distance > ALMOST_ZERO ) {
w.Add( BRepBuilderAPI_MakeEdge( last_vertex, first_vertex ) );
}
}*/
w.Add(wire2);
//last_vertex = w.Vertex();
if ( w.Error() != BRepBuilderAPI_WireDone ) {
Logger::Message(Logger::LOG_ERROR,"Failed to join curve segments:",l->entity);
return false;
if (!(*it)->SameSense()) {
segment.Reverse();
}
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(segment, getValue(GV_PRECISION), TopAbs_WIRE);
converted_segments.Append(segment);
}
wire = w.Wire();
BRepBuilderAPI_MakeWire w;
TopoDS_Vertex wire_first_vertex, wire_last_vertex, edge_first_vertex, edge_last_vertex;
const double precision_sq_2 = 2 * getValue(GV_PRECISION) * getValue(GV_PRECISION);
TopTools_ListIteratorOfListOfShape it(converted_segments);
IfcEntityList::ptr profile = l->data().getInverse(&IfcSchema::IfcProfileDef::Class(), -1);
const bool force_close = profile && profile->size() > 0;
wire_builder bld(getValue(GV_PRECISION), l);
shape_pair_enumerate(it, bld, force_close);
wire = bld.wire();
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& wire) {
IfcSchema::IfcCurve* basis_curve = l->BasisCurve();
bool isConic = basis_curve->is(IfcSchema::Type::IfcConic);
bool isConic = basis_curve->declaration().is(IfcSchema::IfcConic::Class());
double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT);
Handle(Geom_Curve) curve;
if ( !convert_curve(basis_curve,curve) ) return false;
bool trim_cartesian = l->MasterRepresentation() == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN;
bool trim_cartesian = l->MasterRepresentation() != IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER;
IfcEntityList::ptr trims1 = l->Trim1();
IfcEntityList::ptr trims2 = l->Trim2();
bool trimmed1 = false;
bool trimmed2 = false;
unsigned sense_agreement = l->SenseAgreement() ? 0 : 1;
double flts[2];
gp_Pnt pnts[2];
bool has_flts[2] = {false,false};
bool has_pnts[2] = {false,false};
BRepBuilderAPI_MakeWire w;
for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) {
IfcUtil::IfcBaseClass* i = *it;
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
if ( i->declaration().is(IfcSchema::IfcCartesianPoint::Class()) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] );
has_pnts[sense_agreement] = true;
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
} else if ( i->declaration().is(IfcSchema::IfcParameterValue::Class()) ) {
const double value = *((IfcSchema::IfcParameterValue*)i);
flts[sense_agreement] = value * parameterFactor;
has_flts[sense_agreement] = true;
}
}
for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) {
IfcUtil::IfcBaseClass* i = *it;
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
if ( i->declaration().is(IfcSchema::IfcCartesianPoint::Class()) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] );
has_pnts[1-sense_agreement] = true;
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
} else if ( i->declaration().is(IfcSchema::IfcParameterValue::Class()) ) {
const double value = *((IfcSchema::IfcParameterValue*)i);
flts[1-sense_agreement] = value * parameterFactor;
has_flts[1-sense_agreement] = true;
}
}
trim_cartesian &= has_pnts[0] && has_pnts[1];
bool trim_cartesian_failed = !trim_cartesian;
if ( trim_cartesian ) {
if ( pnts[0].Distance(pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE) ) {
Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l->entity);
if ( pnts[0].Distance(pnts[1]) < 2 * getValue(GV_PRECISION) ) {
Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l);
return false;
}
ShapeFix_ShapeTolerance FTol;
TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(pnts[0]);
TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(pnts[1]);
FTol.SetTolerance(v1, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
FTol.SetTolerance(v2, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
FTol.SetTolerance(v1, getValue(GV_PRECISION), TopAbs_VERTEX);
FTol.SetTolerance(v2, getValue(GV_PRECISION), TopAbs_VERTEX);
BRepBuilderAPI_MakeEdge e (curve,v1,v2);
if ( ! e.IsDone() ) {
BRepBuilderAPI_EdgeError err = e.Error();
if ( err == BRepBuilderAPI_PointProjectionFailed ) {
Logger::Message(Logger::LOG_WARNING,"Point projection failed for:",l->entity);
Logger::Message(Logger::LOG_WARNING,"Point projection failed for:",l);
trim_cartesian_failed = true;
}
} else {
w.Add(e.Edge());
}
}
if ( (!trim_cartesian || trim_cartesian_failed) && (has_flts[0] && has_flts[1]) ) {
// The Geom_Line is constructed from a gp_Pnt and gp_Dir, whereas the IfcLine
// is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because
// the vector is normalised when passed to Geom_Line constructor the magnitude
// needs to be factored in with the IfcParameterValue here.
if ( basis_curve->is(IfcSchema::Type::IfcLine) ) {
if ( basis_curve->declaration().is(IfcSchema::IfcLine::Class()) ) {
IfcSchema::IfcLine* line = static_cast<IfcSchema::IfcLine*>(basis_curve);
const double magnitude = line->Dir()->Magnitude();
flts[0] *= magnitude; flts[1] *= magnitude;
}
if ( basis_curve->is(IfcSchema::Type::IfcEllipse) ) {
if ( basis_curve->declaration().is(IfcSchema::IfcEllipse::Class()) ) {
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);
@@ -255,7 +455,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
flts[1] -= M_PI / 2.;
}
}
if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],(double)(M_PI*2.0)),0.0f) ) {
if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],M_PI*2.),0.) ) {
w.Add(BRepBuilderAPI_MakeEdge(curve));
} else {
BRepBuilderAPI_MakeEdge e (curve,flts[0],flts[1]);
@@ -264,8 +464,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
} else if ( trim_cartesian_failed && (has_pnts[0] && has_pnts[1]) ) {
w.Add(BRepBuilderAPI_MakeEdge(pnts[0],pnts[1]));
}
if ( w.IsDone() ) {
if (w.IsDone()) {
wire = w.Wire();
// When SenseAgreement == .F. the vertices above have been reversed to
// comply with the direction of conical curves. The ordering of the
// vertices then still needs to be reversed in order to have begin and
// end vertex consistent with IFC.
if (sense_agreement != 0) { // .F.
wire.Reverse();
}
return true;
} else {
return false;
@@ -283,14 +493,25 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& resu
polygon.Append(pnt);
}
const double eps = getValue(GV_PRECISION) * 10;
const bool closed_by_proximity = polygon.Length() >= 2 && polygon.First().Distance(polygon.Last()) < eps;
if (closed_by_proximity) {
// tfk: note 1-based
polygon.Remove(polygon.Length());
}
// Remove points that are too close to one another
remove_redundant_points_from_loop(polygon, false);
remove_duplicate_points_from_loop(polygon, closed_by_proximity, eps);
BRepBuilderAPI_MakePolygon w;
for (int i = 1; i <= polygon.Length(); ++i) {
w.Add(polygon.Value(i));
}
if (closed_by_proximity) {
w.Close();
}
result = w.Wire();
return true;
}
@@ -309,21 +530,22 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& resu
// A loop should consist of at least three vertices
int original_count = polygon.Length();
if (original_count < 3) {
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l);
return false;
}
// Remove points that are too close to one another
remove_redundant_points_from_loop(polygon, true);
const double eps = getValue(GV_PRECISION) * 10;
remove_duplicate_points_from_loop(polygon, true, eps);
int count = polygon.Length();
if (original_count - count != 0) {
std::stringstream ss; ss << (original_count - count) << " edges removed for:";
Logger::Message(Logger::LOG_WARNING, ss.str(), l->entity);
Logger::Message(Logger::LOG_WARNING, ss.str(), l);
}
if (count < 3) {
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l);
return false;
}
@@ -333,7 +555,14 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& resu
}
w.Close();
result = w.Wire();
result = w.Wire();
TopTools_ListOfShape results;
if (wire_intersections(result, results)) {
Logger::Error("Self-intersections with " + boost::lexical_cast<std::string>(results.Extent()) + " cycles detected", l);
select_largest(results, result);
}
return true;
}
@@ -344,8 +573,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryOpenProfileDef* l, To
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeCurve* l, TopoDS_Wire& result) {
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry();
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry();
if (!pnt1->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) {
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l->entity);
if (!pnt1->declaration().is(IfcSchema::IfcCartesianPoint::Class()) || !pnt2->declaration().is(IfcSchema::IfcCartesianPoint::Class())) {
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l);
return false;
}
@@ -364,36 +593,53 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeCurve* l, TopoDS_Wire& res
// assumed that a topological wire can be crafted from it. After which an
// attempt is made to reconstruct it from the individual curves and the vertices
// of the IfcEdgeCurve.
const bool is_bounded = l->EdgeGeometry()->is(IfcSchema::Type::IfcBoundedCurve);
const bool is_bounded = l->EdgeGeometry()->declaration().is(IfcSchema::IfcBoundedCurve::Class());
if (!is_bounded && convert_curve(l->EdgeGeometry(), crv)) {
mw.Add(BRepBuilderAPI_MakeEdge(crv, p1, p2));
result = mw;
return true;
} else if (is_bounded && convert_wire(l->EdgeGeometry(), result)) {
if (!l->SameSense()) std::swap(pnt1, pnt2);
TopExp_Explorer exp(result, TopAbs_EDGE);
if (!l->SameSense()) {
result.Reverse();
}
bool first = true;
TopExp_Explorer exp(result, TopAbs_EDGE);
while (exp.More()) {
const TopoDS_Edge& ed = TopoDS::Edge(exp.Current());
Standard_Real u1, u2;
Handle(Geom_Curve) ecrv = BRep_Tool::Curve(ed, u1, u2);
exp.Next();
const bool last = !exp.More();
first = false;
gp_Pnt a, b;
if (first && last) {
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, p1, p2));
a = p1;
b = p2;
} else if (first) {
gp_Pnt pu;
ecrv->D0(u2, pu);
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, p1, pu));
a = p1;
ecrv->D0(u2, b);
} else if (last) {
gp_Pnt pu;
ecrv->D0(u1, pu);
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, pu, p2));
ecrv->D0(u1, a);
b = p2;
} else {
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, u1, u2));
first = false;
continue;
}
BRep_Builder builder;
TopoDS_Vertex v1, v2;
/// @todo project first and emit warnings accordingly
builder.MakeVertex(v1, a, getValue(GV_PRECISION));
builder.MakeVertex(v2, b, getValue(GV_PRECISION));
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, v1, v2));
first = false;
}
result = mw;
return true;
@@ -406,32 +652,140 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeLoop* l, TopoDS_Wire& resu
IfcSchema::IfcOrientedEdge::list::ptr li = l->EdgeList();
BRepBuilderAPI_MakeWire mw;
for (IfcSchema::IfcOrientedEdge::list::it it = li->begin(); it != li->end(); ++it) {
IfcSchema::IfcOrientedEdge* e = *it;
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) e->EdgeStart())->VertexGeometry();
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) e->EdgeEnd())->VertexGeometry();
if (!pnt1->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) {
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l->entity);
return false;
}
gp_Pnt p1, p2;
if (!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
{
return false;
}
mw.Add(BRepBuilderAPI_MakeEdge(p1, p2));
continue;
IfcSchema::IfcEdge* base = e->EdgeElement();
TopoDS_Wire w;
if (convert_wire(e->EdgeElement(), w)) {
if (!e->Orientation()) w.Reverse();
mw.Add(w);
if (convert_wire(*it, w)) {
mw.Add(TopoDS::Edge(TopoDS_Iterator(w).Value()));
}
}
result = mw;
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdge* l, TopoDS_Wire& result) {
if (!l->EdgeStart()->declaration().is(IfcSchema::IfcVertexPoint::Class()) || !l->EdgeEnd()->declaration().is(IfcSchema::IfcVertexPoint::Class())) {
Logger::Message(Logger::LOG_ERROR, "Only IfcVertexPoints are supported for EdgeStart and -End", l);
return false;
}
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry();
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry();
if (!pnt1->declaration().is(IfcSchema::IfcCartesianPoint::Class()) || !pnt2->declaration().is(IfcSchema::IfcCartesianPoint::Class())) {
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l);
return false;
}
gp_Pnt p1, p2;
if (!convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
!convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
{
return false;
}
BRepBuilderAPI_MakeWire mw;
mw.Add(BRepBuilderAPI_MakeEdge(p1, p2));
result = mw.Wire();
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcOrientedEdge* l, TopoDS_Wire& result) {
if (convert_wire(l->EdgeElement(), result)) {
if (!l->Orientation()) {
result.Reverse();
}
return true;
} else {
return false;
}
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSubedge* l, TopoDS_Wire& result) {
TopoDS_Wire temp;
if (convert_wire(l->ParentEdge(), result) && convert((IfcSchema::IfcEdge*) l, temp)) {
TopExp_Explorer exp(result, TopAbs_EDGE);
TopoDS_Edge edge = TopoDS::Edge(exp.Current());
Standard_Real u1, u2;
Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u1, u2);
TopoDS_Vertex v1, v2;
TopExp::Vertices(temp, v1, v2);
BRepBuilderAPI_MakeWire mw;
mw.Add(BRepBuilderAPI_MakeEdge(crv, v1, v2));
result = mw.Wire();
return true;
} else {
return false;
}
}
#ifdef USE_IFC4
#include <GC_MakeCircle.hxx>
bool IfcGeom::Kernel::convert(const IfcSchema::IfcIndexedPolyCurve* l, TopoDS_Wire& result) {
IfcSchema::IfcCartesianPointList* point_list = l->Points();
std::vector< std::vector<double> > coordinates;
if (point_list->as<IfcSchema::IfcCartesianPointList2D>()) {
coordinates = point_list->as<IfcSchema::IfcCartesianPointList2D>()->CoordList();
} else if (point_list->as<IfcSchema::IfcCartesianPointList3D>()) {
coordinates = point_list->as<IfcSchema::IfcCartesianPointList3D>()->CoordList();
}
std::vector<gp_Pnt> points;
points.reserve(coordinates.size());
for (std::vector< std::vector<double> >::const_iterator it = coordinates.begin(); it != coordinates.end(); ++it) {
const std::vector<double>& coords = *it;
points.push_back(gp_Pnt(
coords.size() < 1 ? 0. : coords[0] * getValue(GV_LENGTH_UNIT),
coords.size() < 2 ? 0. : coords[1] * getValue(GV_LENGTH_UNIT),
coords.size() < 3 ? 0. : coords[2] * getValue(GV_LENGTH_UNIT)));
}
int max_index = points.size();
BRepBuilderAPI_MakeWire w;
IfcEntityList::ptr segments = l->Segments();
for (IfcEntityList::it it = segments->begin(); it != segments->end(); ++it) {
IfcUtil::IfcBaseClass* segment = *it;
if (segment->declaration().is(IfcSchema::IfcLineIndex::Class())) {
IfcSchema::IfcLineIndex* line = (IfcSchema::IfcLineIndex*) segment;
std::vector<int> indices = *line;
gp_Pnt previous;
for (std::vector<int>::const_iterator jt = indices.begin(); jt != indices.end(); ++jt) {
if (*jt < 1 || *jt > max_index) {
throw IfcParse::IfcException("IfcIndexedPolyCurve index out of bounds for index " + boost::lexical_cast<std::string>(*jt));
}
const gp_Pnt& current = points[*jt - 1];
if (jt != indices.begin()) {
w.Add(BRepBuilderAPI_MakeEdge(previous, current));
}
previous = current;
}
} else if (segment->declaration().is(IfcSchema::IfcArcIndex::Class())) {
IfcSchema::IfcArcIndex* arc = (IfcSchema::IfcArcIndex*) segment;
std::vector<int> indices = *arc;
if (indices.size() != 3) {
throw IfcParse::IfcException("Invalid IfcArcIndex encountered");
}
for (int i = 0; i < 3; ++i) {
const int& idx = indices[i];
if (idx < 1 || idx > max_index) {
throw IfcParse::IfcException("IfcIndexedPolyCurve index out of bounds for index " + boost::lexical_cast<std::string>(idx));
}
}
const gp_Pnt& a = points[indices[0] - 1];
const gp_Pnt& b = points[indices[1] - 1];
const gp_Pnt& c = points[indices[2] - 1];
Handle(Geom_Circle) circ = GC_MakeCircle(a, b, c).Value();
w.Add(BRepBuilderAPI_MakeEdge(circ, a, c));
} else {
throw IfcParse::IfcException("Unexpected IfcIndexedPolyCurve segment of type " + segment->declaration().name());
}
}
result = w.Wire();
return true;
}
#endif
+62 -12
View File
@@ -18,34 +18,84 @@
********************************************************************************/
#include "IfcGeom.h"
#include "IfcGeomShapeType.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
using namespace IfcSchema;
using namespace IfcUtil;
bool IfcGeom::Kernel::convert_shapes(const IfcBaseClass* l, IfcRepresentationShapeItems& r) {
if (shape_type(l) != ST_SHAPELIST) {
TopoDS_Shape shp;
if (convert_shape(l, shp)) {
r.push_back(IfcGeom::IfcRepresentationShapeItem(shp, get_style(l->as<IfcSchema::IfcRepresentationItem>())));
return true;
}
return false;
}
#include "IfcRegisterConvertShapes.h"
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
return false;
}
bool IfcGeom::Kernel::is_shape_collection(const IfcBaseClass* l) {
#include "IfcRegisterIsShapeCollection.h"
return false;
IfcGeom::ShapeType IfcGeom::Kernel::shape_type(const IfcBaseClass* l) {
#include "IfcRegisterShapeType.h"
return ST_OTHER;
}
bool IfcGeom::Kernel::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) {
const unsigned int id = l->entity->id();
const unsigned int id = l->data().id();
bool success = false;
bool processed = false;
bool ignored = false;
#ifndef NO_CACHE
std::map<int,TopoDS_Shape>::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_SHAPELIST) {
processed = true;
IfcRepresentationShapeItems items;
success = convert_shapes(l, items) && flatten_shape_list(items, r, false);
} else if (st == ST_SHAPE && include_solids_and_surfaces) {
#include "IfcRegisterConvertShape.h"
if ( processed ) {
} else if (st == ST_FACE && include_solids_and_surfaces) {
processed = true;
success = convert_face(l, r);
} else if (st == ST_WIRE && include_curves) {
processed = true;
TopoDS_Wire w;
success = convert_wire(l, w);
if (success) {
r = w;
}
} else if (st == ST_CURVE && include_curves) {
processed = true;
Handle(Geom_Curve) crv;
TopoDS_Wire w;
success = convert_curve(l, crv) && convert_curve_to_wire(crv, w);
if (success) {
r = w;
}
}
if ( processed && success ) {
const double precision = getValue(GV_PRECISION);
apply_tolerance(r, precision);
#ifndef NO_CACHE
cache.Shape[id] = r;
} else {
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
#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;
}
@@ -56,18 +106,18 @@ bool IfcGeom::Kernel::convert_wire(const IfcBaseClass* l, TopoDS_Wire& r) {
if (IfcGeom::Kernel::convert_curve(l, curve)) {
return IfcGeom::Kernel::convert_curve_to_wire(curve, r);
}
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
return false;
}
bool IfcGeom::Kernel::convert_face(const IfcBaseClass* l, TopoDS_Shape& r) {
#include "IfcRegisterConvertFace.h"
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
return false;
}
bool IfcGeom::Kernel::convert_curve(const IfcBaseClass* l, Handle(Geom_Curve)& r) {
#include "IfcRegisterConvertCurve.h"
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
return false;
}
+25 -6
View File
@@ -38,26 +38,36 @@
#include <gp_Trsf.hxx>
#include <gp_Trsf2d.hxx>
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcParse.h"
SHAPES(IfcShellBasedSurfaceModel);
SHAPES(IfcFaceBasedSurfaceModel);
SHAPES(IfcShapeRepresentation);
SHAPES(IfcRepresentation);
SHAPES(IfcMappedItem);
SHAPES(IfcFacetedBrep);
// IfcFacetedBrep included
// IfcAdvancedBrep included
// IfcFacetedBrepWithVoids included
// IfcAdvancedBrepWithVoids included
SHAPES(IfcManifoldSolidBrep);
SHAPES(IfcGeometricSet);
#ifdef USE_IFC4
SHAPE(IfcCylindricalSurface);
SHAPE(IfcAdvancedBrep);
// FIXME: Surfaces should have a shape type of their own
SHAPE(IfcBSplineSurfaceWithKnots);
SHAPE(IfcTriangulatedFaceSet);
SHAPE(IfcExtrudedAreaSolidTapered);
#endif
SHAPE(IfcPlane);
SHAPE(IfcExtrudedAreaSolid);
SHAPE(IfcRevolvedAreaSolid);
SHAPE(IfcConnectedFaceSet);
SHAPE(IfcBooleanResult);
SHAPE(IfcPolygonalBoundedHalfSpace);
SHAPE(IfcHalfSpaceSolid);
// FIXME: Surfaces should have a shape type of their own
SHAPE(IfcSurfaceOfLinearExtrusion);
SHAPE(IfcSurfaceOfRevolution);
SHAPE(IfcBlock);
@@ -71,9 +81,6 @@ SHAPE(IfcRectangularTrimmedSurface);
SHAPE(IfcSurfaceCurveSweptAreaSolid);
SHAPE(IfcSweptDiskSolid);
#ifdef USE_IFC4
FACE(IfcAdvancedFace);
#endif
FACE(IfcArbitraryProfileDefWithVoids);
FACE(IfcArbitraryClosedProfileDef);
FACE(IfcRoundedRectangleProfileDef);
@@ -93,19 +100,31 @@ 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);
#ifdef USE_IFC4
WIRE(IfcIndexedPolyCurve)
#endif
CURVE(IfcCircle);
CURVE(IfcEllipse);
CURVE(IfcLine);
#ifdef USE_IFC4
// IfcRationalBSplineCurveWithKnots included
CURVE(IfcBSplineCurveWithKnots);
#endif
CLASS(IfcCartesianPoint,gp_Pnt);
CLASS(IfcDirection,gp_Dir);
+1 -1
View File
@@ -1,6 +1,6 @@
#include "IfcRegisterUndef.h"
#define CURVE(T) \
if ( l->is(T::Class()) ) return convert((T*)l,r);
if ( l->declaration().is(IfcSchema::T::Class()) ) return convert((IfcSchema::T*)l,r);
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
+1 -1
View File
@@ -1,6 +1,6 @@
#include "IfcRegisterUndef.h"
#define FACE(T) \
if ( l->is(T::Class()) ) return convert((T*)l,r);
if ( l->declaration().is(IfcSchema::T::Class()) ) return convert((IfcSchema::T*)l,r);
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
+14 -5
View File
@@ -1,14 +1,23 @@
#include "IfcRegisterUndef.h"
#define SHAPE(T) \
if ( !processed && l->is(T::Class()) ) { \
if ( !processed && l->declaration().is(IfcSchema::T::Class()) ) { \
processed = true; \
try { \
if ( convert((T*)l,r) ) { \
if ( convert((IfcSchema::T*)l,r) ) { \
success = true; \
} \
} catch(...) { } \
if ( !success) { \
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
} catch (const std::exception& e) { \
Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \
return false; \
} catch (const Standard_Failure& f) { \
if (f.GetMessageString() && strlen(f.GetMessageString())) \
Logger::Message(Logger::LOG_ERROR, std::string("Error in: ") + f.GetMessageString() + "\nFailed to convert:", l); \
else \
Logger::Message(Logger::LOG_ERROR, "Failed to convert:", l); \
return false; \
} \
if (!success) { \
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l); \
return false; \
} \
}
+10 -4
View File
@@ -1,10 +1,16 @@
#include "IfcRegisterUndef.h"
#define SHAPES(T) \
if ( l->is(T::Class()) ) { \
if ( l->declaration().is(IfcSchema::T::Class()) ) { \
try { \
return convert((T*)l,r); \
} catch (...) { } \
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
return convert((IfcSchema::T*)l,r); \
} catch (const std::exception& e) { \
Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \
} catch (const Standard_Failure& f) { \
if (f.GetMessageString()) \
Logger::Message(Logger::LOG_ERROR, std::string("Error in: ") + f.GetMessageString() + "\nFailed to convert:", l); \
else \
Logger::Message(Logger::LOG_ERROR, "Failed to convert:", l); \
} \
return false; \
}
#include "IfcRegisterDef.h"
+1 -1
View File
@@ -1,6 +1,6 @@
#include "IfcRegisterUndef.h"
#define WIRE(T) \
if ( l->is(T::Class()) ) return convert((T*)l,r);
if ( l->declaration().is(IfcSchema::T::Class()) ) return convert((IfcSchema::T*)l,r);
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
@@ -1,6 +0,0 @@
#include "IfcRegisterUndef.h"
#define SHAPES(T) \
if ( l->is(T::Class()) ) return true;
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
+14
View File
@@ -0,0 +1,14 @@
#include "IfcRegisterUndef.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 "IfcRegisterDef.h"
#include "IfcRegister.h"
+3 -2
View File
@@ -23,10 +23,10 @@
#include <gp_GTrsf.hxx>
#include <TopoDS_Shape.hxx>
#include "../ifcgeom/IfcGeomRenderStyles.h"
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
namespace IfcGeom {
class IfcRepresentationShapeItem {
class IFC_GEOM_API IfcRepresentationShapeItem {
private:
gp_GTrsf placement;
TopoDS_Shape shape;
@@ -46,6 +46,7 @@ namespace IfcGeom {
const gp_GTrsf& Placement() const { return placement; }
bool hasStyle() const { return style != 0; }
const SurfaceStyle& Style() const { return *style; }
void setStyle(const SurfaceStyle* style) { this->style = style; }
};
typedef std::vector<IfcRepresentationShapeItem> IfcRepresentationShapeItems;
}
+37
View File
@@ -0,0 +1,37 @@
/********************************************************************************
* *
* 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 IFC_GEOM_API_H
#define IFC_GEOM_API_H
#ifdef IFC_SHARED_BUILD
#ifdef _WIN32
#ifdef IFC_GEOM_EXPORTS
#define IFC_GEOM_API __declspec(dllexport)
#else
#define IFC_GEOM_API __declspec(dllimport)
#endif
#else // simply assume *nix + GCC-like compiler
#define IFC_GEOM_API __attribute__((visibility("default")))
#endif
#else
#define IFC_GEOM_API
#endif
#endif
@@ -0,0 +1,115 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) *
* and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). *
* *
* IfcGeom::Representation::Triangulation is a class that represents a *
* triangulated IfcShapeRepresentation. *
* Triangulation.verts is a 1 dimensional vector of float defining the *
* cartesian coordinates of the vertices of the triangulated shape in the *
* format of [x1,y1,z1,..,xn,yn,zn] *
* Triangulation.faces is a 1 dimensional vector of int containing the *
* indices of the triangles referencing positions in Triangulation.verts *
* Triangulation.edges is a 1 dimensional vector of int in {0,1} that dictates*
* the visibility of the edges that span the faces in Triangulation.faces *
* *
* IfcGeom::Element represents the actual IfcBuildingElements. *
* IfcGeomObject.name is the GUID of the element *
* IfcGeomObject.type is the datatype of the element e.g. IfcWindow *
* IfcGeomObject.mesh is a pointer to an IfcMesh *
* IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the *
* orientation and translation of the mesh in relation to the world origin *
* *
* IfcGeom::Iterator::initialize() *
* finds the most suitable representation contexts. Returns true iff *
* at least a single representation will process successfully *
* *
* IfcGeom::Iterator::get() *
* returns a pointer to the current IfcGeom::Element *
* *
* IfcGeom::Iterator::next() *
* returns true iff a following entity is available for a successive call to *
* IfcGeom::Iterator::get() *
* *
* IfcGeom::Iterator::progress() *
* returns an int in [0..100] that indicates the overall progress *
* *
********************************************************************************/
#ifndef IFCGEOMITERATOR_H
#define IFCGEOMITERATOR_H
#include "../ifcgeom_schema_agnostic/IteratorImplementation.h"
// The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
namespace IfcGeom {
template <typename P = double, typename PP = P>
class Iterator {
private:
Iterator(const Iterator&); // N/I
Iterator& operator=(const Iterator&); // N/I
IfcParse::IfcFile* file_;
IfcGeom::IteratorSettings settings_;
IteratorImplementation<P, PP>* implementation_;
public:
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file)
: file_(file)
, settings_(settings)
{
implementation_ = iterator_implementations<P, PP>().construct(file_->schema()->name(), settings, file);
}
bool initialize() {
return implementation_->initialize();
}
int progress() const { return implementation_->progress(); }
const std::string& unit_name() const { return implementation_->getUnitName(); }
double unit_magnitude() const { return implementation_->getUnitMagnitude(); }
IfcParse::IfcFile* file() const { return implementation_->file(); }
IfcUtil::IfcBaseClass* next() const { return implementation_->next(); }
Element<P, PP>* get() { return implementation_->get(); }
BRepElement<P, PP>* get_native() { return implementation_->get_native(); }
const Element<P, PP>* get_object(int id) { return implementation_->get_object(id); }
IfcUtil::IfcBaseClass* create() { return implementation_->create(); }
};
}
#endif
@@ -30,5 +30,6 @@ const double* IfcGeom::Material::diffuse() const { if (hasDiffuse()) return &((*
const double* IfcGeom::Material::specular() const { if (hasSpecular()) return &((*style->Specular()).R()); else return black; }
double IfcGeom::Material::transparency() const { if (hasTransparency()) return *style->Transparency(); else return 0; }
double IfcGeom::Material::specularity() const { if (hasSpecularity()) return *style->Specularity(); else return 0; }
const std::string IfcGeom::Material::name() const { return style->Name(); }
const std::string &IfcGeom::Material::name() const { return style->Name(); }
const std::string &IfcGeom::Material::original_name() const { return style->original_name(); }
bool IfcGeom::Material::operator==(const IfcGeom::Material& other) const { return style == other.style; }
@@ -22,11 +22,11 @@
#include <string>
#include "../ifcgeom/IfcGeomRenderStyles.h"
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
namespace IfcGeom {
class Material {
class IFC_GEOM_API Material {
private:
const IfcGeom::SurfaceStyle* style;
public:
@@ -41,10 +41,11 @@ namespace IfcGeom {
const double* specular() const;
double transparency() const;
double specularity() const;
const std::string name() const;
const std::string &name() const;
const std::string &original_name() const;
bool operator==(const Material& other) const;
};
}
#endif
#endif
@@ -20,24 +20,20 @@
#ifndef IFCGEOMRENDERSTYLES_H
#define IFCGEOMRENDERSTYLES_H
#ifdef __GNUC__
#include <tr1/array>
#else
#include <array>
#endif
#include "../ifcgeom/ifc_geom_api.h"
#ifdef USE_IFC4
#include "../ifcparse/Ifc4.h"
#else
#include "../ifcparse/Ifc2x3.h"
#endif
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/optional.hpp>
#include <sstream>
namespace IfcGeom {
class SurfaceStyle {
class IFC_GEOM_API SurfaceStyle {
public:
class ColorComponent {
private:
std::tr1::array<double, 3> data;
double data[3];
public:
ColorComponent(double r, double g, double b) {
data[0] = r; data[1] = g; data[2] = b;
@@ -50,24 +46,27 @@ namespace IfcGeom {
double& B() { return data[2]; }
};
private:
boost::optional<std::string> name;
std::string name;
std::string original_name_;
boost::optional<int> id;
boost::optional<ColorComponent> diffuse, specular;
boost::optional<double> transparency;
boost::optional<double> specularity;
public:
SurfaceStyle() {
this->name = "IfcSurfaceStyleShading";
}
SurfaceStyle() : name("surface-style") {}
SurfaceStyle(int id) : id(id) {
std::stringstream sstr;
sstr << "IfcSurfaceStyleShading_" << id;
sstr << "surface-style-" << id;
this->name = sstr.str();
}
SurfaceStyle(const std::string& name) : name(name) {}
SurfaceStyle(int id, const std::string& name) : id(id) {
SurfaceStyle(const std::string& name) : name(name), original_name_(name) {}
SurfaceStyle(int id, const std::string& name) : original_name_(name), id(id)
{
std::stringstream sstr;
sstr << id << "_" << name;
std::string sanitized = name;
boost::to_lower(sanitized);
boost::replace_all(sanitized, " ", "-");
sstr << "surface-style-" << id << "-" << sanitized;
this->name = sstr.str();
}
@@ -76,16 +75,14 @@ namespace IfcGeom {
// pointer addresses of the styles, as they are always referenced
// from out of a global map of some sort.
bool operator==(const SurfaceStyle& other) {
if (name && other.name) {
return *name == *other.name;
} else if (id && other.id) {
return *id == *other.id;
} else {
return false;
}
return name == other.name;
}
const std::string& Name() const { return *name; }
/// ID name, e.g. "surface-style-66675-metal---aluminium"
const std::string& Name() const { return name; }
/// Original name, if available, e.g. "Metal - Aluminium"
const std::string& original_name() const { return original_name_; }
const boost::optional<ColorComponent>& Diffuse() const { return diffuse; }
const boost::optional<ColorComponent>& Specular() const { return specular; }
@@ -97,7 +94,7 @@ namespace IfcGeom {
boost::optional<double>& Specularity() { return specularity; }
};
const SurfaceStyle* get_default_style(const std::string& ifc_type);
IFC_GEOM_API const SurfaceStyle* get_default_style(const std::string& ifc_type);
}
#endif
#endif
@@ -0,0 +1,47 @@
#include "IteratorImplementation.h"
#include <boost/algorithm/string/case_conv.hpp>
template <typename P, typename PP>
IteratorFactoryImplementation<P, PP>& iterator_implementations() {
static IteratorFactoryImplementation<P, PP> impl;
return impl;
}
template IteratorFactoryImplementation<float, float>& iterator_implementations<float, float>();
template IteratorFactoryImplementation<float, double>& iterator_implementations<float, double>();
template IteratorFactoryImplementation<double, double>& iterator_implementations<double, double>();
template <typename P, typename PP>
extern void init_IteratorImplementation_Ifc2x3(IteratorFactoryImplementation<P, PP>*);
template <typename P, typename PP>
extern void init_IteratorImplementation_Ifc4(IteratorFactoryImplementation<P, PP>*);
template <typename P, typename PP>
IteratorFactoryImplementation<P, PP>::IteratorFactoryImplementation() {
init_IteratorImplementation_Ifc2x3(this);
init_IteratorImplementation_Ifc4(this);
}
template <typename P, typename PP>
void IteratorFactoryImplementation<P, PP>::bind(const std::string& schema_name, typename get_factory_type<P, PP>::type fn) {
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
this->insert(std::make_pair(schema_name_lower, fn));
}
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::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);
}
template class IteratorFactoryImplementation<float, float>;
template class IteratorFactoryImplementation<float, double>;
template class IteratorFactoryImplementation<double, double>;
@@ -0,0 +1,75 @@
#ifndef ITERATOR_IMPLEMENTATION_H
#define ITERATOR_IMPLEMENTATION_H
#include "../ifcparse/IfcFile.h"
#include "../ifcgeom/IfcGeomIteratorSettings.h"
#include <boost/function.hpp>
#include <map>
#include <string>
namespace IfcGeom {
template <typename P, typename PP>
class IteratorImplementation;
template <typename P, typename PP>
class Element;
template <typename P, typename PP>
class BRepElement;
}
typedef boost::function2<IfcGeom::IteratorImplementation<float, float>*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*> iterator_float_float_fn;
typedef boost::function2<IfcGeom::IteratorImplementation<float, double>*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*> iterator_float_double_fn;
typedef boost::function2<IfcGeom::IteratorImplementation<double, double>*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*> iterator_double_double_fn;
template <typename P, typename PP>
struct get_factory_type {};
template <>
struct get_factory_type<float, float> {
typedef iterator_float_float_fn type;
};
template <>
struct get_factory_type<float, double> {
typedef iterator_float_double_fn type;
};
template <>
struct get_factory_type<double, double> {
typedef iterator_double_double_fn type;
};
template <typename P, typename PP>
class IteratorFactoryImplementation : public std::map<std::string, typename get_factory_type<P, PP>::type> {
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*);
};
template <typename P, typename PP>
IteratorFactoryImplementation<P, PP>& iterator_implementations();
namespace IfcGeom {
template <typename P, typename PP>
class IteratorImplementation {
public:
virtual bool initialize() = 0;
virtual int progress() const = 0;
virtual const std::string& getUnitName() const = 0;
virtual double getUnitMagnitude() const = 0;
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 const Element<P, PP>* get_object(int id) = 0;
virtual IfcUtil::IfcBaseClass* create() = 0;
};
}
#endif
+49
View File
@@ -0,0 +1,49 @@
#include "Kernel.h"
IfcGeom::Kernel::Kernel(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);
}
}
int IfcGeom::Kernel::count(const TopoDS_Shape& s, TopAbs_ShapeEnum t) {
int i = 0;
TopExp_Explorer exp(s, t);
for (; exp.More(); exp.Next()) {
++i;
}
return i;
}
IfcGeom::impl::KernelFactoryImplementation& IfcGeom::impl::kernel_implementations() {
static KernelFactoryImplementation impl;
return impl;
}
extern void init_KernelImplementation_Ifc2x3(IfcGeom::impl::KernelFactoryImplementation*);
extern void init_KernelImplementation_Ifc4(IfcGeom::impl::KernelFactoryImplementation*);
IfcGeom::impl::KernelFactoryImplementation::KernelFactoryImplementation() {
init_KernelImplementation_Ifc2x3(this);
init_KernelImplementation_Ifc4(this);
}
void IfcGeom::impl::KernelFactoryImplementation::bind(const std::string& schema_name, 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));
}
IfcGeom::Kernel* IfcGeom::impl::KernelFactoryImplementation::construct(const std::string& schema_name, 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);
if (it == end()) {
throw IfcParse::IfcException("No geometry kernel registered for " + schema_name);
}
return it->second(file);
}
+138
View File
@@ -0,0 +1,138 @@
#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 <boost/function.hpp>
#include <TopExp_Explorer.hxx>
namespace {
// LayerAssignments renamed from plural to singular, LayerAssignment, so work around that
IfcEntityList::ptr getLayerAssignments(Ifc2x3::IfcRepresentationItem* item) {
return item->LayerAssignments()->generalize();
}
IfcEntityList::ptr getLayerAssignments(Ifc4::IfcRepresentationItem* item) {
return item->LayerAssignment()->generalize();
}
}
namespace IfcGeom {
template <typename P, typename PP>
class BRepElement;
class Kernel {
private:
Kernel* implementation_;
public:
// Tolerances and settings for various geometrical operations:
enum GeomValue {
// Specifies the deflection of the mesher
// Default: 0.001m / 1mm
GV_DEFLECTION_TOLERANCE,
// Specifies the tolerance of the wire builder, most notably for trimmed curves
// Defailt: 0.0001m / 0.1mm
GV_WIRE_CREATION_TOLERANCE,
// Specifies the minimal area of a face to be included in an IfcConnectedFaceset
// Read-only
GV_MINIMAL_FACE_AREA,
// Specifies the treshold distance under which cartesian points are deemed equal
// Default: 0.00001m / 0.01mm
GV_POINT_EQUALITY_TOLERANCE,
// Specifies maximum number of faces for a shell to be sewed. Sewing shells
// that consist of many faces is really detrimental for the performance.
// Default: 1000
GV_MAX_FACES_TO_SEW,
// The length unit used the creation of TopoDS_Shapes, primarily affects the
// interpretation of IfcCartesianPoints and IfcVector magnitudes
// DefaultL 1.0
GV_LENGTH_UNIT,
// The plane angle unit used for the creation of TopoDS_Shapes, primarily affects
// the interpretation of IfcParamaterValues of IfcTrimmedCurves
// Default: -1.0 (= not set, fist try degrees, then radians)
GV_PLANEANGLE_UNIT,
// The precision used in boolean operations, setting this value too low results
// in artefacts and potentially modelling failures
// Default: 0.00001 (obtained from IfcGeometricRepresentationContext if available)
GV_PRECISION,
// Whether to process shapes of type Face or higher (1) Wire or lower (-1) or all (0)
GV_DIMENSIONALITY
};
Kernel(IfcParse::IfcFile* file_ = 0);
virtual ~Kernel() {}
virtual void setValue(GeomValue var, double value) {
implementation_->setValue(var, value);
}
virtual double getValue(GeomValue var) const {
return implementation_->getValue(var);
}
virtual BRepElement<double, double>* convert(
const IteratorSettings& settings, IfcUtil::IfcBaseClass* representation,
IfcUtil::IfcBaseClass* product)
{
return implementation_->convert(settings, representation, product);
}
virtual IfcRepresentationShapeItems convert(IfcUtil::IfcBaseClass* item) {
return implementation_->convert(item);
}
virtual bool convert(IfcUtil::IfcBaseClass* item, gp_Trsf& trsf) {
return implementation_->convert(item, trsf);
}
static int count(const TopoDS_Shape&, TopAbs_ShapeEnum);
template <typename Schema>
static std::map<std::string, typename Schema::IfcPresentationLayerAssignment*> get_layers(typename Schema::IfcProduct* prod) {
std::map<std::string, typename Schema::IfcPresentationLayerAssignment*> layers;
if (prod->hasRepresentation()) {
IfcEntityList::ptr r = IfcParse::traverse(prod->Representation());
typename Schema::IfcRepresentation::list::ptr representations = r->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) {
layers[(*jt)->Name()] = *jt;
}
}
typename Schema::IfcRepresentationItem::list::ptr items = r->as<typename Schema::IfcRepresentationItem>();
for (typename Schema::IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++it) {
typename Schema::IfcPresentationLayerAssignment::list::ptr a = getLayerAssignments(*it)->template as<typename Schema::IfcPresentationLayerAssignment>();
for (typename Schema::IfcPresentationLayerAssignment::list::it jt = a->begin(); jt != a->end(); ++jt) {
layers[(*jt)->Name()] = *jt;
}
}
}
return layers;
}
};
namespace impl {
typedef boost::function1<Kernel*, IfcParse::IfcFile*> kernel_fn;
class KernelFactoryImplementation : public std::map<std::string, kernel_fn> {
public:
KernelFactoryImplementation();
void bind(const std::string& schema_name, kernel_fn);
Kernel* construct(const std::string& schema_name, IfcParse::IfcFile*);
};
KernelFactoryImplementation& kernel_implementations();
}
}
#endif
@@ -0,0 +1,30 @@
#include "Serialization.h"
#include <boost/algorithm/string/case_conv.hpp>
namespace IfcGeom {
extern IfcUtil::IfcBaseClass* tesselate_Ifc2x3(const TopoDS_Shape& shape, double deflection);
extern IfcUtil::IfcBaseClass* tesselate_Ifc4(const TopoDS_Shape& shape, double deflection);
extern IfcUtil::IfcBaseClass* serialise_Ifc2x3(const TopoDS_Shape& shape, bool advanced);
extern IfcUtil::IfcBaseClass* serialise_Ifc4(const TopoDS_Shape& shape, bool advanced);
}
template <typename Fn, typename T>
IfcUtil::IfcBaseClass* execute_based_on_schema(Fn fn1, Fn fn2, const std::string& schema_name, const TopoDS_Shape& shape, T t) {
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
if (schema_name_lower == "ifc2x3") {
return fn1(shape, t);
} else if (schema_name_lower == "ifc4") {
return fn2(shape, t);
} else {
throw IfcParse::IfcException("No geometry serialization available for " + schema_name);
}
}
IfcUtil::IfcBaseClass* IfcGeom::tesselate(const std::string& schema_name, const TopoDS_Shape& shape, double deflection) {
return execute_based_on_schema(IfcGeom::tesselate_Ifc2x3, IfcGeom::tesselate_Ifc4, schema_name, shape, deflection);
}
IfcUtil::IfcBaseClass* IfcGeom::serialise(const std::string& schema_name, const TopoDS_Shape& shape, bool advanced) {
return execute_based_on_schema(IfcGeom::serialise_Ifc2x3, IfcGeom::serialise_Ifc4, schema_name, shape, advanced);
}
@@ -0,0 +1,11 @@
#include "../ifcgeom/ifc_geom_api.h"
#include "../ifcparse/IfcBaseClass.h"
#include <TopoDS_Shape.hxx>
#include <string>
namespace IfcGeom {
IFC_GEOM_API IfcUtil::IfcBaseClass* tesselate(const std::string& schema_name, const TopoDS_Shape& shape, double deflection);
IFC_GEOM_API IfcUtil::IfcBaseClass* serialise(const std::string& schema_name, const TopoDS_Shape& shape, bool advanced);
}
@@ -0,0 +1,57 @@
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
#include <map>
static std::map<std::string, IfcGeom::SurfaceStyle> default_materials;
static IfcGeom::SurfaceStyle default_material;
static bool default_materials_initialized = false;
void InitDefaultMaterials() {
default_materials.insert(std::make_pair("IfcSite", IfcGeom::SurfaceStyle("IfcSite")));
default_materials["IfcSite"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.8, 0.65));
default_materials.insert(std::make_pair("IfcSlab", IfcGeom::SurfaceStyle("IfcSlab")));
default_materials["IfcSlab"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.4, 0.4, 0.4));
default_materials.insert(std::make_pair("IfcWallStandardCase", IfcGeom::SurfaceStyle("IfcWallStandardCase")));
default_materials["IfcWallStandardCase"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.9, 0.9, 0.9));
default_materials.insert(std::make_pair("IfcWall", IfcGeom::SurfaceStyle("IfcWall")));
default_materials["IfcWall"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.9, 0.9, 0.9));
default_materials.insert(std::make_pair("IfcWindow", IfcGeom::SurfaceStyle("IfcWindow")));
default_materials["IfcWindow"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.8, 0.75));
default_materials["IfcWindow"].Transparency().reset(0.3);
default_materials.insert(std::make_pair("IfcDoor", IfcGeom::SurfaceStyle("IfcDoor")));
default_materials["IfcDoor"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.55, 0.3, 0.15));
default_materials.insert(std::make_pair("IfcBeam", IfcGeom::SurfaceStyle("IfcBeam")));
default_materials["IfcBeam"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.7, 0.7));
default_materials.insert(std::make_pair("IfcRailing", IfcGeom::SurfaceStyle("IfcRailing")));
default_materials["IfcRailing"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.65, 0.6, 0.6));
default_materials.insert(std::make_pair("IfcMember", IfcGeom::SurfaceStyle("IfcMember")));
default_materials["IfcMember"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.65, 0.6, 0.6));
default_materials.insert(std::make_pair("IfcPlate", IfcGeom::SurfaceStyle("IfcPlate")));
default_materials["IfcPlate"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.8, 0.8, 0.8));
default_material = IfcGeom::SurfaceStyle("DefaultMaterial");
default_material.Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.7, 0.7, 0.7));
default_materials_initialized = true;
}
const IfcGeom::SurfaceStyle* IfcGeom::get_default_style(const std::string& s) {
if (!default_materials_initialized) InitDefaultMaterials();
std::map<std::string, IfcGeom::SurfaceStyle>::const_iterator it = default_materials.find(s);
if (it == default_materials.end()) {
default_materials.insert(std::make_pair(s, IfcGeom::SurfaceStyle(s)));
default_materials[s].Diffuse().reset(*default_material.Diffuse());
it = default_materials.find(s);
}
const IfcGeom::SurfaceStyle& surface_style = it->second;
return &surface_style;
}
+275 -49
View File
@@ -27,23 +27,43 @@
#include <iostream>
#include <boost/cstdint.hpp>
#if defined(_WIN32) && !defined(__CYGWIN__)
// NB: Streams are only re-opened as binary when compiled with MSVC currently.
// It is unclear what the correct behaviour would be compiled with e.g MinGW
#if defined(_MSC_VER)
#define SET_BINARY_STREAMS
#endif
#ifdef SET_BINARY_STREAMS
#include <io.h>
#include <fcntl.h>
#endif
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
#include "../ifcgeom/IfcGeomElement.h"
#include "../ifcparse/IfcFile.h"
#include "../ifcparse/IfcLogger.h"
#if USE_VLD
#include <vld.h>
#endif
#include <GProp_GProps.hxx>
#include <BRepGProp.hxx>
#include <Geom_Plane.hxx>
using namespace boost;
template <typename T>
union data_field {
char buffer[sizeof(T)];
T value;
};
template <typename T>
T sread(std::istream& s) {
char buf[sizeof(T)];
s.read(buf, sizeof(T));
return *((T*)buf);
data_field<T> data;
s.read(data.buffer, sizeof(T));
return data.value;
}
template <>
@@ -54,10 +74,21 @@ std::string sread(std::istream& s) {
buf[len] = 0;
while (len++ % 4) s.get();
std::string str(buf);
delete buf;
delete[] buf;
return str;
}
template <typename T>
std::string format_json(const T& t) {
return boost::lexical_cast<std::string>(t);
}
template <>
std::string format_json(const std::string& s) {
// NB: No escaping whatsoever. Only use alphanumeric values.
return "\"" + s + "\"";
}
static std::streambuf *stdout_orig, *stdout_redir;
template <typename T>
@@ -69,7 +100,7 @@ void swrite(std::ostream& s, T t) {
template <>
void swrite(std::ostream& s, std::string t) {
int32_t len = t.size();
int32_t len = (int32_t)t.size();
swrite(s, len);
s.write(t.c_str(), len);
while (len++ % 4) s.put(0);
@@ -109,6 +140,8 @@ const int32_t NEXT = MORE + 1;
const int32_t BYE = NEXT + 1;
const int32_t GET_LOG = BYE + 1;
const int32_t LOG = GET_LOG + 1;
const int32_t DEFLECTION = LOG + 1;
const int32_t SETTING = DEFLECTION + 1;
class Hello : public Command {
private:
@@ -122,7 +155,7 @@ protected:
}
public:
const std::string& string() { return str; }
Hello() : Command(HELLO), str("IfcOpenShell-" IFCOPENSHELL_VERSION) {}
Hello() : Command(HELLO), str("IfcOpenShell-" IFCOPENSHELL_VERSION "-0") {}
};
class More : public Command {
@@ -156,16 +189,16 @@ public:
class Get : public Command {
protected:
void read_content(std::istream& s) {}
void write_content(std::ostream& s) {}
void read_content(std::istream& /*s*/) {}
void write_content(std::ostream& /*s*/) {}
public:
Get() : Command(GET) {};
};
class GetLog : public Command {
protected:
void read_content(std::istream& s) {}
void write_content(std::ostream& s) {}
void read_content(std::istream& /*s*/) {}
void write_content(std::ostream& /*s*/) {}
public:
GetLog() : Command(GET_LOG) {};
};
@@ -184,38 +217,74 @@ public:
WriteLog(const std::string& str) : Command(LOG), str(str) {};
};
class EntityExtension {
public:
virtual void write_contents(std::ostream& s) = 0;
};
class Entity : public Command {
private:
const IfcGeom::TriangulationElement<float>* geom;
const IfcGeom::TriangulationElement<float, double>* geom;
bool append_line_data;
EntityExtension* eext_;
protected:
void read_content(std::istream& s) {}
void read_content(std::istream& /*s*/) {}
void write_content(std::ostream& s) {
swrite<int32_t>(s, geom->id());
swrite(s, geom->guid());
swrite(s, geom->name());
swrite(s, geom->type());
swrite<int32_t>(s, geom->parent_id());
const std::vector<float>& m = geom->transformation().matrix().data();
const float matrix_array[16] = {
const std::vector<double>& m = geom->transformation().matrix().data();
const double matrix_array[16] = {
m[0], m[3], m[6], m[ 9],
m[1], m[4], m[7], m[10],
m[2], m[5], m[8], m[11],
0, 0, 0, 1
};
swrite(s, std::string((char*)matrix_array, 16 * sizeof(float)));
swrite<int32_t>(s, geom->geometry().id());
swrite(s, std::string((char*)matrix_array, 16 * sizeof(double)));
// The first bit of the string is always the instance name of the representation.
const std::string& representation_id = geom->geometry().id();
const int integer_representation_id = atoi(representation_id.c_str());
swrite<int32_t>(s, (int32_t)integer_representation_id);
swrite(s, std::string((char*)geom->geometry().verts().data(), geom->geometry().verts().size() * sizeof(float)));
swrite(s, std::string((char*)geom->geometry().normals().data(), geom->geometry().normals().size() * sizeof(float)));
{ std::vector<int32_t> indices;
for (std::vector<int>::const_iterator it = geom->geometry().faces().begin(); it != geom->geometry().faces().end(); ++it) {
indices.push_back(*it);
}
swrite(s, std::string((char*) indices.data(), indices.size() * sizeof(int32_t))); }
{
std::vector<int32_t> indices;
const std::vector<int>& faces = geom->geometry().faces();
indices.reserve(faces.size());
for (std::vector<int>::const_iterator it = faces.begin(); it != faces.end(); ++it) {
indices.push_back(*it);
}
swrite(s, std::string((char*) indices.data(), indices.size() * sizeof(int32_t)));
if (append_line_data) {
std::vector<int32_t> lines;
std::set<int32_t> faces_set (indices.begin(), indices.end());
const std::vector<int>& edges = geom->geometry().edges();
for ( std::vector<int>::const_iterator it = edges.begin(); it != edges.end(); ) {
const int32_t i1 = *(it++);
const int32_t i2 = *(it++);
if (faces_set.find(i1) != faces_set.end() || faces_set.find(i2) != faces_set.end()) {
continue;
}
lines.push_back(i1);
lines.push_back(i2);
}
swrite(s, std::string((char*) lines.data(), lines.size() * sizeof(int32_t)));
}
}
{ std::vector<float> diffuse_color_array;
for (std::vector<IfcGeom::Material>::const_iterator it = geom->geometry().materials().begin(); it != geom->geometry().materials().end(); ++it) {
const IfcGeom::Material& m = *it;
if (m.hasDiffuse()) {
const double* color = m.diffuse();
const IfcGeom::Material& mat = *it;
if (mat.hasDiffuse()) {
const double* color = mat.diffuse();
diffuse_color_array.push_back(static_cast<float>(color[0]));
diffuse_color_array.push_back(static_cast<float>(color[1]));
diffuse_color_array.push_back(static_cast<float>(color[2]));
@@ -224,8 +293,8 @@ protected:
diffuse_color_array.push_back(0.f);
diffuse_color_array.push_back(0.f);
}
if (m.hasTransparency()) {
diffuse_color_array.push_back(static_cast<float>(1. - m.transparency()));
if (mat.hasTransparency()) {
diffuse_color_array.push_back(static_cast<float>(1. - mat.transparency()));
} else {
diffuse_color_array.push_back(1.f);
}
@@ -236,32 +305,155 @@ protected:
material_indices.push_back(*it);
}
swrite(s, std::string((char*) material_indices.data(), material_indices.size() * sizeof(int32_t))); }
if (eext_) {
eext_->write_contents(s);
}
}
public:
Entity(const IfcGeom::TriangulationElement<float>* geom) : Command(ENTITY), geom(geom) {};
Entity(const IfcGeom::TriangulationElement<float, double>* geom, EntityExtension* eext = 0) : Command(ENTITY), geom(geom), append_line_data(false), eext_(eext) {};
};
class Next : public Command {
protected:
void read_content(std::istream& s) {}
void write_content(std::ostream& s) {}
void read_content(std::istream& /*s*/) {}
void write_content(std::ostream& /*s*/) {}
public:
Next() : Command(NEXT) {};
};
class Bye : public Command {
protected:
void read_content(std::istream& s) {}
void write_content(std::ostream& s) {}
void read_content(std::istream& /*s*/) {}
void write_content(std::ostream& /*s*/) {}
public:
Bye() : Command(BYE) {};
};
int main (int argc, char** argv) {
if (sizeof(float) != 4 || sizeof(int32_t) != 4) {
return 1;
class Deflection : public Command {
private:
double deflection_;
protected:
void read_content(std::istream& s) {
deflection_ = sread<double>(s);
}
void write_content(std::ostream& s) {
swrite(s, deflection_);
}
public:
Deflection(double d = 0.) : Command(DEFLECTION), deflection_(d) {};
double deflection() const { return deflection_; }
};
class Setting : public Command {
private:
uint32_t id_;
uint32_t value_;
protected:
void read_content(std::istream& s) {
id_ = sread<uint32_t>(s);
value_ = sread<uint32_t>(s);
}
void write_content(std::ostream& s) {
swrite(s, id_);
swrite(s, value_);
}
public:
Setting(uint32_t k = 0, uint32_t v = 0) : Command(DEFLECTION), id_(k), value_(v) {};
uint32_t id() const { return id_; }
uint32_t value() const { return value_; }
};
static const std::string TOTAL_SURFACE_AREA = "TOTAL_SURFACE_AREA";
static const std::string TOTAL_SHAPE_VOLUME = "TOTAL_SHAPE_VOLUME";
static const std::string WALKABLE_SURFACE_AREA = "WALKABLE_SURFACE_AREA";
static const double MAX_WALKABLE_SURFACE_ANGLE_DEGREES = 15.;
class QuantityWriter : public EntityExtension {
private:
const IfcGeom::BRepElement<float, double>* elem_;
public:
QuantityWriter(const IfcGeom::BRepElement<float, double>* elem) :
elem_(elem)
{}
void write_contents(std::ostream& s) {
double total_surface_area = 0.;
double total_shape_volume = 0.;
double walkable_surface_area = 0.;
TopoDS_Shape moved_shape = elem_->geometry().as_compound();
{
GProp_GProps prop_area;
BRepGProp::SurfaceProperties(moved_shape, prop_area);
total_surface_area += prop_area.Mass();
}
{
GProp_GProps prop_volume;
BRepGProp::VolumeProperties(moved_shape, prop_volume);
total_shape_volume += prop_volume.Mass();
}
if (elem_->type() == "IfcSpace") {
TopExp_Explorer exp(moved_shape, TopAbs_FACE);
for (; exp.More(); exp.Next()) {
const TopoDS_Face& face = TopoDS::Face(exp.Current());
Handle(Geom_Surface) surf = BRep_Tool::Surface(face);
// Assume we can only walk on planar surfaces
if (surf->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
continue;
}
BRepGProp_Face prop(face);
double u0, u1, v0, v1;
BRepTools::UVBounds(face, u0, u1, v0, v1);
gp_Pnt p;
gp_Vec normal_direction;
prop.Normal((u0 + u1) / 2., (v0 + v1) / 2., p, normal_direction);
gp_Vec normal(0., 0., 0.);
if (normal_direction.Magnitude() > 1.e-5) {
normal = gp_Dir(normal_direction.XYZ());
}
if (normal.Angle(gp::DZ()) < (MAX_WALKABLE_SURFACE_ANGLE_DEGREES * M_PI / 180.0)) {
GProp_GProps prop_face;
BRepGProp::SurfaceProperties(face, prop_face);
walkable_surface_area += prop_face.Mass();
}
}
}
// TODO: Manual JSON formatting is always a bad idea
std::ostringstream ss;
ss.write("{", 1);
ss << format_json(TOTAL_SURFACE_AREA);
ss.write(":", 1);
ss << format_json(total_surface_area);
ss.write(",", 1);
ss << format_json(TOTAL_SHAPE_VOLUME);
ss.write(":", 1);
ss << format_json(total_shape_volume);
if (elem_->type() == "IfcSpace") {
ss.write(",", 1);
ss << format_json(WALKABLE_SURFACE_AREA);
ss.write(":", 1);
ss << format_json(walkable_surface_area);
}
ss.write("}", 1);
// We do a 4-byte manual alignment
std::string payload = ss.str();
s << payload;
if (payload.size() % 4) {
s << std::string(4 - (payload.size() % 4), ' ');
}
}
};
int main () {
// Redirect stdout to this stream, so that involuntary
// writes to stdout do not interfere with our protocol.
std::ostringstream oss;
@@ -276,14 +468,17 @@ int main (int argc, char** argv) {
std::cin.setf(std::ios_base::binary);
#endif
double deflection = 1.e-3;
bool has_more = false;
IfcGeom::Iterator<float>* iterator = 0;
IfcGeom::Iterator<float, double>* iterator = 0;
IfcParse::IfcFile* file = 0;
std::vector< std::pair<uint32_t, uint32_t> > setting_pairs;
Hello().write(std::cout);
int exit_code = 0;
while (1) {
for (;;) {
const int32_t msg_type = sread<int32_t>(std::cin);
switch (msg_type) {
case IFC_MODEL: {
@@ -293,13 +488,21 @@ int main (int argc, char** argv) {
memcpy(data, m.string().c_str(), len);
IfcGeom::IteratorSettings settings;
settings.use_world_coords() = false;
settings.weld_vertices() = false;
settings.convert_back_units() = true;
settings.force_ccw_face_orientation() = true;
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false);
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false);
settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, true);
// settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, true);
iterator = new IfcGeom::Iterator<float>(settings, data, len);
has_more = iterator->findContext();
std::vector< std::pair<uint32_t, uint32_t> >::const_iterator it = setting_pairs.begin();
for (; it != setting_pairs.end(); ++it) {
settings.set(it->first, it->second != 0);
}
settings.set_deflection_tolerance(deflection);
file = new IfcParse::IfcFile(data, (int)len);
iterator = new IfcGeom::Iterator<float, double>(settings, file);
has_more = iterator->initialize();
More(has_more).write(std::cout);
continue;
@@ -310,15 +513,18 @@ int main (int argc, char** argv) {
exit_code = 1;
break;
}
const IfcGeom::TriangulationElement<float>* geom = static_cast<const IfcGeom::TriangulationElement<float>*>(iterator->get());
Entity(geom).write(std::cout);
const IfcGeom::TriangulationElement<float, double>* geom = static_cast<const IfcGeom::TriangulationElement<float, double>*>(iterator->get());
QuantityWriter eext(iterator->get_native());
Entity(geom, &eext).write(std::cout);
continue;
}
case NEXT: {
Next n; n.read(std::cin);
has_more = iterator->next();
has_more = iterator->next() != 0;
if (!has_more) {
delete file;
delete iterator;
file = 0;
iterator = 0;
}
More(has_more).write(std::cout);
@@ -326,7 +532,7 @@ int main (int argc, char** argv) {
}
case GET_LOG: {
GetLog gl; gl.read(std::cin);
WriteLog(iterator->getLog()).write(std::cout);
WriteLog(Logger::GetLog()).write(std::cout);
continue;
}
case BYE: {
@@ -334,7 +540,27 @@ int main (int argc, char** argv) {
exit_code = 0;
break;
}
default:
case DEFLECTION: {
Deflection d; d.read(std::cin);
if (!iterator) {
deflection = d.deflection();
continue;
} else {
exit_code = 1;
break;
}
}
case SETTING: {
Setting s; s.read(std::cin);
if (!iterator) {
setting_pairs.push_back(std::make_pair(s.id(), s.value()));
continue;
} else {
exit_code = 1;
break;
}
}
default:
exit_code = 1;
break;
}
+4
View File
@@ -0,0 +1,4 @@
IfcGeomServer
-------------
A command-line executable intented to be ran as a child process that receives an IFC model from stdin and will send binary geometry information of products found in the IFC file in separate messages on stdout. The advantage over conventional static or dynamic linking is that, in case the IfcOpenShell process would crash (either due to invalid input, heap overflow, bugs, ...), this does not affect the main process. Currently, the only implementation of a consumer for this process is the Java module over at: https://github.com/opensourceBIM/IfcOpenShell-BIMserver-plugin/blob/master/src/org/ifcopenshell/IfcGeomServerClient.java
+40
View File
@@ -0,0 +1,40 @@
################################################################################
# #
# 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_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} ${ICU_INCLUDE_DIR}
${Boost_INCLUDE_DIRS} ${THREEDS_MAX_SDK_HOME}/include
)
# All recent versions of 3ds Max (2014 and newer) are 64-bit only so assume lib/x64 directory
LINK_DIRECTORIES(${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} ${OPENCOLLADA_LIBRARY_DIR}
${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS} ${THREEDS_MAX_SDK_HOME}/lib/x64/Release
)
ADD_LIBRARY(IfcMax SHARED IfcMax.h IfcMax.cpp)
# TODO: find the minimal subset of 3dsmax libraries to reference
TARGET_LINK_LIBRARIES(IfcMax ${IFCOPENSHELL_LIBRARIES} Comctl32.lib zlibdll.lib bmm.lib core.lib CustDlg.lib edmodel.lib expr.lib
flt.lib geom.lib gfx.lib gup.lib imageViewers.lib ManipSys.lib maxnet.lib Maxscrpt.lib
maxutil.lib MenuMan.lib menus.lib mesh.lib MNMath.lib Paramblk2.lib particle.lib Poly.lib RenderUtil.lib
tessint.lib viewfile.lib ${OPENCASCADE_LIBRARIES}
)
SET_TARGET_PROPERTIES(IfcMax PROPERTIES SUFFIX ".dli")
INSTALL(TARGETS IfcMax RUNTIME DESTINATION ${BINDIR})
+89 -50
View File
@@ -17,49 +17,57 @@
* *
********************************************************************************/
#include <Max.h>
#include <map>
#include <set>
#include <stdmat.h>
#include <istdplug.h>
#include "../ifcmax/IfcMax.h"
#include "IfcMax.h"
#include "../ifcgeom/IfcGeomIterator.h"
static const int NUM_MATERIAL_SLOTS = 24;
int controlsInit = false;
BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) {
BOOL WINAPI DllMain(HINSTANCE /*hinstDLL*/, ULONG /*fdwReason*/, LPVOID /*lpvReserved*/) {
static int controlsInit = false;
if (!controlsInit) {
controlsInit = true;
InitCommonControls();
}
return true;
}
return TRUE;
}
__declspec( dllexport ) const TCHAR* LibDescription() {
return _T("IfcOpenShell IFC Importer");
}
__declspec( dllexport ) int LibNumberClasses() { return 1; }
static class IFCImpClassDesc:public ClassDesc {
static class IFCImpClassDesc :public ClassDesc {
public:
int IsPublic() {return 1;}
void * Create(BOOL loading = FALSE) {return new IFCImp;}
const TCHAR * ClassName() {return _T("IFCImp");}
SClass_ID SuperClassID() {return SCENE_IMPORT_CLASS_ID;}
Class_ID ClassID() {return Class_ID(0x3f230dbf, 0x5b3015c2);}
const TCHAR* Category() {return _T("Chrutilities");}
int IsPublic() { return 1; }
void * Create(BOOL /*loading = FALSE*/) { return new IFCImp; }
// TODO Delete() function?
const TCHAR * ClassName() { return _T("IFCImp"); }
SClass_ID SuperClassID() { return SCENE_IMPORT_CLASS_ID; }
Class_ID ClassID() { return Class_ID(0x3f230dbf, 0x5b3015c2); }
const TCHAR* Category() { return _T("Chrutilities"); }
} IFCImpDesc;
__declspec( dllexport ) ClassDesc* LibClassDesc(int i) {
return i == 0 ? &IFCImpDesc : 0;
#define DLLEXPORT __declspec(dllexport)
extern "C" {
DLLEXPORT const TCHAR* LibDescription() {
return _T("IfcOpenShell IFC Importer");
}
__declspec( dllexport ) ULONG LibVersion() {
return VERSION_3DSMAX;
DLLEXPORT int LibNumberClasses() { return 1; }
DLLEXPORT ClassDesc* LibClassDesc(int i) {
return i == 0 ? &IFCImpDesc : 0;
}
DLLEXPORT ULONG LibVersion() {
return VERSION_3DSMAX;
}
} // extern "C"
int IFCImp::ExtCount() { return 1; }
const TCHAR * IFCImp::Ext(int n) {
@@ -79,7 +87,7 @@ const TCHAR * IFCImp::AuthorName() {
}
const TCHAR * IFCImp::CopyrightMessage() {
return _T("Copyight (c) 2011 IfcOpenShell");
return _T("Copyright (c) 2011-2016 IfcOpenShell");
}
const TCHAR * IFCImp::OtherMessage1() {
@@ -94,13 +102,14 @@ unsigned int IFCImp::Version() {
return 12;
}
static BOOL CALLBACK AboutBoxDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
return TRUE;
}
// TODO Use this in IFCImp::ShowAbout() if/when wanted
//static BOOL CALLBACK AboutBoxDlgProc(HWND /*hWnd*/, UINT /*msg*/, WPARAM /*wParam*/, LPARAM /*lParam*/) {
// return TRUE;
//}
void IFCImp::ShowAbout(HWND hWnd) {}
void IFCImp::ShowAbout(HWND /*hWnd*/) {}
DWORD WINAPI fn(LPVOID arg) { return 0; }
DWORD WINAPI fn(LPVOID /*arg*/) { return 0; }
#if MAX_RELEASE > 14000
# define S(x) (TSTR::FromCStr(x.c_str()))
@@ -110,8 +119,9 @@ DWORD WINAPI fn(LPVOID arg) { return 0; }
# define S(x) (CStr(x.c_str()))
#endif
Mtl* FindMaterialByName(MtlBaseLib* library, const std::string& material_name) {
const int mat_index = library->FindMtlByName(S(material_name));
static Mtl* FindMaterialByName(MtlBaseLib* library, const std::string& material_name) {
TSTR mat_name = S(material_name);
const int mat_index = library->FindMtlByName(mat_name);
Mtl* m = 0;
if (mat_index != -1) {
m = static_cast<Mtl*>((*library)[mat_index]);
@@ -119,7 +129,7 @@ Mtl* FindMaterialByName(MtlBaseLib* library, const std::string& material_name) {
return m;
}
Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& slot, const IfcGeom::Material& material) {
static Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& slot, const IfcGeom::Material& material) {
Mtl* m = FindMaterialByName(library, material.name());
if (m == 0) {
StdMat2* stdm = NewDefaultStdMat();
@@ -133,10 +143,10 @@ Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& sl
stdm->SetSpecular(Color(specular[0], specular[1], specular[2]),t);
}
if (material.hasSpecularity()) {
stdm->SetShininess(material.specularity(), t);
stdm->SetShininess((float)material.specularity(), t);
}
if (material.hasTransparency()) {
stdm->SetOpacity(1.0 - material.transparency(), t);
stdm->SetOpacity(1.0f - (float)material.transparency(), t);
}
m = stdm;
m->SetName(S(material.name()));
@@ -148,7 +158,10 @@ Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& sl
return m;
}
Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi_mats, MtlBaseLib* library, Interface* max_interface, int& slot, const std::vector<IfcGeom::Material>& materials, const std::string& object_type, const std::vector<int>& material_ids) {
static Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi_mats, MtlBaseLib* library,
Interface* max_interface, int& slot, const std::vector<IfcGeom::Material>& materials,
const std::string& object_type, const std::vector<int>& material_ids)
{
std::vector<std::string> material_names;
bool needs_default = std::find(material_ids.begin(), material_ids.end(), -1) != material_ids.end();
if (needs_default) {
@@ -181,7 +194,7 @@ Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi_mats,
return i->second;
}
MultiMtl* multi_mat = NewDefaultMultiMtl();
multi_mat->SetNumSubMtls(material_names.size());
multi_mat->SetNumSubMtls((int)material_names.size());
int mtl_id = 0;
if (needs_default) {
multi_mat->SetSubMtlAndName(mtl_id ++, default_material, default_material->GetName());
@@ -198,12 +211,12 @@ Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi_mats,
return multi_mat;
}
int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, BOOL suppressPrompts) {
int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, BOOL /*suppressPrompts*/) {
IfcGeom::IteratorSettings settings;
settings.use_world_coords() = false;
settings.weld_vertices() = true;
settings.sew_shells() = true;
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false);
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, true);
settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, true);
#ifdef _UNICODE
int fn_buffer_size = WideCharToMultiByte(CP_UTF8, 0, name, -1, 0, 0, 0, 0);
@@ -214,8 +227,8 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
#endif
IfcGeom::Iterator<float> iterator(settings, fn_mb);
if (!iterator.findContext()) return false;
delete fn_mb;
if (!iterator.initialize()) return false;
itfc->ProgressStart(_T("Importing file..."), TRUE, fn, NULL);
@@ -234,21 +247,47 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
TriObject* tri = CreateNewTriObject();
const int numVerts = o->geometry().verts().size()/3;
const int numVerts = (int)o->geometry().verts().size()/3;
tri->mesh.setNumVerts(numVerts);
for( int i = 0; i < numVerts; i ++ ) {
tri->mesh.setVert(i,o->geometry().verts()[3*i+0],o->geometry().verts()[3*i+1],o->geometry().verts()[3*i+2]);
}
const int numFaces = o->geometry().faces().size()/3;
const int numFaces = (int)o->geometry().faces().size()/3;
tri->mesh.setNumFaces(numFaces);
bool needs_default = std::find(o->geometry().material_ids().begin(), o->geometry().material_ids().end(), -1) != o->geometry().material_ids().end();
typedef std::pair<int, int> edge_t;
std::set<edge_t> face_boundaries;
for(std::vector<int>::const_iterator it = o->geometry().edges().begin(); it != o->geometry().edges().end();) {
const int v1 = *it++;
const int v2 = *it++;
const edge_t e((std::min)(v1, v2), (std::max)(v1, v2));
face_boundaries.insert(e);
}
for( int i = 0; i < numFaces; i ++ ) {
tri->mesh.faces[i].setVerts(o->geometry().faces()[3*i+0],o->geometry().faces()[3*i+1],o->geometry().faces()[3*i+2]);
tri->mesh.faces[i].setEdgeVisFlags(o->geometry().edges()[3*i+0],o->geometry().edges()[3*i+1],o->geometry().edges()[3*i+2]);
MtlID mtlid = o->geometry().material_ids()[i];
if (needs_default) mtlid ++;
const int v1 = o->geometry().faces()[3*i+0];
const int v2 = o->geometry().faces()[3*i+1];
const int v3 = o->geometry().faces()[3*i+2];
const edge_t e1((std::min)(v1, v2), (std::max)(v1, v2));
const edge_t e2((std::min)(v2, v3), (std::max)(v2, v3));
const edge_t e3((std::min)(v3, v1), (std::max)(v3, v1));
const bool b1 = face_boundaries.find(e1) != face_boundaries.end();
const bool b2 = face_boundaries.find(e2) != face_boundaries.end();
const bool b3 = face_boundaries.find(e3) != face_boundaries.end();
tri->mesh.faces[i].setVerts(v1, v2, v3);
tri->mesh.faces[i].setEdgeVisFlags(b1, b2, b3);
MtlID mtlid = (MtlID)o->geometry().material_ids()[i];
if (needs_default) {
mtlid ++;
}
tri->mesh.faces[i].setMatID(mtlid);
}
@@ -281,4 +320,4 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
itfc->ProgressEnd();
return true;
}
}
-8
View File
@@ -1,8 +0,0 @@
LIBRARY ifcmax.dli
EXPORTS
LibDescription @1
LibNumberClasses @2
LibClassDesc @3
LibVersion @4
SECTIONS
.data READ WRITE
+1 -7
View File
@@ -21,12 +21,6 @@
#define IFCMAX_H
#include "Max.h"
#include "istdplug.h"
#include "stdmat.h"
#include "decomp.h"
#include "shape.h"
#include "splshape.h"
#include "dummy.h"
extern ClassDesc* GetIFCImpDesc();
@@ -38,7 +32,7 @@ public:
const TCHAR * LongDesc(); // = "IfcOpenShell IFC Importer for 3ds Max"
const TCHAR * ShortDesc(); // = "Industry Foundation Classes"
const TCHAR * AuthorName(); // = "Thomas Krijnen"
const TCHAR * CopyrightMessage(); // = "Copyight (c) 2011 IfcOpenShell"
const TCHAR * CopyrightMessage(); // = "Copyright (c) 2011-2016 IfcOpenShell"
const TCHAR * OtherMessage1(); // = ""
const TCHAR * OtherMessage2(); // = ""
unsigned int Version(); // = 12
+46 -101
View File
@@ -17,117 +17,62 @@
# #
###############################################################################
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import sys
import platform
import functools
import itertools
from functools import reduce
if hasattr(os, 'uname'):
platform_system = os.uname()[0].lower()
else:
platform_system = 'windows'
from . import guid
if sys.maxsize == (1 << 31) - 1:
platform_architecture = '32bit'
else:
platform_architecture = '64bit'
python_distribution = os.path.join(platform.system().lower(),
platform.architecture()[0],
'python%s.%s' % platform.python_version_tuple()[:2])
python_version_tuple = tuple(sys.version.split(' ')[0].split('.'))
python_distribution = os.path.join(platform_system,
platform_architecture,
'python%s.%s' % python_version_tuple[:2])
sys.path.append(os.path.abspath(os.path.join(
os.path.dirname(__file__),
'lib', python_distribution)))
os.path.dirname(__file__),
'lib', python_distribution)))
try:
from . import ifcopenshell_wrapper
except:
raise ImportError("IfcOpenShell not built for '%s'" % python_distribution)
from . import ifcopenshell_wrapper
except Exception as e:
if int(python_version_tuple[0]) == 2:
# Only for py2, as py3 has exception chaining
import traceback
class entity_instance(object):
def __init__(self, e):
super(entity_instance, self).__setattr__('wrapped_data', e)
def __getattr__(self, name):
try: return entity_instance.wrap_value(self.wrapped_data.get_argument(self.wrapped_data.get_argument_index(name)))
except:
try: return entity_instance.wrap_value(self.wrapped_data.get_inverse(name))
except: raise AttributeError("entity instance of type '%s' has no attribute '%s'"%(self.wrapped_data.is_a(), name))
@staticmethod
def map_value(v):
if isinstance(v, entity_instance): return v.wrapped_data
elif isinstance(v, (tuple, list)) and len(v):
classes = list(map(type, v))
if float in classes: return ifcopenshell_wrapper.double_vector(v)
elif int in classes: return ifcopenshell_wrapper.int_vector(v)
elif str in classes: return ifcopenshell_wrapper.string_vector(v)
elif entity_instance in classes: return list(map(lambda e: e.wrapped_data, v))
return v
@staticmethod
def wrap_value(v):
wrap = lambda e: entity_instance(e)
if isinstance(v, ifcopenshell_wrapper.entity_instance): return wrap(v)
elif isinstance(v, (tuple, list)) and len(v):
classes = list(map(type, v))
if ifcopenshell_wrapper.entity_instance in classes: return list(map(wrap, v))
return v
def attribute_type(self, attr):
attr_idx = attr if isinstance(attr, int) else self.wrapped_data.get_argument_index(attr)
return self.wrapped_data.get_argument_type(attr_idx)
def attribute_name(self, attr_idx):
return self.wrapped_data.get_argument_name(attr_idx)
def __setattr__(self, key, value):
self[self.wrapped_data.get_argument_index(key)] = value
def __getitem__(self, key):
return entity_instance.wrap_value(self.wrapped_data.get_argument(key))
def __setitem__(self, idx, value):
self.wrapped_data.set_argument(idx, entity_instance.map_value(value))
def __len__(self): return len(self.wrapped_data)
def __repr__(self): return repr(self.wrapped_data)
def is_a(self, *args): return self.wrapped_data.is_a(*args)
def id(self): return self.wrapped_data.id()
def __dir__(self):
return sorted(set(itertools.chain(
dir(type(self)),
self.wrapped_data.get_attribute_names(),
self.wrapped_data.get_inverse_attribute_names()
)))
traceback.print_exc()
print('-' * 64)
raise ImportError("IfcOpenShell not built for '%s'" % python_distribution)
from . import guid
from .file import file
from .entity_instance import entity_instance
class file(object):
def __init__(self, f=None):
self.wrapped_data = f or ifcopenshell_wrapper.file(True)
def create_entity(self,type,*args,**kwargs):
e = entity_instance(ifcopenshell_wrapper.entity_instance(type))
attrs = list(enumerate(args)) + \
[(e.wrapped_data.get_argument_index(name), arg) for name, arg in kwargs.items()]
for idx, arg in attrs: e[idx] = arg
self.wrapped_data.add(e.wrapped_data)
e.wrapped_data.this.disown()
return e
def __getattr__(self, attr):
if attr[0:6] == 'create': return functools.partial(self.create_entity,attr[6:])
else: return getattr(self.wrapped_data, attr)
def __getitem__(self, key):
if isinstance(key, int):
return entity_instance(self.wrapped_data.by_id(key))
elif isinstance(key, str):
return entity_instance(self.wrapped_data.by_guid(key))
def add(self, inst):
inst.wrapped_data.this.disown()
return entity_instance(self.wrapped_data.add(inst.wrapped_data))
def by_type(self, type):
return [entity_instance(e) for e in self.wrapped_data.by_type(type)]
def traverse(self, inst):
return [entity_instance(e) for e in self.wrapped_data.traverse(inst.wrapped_data)]
def remove(self, inst):
return self.wrapped_data.remove(inst.wrapped_data)
def __iter__(self):
return iter(self[id] for id in self.wrapped_data.entity_names())
def open(fn):
f = ifcopenshell_wrapper.open(os.path.abspath(fn))
if f.good():
return file(f)
else:
raise IOError("Unable to open file for reading")
def create_entity(type, *args, **kwargs):
e = entity_instance(type)
attrs = list(enumerate(args)) + \
[(e.wrapped_data.get_argument_index(name), arg) for name, arg in kwargs.items()]
for idx, arg in attrs:
e[idx] = arg
return e
def open(fn=None):
return file(ifcopenshell_wrapper.open(os.path.abspath(fn))) if fn else file()
def create_entity(type,*args,**kwargs):
e = entity_instance(ifcopenshell_wrapper.entity_instance(type))
attrs = list(enumerate(args)) + \
[(e.wrapped_data.get_argument_index(name), arg) for name, arg in kwargs.items()]
for idx, arg in attrs: e[idx] = arg
return e
from .main import *
@@ -0,0 +1,203 @@
###############################################################################
# #
# 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/>. #
# #
###############################################################################
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import functools
import numbers
import itertools
from . import ifcopenshell_wrapper
try:
import logging
except ImportError as e:
logging = type('logger', (object,), {'exception': staticmethod(lambda s: print(s))})
class entity_instance(object):
"""
This is the base python class for all IFC objects.
An instantiated entity_instance will have methods of Python and the IFC class itself.
example:
ifc_file = ifcopenshell.open(file_path)
products = ifc_file.by_type("IfcProduct")
print(products[0].__class__)
>>> <class 'ifcopenshell.entity_instance.entity_instance'>
print(products[0].Representation)
>>> #423=IfcProductDefinitionShape($,$,(#409,#421))
"""
def __init__(self, e):
if isinstance(e, tuple):
e = ifcopenshell_wrapper.new_IfcBaseClass(*e)
super(entity_instance, self).__setattr__('wrapped_data', e)
def __getattr__(self, name):
INVALID, FORWARD, INVERSE = range(3)
attr_cat = self.wrapped_data.get_attribute_category(name)
if attr_cat == FORWARD:
return entity_instance.wrap_value(
self.wrapped_data.get_argument(self.wrapped_data.get_argument_index(name)))
elif attr_cat == INVERSE:
return entity_instance.wrap_value(self.wrapped_data.get_inverse(name))
else:
raise AttributeError(
"entity instance of type '%s' has no attribute '%s'" % (self.wrapped_data.is_a(), name))
@staticmethod
def walk(f, g, value):
if isinstance(value, (tuple, list)):
return tuple(map(functools.partial(entity_instance.walk, f, g), value))
elif f(value):
return g(value)
else:
return value
@staticmethod
def wrap_value(v):
def wrap(e): return entity_instance(e)
def is_instance(e): return isinstance(e, ifcopenshell_wrapper.entity_instance)
return entity_instance.walk(is_instance, wrap, v)
@staticmethod
def unwrap_value(v):
def unwrap(e): return e.wrapped_data
def is_instance(e): return isinstance(e, entity_instance)
return entity_instance.walk(is_instance, unwrap, v)
def attribute_type(self, attr):
attr_idx = attr if isinstance(attr, numbers.Integral) else self.wrapped_data.get_argument_index(attr)
return self.wrapped_data.get_argument_type(attr_idx)
def attribute_name(self, attr_idx):
return self.wrapped_data.get_argument_name(attr_idx)
def __setattr__(self, key, value):
self[self.wrapped_data.get_argument_index(key)] = value
def __getitem__(self, key):
if key < 0 or key >= len(self):
raise IndexError("Attribute index {} out of range for instance of type {}".format(key, self.is_a()))
return entity_instance.wrap_value(self.wrapped_data.get_argument(key))
def __setitem__(self, idx, value):
if value is None:
self.wrapped_data.setArgumentAsNull(idx)
else:
attr_type = real_attr_type = self.attribute_type(idx).title().replace(' ', '')
attr_type = attr_type.replace('Binary', 'String')
attr_type = attr_type.replace('Enumeration', 'String')
try:
if isinstance(value, unicode):
value = value.encode("utf-8")
except BaseException:
pass
try:
getattr(self.wrapped_data, "setArgumentAs%s" % attr_type)(idx, entity_instance.unwrap_value(value))
except BaseException:
raise ValueError("Expected %s for attribute %s.%s, got %r" % (
real_attr_type, self.is_a(), self.attribute_name(idx), value))
return value
def __len__(self):
return len(self.wrapped_data)
def __repr__(self):
return repr(self.wrapped_data)
def is_a(self, *args):
return self.wrapped_data.is_a(*args)
def id(self):
return self.wrapped_data.id()
def __eq__(self, other):
if not isinstance(self, type(other)):
return False
return self.wrapped_data == other.wrapped_data
def __hash__(self):
return hash((self.id(), self.wrapped_data.file_pointer()))
def __dir__(self):
return sorted(set(itertools.chain(
dir(type(self)),
map(str, self.wrapped_data.get_attribute_names()),
map(str, self.wrapped_data.get_inverse_attribute_names())
)))
def get_info(self, include_identifier=True, recursive=False, return_type=dict, ignore=()):
"""
Return a dictionary of the entity_instance's properties (Python and IFC) and their values.
example:
ifc_file = ifcopenshell.open(file_path)
products = ifc_file.by_type("IfcProduct")
obj_info = products[0].get_info()
print(obj_info.keys())
>>> dict_keys(['Description', 'Name', 'BuildingAddress', 'LongName', 'GlobalId', 'ObjectPlacement', 'OwnerHistory', 'ObjectType',
>>> ...'ElevationOfTerrain', 'CompositionType', 'id', 'Representation', 'type', 'ElevationOfRefHeight'])
"""
def _():
try:
if include_identifier:
yield "id", self.id()
yield "type", self.is_a()
except BaseException:
logging.exception("unhandled exception while getting id / type info on {}".format(self))
for i in range(len(self)):
try:
if self.wrapped_data.get_attribute_names()[i] in ignore:
continue
attr_value = self[i]
if recursive:
def is_instance(e): return isinstance(e, entity_instance)
def get_info_(inst):
# for ty in ignore:
# if inst.is_a(ty):
# return None
return entity_instance.get_info(inst,
include_identifier=include_identifier,
recursive=recursive,
return_type=return_type,
ignore=ignore
)
attr_value = entity_instance.walk(is_instance, get_info_, attr_value)
yield self.attribute_name(i), attr_value
except BaseException:
logging.exception("unhandled exception occured setting attribute name for {}".format(self))
return return_type(_())
__dict__ = property(get_info)
@@ -0,0 +1,132 @@
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import numbers
import functools
from . import ifcopenshell_wrapper
from .entity_instance import entity_instance
try:
# Python 2
basestring
except NameError:
# Python 3 or newer
basestring = (str, bytes)
class file(object):
"""
Base class for containing IFC files.
Class has instance methods for filtering by element Id, Type, etc.
Instantiated objects can be subscripted by Id or Guid
example:
ifc_file = ifcopenshell.open(file_path)
products = ifc_file.by_type("IfcProduct")
print(products[0].id(), products[0].GlobalId)
>>> 122 2XQ$n5SLP5MBLyL442paFx
# Subscripting
print(products[0] == ifc_file[122] == ifc_file['2XQ$n5SLP5MBLyL442paFx'])
>>> True
"""
def __init__(self, f=None, schema=None):
if f is not None:
self.wrapped_data = f
else:
args = filter(None, [schema])
args = map(ifcopenshell_wrapper.schema_by_name, args)
self.wrapped_data = ifcopenshell_wrapper.file(*args)
def create_entity(self, type, *args, **kwargs):
e = entity_instance((self.schema, type))
self.wrapped_data.add(e.wrapped_data)
e.wrapped_data.this.disown()
attrs = list(enumerate(args)) + \
[(e.wrapped_data.get_argument_index(name), arg) for name, arg in kwargs.items()]
for idx, arg in attrs:
e[idx] = arg
return e
def __getattr__(self, attr):
if attr[0:6] == 'create':
return functools.partial(self.create_entity, attr[6:])
else:
return getattr(self.wrapped_data, attr)
def __getitem__(self, key):
if isinstance(key, numbers.Integral):
return entity_instance(self.wrapped_data.by_id(key))
elif isinstance(key, basestring):
return entity_instance(self.wrapped_data.by_guid(str(key)))
def by_id(self, id):
"""
Return IFC objects filtered by IFC ID.
Returned objects are unwrapped IFC objects.
"""
return self[id]
def by_guid(self, guid):
"""
Return IFC objects filtered by IFC GUID.
Returned objects are unwrapped IFC objects.
"""
return self[guid]
def add(self, inst):
inst.wrapped_data.this.disown()
return entity_instance(self.wrapped_data.add(inst.wrapped_data))
def by_type(self, type):
"""
Return IFC objects filtered by IFC Type and wrapped with the entity_instance class.
See ifcopenshell.entity_instance for class methods and properties
"""
return [entity_instance(e) for e in self.wrapped_data.by_type(type)]
def traverse(self, inst, max_levels=None):
if max_levels is None:
max_levels = -1
return [entity_instance(e) for e in self.wrapped_data.traverse(inst.wrapped_data, max_levels)]
def get_inverse(self, inst):
return [entity_instance(e) for e in self.wrapped_data.get_inverse(inst.wrapped_data)]
def remove(self, inst):
return self.wrapped_data.remove(inst.wrapped_data)
def __iter__(self):
return iter(self[id] for id in self.wrapped_data.entity_names())
@staticmethod
def from_string(s):
return file(ifcopenshell_wrapper.read(s))
@@ -17,66 +17,9 @@
# #
###############################################################################
import os
import sys
from .. import ifcopenshell_wrapper
def has_occ():
try: import OCC.BRepTools
except: return False
return True
has_occ = has_occ()
wrap_shape_creation = lambda settings, shape: shape
if has_occ:
import occ_utils as utils
wrap_shape_creation = lambda settings, shape: utils.create_shape_from_serialization(shape) if getattr(settings, 'use_python_opencascade', False) else shape
# Subclass the settings module to provide an additional
# setting to enable pythonOCC when available
class settings(ifcopenshell_wrapper.settings):
if has_occ:
USE_PYTHON_OPENCASCADE = -1
def set(self, *args):
setting, value = args
if setting == settings.USE_PYTHON_OPENCASCADE:
self.set(settings.USE_BREP_DATA, value)
self.set(settings.USE_WORLD_COORDS, value)
self.set(settings.DISABLE_TRIANGULATION, value)
self.use_python_opencascade = value
else:
ifcopenshell_wrapper.settings.set(self, *args)
# Hide templating precision to the user by choosing based on Python's
# internal float type. This is probably always going to be a double.
for ty in (ifcopenshell_wrapper.iterator_single_precision, ifcopenshell_wrapper.iterator_double_precision):
if ty.mantissa_size() == sys.float_info.mant_dig:
_iterator = ty
# Make sure people are able to use python's platform agnostic paths
class iterator(_iterator):
def __init__(self, settings, filename):
self.settings = settings
_iterator.__init__(self, settings, os.path.abspath(filename))
if has_occ:
def get(self):
return wrap_shape_creation(self.settings, _iterator.get(self))
def create_shape(settings, inst):
return wrap_shape_creation(settings, ifcopenshell_wrapper.create_shape(settings, inst.wrapped_data))
def iterate(settings, filename):
it = iterator(settings, filename)
if it.findContext():
while True:
yield it.get()
if not it.next(): break
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from . import occ_utils as utils
from .main import *
@@ -0,0 +1,611 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import sys
import time
import operator
import functools
import OCC.AIS
from collections import defaultdict, Iterable, OrderedDict
try:
QString = unicode
except NameError:
# Python 3
QString = str
os.environ['QT_API'] = 'pyqt5'
try:
from pyqode.qt import QtCore
except BaseException:
pass
from PyQt5 import QtCore, QtGui, QtWidgets
from .code_editor_pane import code_edit
try:
from OCC.Display.pyqt5Display import qtViewer3d
except BaseException:
import OCC.Display
try:
import OCC.Display.backend
except BaseException:
pass
try:
OCC.Display.backend.get_backend("qt-pyqt5")
except BaseException:
OCC.Display.backend.load_backend("qt-pyqt5")
from OCC.Display.qtDisplay import qtViewer3d
from .main import settings, iterator
from .occ_utils import display_shape
from .. import open as open_ifc_file
from .. import version as ifcopenshell_version
if ifcopenshell_version < "0.6":
# not yet ported
from .. import get_supertype
class configuration(object):
def __init__(self):
try:
import ConfigParser
Cfg = ConfigParser.RawConfigParser
except BaseException:
import configparser
def Cfg():
return configparser.ConfigParser(interpolation=None)
conf_file = os.path.expanduser(os.path.join("~", ".ifcopenshell", "app", "snippets.conf"))
if conf_file.startswith("~"):
conf_file = None
return
self.config_encode = lambda s: s.replace("\\", "\\\\").replace("\n", "\n|")
self.config_decode = lambda s: s.replace("\n|", "\n").replace("\\\\", "\\")
if not os.path.exists(os.path.dirname(conf_file)):
os.makedirs(os.path.dirname(conf_file))
if not os.path.exists(conf_file):
config = Cfg()
config.add_section("snippets")
config.set("snippets", "print all wall ids", self.config_encode("""
###########################################################################
# A simple script that iterates over all walls in the current model #
# and prints their Globally unique IDs (GUIDS) to the console window #
###########################################################################
for wall in model.by_type("IfcWall"):
print ("wall with global id: "+str(wall.GlobalId))
""".lstrip()))
config.set("snippets", "print properties of current selection", self.config_encode("""
###########################################################################
# A simple script that iterates over all IfcPropertySets of the currently #
# selected object and prints them to the console #
###########################################################################
# check if something is selected
if selection:
#get the IfcProduct that is stored in the global variable 'selection'
obj = selection
for relDefinesByProperties in obj.IsDefinedBy:
print("[{0}]".format(relDefinesByProperties.RelatingPropertyDefinition.Name))
for prop in relDefinesByProperties.RelatingPropertyDefinition.HasProperties:
print ("{:<20} :{}".format(prop.Name,prop.NominalValue.wrappedValue))
print ("\\n")
""".lstrip()))
with open(conf_file, 'w') as configfile:
config.write(configfile)
self.config = Cfg()
self.config.read(conf_file)
def options(self, s):
return OrderedDict([(k, self.config_decode(self.config.get(s, k))) for k in self.config.options(s)])
class application(QtWidgets.QApplication):
"""A pythonOCC, PyQt based IfcOpenShell application
with two tree views and a graphical 3d view"""
class abstract_treeview(QtWidgets.QTreeWidget):
"""Base class for the two treeview controls"""
instanceSelected = QtCore.pyqtSignal([object])
instanceVisibilityChanged = QtCore.pyqtSignal([object, int])
instanceDisplayModeChanged = QtCore.pyqtSignal([object, int])
def __init__(self):
QtWidgets.QTreeView.__init__(self)
self.setColumnCount(len(self.ATTRIBUTES))
self.setHeaderLabels(self.ATTRIBUTES)
self.children = defaultdict(list)
def get_children(self, inst):
c = [inst]
i = 0
while i < len(c):
c.extend(self.children[c[i]])
i += 1
return c
def contextMenuEvent(self, event):
menu = QtWidgets.QMenu(self)
visibility = [menu.addAction("Show"), menu.addAction("Hide")]
displaymode = [menu.addAction("Solid"), menu.addAction("Wireframe")]
action = menu.exec_(self.mapToGlobal(event.pos()))
index = self.selectionModel().currentIndex()
inst = index.data(QtCore.Qt.UserRole)
if hasattr(inst, 'toPyObject'):
inst = inst
if action in visibility:
self.instanceVisibilityChanged.emit(inst, visibility.index(action))
elif action in displaymode:
self.instanceDisplayModeChanged.emit(inst, displaymode.index(action))
def clicked_(self, index):
inst = index.data(QtCore.Qt.UserRole)
if hasattr(inst, 'toPyObject'):
inst = inst
if inst:
self.instanceSelected.emit(inst)
def select(self, product):
itm = self.product_to_item.get(product)
if itm is None:
return
self.selectionModel().setCurrentIndex(itm,
QtCore.QItemSelectionModel.SelectCurrent | QtCore.QItemSelectionModel.Rows)
class decomposition_treeview(abstract_treeview):
"""Treeview with typical IFC decomposition relationships"""
ATTRIBUTES = ['Entity', 'GlobalId', 'Name']
def parent(self, instance):
if instance.is_a("IfcOpeningElement"):
return instance.VoidsElements[0].RelatingBuildingElement
if instance.is_a("IfcElement"):
fills = instance.FillsVoids
if len(fills):
return fills[0].RelatingOpeningElement
containments = instance.ContainedInStructure
if len(containments):
return containments[0].RelatingStructure
if instance.is_a("IfcObjectDefinition"):
decompositions = instance.Decomposes
if len(decompositions):
return decompositions[0].RelatingObject
def load_file(self, f, **kwargs):
products = list(f.by_type("IfcProduct")) + list(f.by_type("IfcProject"))
parents = list(map(self.parent, products))
items = {}
skipped = 0
ATTRS = self.ATTRIBUTES
while len(items) + skipped < len(products):
for product, parent in zip(products, parents):
if parent is None and not product.is_a("IfcProject"):
skipped += 1
continue
if (parent is None or parent in items) and product not in items:
sl = []
for attr in ATTRS:
if attr == 'Entity':
sl.append(product.is_a())
else:
sl.append(getattr(product, attr) or '')
itm = items[product] = QtWidgets.QTreeWidgetItem(items.get(parent, self), sl)
itm.setData(0, QtCore.Qt.UserRole, product)
self.children[parent].append(product)
self.product_to_item = dict(zip(items.keys(), map(self.indexFromItem, items.values())))
self.clicked.connect(self.clicked_)
self.expandAll()
class type_treeview(abstract_treeview):
"""Treeview with typical IFC decomposition relationships"""
ATTRIBUTES = ['Name']
def load_file(self, f, **kwargs):
products = list(f.by_type("IfcProduct"))
types = set(map(lambda i: i.is_a(), products))
items = {}
for t in types:
def add(t):
s = get_supertype(t)
if s:
add(s)
s2, t2 = map(QString, (s, t))
if t2 not in items:
itm = items[t2] = QtWidgets.QTreeWidgetItem(items.get(s2, self), [t2])
itm.setData(0, QtCore.Qt.UserRole, t2)
self.children[s2].append(t2)
if ifcopenshell_version < "0.6":
add(t)
for p in products:
t = QString(p.is_a())
itm = items[p] = QtWidgets.QTreeWidgetItem(items.get(t, self), [p.Name or '<no name>'])
itm.setData(0, QtCore.Qt.UserRole, t)
self.children[t].append(p)
self.product_to_item = dict(zip(items.keys(), map(self.indexFromItem, items.values())))
self.clicked.connect(self.clicked)
self.expandAll()
class property_table(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
self.layout = QtWidgets.QVBoxLayout(self)
self.setLayout(self.layout)
self.scroll = QtWidgets.QScrollArea(self)
self.layout.addWidget(self.scroll)
self.scroll.setWidgetResizable(True)
self.scrollContent = QtWidgets.QWidget(self.scroll)
self.scrollLayout = QtWidgets.QVBoxLayout(self.scrollContent)
self.scrollContent.setLayout(self.scrollLayout)
self.scroll.setWidget(self.scrollContent)
self.prop_dict = {}
# triggered by selection event in either component of parent
def select(self, product):
# Clear the old contents if any
while self.scrollLayout.count():
child = self.scrollLayout.takeAt(0)
if child is not None:
if child.widget() is not None:
child.widget().deleteLater()
self.scroll = QtWidgets.QScrollArea()
self.scroll.setWidgetResizable(True)
prop_sets = self.prop_dict.get(str(product))
if prop_sets is not None:
for k, v in prop_sets:
group_box = QtWidgets.QGroupBox()
group_box.setTitle(k)
group_layout = QtWidgets.QVBoxLayout()
group_box.setLayout(group_layout)
for name, value in v.items():
prop_name = str(name)
value_str = value
if hasattr(value_str, "wrappedValue"):
value_str = value_str.wrappedValue
if isinstance(value_str, unicode):
value_str = value_str.encode('utf-8')
else:
value_str = str(value_str)
if hasattr(value, "is_a"):
type_str = " <i>(%s)</i>" % value.is_a()
else:
type_str = ""
label = QtWidgets.QLabel("<b>%s</b>: %s%s" % (prop_name, value_str, type_str))
group_layout.addWidget(label)
group_layout.addStretch()
self.scrollLayout.addWidget(group_box)
self.scrollLayout.addStretch()
else:
label = QtWidgets.QLabel("No IfcPropertySets asscociated with selected entity instance")
self.scrollLayout.addWidget(label)
def load_file(self, f, **kwargs):
for p in f.by_type("IfcProduct"):
propsets = []
def process_pset(prop_def):
if prop_def is not None:
prop_set_name = prop_def.Name
props = {}
if prop_def.is_a("IfcElementQuantity"):
for q in prop_def.Quantities:
if q.is_a("IfcPhysicalSimpleQuantity"):
props[q.Name] = q[3]
elif prop_def.is_a("IfcPropertySet"):
for prop in prop_def.HasProperties:
if prop.is_a("IfcPropertySingleValue"):
props[prop.Name] = prop.NominalValue
else:
# Entity introduced in IFC4
# prop_def.is_a("IfcPreDefinedPropertySet"):
for prop in range(4, len(prop_def)):
props[prop_def.attribute_name(prop)] = prop_def[prop]
return prop_set_name, props
try:
for is_def_by in p.IsDefinedBy:
if is_def_by.is_a("IfcRelDefinesByProperties"):
propsets.append(process_pset(is_def_by.RelatingPropertyDefinition))
elif is_def_by.is_a("IfcRelDefinesByType"):
type_psets = is_def_by.RelatingType.HasPropertySets
if type_psets is None:
continue
for propset in type_psets:
propsets.append(process_pset(propset))
except Exception as e:
import traceback
print("failed to load properties: {}".format(e))
traceback.print_exc()
if len(propsets):
self.prop_dict[str(p)] = propsets
print("property set dictionary has {} entries".format(len(self.prop_dict)))
class viewer(qtViewer3d):
instanceSelected = QtCore.pyqtSignal([object])
@staticmethod
def ais_to_key(ais_handle):
def yield_shapes():
ais = ais_handle.GetObject()
if hasattr(ais, 'Shape'):
yield ais.Shape()
return
shp = OCC.AIS.Handle_AIS_Shape.DownCast(ais_handle)
if not shp.IsNull():
yield shp.Shape()
return
mult = ais_handle
if mult.IsNull():
shp = OCC.AIS.Handle_AIS_Shape.DownCast(ais_handle)
if not shp.IsNull():
yield shp
else:
li = mult.GetObject().ConnectedTo()
for i in range(li.Length()):
shp = OCC.AIS.Handle_AIS_Shape.DownCast(li.Value(i + 1))
if not shp.IsNull():
yield shp
return tuple(shp.HashCode(1 << 24) for shp in yield_shapes())
def __init__(self, widget):
qtViewer3d.__init__(self, widget)
self.ais_to_product = {}
self.product_to_ais = {}
self.counter = 0
self.window = widget
def initialize(self):
self.InitDriver()
self._display.Select = self.HandleSelection
def load_file(self, f, setting=None):
if setting is None:
setting = settings()
setting.set(setting.USE_PYTHON_OPENCASCADE, True)
v = self._display
t = {0: time.time()}
def update(dt=None):
t1 = time.time()
if t1 - t[0] > (dt or -1):
v.FitAll()
v.Repaint()
t[0] = t1
terminate = [False]
self.window.window_closed.connect(lambda *args: operator.setitem(terminate, 0, True))
t0 = time.time()
it = iterator(setting, f)
if not it.initialize():
return
old_progress = -1
while True:
if terminate[0]:
break
shape = it.get()
product = f[shape.data.id]
ais = display_shape(shape, viewer_handle=v)
ais.GetObject().SetSelectionPriority(self.counter)
self.ais_to_product[self.counter] = product
self.product_to_ais[product] = ais
self.counter += 1
QtWidgets.QApplication.processEvents()
if product.is_a() in {'IfcSpace', 'IfcOpeningElement'}:
v.Context.Erase(ais, True)
progress = it.progress() // 2
if progress > old_progress:
print("\r[" + "#" * progress + " " * (50 - progress) + "]", end="")
old_progress = progress
if not it.next():
break
update(0.2)
print("\rOpened file in %.2f seconds%s" % (time.time() - t0, " " * 25))
update()
def select(self, product):
ais = self.product_to_ais.get(product)
if ais is None:
return
v = self._display.Context
v.ClearSelected(False)
v.SetSelected(ais, True)
def toggle(self, product_or_products, fn):
if not isinstance(product_or_products, Iterable):
product_or_products = [product_or_products]
aiss = list(filter(None, map(self.product_to_ais.get, product_or_products)))
last = len(aiss) - 1
for i, ais in enumerate(aiss):
fn(ais, i == last)
def toggle_visibility(self, product_or_products, flag):
v = self._display.Context
if flag:
def visibility(ais, last):
v.Erase(ais, last)
else:
def visibility(ais, last):
v.Display(ais, last)
self.toggle(product_or_products, visibility)
def toggle_wireframe(self, product_or_products, flag):
v = self._display.Context
if flag:
def wireframe(ais, last):
if v.IsDisplayed(ais):
v.SetDisplayMode(ais, 0, last)
else:
def wireframe(ais, last):
if v.IsDisplayed(ais):
v.SetDisplayMode(ais, 1, last)
self.toggle(product_or_products, wireframe)
def HandleSelection(self, X, Y):
v = self._display.Context
v.Select()
v.InitSelected()
if v.MoreSelected():
ais = v.SelectedInteractive()
inst = self.ais_to_product[ais.GetObject().SelectionPriority()]
self.instanceSelected.emit(inst)
class window(QtWidgets.QMainWindow):
TITLE = "IfcOpenShell IFC viewer"
window_closed = QtCore.pyqtSignal([])
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.setWindowTitle(self.TITLE)
self.menu = self.menuBar()
self.menus = {}
def closeEvent(self, *args):
self.window_closed.emit()
def add_menu_item(self, menu, label, callback, icon=None, shortcut=None):
m = self.menus.get(menu)
if m is None:
m = self.menu.addMenu(menu)
self.menus[menu] = m
if icon:
a = QtWidgets.QAction(QtGui.QIcon(icon), label, self)
else:
a = QtWidgets.QAction(label, self)
if shortcut:
a.setShortcut(shortcut)
a.triggered.connect(callback)
m.addAction(a)
def makeSelectionHandler(self, component):
def handler(inst):
for c in self.components:
if c != component:
c.select(inst)
return handler
def __init__(self, settings=None):
QtWidgets.QApplication.__init__(self, sys.argv)
self.window = application.window()
self.tree = application.decomposition_treeview()
self.tree2 = application.type_treeview()
self.propview = self.property_table()
self.canvas = application.viewer(self.window)
self.tabs = QtWidgets.QTabWidget()
self.window.resize(800, 600)
splitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
splitter.addWidget(self.tabs)
self.tabs.addTab(self.tree, 'Decomposition')
self.tabs.addTab(self.tree2, 'Types')
self.tabs.addTab(self.propview, "Properties")
splitter2 = QtWidgets.QSplitter(QtCore.Qt.Vertical)
splitter2.addWidget(self.canvas)
self.editor = code_edit(self.canvas, configuration().options('snippets'))
splitter2.addWidget(self.editor)
splitter.addWidget(splitter2)
splitter.setSizes([200, 600])
splitter2.setSizes([400, 200])
self.window.setCentralWidget(splitter)
self.canvas.initialize()
self.components = [self.tree, self.tree2, self.canvas, self.propview, self.editor]
self.files = {}
self.window.add_menu_item('File', '&Open', self.browse, shortcut='CTRL+O')
self.window.add_menu_item('File', '&Close', self.clear, shortcut='CTRL+W')
self.window.add_menu_item('File', '&Exit', self.window.close, shortcut='ALT+F4')
self.tree.instanceSelected.connect(self.makeSelectionHandler(self.tree))
self.tree2.instanceSelected.connect(self.makeSelectionHandler(self.tree2))
self.canvas.instanceSelected.connect(self.makeSelectionHandler(self.canvas))
for t in [self.tree, self.tree2]:
t.instanceVisibilityChanged.connect(functools.partial(self.change_visibility, t))
t.instanceDisplayModeChanged.connect(functools.partial(self.change_displaymode, t))
self.settings = settings
def change_visibility(self, tree, inst, flag):
insts = tree.get_children(inst)
self.canvas.toggle_visibility(insts, flag)
def change_displaymode(self, tree, inst, flag):
insts = tree.get_children(inst)
self.canvas.toggle_wireframe(insts, flag)
def start(self):
self.window.show()
sys.exit(self.exec_())
def browse(self):
filename = QtWidgets.QFileDialog.getOpenFileName(self.window, 'Open file', ".",
"Industry Foundation Classes (*.ifc)")[0]
self.load(filename)
def clear(self):
self.canvas._display.Context.RemoveAll()
self.tree.clear()
self.files.clear()
def load(self, fn):
if fn in self.files:
return
f = open_ifc_file(str(fn))
self.files[fn] = f
for c in self.components:
c.load_file(f, setting=self.settings)
if __name__ == "__main__":
application().start()
@@ -0,0 +1,149 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import sys
import logging
from code import InteractiveConsole
from PyQt5 import QtCore, QtGui, QtWidgets
try:
from PyQt5 import QtWidgets
except BaseException:
QtWidgets = QtGui
try:
from pyqode.core.panels import CheckerPanel
from pyqode.core import api
from pyqode.core import modes
from pyqode.core import panels
from pyqode.core.api import CodeEdit, ColorScheme
from pyqode.python.modes import PyAutoIndentMode, PythonSH
from pyqode.python.backend import server
from pyqode.python import modes as pymodes, panels as pypanels, widgets
from pyqode.python.widgets import PyInteractiveConsole
has_pyqode = True
except BaseException:
has_pyqode = False
CodeEdit = QtWidgets.QPlainTextEdit
class StdoutRedirector(object):
"""A class for redirecting stdout to this Text widget."""
def __init__(self, widget):
self.widget = widget
self.isError = False
def write(self, myStr):
self.widget.moveCursor(QtGui.QTextCursor.End)
if self.isError:
self.widget.setTextColor(QtCore.Qt.red)
else:
self.widget.setTextColor(QtCore.Qt.white)
self.widget.insertPlainText(myStr)
self.widget.moveCursor(QtGui.QTextCursor.End)
class code_edit(QtWidgets.QWidget):
class Console(InteractiveConsole):
def __init__(*args):
InteractiveConsole.__init__(*args)
def enter(self, source):
self.runcode(source)
def runCode(self):
sys.stdout = StdoutRedirector(self.output)
sys.stderr = StdoutRedirector(self.output)
sys.stderr.isError = True
if not self.model:
print("please load a model first", file=sys.stderr)
else:
self.c.enter(str(self.editor.toPlainText()))
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
def select(self, product):
self.c = self.Console({'model': self.model, 'viewer': self.viewer, 'selection': product})
def __init__(self, viewer, snippets=None):
self.model = None
self.viewer = viewer
QtWidgets.QWidget.__init__(self)
self.layout = QtWidgets.QVBoxLayout(self)
self.setLayout(self.layout)
self.c = None
self.tools = QtWidgets.QHBoxLayout(self)
self.layout.addLayout(self.tools)
self.runbutton = QtWidgets.QPushButton("Run")
width = self.runbutton.fontMetrics().boundingRect("Run").width() + 20
self.runbutton.setMaximumWidth(width)
self.tools.addWidget(self.runbutton)
self.runbutton.clicked.connect(self.runCode)
editor = CodeEdit()
if has_pyqode:
editor.backend.start(server.__file__)
editor.panels.append(panels.FoldingPanel())
editor.panels.append(panels.LineNumberPanel())
editor.panels.append(panels.SearchAndReplacePanel(),
panels.SearchAndReplacePanel.Position.BOTTOM)
editor.panels.append(panels.EncodingPanel(), api.Panel.Position.TOP)
editor.add_separator()
editor.panels.append(pypanels.QuickDocPanel(), api.Panel.Position.BOTTOM)
sh = editor.modes.append(PythonSH(editor.document()))
editor.modes.append(modes.CaretLineHighlighterMode())
editor.modes.append(modes.CodeCompletionMode())
editor.modes.append(modes.ExtendedSelectionMode())
editor.modes.append(modes.FileWatcherMode())
editor.modes.append(modes.OccurrencesHighlighterMode())
editor.modes.append(modes.RightMarginMode())
editor.modes.append(modes.SmartBackSpaceMode())
editor.modes.append(modes.SymbolMatcherMode())
editor.modes.append(modes.ZoomMode())
editor.modes.append(pymodes.CommentsMode())
editor.modes.append(pymodes.CalltipsMode())
auto = pymodes.PyAutoCompleteMode()
auto.logger.setLevel(logging.CRITICAL)
editor.modes.append(auto)
editor.modes.append(pymodes.PyAutoIndentMode())
editor.modes.append(pymodes.PyIndenterMode())
editor.show()
else:
editor.setStyleSheet('font-size: 10pt; font-family: Consolas, Courier;')
self.editor = editor
self.snippets = snippets
if self.snippets:
self.list = QtWidgets.QComboBox(self)
self.replace_snippet(0)
for snip_name in self.snippets.keys():
self.list.addItem(snip_name)
self.tools.addWidget(self.list)
self.list.currentIndexChanged[int].connect(self.replace_snippet)
self.layout.addWidget(self.editor)
self.output = QtWidgets.QTextEdit()
self.output.setReadOnly(True)
self.output.setStyleSheet('font-size: 10pt; font-family: Consolas, Courier; background-color: #444;')
self.layout.addWidget(self.output)
def replace_snippet(self, number=None):
snip = list(self.snippets.values())[number]
if has_pyqode:
self.editor.setPlainText(snip, "", "")
else:
self.editor.setPlainText(snip)
def load_file(self, f, **kwargs):
output = []
sys.stdout = StdoutRedirector(self.output)
self.model = f
self.c = self.Console({'model': self.model, 'selection': None, 'viewer': self.viewer})
sys.stdout = sys.__stdout__
@@ -0,0 +1,201 @@
###############################################################################
# #
# 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/>. #
# #
###############################################################################
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import sys
from .. import ifcopenshell_wrapper
from ..file import file
from ..entity_instance import entity_instance
def has_occ():
try:
import OCC.BRepTools
except BaseException:
return False
return True
has_occ = has_occ()
def wrap_shape_creation(settings, shape):
return shape
if has_occ:
from . import occ_utils as utils
def wrap_shape_creation(settings, shape): return utils.create_shape_from_serialization(shape) if getattr(settings,
'use_python_opencascade',
False) else shape
# Subclass the settings module to provide an additional
# setting to enable pythonOCC when available
class settings(ifcopenshell_wrapper.settings):
if has_occ:
USE_PYTHON_OPENCASCADE = -1
def set(self, *args):
setting, value = args
if setting == settings.USE_PYTHON_OPENCASCADE:
self.set(settings.USE_BREP_DATA, value)
self.set(settings.USE_WORLD_COORDS, value)
self.set(settings.DISABLE_TRIANGULATION, value)
self.use_python_opencascade = value
else:
ifcopenshell_wrapper.settings.set(self, *args)
# Assert templated precision to match Python's internal float type
assert ifcopenshell_wrapper.iterator_double_precision.mantissa_size() == sys.float_info.mant_dig
_iterator = ifcopenshell_wrapper.iterator_double_precision
# Make sure people are able to use python's platform agnostic paths
class iterator(_iterator):
def __init__(self, settings, file_or_filename):
self.settings = settings
if isinstance(file_or_filename, file):
file_or_filename = file_or_filename.wrapped_data
else:
file_or_filename = os.path.abspath(file_or_filename)
_iterator.__init__(self, settings, file_or_filename)
if has_occ:
def get(self):
return wrap_shape_creation(self.settings, _iterator.get(self))
def __iter__(self):
if self.initialize():
while True:
yield self.get()
if not self.next(): break
class tree(ifcopenshell_wrapper.tree):
def __init__(self, file=None, settings=None):
args = [self]
if file is not None:
args.append(file.wrapped_data)
if settings is not None:
args.append(settings)
ifcopenshell_wrapper.tree.__init__(*args)
def add_file(self, file, settings):
ifcopenshell_wrapper.tree.add_file(self, file.wrapped_data, settings)
def select(self, value, **kwargs):
def unwrap(value):
if isinstance(value, entity_instance):
return value.wrapped_data
elif all(map(lambda v: hasattr(value, v), "XYZ")):
return value.X(), value.Y(), value.Z()
return value
args = [self, unwrap(value)]
if isinstance(value, entity_instance):
args.append(kwargs.get("completely_within", False))
elif has_occ:
import OCC.TopoDS
if isinstance(value, OCC.TopoDS.TopoDS_Shape):
args[1] = utils.serialize_shape(value)
return [entity_instance(e) for e in ifcopenshell_wrapper.tree.select(*args)]
def select_box(self, value, **kwargs):
def unwrap(value):
if isinstance(value, entity_instance):
return value.wrapped_data
elif hasattr(value, "Get"):
return value.Get()[:3], value.Get()[3:]
return value
args = [self, unwrap(value)]
if "extend" in kwargs or "completely_within" in kwargs:
args.append(kwargs.get("completely_within", False))
if "extend" in kwargs:
args.append(kwargs.get("extend", -1.e-5))
return [entity_instance(e) for e in ifcopenshell_wrapper.tree.select_box(*args)]
def create_shape(settings, inst, repr=None):
"""
Return a geometric representation from STEP-based IFCREPRESENTATIONSHAPE
or
Return an OpenCASCADE BRep if settings.USE_PYTHON_OPENCASCADE == True
example:
settings = ifcopenshell.geom.settings()
settings.set(settings.USE_PYTHON_OPENCASCADE, True)
ifc_file = ifcopenshell.open(file_path)
products = ifc_file.by_type("IfcProduct")
for i, product in enumerate(products):
if product.Representation is not None:
try:
shape = geom.create_shape(settings, inst=product).geometry
shape_gpXYZ = shape.Location().Transformation().TranslationPart() # These are methods of the TopoDS_Shape class from pythonOCC
print(shape_gpXYZ.X(), shape_gpXYZ.Y(), shape_gpXYZ.Z()) # These are methods of the gpXYZ class from pythonOCC
"""
return wrap_shape_creation(
settings,
ifcopenshell_wrapper.create_shape(
settings,
inst.wrapped_data,
repr.wrapped_data if repr is not None else None
))
def iterate(settings, filename):
it = iterator(settings, filename)
if it.initialize():
while True:
yield it.get()
if not it.next():
break
def make_shape_function(fn):
def entity_instance_or_none(e):
return None if e is None else entity_instance(e)
if has_occ:
import OCC.TopoDS
def _(string_or_shape, *args):
if isinstance(string_or_shape, OCC.TopoDS.TopoDS_Shape):
string_or_shape = utils.serialize_shape(string_or_shape)
return entity_instance_or_none(fn(string_or_shape, *args))
else:
def _(string, *args):
return entity_instance_or_none(fn(string, *args))
return _
serialise = make_shape_function(ifcopenshell_wrapper.serialise)
tesselate = make_shape_function(ifcopenshell_wrapper.tesselate)
@@ -1,42 +1,188 @@
###############################################################################
# #
# 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/>. #
# #
###############################################################################
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import random
from collections import namedtuple
import operator
from collections import namedtuple, Iterable
import OCC.gp
import OCC.V3d
import OCC.Quantity
import OCC.BRepTools
import OCC.Display.SimpleGui
tuple = namedtuple('shape', ('data', 'geometry'))
shape_tuple = namedtuple('shape_tuple', ('data', 'geometry', 'styles'))
handle, main_loop, add_menu, add_function_to_menu = None, None, None, None
DEFAULT_STYLES = {
"DEFAULT": (.7, .7, .7),
"IfcWall": (.8, .8, .8),
"IfcSite": (.75, .8, .65),
"IfcSlab": (.4, .4, .4),
"IfcWallStandardCase": (.9, .9, .9),
"IfcWall": (.9, .9, .9),
"IfcWindow": (.75, .8, .75, .3),
"IfcDoor": (.55, .3, .15),
"IfcBeam": (.75, .7, .7),
"IfcRailing": (.65, .6, .6),
"IfcMember": (.65, .6, .6),
"IfcPlate": (.8, .8, .8)
}
def initialize_display():
import OCC.V3d
import OCC.Display.SimpleGui
global handle, main_loop, add_menu, add_function_to_menu
handle, main_loop, add_menu, add_function_to_menu = OCC.Display.SimpleGui.init_display()
def setup():
viewer_handle = handle.GetViewer()
viewer = viewer_handle.GetObject()
while True:
def lights():
viewer.InitActiveLights()
try: active_light = viewer.ActiveLight()
except: break
viewer.DelLight(active_light)
viewer.NextActiveLights()
for dir in [(1,2,-3), (-2,-1,1)]:
while True:
try:
active_light = viewer.ActiveLight()
except BaseException:
break
yield active_light
viewer.NextActiveLights()
lights = list(lights())
for l in lights:
viewer.DelLight(l)
for dir in [(3, 2, 1), (-1, -2, -3)]:
light = OCC.V3d.V3d_DirectionalLight(viewer_handle)
light.SetDirection(*dir)
viewer.SetLightOn(light.GetHandle())
setup()
return handle
def display_shape(shape, clr=None):
if not clr:
r = lambda: random.random() * 0.3 + 0.7
def yield_subshapes(shape):
import OCC.TopoDS
it = OCC.TopoDS.TopoDS_Iterator(shape)
while it.More():
yield it.Value()
it.Next()
def display_shape(shape, clr=None, viewer_handle=None):
import OCC.gp
import OCC.AIS
import OCC.Quantity
if viewer_handle is None:
viewer_handle = handle
if isinstance(shape, shape_tuple):
shape, representation = shape.geometry, shape
else:
representation = None
material = OCC.Graphic3d.Graphic3d_MaterialAspect(OCC.Graphic3d.Graphic3d_NOM_PLASTER)
material.SetDiffuse(1)
if representation and not clr:
if len(set(representation.styles)) == 1:
clr = representation.styles[0]
if min(clr) < 0. or max(clr) > 1.:
clr = DEFAULT_STYLES.get(representation.data.type, DEFAULT_STYLES["DEFAULT"])
if clr:
ais = OCC.AIS.AIS_Shape(shape)
ais.SetMaterial(material)
if isinstance(clr, str):
qclr = getattr(OCC.Quantity, "Quantity_NOC_%s" % clr.upper(),
getattr(OCC.Quantity, "Quantity_NOC_%s1" % clr.upper(), None))
if qclr is None:
raise Exception("No color named '%s'" % clr.upper())
elif isinstance(clr, Iterable):
clr = tuple(clr)
if len(clr) < 3 and len(clr) > 4:
raise Exception("Need 3 or 4 colour components. Got '%r'." % clr)
qclr = OCC.Quantity.Quantity_Color(clr[0], clr[1], clr[2], OCC.Quantity.Quantity_TOC_RGB)
elif isinstance(clr, OCC.Quantity.Quantity_Color):
qclr = clr
else:
raise Exception("Object of type %r cannot be used as a color." % type(clr))
ais.SetColor(qclr)
if isinstance(clr, tuple) and len(clr) == 4 and clr[3] < 1.:
ais.SetTransparency(1. - clr[3])
elif representation and hasattr(OCC.AIS, "AIS_MultipleConnectedShape"):
default_style_applied = None
ais = OCC.AIS.AIS_MultipleConnectedShape(shape)
subshapes = list(yield_subshapes(shape))
lens = len(representation.styles), len(subshapes)
if lens[0] != lens[1]:
import warnings
warnings.warn("Unable to assign styles to subshapes. Encountered %d styles for %d shapes." % lens)
else:
for shp, stl in zip(subshapes, representation.styles):
subshape = OCC.AIS.AIS_Shape(shp)
if min(stl) < 0. or max(stl) > 1.:
default_style_applied = stl = DEFAULT_STYLES.get(representation.data.type,
DEFAULT_STYLES["DEFAULT"])
subshape.SetColor(OCC.Quantity.Quantity_Color(stl[0], stl[1], stl[2], OCC.Quantity.Quantity_TOC_RGB))
subshape.SetMaterial(material)
if len(stl) == 4 and stl[3] < 1.:
subshape.SetTransparency(1. - stl[3])
ais.Connect(subshape.GetHandle())
# For some reason it is necessary to set transparency here again
# in order for transparency to be rendered on the subshape.
applied_styles = representation.styles
if default_style_applied:
if len(default_style_applied) == 3:
default_style_applied += (1.,)
applied_styles += (default_style_applied,)
if len(applied_styles):
# The only way for this not to be true if is the entire shape is NULL
min_transp = min(map(operator.itemgetter(3), applied_styles))
if min_transp < 1.:
ais.SetTransparency(1.)
else:
ais = OCC.AIS.AIS_Shape(shape)
ais.SetMaterial(material)
def r():
return random.random() * 0.3 + 0.7
clr = OCC.Quantity.Quantity_Color(r(), r(), r(), OCC.Quantity.Quantity_TOC_RGB)
return handle.DisplayShape(shape, color=clr, update=True)
ais.SetColor(clr)
ais_handle = ais.GetHandle()
viewer_handle.Context.Display(ais_handle, False)
return ais_handle
def set_shape_transparency(ais, t):
@@ -44,23 +190,52 @@ def set_shape_transparency(ais, t):
def get_bounding_box_center(bbox):
bbmin = [0.]*3; bbmax = [0.]*3
import OCC.gp
bbmin = [0.] * 3
bbmax = [0.] * 3
bbmin[0], bbmin[1], bbmin[2], bbmax[0], bbmax[1], bbmax[2] = bbox.Get()
return OCC.gp.gp_Pnt(*map(lambda xy: (xy[0]+xy[1])/2., zip(bbmin, bbmax)))
return OCC.gp.gp_Pnt(*map(lambda xy: (xy[0] + xy[1]) / 2., zip(bbmin, bbmax)))
def serialize_shape(shape):
import OCC.BRepTools
shapes = OCC.BRepTools.BRepTools_ShapeSet()
shapes.Add(shape)
return shapes.WriteToString()
def create_shape_from_serialization(brep_object):
brep_data, occ_shape = None, None
try: brep_data = brep_object.geometry.brep_data
except: pass
if not brep_data: return tuple(brep_object, None)
import OCC.BRepTools
brep_data, occ_shape, styles = None, None, ()
is_product_shape = True
try:
brep_data = brep_object.geometry.brep_data
styles = brep_object.geometry.surface_styles
except BaseException:
try:
brep_data = brep_object.brep_data
styles = brep_object.surface_styles
is_product_shape = False
except BaseException:
pass
styles = tuple(styles[i:i + 4] for i in range(0, len(styles), 4))
if not brep_data:
return shape_tuple(brep_object, None, styles)
try:
ss = OCC.BRepTools.BRepTools_ShapeSet()
ss.ReadFromString(brep_data)
occ_shape = ss.Shape(ss.NbShapes())
except: pass
return tuple(brep_object, occ_shape)
except BaseException:
pass
if is_product_shape:
return shape_tuple(brep_object, occ_shape, styles)
else:
return occ_shape
+21 -7
View File
@@ -17,27 +17,41 @@
# #
###############################################################################
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import uuid
import string
from functools import reduce
chars = string.digits + string.ascii_uppercase + string.ascii_lowercase + '_$'
def compress(g):
bs = [int(g[i:i+2], 16) for i in range(0, len(g), 2)]
bs = [int(g[i:i + 2], 16) for i in range(0, len(g), 2)]
def b64(v, l=4):
return ''.join([chars[(v // (64**i))%64] for i in range(l)][::-1])
return ''.join([b64(bs[0], 2)] + [b64((bs[i] << 16) + (bs[i+1] << 8) + bs[i+2]) for i in range(1,16,3)])
return ''.join([chars[(v // (64 ** i)) % 64] for i in range(l)][::-1])
return ''.join([b64(bs[0], 2)] + [b64((bs[i] << 16) + (bs[i + 1] << 8) + bs[i + 2]) for i in range(1, 16, 3)])
def expand(g):
def b64(v):
return reduce(lambda a, b: a * 64 + b, map(lambda c: chars.index(c), v))
bs = [b64(g[0:2])]
for i in range(5):
d = b64(g[2+4*i:6+4*i])
bs += [(d >> (8*(2-j)))%256 for j in range(3)]
return ''.join(['%02x'%b for b in bs])
d = b64(g[2 + 4 * i:6 + 4 * i])
bs += [(d >> (8 * (2 - j))) % 256 for j in range(3)]
return ''.join(['%02x' % b for b in bs])
def split(g):
return '{%s-%s-%s-%s-%s}'%(g[:8], g[8:12], g[12:16], g[16:20], g[20:])
return '{%s-%s-%s-%s-%s}' % (g[:8], g[8:12], g[12:16], g[16:20], g[20:])
def new():
return compress(uuid.uuid4().hex)
@@ -17,19 +17,11 @@
# #
###############################################################################
import templates
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
class LateBoundHeader:
def __init__(self, mapping):
self.str = templates.lb_header % {
'schema_name_upper' : mapping.schema.name.upper(),
'schema_name' : mapping.schema.name.capitalize()
}
self.schema_name = mapping.schema.name.capitalize()
def __repr__(self):
return self.str
def emit(self):
f = open('%s-latebound.h'%self.schema_name, 'w', encoding='utf-8')
f.write(str(self))
f.close()
from . import ifcopenshell_wrapper
version = ifcopenshell_wrapper.version()
get_log = ifcopenshell_wrapper.get_log
@@ -0,0 +1,86 @@
###############################################################################
# #
# 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/>. #
# #
###############################################################################
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import time
import uuid
from .file import file
from .guid import compress
from . import main
# A quick way to setup an 'empty' IFC file, taken from:
# http://academy.ifcopenshell.org/creating-a-simple-wall-with-property-set-and-quantity-information/
TEMPLATE = """ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('ViewDefinition [CoordinationView]'),'2;1');
FILE_NAME('%(filename)s','%(timestring)s',('%(creator)s'),('%(organization)s'),'%(application)s','%(application)s','');
FILE_SCHEMA(('%(schema_identifier)s'));
ENDSEC;
DATA;
#1=IFCPERSON($,$,'%(creator)s',$,$,$,$,$);
#2=IFCORGANIZATION($,'%(organization)s',$,$,$);
#3=IFCPERSONANDORGANIZATION(#1,#2,$);
#4=IFCAPPLICATION(#2,'%(application_version)s','%(application)s','');
#5=IFCOWNERHISTORY(#3,#4,$,.ADDED.,$,#3,#4,%(timestamp)s);
#6=IFCDIRECTION((1.,0.,0.));
#7=IFCDIRECTION((0.,0.,1.));
#8=IFCCARTESIANPOINT((0.,0.,0.));
#9=IFCAXIS2PLACEMENT3D(#8,#7,#6);
#10=IFCDIRECTION((0.,1.,0.));
#11=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#9,#10);
#12=IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0);
#13=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.);
#14=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.);
#15=IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.);
#16=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.);
#17=IFCMEASUREWITHUNIT(IFCPLANEANGLEMEASURE(0.017453292519943295),#16);
#18=IFCCONVERSIONBASEDUNIT(#12,.PLANEANGLEUNIT.,'DEGREE',#17);
#19=IFCUNITASSIGNMENT((#13,#14,#15,#18));
#20=IFCPROJECT('%(project_globalid)s',#5,'%(project_name)s',$,$,$,$,(#11),#19);
ENDSEC;
END-ISO-10303-21;
"""
DEFAULTS = {
"application": lambda d: 'IfcOpenShell-%s' % main.version,
"application_version": lambda d: main.version,
"project_globalid": lambda d: compress(uuid.uuid4().hex),
"schema_identifier": lambda d: main.schema_identifier,
"timestamp": lambda d: time.time(),
"timestring": lambda d: time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime(d.get('timestamp') or time.time()))
}
def create(filename=None, timestring=None, organization=None, creator=None,
schema_identifier=None, application_version=None, timestamp=None,
application=None, project_globalid=None, project_name=None):
d = dict(locals())
def _():
for var, value in d.items():
if value is None:
yield var, DEFAULTS.get(var, lambda *args: '')(d)
d.update(dict(_()))
return file.from_string(TEMPLATE % d)

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