Compare commits

..

1 Commits

Author SHA1 Message Date
Thomas Krijnen 214c228962 Change signature of attribute setters to take and return boost::optionals
Remove set- prefix for setters
2015-03-20 21:11:46 +00:00
220 changed files with 63107 additions and 117127 deletions
-14
View File
@@ -1,14 +0,0 @@
# 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
@@ -1,56 +0,0 @@
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
@@ -0,0 +1,65 @@
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
@@ -1,228 +0,0 @@
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"
+182 -643
View File
@@ -1,696 +1,235 @@
################################################################################
# #
# 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)
cmake_minimum_required (VERSION 2.6)
project (IfcOpenShell)
OPTION(UNICODE_SUPPORT "Build IfcOpenShell with Unicode support (requires ICU)." ON)
OPTION(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON)
OPTION(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})
FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options)
MESSAGE(STATUS "Boost include files found in ${Boost_INCLUDE_DIRS}")
MESSAGE(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}")
# 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}")
# 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}")
MESSAGE(STATUS "Use OCC_INCLUDE_DIR to specify another directory")
ELSE()
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}")
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}")
ENDIF()
FIND_FILE(gp_Pnt_hxx "gp_Pnt.hxx" ${OCC_INCLUDE_DIR})
FIND_FILE(gp_Pnt_hxx "gp_Pnt.hxx" ${OCC_INCLUDE_DIR} /usr/inc /usr/local/inc /usr/local/include/oce)
IF(gp_Pnt_hxx)
MESSAGE(STATUS "Header files found")
ELSE()
MESSAGE(FATAL_ERROR "Unable to find header files, aborting")
ENDIF()
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 "")
# Find Open CASCADE library files
IF("$ENV{OCC_LIBRARY_DIR}" STREQUAL "")
SET(OCC_LIBRARY_DIR "/usr/lib/" CACHE FILEPATH "Open CASCADE library files")
MESSAGE(STATUS "Looking for Open CASCADE library files in: ${OCC_LIBRARY_DIR}")
MESSAGE(STATUS "Looking for opencascade library files in: ${OCC_LIBRARY_DIR}")
MESSAGE(STATUS "Use OCC_LIBRARY_DIR to specify another directory")
ELSE()
SET(OCC_LIBRARY_DIR ${OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files")
MESSAGE(STATUS "Looking for Open CASCADE library files in: ${OCC_LIBRARY_DIR}")
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}")
ENDIF()
FIND_LIBRARY(libTKernel NAMES TKernel TKerneld PATHS ${OCC_LIBRARY_DIR} NO_DEFAULT_PATH)
FIND_LIBRARY(libTKernel "TKernel" ${OCC_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64)
IF(libTKernel)
MESSAGE(STATUS "Library files found")
ELSE()
MESSAGE(FATAL_ERROR "Unable to find library files, aborting")
ENDIF()
# 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()
IF("$ENV{ICU_INCLUDE_DIR}" STREQUAL "")
MESSAGE(STATUS "No ICU include directory specified")
ElSE()
SET(ICU_INCLUDE_DIR CACHE FILEPATH "ICU header files")
ENDIF()
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()
IF("$ENV{ICU_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No ICU library directory specified")
ElSE()
SET(ICU_LIBRARY_DIR CACHE FILEPATH "ICU library files")
ENDIF()
# 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()
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)
IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE "Release")
ENDIF()
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()
SET(CMAKE_BUILD_TYPE "Release")
ENDIF(NOT CMAKE_BUILD_TYPE)
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_DEFINITIONS(-D_UNICODE)
ElSE(MSVC)
ADD_DEFINITIONS(-fPIC -Wno-non-virtual-dtor)
ENDIF(MSVC)
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()
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})
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}
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
)
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_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(COMPILE_SCHEMA)
find_package(PythonInterp)
IF(NOT PYTHONINTERP_FOUND)
MESSAGE(FATAL_ERROR "A Python interpreter is necessary when COMPILE_SCHEMA is enabled. Disable COMPILE_SCHEMA or fix Python paths to proceed.")
ENDIF()
set(IFC_RELEASE_NOT_USED "2x3" "4")
# Install pyparsing if necessary
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST)
if ("${PYTHON_PACKAGE_LIST}" STREQUAL "")
execute_process(COMMAND pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST)
if ("${PYTHON_PACKAGE_LIST}" STREQUAL "")
message(WARNING "Failed to find pip. Pip is required to automatically install pyparsing")
endif()
endif()
string(FIND "${PYTHON_PACKAGE_LIST}" pyparsing PYPARSING_FOUND)
if ("${PYPARSING_FOUND}" STREQUAL "-1")
message(STATUS "Installing pyparsing")
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip "install" --user pyparsing RESULT_VARIABLE SUCCESS)
if (NOT "${SUCCESS}" STREQUAL "0")
execute_process(COMMAND pip "install" --user pyparsing RESULT_VARIABLE SUCCESS)
if (NOT "${SUCCESS}" STREQUAL "0")
message(WARNING "Failed to automatically install pyparsing. Please install manually")
endif()
endif()
else()
message(STATUS "Python interpreter with pyparsing found")
endif()
# Bootstrap the parser
message(STATUS "Compiling schema, this will take a while...")
execute_process(COMMAND ${PYTHON_EXECUTABLE} bootstrap.py express.bnf
WORKING_DIRECTORY ../src/ifcexpressparser
OUTPUT_FILE express_parser.py
RESULT_VARIABLE SUCCESS)
if (NOT "${SUCCESS}" STREQUAL "0")
MESSAGE(FATAL_ERROR "Failed to bootstrap parser. Make sure pyparsing is installed")
endif()
# Generate code
execute_process(COMMAND ${PYTHON_EXECUTABLE} ../ifcexpressparser/express_parser.py ../../${COMPILE_SCHEMA}
WORKING_DIRECTORY ../src/ifcparse
OUTPUT_VARIABLE COMPILED_SCHEMA_NAME)
# Prevent the schema that had just been compiled from being excluded
if("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC2X3")
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "2x3")
add_definitions(-DUSE_IFC2x3)
elseif("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC4")
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "4")
add_definitions(-DUSE_IFC4)
endif()
endif()
# Boost >= 1.58 requires BOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE to build on some Linux distros.
if(NOT Boost_VERSION LESS 105800)
add_definitions(-DBOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE)
endif()
# 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})
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})
IF(icu)
TARGET_LINK_LIBRARIES(IfcParse icuuc)
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})
TARGET_LINK_LIBRARIES(IfcGeom IfcParse)
add_library(IfcGeom_ifc2x3 ${IFCGEOM_FILES})
add_library(IfcGeom_ifc4 ${IFCGEOM_FILES})
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})
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")
ADD_EXECUTABLE(IfcConvert
../src/ifcconvert/ColladaSerializer.cpp
../src/ifcconvert/IfcConvert.cpp
../src/ifcconvert/OpenCascadeBasedSerializer.cpp
../src/ifcconvert/WavefrontObjSerializer.cpp
../src/ifcconvert/XmlSerializer.cpp
)
TARGET_LINK_LIBRARIES(IfcGeom_ifc2x3 IfcParse ${OPENCASCADE_LIBRARIES})
TARGET_LINK_LIBRARIES(IfcGeom_ifc4 IfcParse ${OPENCASCADE_LIBRARIES})
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})
# 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_EXECUTABLE(IfcGeomServer
../src/ifcgeomserver/IfcGeomServer.cpp
)
add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES})
set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS)
TARGET_LINK_LIBRARIES(IfcGeom IfcGeom_ifc2x3 IfcGeom_ifc4)
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)
# 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})
# Build python wrapper using separate CMakeLists.txt
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
add_library(Serializers_ifc2x3 ${SERIALIZERS_S_FILES})
add_library(Serializers_ifc4 ${SERIALIZERS_S_FILES})
# Build IfcParseExamples using separate CMakeLists.txt
ADD_SUBDIRECTORY(../src/examples examples)
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()
# ADD_SUBDIRECTORY(../src/qtviewer qtviewer)
# CMake installation targets
INSTALL(FILES ${IFCPARSE_H_FILES}
DESTINATION ${INCLUDEDIR}/ifcparse
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 ${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}
SET(include_files_parse
../src/ifcparse/Ifc2x3-latebound.h
../src/ifcparse/Ifc2x3.h
../src/ifcparse/Ifc2x3enum.h
../src/ifcparse/Ifc4-latebound.h
../src/ifcparse/Ifc4.h
../src/ifcparse/Ifc4enum.h
../src/ifcparse/IfcCharacterDecoder.h
../src/ifcparse/IfcEntityDescriptor.h
../src/ifcparse/IfcException.h
../src/ifcparse/IfcFile.h
../src/ifcparse/IfcHierarchyHelper.h
../src/ifcparse/IfcLateBoundEntity.h
../src/ifcparse/IfcParse.h
../src/ifcparse/IfcSIPrefix.h
../src/ifcparse/IfcSpfHeader.h
../src/ifcparse/IfcSpfStream.h
../src/ifcparse/IfcUtil.h
../src/ifcparse/IfcWritableEntity.h
../src/ifcparse/IfcWrite.h
../src/ifcparse/SharedPointer.h
)
INSTALL(FILES ${include_files_geom} DESTINATION include/ifcgeom)
INSTALL(FILES ${include_files_parse} DESTINATION include/ifcparse)
INSTALL(TARGETS IfcConvert DESTINATION bin)
INSTALL(TARGETS IfcParse IfcGeom DESTINATION lib)
-29
View File
@@ -1,29 +0,0 @@
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
@@ -1,34 +0,0 @@
# 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
@@ -1,36 +0,0 @@
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
@@ -1,619 +0,0 @@
#!/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
@@ -1,32 +0,0 @@
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);
}
+2 -27
View File
@@ -1,30 +1,5 @@
################################################################################
# #
# 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)
set_target_properties(IfcParseExamples PROPERTIES FOLDER Examples)
TARGET_LINK_LIBRARIES (IfcParseExamples IfcParse)
ADD_EXECUTABLE(IfcOpenHouse IfcOpenHouse.cpp)
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)
TARGET_LINK_LIBRARIES (IfcOpenHouse IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKOffset)
-182
View File
@@ -1,182 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include <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 -98
View File
@@ -28,53 +28,44 @@
#include <Geom_BSplineSurface.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <Standard_Version.hxx>
#include <BRepGProp.hxx>
#include <GProp_GProps.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/IfcUtil.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 IfcParse::IfcGlobalId guid;
typedef IfcWrite::IfcGuidHelper guid;
typedef std::pair<double, double> XY;
boost::none_t const null = boost::none;
boost::none_t const null = (static_cast<boost::none_t>(0));
// The creation of Nurbs-surface for the IfcSite mesh, to be implemented lateron
void createGroundShape(TopoDS_Shape& shape);
int main() {
int main(int argc, char** argv) {
// The IfcHierarchyHelper is a subclass of the regular IfcFile that provides several
// convenience functions for working with geometry in IFC files.
IfcHierarchyHelper<IfcSchema> file;
IfcHierarchyHelper file;
file.header().file_name().name("IfcOpenHouse.ifc");
// Start by adding a wall to the file, initially leaving most attributes blank.
IfcSchema::IfcWallStandardCase* south_wall = new IfcSchema::IfcWallStandardCase(
guid(), // GlobalId
0, // OwnerHistory
0, // OwnerHistory
S("South wall"), // Name
null, // Description
null, // ObjectType
0, // ObjectPlacement
0, // Representation
null, // ObjectPlacement
null, // Representation
null // Tag
#ifdef USE_IFC4
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
@@ -87,10 +78,10 @@ int main() {
// 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");
file.getSingle<IfcSchema::IfcProject>()->Name(S("IfcOpenHouse"));
// An IfcOwnerHistory has been initialized as well, which should be assigned to the wall.
south_wall->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
south_wall->OwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
// The wall will be shaped as a box, with the dimensions specified in millimeters. The resulting
// product definition will consist of both a body representation as well as an axis representation
@@ -99,12 +90,12 @@ int main() {
// Obtain a reference to the placement of the IfcBuildingStorey in order to create a hierarchy
// of placements for the products
IfcSchema::IfcObjectPlacement* storey_placement = file.getSingle<IfcSchema::IfcBuildingStorey>()->ObjectPlacement();
IfcSchema::IfcObjectPlacement* storey_placement = *file.getSingle<IfcSchema::IfcBuildingStorey>()->ObjectPlacement();
// The shape has to be assigned to the representation of the wall and is placed at the origin
// of the coordinate system.
south_wall->setRepresentation(south_wall_shape);
south_wall->setObjectPlacement(file.addLocalPlacement(storey_placement));
south_wall->Representation(south_wall_shape);
south_wall->ObjectPlacement(file.addLocalPlacement(storey_placement));
// A pale white colour is assigned to the wall.
IfcSchema::IfcPresentationStyleAssignment* wall_colour = file.setSurfaceColour(
@@ -112,17 +103,17 @@ int main() {
// Now create a footing for the wall to rest on.
IfcSchema::IfcFooting* footing = new IfcSchema::IfcFooting(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
S("Footing"), null, null, 0, 0, null, IfcSchema::IfcFootingTypeEnum::IfcFootingType_STRIP_FOOTING);
S("Footing"), null, null, null, null, null, IfcSchema::IfcFootingTypeEnum::IfcFootingType_STRIP_FOOTING);
file.addBuildingProduct(footing);
// The footing will span the entire floor plan of our building. The IfcRepresentationContext is
// something that has been created automatically as well, but representations could have been
// assigned to a specific context, for example to add a two dimensional plan representation as well.
footing->setRepresentation(file.addBox(10100, 5460, 2000));
footing->setObjectPlacement(file.addLocalPlacement(storey_placement, 0, 2500, -2000));
footing->Representation(file.addBox(10100, 5460, 2000));
footing->ObjectPlacement(file.addLocalPlacement(storey_placement, 0, 2500, -2000));
// The footing will have a dark gray colour
IfcSchema::IfcPresentationStyleAssignment* footing_colour = file.setSurfaceColour(footing->Representation(), 0.26, 0.22, 0.18);
IfcSchema::IfcPresentationStyleAssignment* footing_colour = file.setSurfaceColour(*footing->Representation(), 0.26, 0.22, 0.18);
// IFC has two ways to apply boolean operations to geometry. IfcBooleanResults are commonly used
// to clip geometry to a surface, for example to a slanted roof. For openings that are filled
@@ -130,7 +121,7 @@ int main() {
// An opening element is created with rectangular geometry:
IfcSchema::IfcOpeningElement* west_opening = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
null, null, null, file.addLocalPlacement(south_wall->ObjectPlacement(), -2500, 0, 400),
null, null, null, file.addLocalPlacement(*south_wall->ObjectPlacement(), -2500, 0, 400),
file.addBox(6000, 3630, 1600), null
#ifdef USE_IFC4
, IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING
@@ -156,7 +147,7 @@ int main() {
// Create a roof element that will consist of two slabs:
IfcSchema::IfcRoof* roof = new IfcSchema::IfcRoof(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("Roof"), null, null,
file.addLocalPlacement(storey_placement), 0, null, IfcSchema::IfcRoofTypeEnum::IfcRoofType_GABLE_ROOF);
file.addLocalPlacement(storey_placement), null, null, IfcSchema::IfcRoofTypeEnum::IfcRoofType_GABLE_ROOF);
// The roof geometry is slanted 45 degrees by specifying a direction for the box extrusion
IfcSchema::IfcShapeRepresentation* roof_rep = file.addEmptyRepresentation();
@@ -165,21 +156,21 @@ int main() {
// CV-2x3-144: Roofs are aggregates and shall have at least one contained element and no own geometry
IfcSchema::IfcSlab* south_roof_part = new IfcSchema::IfcSlab(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("South roof"),
null, null, 0, 0, null, IfcSchema::IfcSlabTypeEnum::IfcSlabType_ROOF);
null, null, null, null, null, IfcSchema::IfcSlabTypeEnum::IfcSlabType_ROOF);
// The geometry is instantiated by using IfcMappedItems. This way geometry definitions can
// be reused while maintaining the cardinality constraint that the ShapeOfProduct relation
// imposes on the IfcProductDefinitionShape. Note that this constrained is lifted in IFC4.
south_roof_part->setRepresentation(file.addMappedItem(roof_rep));
south_roof_part->setObjectPlacement(file.addLocalPlacement(roof->ObjectPlacement(), 0, -400, 2700));
south_roof_part->Representation(file.addMappedItem(roof_rep));
south_roof_part->ObjectPlacement(file.addLocalPlacement(*roof->ObjectPlacement(), 0, -400, 2700));
// The same roof geometry is re-used on the north side of the roof, by inverting the X-axis of
// the local placement the roof is rotated 180 degrees around the Z-axis
IfcSchema::IfcSlab* north_roof_part = new IfcSchema::IfcSlab(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), S("North roof"),
null, null, 0, 0, null, IfcSchema::IfcSlabTypeEnum::IfcSlabType_ROOF);
north_roof_part->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
north_roof_part->setRepresentation(file.addMappedItem(roof_rep));
north_roof_part->setObjectPlacement(file.addLocalPlacement(roof->ObjectPlacement(), 0, 5400, 2700, 0, 0, 1, -1, 0, 0));
null, null, null, null, null, IfcSchema::IfcSlabTypeEnum::IfcSlabType_ROOF);
north_roof_part->OwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
north_roof_part->Representation(file.addMappedItem(roof_rep));
north_roof_part->ObjectPlacement(file.addLocalPlacement(*roof->ObjectPlacement(), 0, 5400, 2700, 0, 0, 1, -1, 0, 0));
IfcSchema::IfcObjectDefinition::list::ptr roof_parts(new IfcSchema::IfcObjectDefinition::list);
roof_parts->push(south_roof_part);
@@ -202,48 +193,45 @@ int main() {
#endif
);
file.addBuildingProduct(north_wall);
file.setSurfaceColour(north_wall->Representation(), wall_colour);
file.setSurfaceColour(*north_wall->Representation(), wall_colour);
// Two identical representations are created for the two remaining walls. Mapped items
// are not used, because it is not allowed by the standard for wall body representations.
// MappedItems are not allowed for Axis representations as per CV-2x3-161
IfcSchema::IfcProductDefinitionShape* clipped_wall_body_reps[2];
for (int i = 0; i < 2; ++i) {
IfcSchema::IfcShapeRepresentation* body = file.addEmptyRepresentation();
file.addBox(body, 5000, 360, 6000);
// The wall geometry is clipped using two IfcHalfSpaceSolids, created from an
// 'axis 3d placement' that specifies the plane against which the geometry is clipped.
file.clipRepresentation(body, file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false);
file.clipRepresentation(body, file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false);
file.setSurfaceColour(body, wall_colour);
IfcSchema::IfcShapeRepresentation* axis = file.addEmptyRepresentation("Axis", "Curve2D");
file.addAxis(axis, 5000);
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
reps->push(body);
reps->push(axis);
clipped_wall_body_reps[i] = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
}
IfcSchema::IfcShapeRepresentation* clipped_wall_body_rep = file.addEmptyRepresentation();
file.addBox(clipped_wall_body_rep, 5000, 360, 6000);
// The east wall geometry is clipped using two IfcHalfSpaceSolids, created from an
// 'axis 3d placement' that specifies the plane against which the geometry is clipped.
file.clipRepresentation(clipped_wall_body_rep, file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false);
file.clipRepresentation(clipped_wall_body_rep, file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false);
// Now create a wall on the east of the building, again starting with just a box shape
IfcSchema::IfcWallStandardCase* east_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
S("East wall"), null, null, file.addLocalPlacement(storey_placement, 4820, 2500, 0, 0, 0, 1, 0, 1, 0), clipped_wall_body_reps[0], null
S("East wall"), null, null, file.addLocalPlacement(storey_placement, 4820, 2500, 0, 0, 0, 1, 0, 1, 0), file.addMappedItem(clipped_wall_body_rep), null
#ifdef USE_IFC4
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
#endif
);
file.addBuildingProduct(east_wall);
file.setSurfaceColour(clipped_wall_body_rep, wall_colour);
// The east wall is copied to the west location of the house
IfcSchema::IfcWallStandardCase* west_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
S("West wall"), null, null, file.addLocalPlacement(storey_placement, -4820, 2500, 0, 0, 0, 1, 0, -1, 0), clipped_wall_body_reps[1], null
S("West wall"), null, null, file.addLocalPlacement(storey_placement, -4820, 2500, 0, 0, 0, 1, 0, -1, 0), file.addMappedItem(clipped_wall_body_rep), null
#ifdef USE_IFC4
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
#endif
);
file.addBuildingProduct(west_wall);
for (int i = 0; i < 2; ++i) {
// CV-2x3-161: MappedItems are not allowed for Axis representations
IfcSchema::IfcWallStandardCase* wall = i == 0 ? east_wall : west_wall;
IfcSchema::IfcShapeRepresentation* wall_axis_rep = file.addEmptyRepresentation("Axis", "Curve2D");
file.addAxis(wall_axis_rep, 5000);
IfcSchema::IfcRepresentation::list::ptr reps = wall->Representation().get()->Representations();
reps->push(wall_axis_rep);
wall->Representation().get()->Representations(reps);
}
// The west wall is assigned an opening element we created for the south wall, opening elements are
// not shared accross building elements, even if they share the same representation. Hence, the east
// wall will not feature this opening.
@@ -253,7 +241,7 @@ int main() {
// Not all viewers support opening elements with mapped representations, hence an exact copy of the
// same subtraction box is instantiated for the otherwise identical opening element.
IfcSchema::IfcOpeningElement* west_opening_copy = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
null, null, null, file.addLocalPlacement(west_wall->ObjectPlacement(), 2500, -2500+4820, 400, 0, 0, 1, 0, 1, 0),
null, null, null, file.addLocalPlacement(*west_wall->ObjectPlacement(), 2500, -2500+4820, 400, 0, 0, 1, 0, 1, 0),
file.addBox(6000, 3630, 1600), null
#ifdef USE_IFC4
, IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING
@@ -267,30 +255,14 @@ int main() {
// will be tesselated using the deflection specified.
TopoDS_Shape shape;
createGroundShape(shape);
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::tesselate(STRINGIFY(IfcSchema), shape, 100.)->as<IfcSchema::IfcProductDefinitionShape>();
file.getSingle<IfcSchema::IfcSite>()->setRepresentation(ground_representation);
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"));
IfcEntityList::ptr geometrical_entities(new IfcEntityList);
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::tesselate(shape, 100., geometrical_entities);
file.getSingle<IfcSchema::IfcSite>()->Representation(ground_representation);
file.addEntities(geometrical_entities);
IfcSchema::IfcShapeRepresentation::list::ptr ground_reps = geometrical_entities->as<IfcSchema::IfcShapeRepresentation>();
for (IfcSchema::IfcShapeRepresentation::list::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
(*it)->ContextOfItems(file.getRepresentationContext("Model"));
}
file.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
@@ -341,9 +313,9 @@ int main() {
null,
null,
#ifdef USE_IFC4
file.instances_by_type<IfcSchema::IfcWallStandardCase>()->generalize(),
file.entitiesByType<IfcSchema::IfcWallStandardCase>()->generalize(),
#else
file.instances_by_type<IfcSchema::IfcWallStandardCase>()->as<IfcSchema::IfcRoot>(),
file.entitiesByType<IfcSchema::IfcWallStandardCase>()->as<IfcSchema::IfcRoot>(),
#endif
layer_usage);
@@ -371,7 +343,7 @@ int main() {
);
file.addBuildingProduct(stair);
file.setSurfaceColour(stair->Representation(), footing_colour);
file.setSurfaceColour(*stair->Representation(), footing_colour);
IfcSchema::IfcOpeningElement* door_opening = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
null, null, null, file.addLocalPlacement(storey_placement, 5000-180, 2500-900, 0), file.addBox(1000, 1000, 2200), null
@@ -386,19 +358,19 @@ int main() {
// can be a composition of multiple solids. The following door will be composed of four boxes
// which constitute the door and its frame.
IfcSchema::IfcDoor* door = new IfcSchema::IfcDoor(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, null,
file.addLocalPlacement(storey_placement, 4800, 1600, 0, 0, 0, 1, 0, 1, 0), 0, null, 2200, 1000
file.addLocalPlacement(storey_placement, 4800, 1600, 0, 0, 0, 1, 0, 1, 0), null, null, 2200, 1000
#ifdef USE_IFC4
, IfcSchema::IfcDoorTypeEnum::IfcDoorType_DOOR
, IfcSchema::IfcDoorTypeOperationEnum::IfcDoorTypeOperation_SINGLE_SWING_LEFT
, null
#endif
);
door->setRepresentation(file.addBox(80, 80, 2120, 0, file.addPlacement3d(460, 0, 0)));
IfcSchema::IfcRepresentation::list::ptr door_representations = door->Representation()->Representations();
door->Representation(file.addBox(80, 80, 2120, 0, file.addPlacement3d(460, 0, 0)));
IfcSchema::IfcRepresentation::list::ptr door_representations = door->Representation().get()->Representations();
IfcSchema::IfcShapeRepresentation* door_body = 0;
for (IfcSchema::IfcRepresentation::list::it i = door_representations->begin(); i != door_representations->end(); ++i) {
IfcSchema::IfcRepresentation* rep = *i;
if (rep->declaration().is(IfcSchema::IfcShapeRepresentation::Class()) && rep->RepresentationIdentifier() == "Body") {
if (rep->is(IfcSchema::Type::IfcShapeRepresentation) && *rep->RepresentationIdentifier() == "Body") {
door_body = (IfcSchema::IfcShapeRepresentation*) rep;
}
}
@@ -406,13 +378,9 @@ int main() {
file.addBox(door_body, 1000, 80, 80, 0, file.addPlacement3d( 0, 0, 2120));
file.addBox(door_body, 860, 30, 2120);
file.addBuildingProduct(door);
file.setSurfaceColour(door->Representation(), 0.9, 0.9, 0.9);
file.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.
@@ -461,7 +429,7 @@ int main() {
// Create the window at the current location
IfcSchema::IfcLocalPlacement* place = *it;
IfcSchema::IfcWindow* window = new IfcSchema::IfcWindow(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
null, null, null, place, 0, null, 1600, 1860
null, null, null, place, null, null, 1600, 1860
#ifdef USE_IFC4
, IfcSchema::IfcWindowTypeEnum::IfcWindowType_WINDOW
, IfcSchema::IfcWindowTypePartitioningEnum::IfcWindowTypePartitioning_SINGLE_PANEL
@@ -509,7 +477,7 @@ int main() {
file.addEntity(glass_part);
window_parts->push(glass_part);
file.relatePlacements(window, glass_part);
file.setSurfaceColour(glass_part->Representation(), 0.6, 0.7, 0.75, 0.1);
file.setSurfaceColour(*glass_part->Representation(), 0.6, 0.7, 0.75, 0.1);
// Now create a decomposition relation between the window and the parts. Most viewers and authoring
// tools will consider the window a single entity that can be selected as a whole.
+12 -17
View File
@@ -17,15 +17,9 @@
* *
********************************************************************************/
// TODO: Multiple schemas
#define IfcSchema Ifc2x3
#include "../ifcparse/IfcFile.h"
#include "../ifcparse/Ifc2x3.h"
#if USE_VLD
#include <vld.h>
#endif
using namespace IfcSchema;
int main(int argc, char** argv) {
@@ -38,8 +32,8 @@ int main(int argc, char** argv) {
Logger::SetOutput(&std::cout,&std::cout);
// Parse the IFC file provided in argv[1]
IfcParse::IfcFile file(argv[1]);
if (!file.good()) {
IfcParse::IfcFile file;
if ( ! file.Init(argv[1]) ) {
std::cout << "Unable to parse .ifc file" << std::endl;
return 1;
}
@@ -60,19 +54,20 @@ 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.
IfcSchema::IfcBuildingElement::list::ptr elements = file.instances_by_type<IfcSchema::IfcBuildingElement>();
IfcBuildingElement::list::ptr elements = file.entitiesByType<IfcBuildingElement>();
std::cout << "Found " << elements->size() << " elements in " << argv[1] << ":" << std::endl;
for (IfcSchema::IfcBuildingElement::list::it it = elements->begin(); it != elements->end(); ++it) {
for ( IfcBuildingElement::list::it it = elements->begin(); it != elements->end(); ++ it ) {
const IfcSchema::IfcBuildingElement* element = *it;
std::cout << element->data().toString() << std::endl;
const IfcBuildingElement* element = *it;
std::cout << element->entity->toString() << std::endl;
const IfcSchema::IfcWindow* window;
if ((window = element->as<IfcSchema::IfcWindow>()) != 0) {
if (window->hasOverallWidth() && window->hasOverallHeight()) {
const double area = window->OverallWidth()*window->OverallHeight();
if ( element->is(IfcWindow::Class()) ) {
const IfcWindow* window = (IfcWindow*)element;
if ( window->OverallWidth() && window->OverallHeight() ) {
const double area = window->OverallWidth().get() * window->OverallHeight().get();
std::cout << "The area of this window is " << area << std::endl;
}
}
+11 -11
View File
@@ -33,8 +33,8 @@
#include "../ifcparse/IfcHierarchyHelper.h"
typedef std::string S;
typedef IfcParse::IfcGlobalId guid;
boost::none_t const null = boost::none;
typedef IfcWrite::IfcGuidHelper guid;
boost::none_t const null = (static_cast<boost::none_t>(0));
static int i = 0;
void create_product_from_item(IfcHierarchyHelper& file, IfcSchema::IfcRepresentationItem* item, const std::string& s) {
@@ -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(0, 120 * i++));
product->setObjectPlacement(file.addLocalPlacement(120 * i++));
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
items->push(item);
if (s == "GeometricSet") {
IfcSchema::IfcGeometricSet* set = new IfcSchema::IfcGeometricSet(items->generalize());
file.addEntity(set);
items = IfcSchema::IfcRepresentationItem::list::ptr(new IfcSchema::IfcRepresentationItem::list());
items = IfcSchema::IfcRepresentationItem::list(new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
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(boost::none, boost::none, reps);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, 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.header().file_name().name(filename);
file.filename(filename);
double coords1[] = {-50.0, 0.0};
double coords2[] = { 50.0, 0.0};
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list());
IfcSchema::IfcCartesianPoint::list points (new IfcTemplatedEntityList<IfcSchema::IfcCartesianPoint>());
points->push(new IfcSchema::IfcCartesianPoint(std::vector<double>(coords1, coords1+2)));
points->push(new IfcSchema::IfcCartesianPoint(std::vector<double>(coords2, coords2+2)));
file.addEntities(points->generalize());
@@ -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 IfcSchema::IfcParameterValue( 0.));
trim2->push(new IfcSchema::IfcParameterValue(180.));
trim1->push(new IfcWrite::IfcSelectHelper( 0., Ifc2x3::Type::IfcParameterValue));
trim2->push(new IfcWrite::IfcSelectHelper(180., Ifc2x3::Type::IfcParameterValue));
IfcSchema::IfcTrimmedCurve* trim = new IfcSchema::IfcTrimmedCurve(ellipse, trim1, trim2, true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
file.addEntity(trim);
+7 -7
View File
@@ -32,19 +32,19 @@
#include "../ifcparse/IfcHierarchyHelper.h"
typedef std::string S;
typedef IfcParse::IfcGlobalId guid;
boost::none_t const null = boost::none;
typedef IfcWrite::IfcGuidHelper guid;
boost::none_t const null = (static_cast<boost::none_t>(0));
int main(int argc, char** argv) {
const char filename[] = "IfcCompositeProfileDef.ifc";
IfcHierarchyHelper file;
file.header().file_name().name(filename);
file.filename(filename);
double coords1[] = {100.0, 0.0};
double coords2[] = {200.0, 0.0};
double coords3[] = {300.0, 0.0};
IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list());
IfcSchema::IfcProfileDef::list profiles (new IfcTemplatedEntityList<IfcSchema::IfcProfileDef>());
IfcSchema::IfcCartesianTransformationOperator2D* transform1 = new IfcSchema::IfcCartesianTransformationOperator2D(file.addDoublet<IfcSchema::IfcDirection>(1, 0), file.addDoublet<IfcSchema::IfcDirection>(0, -1), file.addDoublet<IfcSchema::IfcCartesianPoint>(40, 0), null);
IfcSchema::IfcCartesianTransformationOperator2D* transform2 = new IfcSchema::IfcCartesianTransformationOperator2D(file.addDoublet<IfcSchema::IfcDirection>(0, -1), file.addDoublet<IfcSchema::IfcDirection>(1, 0), file.addDoublet<IfcSchema::IfcCartesianPoint>(40, 0), 0.3);
@@ -98,15 +98,15 @@ int main(int argc, char** argv) {
file.addEntity(composite);
file.addEntity(solid);
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
items->push(solid);
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("SweptSolid"), items);
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
file.addEntity(rep);
file.addEntity(shape);
+6 -6
View File
@@ -32,8 +32,8 @@
#include "../ifcparse/IfcHierarchyHelper.h"
typedef std::string S;
typedef IfcParse::IfcGlobalId guid;
boost::none_t const null = boost::none;
typedef IfcWrite::IfcGuidHelper guid;
boost::none_t const null = (static_cast<boost::none_t>(0));
class Node {
private:
@@ -135,7 +135,7 @@ public:
int main(int argc, char** argv) {
const char filename[] = "IfcCsgPrimitive.ifc";
IfcHierarchyHelper file;
file.header().file_name().name(filename);
file.filename(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::ptr reps (new IfcSchema::IfcRepresentation::list());
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
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(null, null, reps);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
file.addEntity(rep);
file.addEntity(shape);
+10 -10
View File
@@ -32,8 +32,8 @@
#include "../ifcparse/IfcHierarchyHelper.h"
typedef std::string S;
typedef IfcParse::IfcGlobalId guid;
boost::none_t const null = boost::none;
typedef IfcWrite::IfcGuidHelper guid;
boost::none_t const null = (static_cast<boost::none_t>(0));
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::ptr points(new Ifc2x3::IfcCartesianPoint::list());
Ifc2x3::IfcCartesianPoint::list points(new IfcTemplatedEntityList<Ifc2x3::IfcCartesianPoint>());
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 Ifc2x3::IfcParameterValue(pie.t1));
trim2->push(new Ifc2x3::IfcParameterValue(pie.t2));
trim1->push(new IfcWrite::IfcSelectHelper(pie.t1, Ifc2x3::Type::IfcParameterValue));
trim2->push(new IfcWrite::IfcSelectHelper(pie.t2, Ifc2x3::Type::IfcParameterValue));
} else {
trim1->push(p2);
trim2->push(p3);
@@ -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::ptr segments(new Ifc2x3::IfcCompositeCurveSegment::list());
Ifc2x3::IfcCompositeCurveSegment::list segments(new IfcTemplatedEntityList<Ifc2x3::IfcCompositeCurveSegment>());
Ifc2x3::IfcCompositeCurveSegment* s2 = new Ifc2x3::IfcCompositeCurveSegment(Ifc2x3::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, trim);
Ifc2x3::IfcPolyline* poly = new Ifc2x3::IfcPolyline(points);
@@ -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(0, 200 * i++));
product->setObjectPlacement(file.addLocalPlacement(200 * i++));
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(profile,
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
file.addEntity(solid);
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList<IfcSchema::IfcRepresentation>());
IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList<IfcSchema::IfcRepresentationItem>());
items->push(solid);
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("SweptSolid"), items);
reps->push(rep);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
file.addEntity(rep);
file.addEntity(shape);
-207
View File
@@ -1,207 +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/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* 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
@@ -1,143 +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/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* 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
@@ -1,85 +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/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* 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.initialize()
valid_file = iterator.findContext()
if not valid_file:
return False
print("Done reading file")
@@ -92,10 +92,8 @@ 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)]
# Depending on version, geometry.id will be either int or str
me = bpy.data.meshes.new('mesh-%r' % ob.geometry.id)
me = bpy.data.meshes.new('mesh%d' % ob.geometry.id)
me.from_pydata(verts, [], faces)
me.validate()
def add_material(mname, props):
if mname in bpy.data.materials:
+278
View File
@@ -0,0 +1,278 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifdef WITH_OPENCOLLADA
#include <string>
#include "ColladaSerializer.h"
std::string collada_id(const std::string& s) {
std::string id;
id.reserve(s.size());
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
const std::string::value_type c = *it;
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_')) {
id.push_back(c);
}
}
return id;
}
void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<double>& floats, const char* coords /* = "XYZ" */) {
COLLADASW::FloatSource source(mSW);
source.setId(mesh_id + suffix);
source.setArrayId(mesh_id + suffix + COLLADASW::LibraryGeometries::ARRAY_ID_SUFFIX);
source.setAccessorStride(strlen(coords));
source.setAccessorCount(floats.size() / 3);
for (unsigned int i = 0; i < source.getAccessorStride(); ++i) {
source.getParameterNameList().push_back(std::string(1, coords[i]));
}
source.prepareToAppendValues();
for (std::vector<double>::const_iterator it = floats.begin(); it != floats.end(); ++it) {
source.appendValues(*it);
}
source.finish();
}
void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials) {
// The goal of the IfcGeom::Iterator is to filter out empty geometries, but
// since this function would crash trying to deference the material_ids in
// that case, a hard return statement is added just in case.
if (indices.empty()) return;
openMesh(mesh_id);
// The normals vector can be empty for example when the WELD_VERTICES setting is used.
// IfcOpenShell does not provide them with multiple face normals collapsed into a single vertex.
const bool has_normals = !normals.empty();
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX, positions);
if (has_normals) {
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, normals);
}
COLLADASW::VerticesElement vertices(mSW);
vertices.setId(mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX );
vertices.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::POSITION, "#" + mesh_id + COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX));
vertices.add();
std::vector<int>::const_iterator index_range_start = indices.begin();
std::vector<int>::const_iterator material_it = material_ids.begin();
int previous_material_id = -1;
for (std::vector<int>::const_iterator it = indices.begin(); ; it += 3) {
const int current_material_id = *(material_it++);
const int num_triangles = std::distance(index_range_start, it) / 3;
if ((previous_material_id != current_material_id && num_triangles > 0) || (it == indices.end())) {
COLLADASW::Triangles triangles(mSW);
triangles.setMaterial(materials[previous_material_id].name());
triangles.setCount(num_triangles);
int offset = 0;
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX,"#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++ ) );
if (has_normals) {
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::NORMAL,"#" + mesh_id + COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, offset++ ) );
}
triangles.prepareToAppendValues();
for (std::vector<int>::const_iterator jt = index_range_start; jt != it; ++jt) {
const int idx = *jt;
if (has_normals) {
triangles.appendValues(idx, idx);
} else {
triangles.appendValues(idx);
}
}
triangles.finish();
index_range_start = it;
}
previous_material_id = current_material_id;
if (it == indices.end()) {
break;
}
}
closeMesh();
closeGeometry();
}
void ColladaSerializer::ColladaExporter::ColladaGeometries::close() {
closeLibrary();
}
void ColladaSerializer::ColladaExporter::ColladaScene::add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<double>& matrix) {
if (!scene_opened) {
openVisualScene(scene_id);
scene_opened = true;
}
COLLADASW::Node node(mSW);
node.setNodeId(node_id);
node.setNodeName(node_name);
node.setType(COLLADASW::Node::NODE);
// The matrix attribute of an entity is basically a 4x3 representation of its ObjectPlacement.
// Note that this placement is absolute, ie it is multiplied with all parent placements.
double matrix_array[4][4] = {
{matrix[0], matrix[3], matrix[6], matrix[ 9]},
{matrix[1], matrix[4], matrix[7], matrix[10]},
{matrix[2], matrix[5], matrix[8], matrix[11]},
{ 0, 0, 0, 1}
};
node.start();
node.addMatrix(matrix_array);
COLLADASW::InstanceGeometry instanceGeometry(mSW);
instanceGeometry.setUrl ("#" + geom_name);
for (std::vector<std::string>::const_iterator it = material_ids.begin(); it != material_ids.end(); ++it) {
COLLADASW::InstanceMaterial material (*it, "#" + *it);
instanceGeometry.getBindMaterial().getInstanceMaterialList().push_back(material);
}
instanceGeometry.add();
node.end();
}
void ColladaSerializer::ColladaExporter::ColladaScene::write() {
if (scene_opened) {
closeVisualScene();
closeLibrary();
COLLADASW::Scene scene (mSW, COLLADASW::URI ("#" + scene_id));
scene.add();
}
}
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeom::Material& material) {
openEffect(collada_id(material.name()) + "-fx");
COLLADASW::EffectProfile effect(mSW);
effect.setShaderType(COLLADASW::EffectProfile::LAMBERT);
if (material.hasDiffuse()) {
const double* diffuse = material.diffuse();
effect.setDiffuse(COLLADASW::ColorOrTexture(COLLADASW::Color(diffuse[0],diffuse[1],diffuse[2])));
}
if (material.hasSpecular()) {
const double* specular = material.specular();
effect.setSpecular(COLLADASW::ColorOrTexture(COLLADASW::Color(specular[0],specular[1],specular[2])));
}
if (material.hasSpecularity()) {
effect.setShininess(material.specularity());
}
if (material.hasTransparency()) {
const double transparency = material.transparency();
if (transparency > 0) {
// The default opacity mode for Collada is A_ONE, which apparently indicates a
// transparency value of 1 to be fully opaque. Hence transparency is inverted.
effect.setTransparency(1.0 - transparency);
}
}
addEffectProfile(effect);
closeEffect();
}
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::close() {
closeLibrary();
}
void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const IfcGeom::Material& material) {
if (!contains(material)) {
effects.write(material);
materials.push_back(material);
}
}
bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeom::Material& material) {
return std::find(materials.begin(), materials.end(), material) != materials.end();
}
void ColladaSerializer::ColladaExporter::ColladaMaterials::write() {
effects.close();
for (std::vector<IfcGeom::Material>::const_iterator it = materials.begin(); it != materials.end(); ++it) {
const std::string& material_name = collada_id((*it).name());
openMaterial(material_name);
addInstanceEffect("#" + material_name + "-fx");
closeMaterial();
}
closeLibrary();
}
void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_name, float unit_magnitude) {
stream.startDocument();
COLLADASW::Asset asset(&stream);
asset.getContributor().mAuthoringTool = std::string("IfcOpenShell ") + IFCOPENSHELL_VERSION;
asset.setUnit(unit_name, unit_magnitude);
asset.setUpAxisType(COLLADASW::Asset::Z_UP);
asset.add();
}
void ColladaSerializer::ColladaExporter::write(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& _materials) {
std::vector<std::string> material_references;
for (std::vector<IfcGeom::Material>::const_iterator it = _materials.begin(); it != _materials.end(); ++it) {
const IfcGeom::Material& material = *it;
if (!materials.contains(material)) {
materials.add(material);
}
material_references.push_back(collada_id(material.name()));
}
deferreds.push_back(DeferredObject(guid, name, type, obj_id, matrix, vertices, normals, indices, material_ids, _materials, material_references));
}
const std::string ColladaSerializer::ColladaExporter::DeferredObject::Name() const {
std::stringstream ss;
if (!this->name.empty()) {
ss << this->obj_id << "_" << this->name;
} else {
ss << this->guid;
}
return collada_id(ss.str());
}
void ColladaSerializer::ColladaExporter::endDocument() {
// In fact due the XML based nature of Collada and its dependency on library nodes,
// only at this point all objects are written to the stream.
materials.write();
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
const std::string object_name = it->Name();
geometries.write(object_name, it->type, it->vertices, it->normals, it->indices, it->material_ids, it->materials);
}
geometries.close();
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
const std::string object_name = it->Name();
scene.add(object_name + "-instance", object_name, object_name, it->material_references, it->matrix);
}
scene.write();
stream.endDocument();
}
bool ColladaSerializer::ready() {
return true;
}
void ColladaSerializer::writeHeader() {
exporter.startDocument(unit_name, unit_magnitude);
}
void ColladaSerializer::write(const IfcGeom::TriangulationElement<double>* o) {
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
exporter.write(o->guid(), o->name(), o->type(), o->id(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.material_ids(), mesh.materials());
}
void ColladaSerializer::finalize() {
exporter.endDocument();
}
#endif
+165
View File
@@ -0,0 +1,165 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifdef WITH_OPENCOLLADA
#ifndef COLLADASERIALIZER_H
#define COLLADASERIALIZER_H
#include <COLLADASWStreamWriter.h>
#include <COLLADASWPrimitves.h>
#include <COLLADASWLibraryGeometries.h>
#include <COLLADASWSource.h>
#include <COLLADASWScene.h>
#include <COLLADASWNode.h>
#include <COLLADASWInstanceGeometry.h>
#include <COLLADASWLibraryVisualScenes.h>
#include <COLLADASWLibraryEffects.h>
#include <COLLADASWLibraryMaterials.h>
#include <COLLADASWBaseInputElement.h>
#include <COLLADASWAsset.h>
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcconvert/GeometrySerializer.h"
class ColladaSerializer : public GeometrySerializer
{
private:
class ColladaExporter
{
private:
class ColladaGeometries : public COLLADASW::LibraryGeometries
{
public:
explicit ColladaGeometries(COLLADASW::StreamWriter& stream)
: COLLADASW::LibraryGeometries(&stream)
{}
void addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<double>& floats, const char* coords = "XYZ");
void write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials);
void close();
};
class ColladaScene : public COLLADASW::LibraryVisualScenes
{
private:
const std::string scene_id;
bool scene_opened;
public:
ColladaScene(const std::string& scene_id, COLLADASW::StreamWriter& stream)
: COLLADASW::LibraryVisualScenes(&stream)
, scene_id(scene_id)
, scene_opened(false)
{}
void add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<double>& matrix);
void write();
};
class ColladaMaterials : public COLLADASW::LibraryMaterials
{
private:
class ColladaEffects : public COLLADASW::LibraryEffects
{
public:
explicit ColladaEffects(COLLADASW::StreamWriter& stream)
: COLLADASW::LibraryEffects(&stream)
{}
void write(const IfcGeom::Material& material);
void close();
};
std::vector<IfcGeom::Material> materials;
ColladaEffects effects;
public:
explicit ColladaMaterials(COLLADASW::StreamWriter& stream)
: COLLADASW::LibraryMaterials(&stream)
, effects(stream)
{}
void add(const IfcGeom::Material& material);
bool contains(const IfcGeom::Material& material);
void write();
};
class DeferredObject {
public:
std::string guid, name, type;
int obj_id;
std::vector<double> matrix;
std::vector<double> vertices;
std::vector<double> normals;
std::vector<int> indices;
std::vector<int> material_ids;
std::vector<IfcGeom::Material> materials;
std::vector<std::string> material_references;
DeferredObject(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<double>& matrix, const std::vector<double>& vertices,
const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids,
const std::vector<IfcGeom::Material>& materials, const std::vector<std::string>& material_references)
: guid(guid)
, name(name)
, type(type)
, obj_id(obj_id)
, matrix(matrix)
, vertices(vertices)
, normals(normals)
, indices(indices)
, material_ids(material_ids)
, materials(materials)
, material_references(material_references)
{}
const std::string Name() const;
};
COLLADABU::NativeString filename;
COLLADASW::StreamWriter stream;
ColladaGeometries geometries;
ColladaScene scene;
ColladaMaterials materials;
public:
ColladaExporter(const std::string& scene_name, const std::string& fn)
: filename(fn.c_str())
, stream(filename)
, geometries(stream)
, scene(scene_name, stream)
, materials(stream)
{}
std::vector<DeferredObject> deferreds;
virtual ~ColladaExporter() {}
void startDocument(const std::string& unit_name, float unit_magnitude);
void write(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& indices, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& materials);
void endDocument();
};
ColladaExporter exporter;
std::string unit_name;
float unit_magnitude;
public:
ColladaSerializer(const std::string& dae_filename)
: GeometrySerializer()
, exporter("IfcOpenShell", dae_filename)
{}
bool ready();
void writeHeader();
void write(const IfcGeom::TriangulationElement<double>* o);
void write(const IfcGeom::BRepElement<double>* o) {}
void finalize();
bool isTesselated() const { return true; }
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
unit_name = name;
unit_magnitude = magnitude;
}
void setFile(IfcParse::IfcFile*) {}
};
#endif
#endif
@@ -17,30 +17,20 @@
* *
********************************************************************************/
#ifndef IFCGLOBALID_H
#define IFCGLOBALID_H
#ifndef GEOMETRYSERIALIZER_H
#define GEOMETRYSERIALIZER_H
#include <string>
#include <boost/uuid/uuid.hpp>
#include "../ifcconvert/Serializer.h"
#include "../ifcgeom/IfcGeomIterator.h"
#include "ifc_parse_api.h"
class GeometrySerializer : public Serializer {
public:
virtual ~GeometrySerializer() {}
namespace IfcParse {
/// A helper class for the creation of IFC GlobalIds.
class IFC_PARSE_API IfcGlobalId {
private:
std::string string_data, formatted_string;
boost::uuids::uuid uuid_data;
public:
static const unsigned int length = 22;
IfcGlobalId();
IfcGlobalId(const std::string&);
operator const std::string&() const;
operator const boost::uuids::uuid&() const;
const std::string& formatted() const;
};
}
virtual bool isTesselated() const = 0;
virtual void write(const IfcGeom::TriangulationElement<double>* o) = 0;
virtual void write(const IfcGeom::BRepElement<double>* o) = 0;
virtual void setUnitNameAndMagnitude(const std::string& name, float magnitude) = 0;
};
#endif
File diff suppressed because it is too large Load Diff
@@ -20,26 +20,21 @@
#ifndef IGESSERIALIZER_H
#define IGESSERIALIZER_H
#include "OpenCascadeBasedSerializer.h"
#include "../ifcparse/IfcLogger.h"
#include <IGESControl_Controller.hxx>
#include <IGESControl_Writer.hxx>
#ifndef HAVE_CONFIG_H
/// @note this is brittle, but apparently the only way to differentiate OCCT
/// from OCE. In the latter including this header fails for some versions.
#include <Interface_Static.hxx>
#endif
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcconvert/OpenCascadeBasedSerializer.h"
class IgesSerializer : public OpenCascadeBasedSerializer
{
private:
IGESControl_Writer writer;
IGESControl_Writer writer;
public:
/// @note IGESControl_Controller::Init() must be called prior to instantiating IgesSerializer.
/// See http://tracker.dev.opencascade.org/view.php?id=23679 for more information.
IgesSerializer(const std::string& out_filename, const SerializerSettings& settings)
: OpenCascadeBasedSerializer(out_filename, settings)
explicit IgesSerializer(const std::string& out_filename)
: OpenCascadeBasedSerializer(out_filename)
{}
virtual ~IgesSerializer() {}
void writeShape(const TopoDS_Shape& shape) {
@@ -48,17 +43,12 @@ public:
void finalize() {
writer.Write(out_filename.c_str());
}
void setUnitNameAndMagnitude(const std::string& /*name*/, float magnitude) {
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
const char* symbol = getSymbolForUnitMagnitude(magnitude);
if (symbol) {
#ifdef HAVE_CONFIG_H
Logger::Warning("Setting IGES units not supported on OCE");
#else
Interface_Static::SetCVal("xstep.cascade.unit", symbol);
Interface_Static::SetCVal("write.iges.unit", symbol);
#endif
}
}
};
#endif
#endif
@@ -21,9 +21,11 @@
#include <fstream>
#include <cstdio>
#include <Standard_Version.hxx>
#include <BRepBuilderAPI_GTransform.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <Standard_Version.hxx>
#include "OpenCascadeBasedSerializer.h"
bool OpenCascadeBasedSerializer::ready() {
@@ -34,17 +36,40 @@ bool OpenCascadeBasedSerializer::ready() {
return succeeded;
}
void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement<real_t>* o) {
TopoDS_Shape compound = o->geometry().as_compound();
void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement<double>* o) {
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) {
gp_GTrsf gtrsf = it->Placement();
if (o->geometry().settings().get(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS)) {
gp_Trsf scale;
scale.SetScaleFactor(1.0 / o->geometry().settings().unit_magnitude());
const std::vector<double>& matrix = o->transformation().matrix().data();
compound = BRepBuilderAPI_Transform(compound, scale, true).Shape();
// Convert the matrix back into a transformation object. The tolerance values
// are taken into consideration to reconstruct the form of the transformation.
gp_Trsf o_trsf;
o_trsf.SetValues(
matrix[0], matrix[3], matrix[6], matrix[ 9],
matrix[1], matrix[4], matrix[7], matrix[10],
matrix[2], matrix[5], matrix[8], matrix[11]
#if OCC_VERSION_HEX < 0x60800
, Precision::Angular(), Precision::Confusion()
#endif
);
gtrsf.PreMultiply(o_trsf);
const TopoDS_Shape& s = it->Shape();
bool trsf_valid = false;
gp_Trsf trsf;
try {
trsf = gtrsf.Trsf();
trsf_valid = true;
} catch (...) {}
const TopoDS_Shape moved_shape = trsf_valid
? BRepBuilderAPI_Transform(s, trsf, true).Shape()
: BRepBuilderAPI_GTransform(s, gtrsf, true).Shape();
writeShape(moved_shape);
}
writeShape(compound);
}
#define RATHER_SMALL (1e-3)
@@ -20,29 +20,28 @@
#ifndef OPENCASCADEBASEDSERIALIZER_H
#define OPENCASCADEBASEDSERIALIZER_H
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
#include "../ifcgeom/IfcGeomIterator.h"
#include "../serializers/GeometrySerializer.h"
#include "../ifcconvert/GeometrySerializer.h"
class OpenCascadeBasedSerializer : public GeometrySerializer {
OpenCascadeBasedSerializer(const OpenCascadeBasedSerializer&); //N/A
OpenCascadeBasedSerializer& operator =(const OpenCascadeBasedSerializer&); //N/A
protected:
const std::string out_filename;
const std::string& out_filename;
const char* getSymbolForUnitMagnitude(float mag);
public:
explicit OpenCascadeBasedSerializer(const std::string& out_filename, const SerializerSettings& settings)
: GeometrySerializer(settings)
explicit OpenCascadeBasedSerializer(const std::string& out_filename)
: GeometrySerializer()
, out_filename(out_filename)
{}
virtual ~OpenCascadeBasedSerializer() {}
void writeHeader() {}
void writeMaterial(const IfcGeom::SurfaceStyle& style) {}
bool ready();
virtual void writeShape(const TopoDS_Shape& shape) = 0;
void write(const IfcGeom::TriangulationElement<real_t>* /*o*/) {}
void write(const IfcGeom::BRepElement<real_t>* o);
void write(const IfcGeom::TriangulationElement<double>* o) {}
void write(const IfcGeom::BRepElement<double>* o);
bool isTesselated() const { return false; }
void setFile(IfcParse::IfcFile*) {}
};
#endif
#endif
@@ -20,20 +20,21 @@
#ifndef STEPSERIALIZER_H
#define STEPSERIALIZER_H
#include <STEPControl_Controller.hxx>
#include <STEPControl_Writer.hxx>
#include <Interface_Static.hxx>
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
#include "../ifcgeom/IfcGeomIterator.h"
#include "../serializers/OpenCascadeBasedSerializer.h"
#include "../ifcconvert/OpenCascadeBasedSerializer.h"
class StepSerializer : public OpenCascadeBasedSerializer
{
private:
STEPControl_Writer writer;
public:
explicit StepSerializer(const std::string& out_filename, const SerializerSettings& settings)
: OpenCascadeBasedSerializer(out_filename, settings)
explicit StepSerializer(const std::string& out_filename)
: OpenCascadeBasedSerializer(out_filename)
{}
virtual ~StepSerializer() {}
void writeShape(const TopoDS_Shape& shape) {
@@ -48,10 +49,9 @@ public:
writer.Write(out_filename.c_str());
std::cout.rdbuf(sb);
}
void setUnitNameAndMagnitude(const std::string& /*name*/, float magnitude) {
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
const char* symbol = getSymbolForUnitMagnitude(magnitude);
if (symbol) {
Interface_Static::SetCVal("xstep.cascade.unit", symbol);
Interface_Static::SetCVal("write.step.unit", symbol);
}
}
+78
View File
@@ -0,0 +1,78 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* This file defines default materials for several IFC datatypes *
* *
********************************************************************************/
#ifndef SURFACESTYLE_H
#define SURFACESTYLE_H
#include <string>
#include <sstream>
#include <array>
class SurfaceStyle {
public:
class ColorComponent {
private:
std::array<double, 3> data;
public:
ColorComponent(double r, double g, double b) {
data[0] = r; data[1] = g; data[2] = b;
}
const double& R() const { return data[0]; }
const double& G() const { return data[1]; }
const double& B() const { return data[2]; }
double& R() { return data[0]; }
double& G() { return data[1]; }
double& B() { return data[2]; }
};
private:
std::string name;
ColorComponent diffuse, specular, ambient;
double transparency;
double specularity;
public:
SurfaceStyle(const std::string& name,
double dr = 0.7, double dg = 0.7, double db = 0.7,
double sr = 0.2, double sg = 0.2, double sb = 0.2,
double ar = 0.1, double ag = 0.1, double ab = 0.1,
double Ns = 10.0, double Tr = 1.0)
: name(name)
, diffuse(dr, dg, db)
, specular(sr, sg, sb)
, ambient(ar, ag, ab)
, transparency(Tr)
, specularity(Ns)
{}
const std::string& Name() const { return name; }
const ColorComponent& Diffuse() const { return diffuse; }
const ColorComponent& Specular() const { return specular; }
const ColorComponent& Ambient() const { return ambient; }
double Transparency() const { return transparency; }
double Specularity() const { return specularity; }
};
SurfaceStyle GetDefaultMaterial(const std::string& s);
#endif
@@ -17,12 +17,10 @@
* *
********************************************************************************/
#include "../ifcgeom/IfcGeomRenderStyles.h"
#include "WavefrontObjSerializer.h"
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
#include <boost/lexical_cast.hpp>
#include <iomanip>
bool WaveFrontOBJSerializer::ready() {
@@ -42,16 +40,11 @@ void WaveFrontOBJSerializer::writeHeader() {
mtl_basename = mtl_basename.substr(slash+1);
}
obj_stream << "mtllib " << mtl_basename << "\n";
mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n";
mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n";
}
void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style)
{
std::string material_name = (settings().get(SerializerSettings::USE_MATERIAL_NAMES)
? style.original_name() : style.name());
IfcUtil::sanitate_material_name(material_name);
mtl_stream << "newmtl " << material_name << "\n";
void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style) {
mtl_stream << "newmtl " << style.name() << "\n";
if (style.hasDiffuse()) {
const double* diffuse = style.diffuse();
mtl_stream << "Kd " << diffuse[0] << " " << diffuse[1] << " " << diffuse[2] << "\n";
@@ -66,55 +59,46 @@ void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style)
if (style.hasTransparency()) {
const double transparency = 1.0 - style.transparency();
if (transparency < 1) {
mtl_stream << "Tr " << transparency << "\n";
mtl_stream << "d " << transparency << "\n";
mtl_stream << "D " << transparency << "\n";
}
}
}
void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<double>* o) {
void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<real_t>* o)
{
const std::string name = (settings().get(SerializerSettings::USE_ELEMENT_GUIDS)
? o->guid() : (settings().get(SerializerSettings::USE_ELEMENT_NAMES)
? o->name() : o->unique_id()));
obj_stream << "g " << name << "\n";
std::string tmp = o->name().empty() ? o->guid() : o->name();
std::replace( tmp.begin(), tmp.end(), ' ', '_');
const std::string name = tmp;
obj_stream << "g " << name << "\n";
obj_stream << "s 1" << "\n";
const IfcGeom::Representation::Triangulation<real_t>& mesh = o->geometry();
const int vcount = (int)mesh.verts().size() / 3;
for ( std::vector<real_t>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) {
const real_t x = *(it++) + (real_t)settings().offset[0];
const real_t y = *(it++) + (real_t)settings().offset[1];
const real_t z = *(it++) + (real_t)settings().offset[2];
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
const int vcount = mesh.verts().size() / 3;
for ( std::vector<double>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) {
const double x = *(it++);
const double y = *(it++);
const double z = *(it++);
obj_stream << "v " << x << " " << y << " " << z << "\n";
}
for ( std::vector<real_t>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) {
const real_t x = *(it++);
const real_t y = *(it++);
const real_t z = *(it++);
for ( std::vector<double>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) {
const double x = *(it++);
const double y = *(it++);
const double z = *(it++);
obj_stream << "vn " << x << " " << y << " " << z << "\n";
}
for (std::vector<real_t>::const_iterator it = mesh.uvs().begin(); it != mesh.uvs().end();) {
const real_t u = *it++;
const real_t v = *it++;
obj_stream << "vt " << u << " " << v << "\n";
}
int previous_material_id = -2;
std::vector<int>::const_iterator material_it = mesh.material_ids().begin();
const bool has_uvs = !mesh.uvs().empty();
const bool has_normals = !mesh.normals().empty();
for ( std::vector<int>::const_iterator it = mesh.faces().begin(); it != mesh.faces().end(); ) {
const int material_id = *(material_it++);
if (material_id != previous_material_id) {
const IfcGeom::Material& material = mesh.materials()[material_id];
std::string material_name = (settings().get(SerializerSettings::USE_MATERIAL_NAMES)
? material.original_name() : material.name());
IfcUtil::sanitate_material_name(material_name);
const std::string material_name = material.name();
obj_stream << "usemtl " << material_name << "\n";
if (materials.find(material_name) == materials.end()) {
writeMaterial(material);
@@ -126,52 +110,7 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<real_t>*
const int v1 = *(it++)+vcount_total;
const int v2 = *(it++)+vcount_total;
const int v3 = *(it++)+vcount_total;
if (has_normals && has_uvs) {
obj_stream << "f " << v1 << "/" << v1 << "/" << v1 << " "
<< v2 << "/" << v2 << "/" << v2 << " "
<< v3 << "/" << v3 << "/" << v3 << "\n";
} else if (has_normals) {
obj_stream << "f " << v1 << "//" << v1 << " "
<< v2 << "//" << v2 << " "
<< v3 << "//" << v3 << "\n";
} else {
obj_stream << "f " << v1 << " " << v2 << " " << v3 << "\n";
}
obj_stream << "f " << v1 << "//" << v1 << " " << v2 << "//" << v2 << " " << v3 << "//" << v3 << "\n";
}
std::set<int> faces_set (mesh.faces().begin(), mesh.faces().end());
const std::vector<int>& edges = mesh.edges();
for ( std::vector<int>::const_iterator it = edges.begin(); it != edges.end(); ) {
const int i1 = *(it++);
const int i2 = *(it++);
if (faces_set.find(i1) != faces_set.end() || faces_set.find(i2) != faces_set.end()) {
continue;
}
const int material_id = *(material_it++);
if (material_id != previous_material_id) {
const IfcGeom::Material& material = mesh.materials()[material_id];
std::string material_name = (settings().get(SerializerSettings::USE_MATERIAL_NAMES)
? material.original_name() : material.name());
IfcUtil::sanitate_material_name(material_name);
obj_stream << "usemtl " << material_name << "\n";
if (materials.find(material_name) == materials.end()) {
writeMaterial(material);
materials.insert(material_name);
}
previous_material_id = material_id;
}
const int v1 = i1 + vcount_total;
const int v2 = i2 + vcount_total;
obj_stream << "l " << v1 << " " << v2 << "\n";
}
vcount_total += vcount;
vcount_total += vcount;
}
@@ -24,9 +24,8 @@
#include <string>
#include <fstream>
#include "../serializers/GeometrySerializer.h"
#include "../ifcconvert/GeometrySerializer.h"
// http://people.sc.fsu.edu/~jburkardt/txt/obj_format.txt
class WaveFrontOBJSerializer : public GeometrySerializer {
private:
const std::string mtl_filename;
@@ -35,27 +34,23 @@ private:
unsigned int vcount_total;
std::set<std::string> materials;
public:
WaveFrontOBJSerializer(const std::string& obj_filename, const std::string& mtl_filename, const SerializerSettings& settings)
: GeometrySerializer(settings)
, mtl_filename(mtl_filename)
WaveFrontOBJSerializer(const std::string& obj_filename, const std::string& mtl_filename)
: GeometrySerializer()
, obj_stream(obj_filename.c_str())
, mtl_stream(mtl_filename.c_str())
, mtl_filename(mtl_filename)
, mtl_stream(mtl_filename.c_str())
, vcount_total(1)
{
obj_stream << std::setprecision(settings.precision);
mtl_stream << std::setprecision(settings.precision);
}
{}
virtual ~WaveFrontOBJSerializer() {}
bool ready();
void writeHeader();
void writeMaterial(const IfcGeom::Material& style);
void write(const IfcGeom::TriangulationElement<real_t>* o);
void write(const IfcGeom::BRepElement<real_t>* /*o*/) {}
void write(const IfcGeom::TriangulationElement<double>* o);
void write(const IfcGeom::BRepElement<double>* o) {}
void finalize() {}
bool isTesselated() const { return true; }
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {}
void setFile(IfcParse::IfcFile*) {}
};
#endif
#endif
+262
View File
@@ -0,0 +1,262 @@
#include <map>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/foreach.hpp>
#include <boost/version.hpp>
#include "XmlSerializer.h"
using boost::property_tree::ptree;
using namespace IfcSchema;
static std::map<std::string, std::string> argument_name_map;
// Format an IFC attribute and maybe returns as string. Only literal scalar
// values are converted. Things like entity instances and lists are omitted.
boost::optional<std::string> format_attribute(const Argument* argument, IfcUtil::ArgumentType argument_type) {
boost::optional<std::string> value;
switch(argument_type) {
case IfcUtil::Argument_BOOL: {
const bool b = *argument;
value = b ? "true" : "false";
break; }
case IfcUtil::Argument_DOUBLE: {
const double d = *argument;
std::stringstream stream;
stream << d;
value = stream.str();
break; }
case IfcUtil::Argument_STRING:
case IfcUtil::Argument_ENUMERATION: {
value = static_cast<std::string>(*argument);
break; }
case IfcUtil::Argument_INT: {
const int v = *argument;
std::stringstream stream;
stream << v;
value = stream.str();
break; }
case IfcUtil::Argument_ENTITY: {
IfcUtil::IfcBaseClass* e = *argument;
if (Type::IsSimple(e->type())) {
IfcUtil::IfcBaseType* f = (IfcUtil::IfcBaseType*) e;
value = format_attribute(f->getArgument(0), f->getArgumentType(0));
} else if (e->is(IfcSchema::Type::IfcSIUnit) || e->is(IfcSchema::Type::IfcConversionBasedUnit)) {
// Some string concatenation to have a unit name as a XML attribute.
std::string unit_name;
if (e->is(IfcSchema::Type::IfcSIUnit)) {
IfcSchema::IfcSIUnit* unit = (IfcSchema::IfcSIUnit*) e;
unit_name = IfcSchema::IfcSIUnitName::ToString(unit->Name());
if (unit->Prefix()) {
unit_name = IfcSchema::IfcSIPrefix::ToString(*unit->Prefix()) + unit_name;
}
} else {
IfcSchema::IfcConversionBasedUnit* unit = (IfcSchema::IfcConversionBasedUnit*) e;
unit_name = unit->Name();
}
for (std::string::iterator c = unit_name.begin(); c != unit_name.end(); ++c) *c = tolower(*c);
value = unit_name;
}
break; }
}
return value;
}
// Formats an entity instances as a ptree node, and insert into the DOM. Recurses
// over the entity attributes and writes them as xml attributes of the node.
ptree& format_entity_instance(IfcUtil::IfcBaseEntity* instance, ptree& tree, bool as_link = false) {
ptree child;
const unsigned n = instance->getArgumentCount();
for (unsigned i = 0; i < n; ++i) {
const Argument* argument = instance->getArgument(i);
if (argument->isNull()) continue;
std::string argument_name = instance->getArgumentName(i);
std::map<std::string, std::string>::const_iterator argument_name_it;
argument_name_it = argument_name_map.find(argument_name);
if (argument_name_it != argument_name_map.end()) {
argument_name = argument_name_it->second;
}
const IfcUtil::ArgumentType argument_type = instance->getArgumentType(i);
boost::optional<std::string> value;
try {
value = format_attribute(argument, argument_type);
} catch (...) {}
if (value) {
if (as_link) {
if (argument_name == "id") {
child.put("<xmlattr>.xlink:href", std::string("#") + *value);
}
} else {
std::stringstream stream;
stream << "<xmlattr>." << argument_name;
child.put(stream.str(), *value);
}
}
}
return tree.add_child(Type::ToString(instance->type()), child);
}
// A function to be called recursively. Template specialization is used
// to descend into decomposition, containment and property relationships.
template <typename A>
void descend(A* instance, ptree& tree) {
format_entity_instance(instance, tree);
}
// Returns related entity instances using IFC's objectified relationship
// model. The second and third argument require a member function pointer.
template <typename T, typename U, typename V, typename F, typename G>
typename V::list::ptr get_related(T* t, F f, G g) {
typename U::list::ptr li = (*t.*f)()->template as<U>();
typename V::list::ptr acc(new typename V::list);
for (typename U::list::it it = li->begin(); it != li->end(); ++it) {
U* u = *it;
acc->push((*u.*g)());
}
return acc;
}
// Member functions for IFC attributes have identical names for getters and setters. Hence a full member function signature is needed to identify them.
typedef IfcTemplatedEntityList<IfcProduct>::ptr (IfcRelContainedInSpatialStructure::*get_related_elements) (void) const;
typedef IfcTemplatedEntityList<IfcObjectDefinition>::ptr (IfcRelDecomposes::*get_related_objects) (void) const;
typedef IfcPropertySetDefinition* (IfcRelDefinesByProperties::*get_related_properties) (void) const;
// Descends into the tree by recursing into IfcRelContainedInSpatialStructure,
// IfcRelDecomposes and IfcRelDefinesByProperties relations.
template <>
void descend(IfcProduct* product, ptree& tree) {
ptree& child = format_entity_instance(product, tree);
if (product->is(Type::IfcSpatialStructureElement)) {
IfcSpatialStructureElement* structure = (IfcSpatialStructureElement*) product;
IfcProduct::list::ptr elements = get_related
<IfcSpatialStructureElement, IfcRelContainedInSpatialStructure, IfcProduct>
(structure, &IfcSpatialStructureElement::ContainsElements, static_cast<get_related_elements>(&IfcRelContainedInSpatialStructure::RelatedElements));
for (IfcProduct::list::it it = elements->begin(); it != elements->end(); ++it) {
descend(*it, child);
}
}
IfcObjectDefinition::list::ptr structures = get_related
<IfcProduct, IfcRelDecomposes, IfcObjectDefinition>
(product, &IfcProduct::IsDecomposedBy, static_cast<get_related_objects>(&IfcRelDecomposes::RelatedObjects));
for (IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
IfcObjectDefinition* ob = *it;
if (ob->is(Type::IfcSpatialStructureElement)) {
descend((IfcProduct*)ob, child);
} else {
descend(ob, child);
}
}
IfcPropertySetDefinition::list::ptr property_sets = get_related
<IfcProduct, IfcRelDefinesByProperties, IfcPropertySetDefinition>
(product, &IfcProduct::IsDefinedBy, static_cast<get_related_properties>(&IfcRelDefinesByProperties::RelatingPropertyDefinition));
for (IfcPropertySetDefinition::list::it it = property_sets->begin(); it != property_sets->end(); ++it) {
IfcPropertySetDefinition* pset = *it;
if (pset->is(Type::IfcPropertySet)) {
format_entity_instance(pset, child, true);
}
}
}
// Descends into the tree by recursing into IfcRelDecomposes relations.
template <>
void descend(IfcProject* project, ptree& tree) {
ptree& child = format_entity_instance(project, tree);
IfcObjectDefinition::list::ptr structures = get_related
<IfcProject, IfcRelDecomposes, IfcObjectDefinition>
(project, &IfcProject::IsDecomposedBy, static_cast<get_related_objects>(&IfcRelDecomposes::RelatedObjects));
for (IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) {
IfcObjectDefinition* ob = *it;
if (ob->is(Type::IfcSpatialStructureElement)) {
descend((IfcProduct*)ob, child);
} else {
descend(ob, child);
}
}
}
// Format IfcProperty instances and insert into the DOM. IfcComplexProperties are flattened out.
void format_properties(IfcProperty::list::ptr properties, ptree& node) {
for (IfcProperty::list::it it = properties->begin(); it != properties->end(); ++it) {
IfcProperty* p = *it;
if (p->is(Type::IfcComplexProperty)) {
IfcComplexProperty* complex = (IfcComplexProperty*) p;
format_properties(complex->HasProperties(), node);
} else {
format_entity_instance(p, node);
}
}
}
void XmlSerializer::finalize() {
argument_name_map.insert(std::make_pair("GlobalId", "id"));
IfcProject::list::ptr projects = file->entitiesByType<IfcProject>();
if (projects->size() != 1) {
Logger::Message(Logger::LOG_ERROR, "Expected a single IfcProject");
return;
}
IfcProject* project = *projects->begin();
ptree root, header, decomposition, properties;
// Write the SPF header as XML nodes.
BOOST_FOREACH(const std::string& s, file->header().file_description().description()) {
header.add_child("file_description.description", ptree(s));
}
BOOST_FOREACH(const std::string& s, file->header().file_name().author()) {
header.add_child("file_name.author", ptree(s));
}
BOOST_FOREACH(const std::string& s, file->header().file_name().organization()) {
header.add_child("file_name.organization", ptree(s));
}
BOOST_FOREACH(const std::string& s, file->header().file_schema().schema_identifiers()) {
header.add_child("file_schema.schema_identifiers", ptree(s));
}
header.put("file_description.implementation_level", file->header().file_description().implementation_level());
header.put("file_name.name", file->header().file_name().name());
header.put("file_name.time_stamp", file->header().file_name().time_stamp());
header.put("file_name.preprocessor_version", file->header().file_name().preprocessor_version());
header.put("file_name.originating_system", file->header().file_name().originating_system());
header.put("file_name.authorization", file->header().file_name().authorization());
// Descend into the decomposition structure of the IFC file.
descend(project, decomposition);
// Write all property sets and values as XML nodes.
IfcPropertySet::list::ptr psets = file->entitiesByType<IfcPropertySet>();
for (IfcPropertySet::list::it it = psets->begin(); it != psets->end(); ++it) {
IfcPropertySet* pset = *it;
ptree& node = format_entity_instance(pset, properties);
format_properties(pset->HasProperties(), node);
}
root.add_child("ifc.header", header);
root.add_child("ifc.properties", properties);
root.add_child("ifc.decomposition", decomposition);
root.put("ifc.<xmlattr>.xmlns:xlink", "http://www.w3.org/1999/xlink");
#if BOOST_VERSION >= 105600
boost::property_tree::xml_writer_settings<ptree::key_type> settings = boost::property_tree::xml_writer_make_settings<ptree::key_type>('\t', 1);
#else
boost::property_tree::xml_writer_settings<char> settings('\t', 1);
#endif
boost::property_tree::write_xml(xml_filename, root, std::locale(), settings);
}
@@ -17,29 +17,25 @@
* *
********************************************************************************/
#ifndef XMLSERIALIZERIMPL_H
#define XMLSERIALIZERIMPL_H
#ifndef XMLSERIALIZER_H
#define XMLSERIALIZER_H
#include "../../ifcparse/macros.h"
#include "../../serializers/XmlSerializer.h"
#include "../ifcconvert/Serializer.h"
#define INCLUDE_PARENT_PARENT_DIR(x) STRINGIFY(../../ifcparse/x.h)
#include INCLUDE_PARENT_PARENT_DIR(IfcSchema)
class MAKE_TYPE_NAME(XmlSerializer) : public XmlSerializer {
class XmlSerializer : public Serializer {
private:
IfcParse::IfcFile* file;
std::string xml_filename;
public:
MAKE_TYPE_NAME(XmlSerializer)(IfcParse::IfcFile* file, const std::string& xml_filename)
: XmlSerializer(0, "")
{
this->file = file;
this->xml_filename = xml_filename;
}
XmlSerializer(const std::string& xml_filename)
: Serializer()
, xml_filename(xml_filename)
{}
bool ready() { return true; }
void writeHeader() {}
void finalize();
void setFile(IfcParse::IfcFile*) {}
void setFile(IfcParse::IfcFile* f) { file = f; }
};
#endif
+1 -3
View File
@@ -4,8 +4,6 @@ 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 [1] library is required.
Express file. A python 3 interpreter with the pyparsing library is required.
$ python bootstrap.py express.bnf > express_parser.py && python express_parser.py IFC2X3_TC1.exp
[1] http://pyparsing.wikispaces.com/Download+and+Installation
+29 -53
View File
@@ -19,14 +19,8 @@
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]
@@ -62,12 +56,12 @@ class Keyword:
class Terminal:
def __init__(self, contents):
self.contents = contents[0]
s = self.contents
self.is_keyword = len(s) >= 4 and s[0::len(s)-1] == '""' and \
all(c in alphanums+"_" for c in s[1:-1])
def __repr__(self):
ty = "CaselessKeyword" if self.is_keyword else "CaselessLiteral"
return "%s(%s)" % (ty, self.contents)
s = self.contents
is_keyword = len(s) >= 4 and s[0::len(s)-1] == '""' and \
all(c in alphanums+"_" for c in s[1:-1])
ty = "CaselessKeyword" if is_keyword else "CaselessLiteral"
return "%s(%s)" % (ty, s)
LPAREN = Suppress("(")
@@ -100,16 +94,16 @@ grammar.ignore(HASH + restOfLine)
express = grammar.parseFile(sys.argv[1])
def find_bytype(expr, ty, li = None):
def find_keywords(expr, li = None):
if li is None: li = []
if isinstance(expr, Term):
expr = expr.contents
if isinstance(expr, ty):
li.append(expr)
return set(li)
if isinstance(expr, Keyword):
li.append(repr(expr))
return li
elif isinstance(expr, Expression):
for term in expr:
find_bytype(term, ty, li)
find_keywords(term, li)
return set(li)
actions = {
@@ -121,15 +115,13 @@ 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)
@@ -137,22 +129,18 @@ 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 = map(repr, find_bytype(expr, Keyword))
kws = find_keywords(expr)
found = [k in emitted for k in kws]
if id in to_emit and all(found):
emitted_in_loop.add(id)
emitted.add(id)
stmt = "(%s)" % expr
if id in to_combine:
stmt = " + ".join(itertools.chain(negated_keywords, ("originalTextFor(Combine%s)" % stmt,)))
stmt = "originalTextFor(Combine%s)" % stmt
if id in actions:
stmt = "%s.setParseAction(%s)" % (stmt, actions[id])
statements.append("%s = %s" % (id, stmt))
@@ -170,41 +158,29 @@ for id in to_emit:
stmt = "Suppress%s" % stmt
statements.append("%s << %s" % (id, stmt))
print ("""import os
import sys
import pickle
print ("""import sys
from pyparsing import *
from nodes import *
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
%s
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 schema
import mapping
import header
import enum_header
import implementation
import schema_class
import latebound_header
import latebound_implementation
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
ast = syntax.parseFile(sys.argv[1])
schema = schema.Schema(ast)
mapping = mapping.Mapping(schema)
header.Header(mapping).emit()
enum_header.EnumHeader(mapping).emit()
implementation.Implementation(mapping).emit()
schema_class.SchemaClass(mapping).emit()
sys.stdout.write(schema.name)
"""%('\n '.join(statements)))
latebound_header.LateBoundHeader(mapping).emit()
latebound_implementation.LateBoundImplementation(mapping).emit()
"""%('\n'.join(statements)))
-35
View File
@@ -1,35 +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/>. #
# #
###############################################################################
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()
+5 -12
View File
@@ -27,25 +27,18 @@
# #
###############################################################################
import re
import os
import re,csv
import csv
from schema import OrderedCaseInsensitiveDict
try: from html.entities import entitydefs
except: from htmlentitydefs import entitydefs
make_absolute = lambda fn: os.path.join(os.path.dirname(os.path.realpath(__file__)), fn)
name_to_oid = OrderedCaseInsensitiveDict()
name_to_oid = {}
oid_to_desc = {}
oid_to_name = {}
oid_to_pid = {}
regices = list(zip([re.compile(s,re.M) for s in [r'<[\w\n=" \-/\.;_\t:%#,\?\(\)]+>',r'(\n[\t ]*){2,}',r'^[\t ]+']],['','\n\n',' ']))
definition_files = ['DocEntity.csv', 'DocEnumeration.csv', 'DocDefined.csv', 'DocSelect.csv']
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='"'):
@@ -53,15 +46,15 @@ for fn in definition_files:
oid_to_name[oid] = name
oid_to_desc[oid] = desc
with open(make_absolute('DocEntityAttributes.csv')) as f:
with open('DocEntityAttributes.csv') as f:
for pid, x, oid in csv.reader(f, delimiter=';', quotechar='"'):
oid_to_pid[oid] = pid
with open(make_absolute('DocAttribute.csv')) as f:
with open('DocAttribute.csv') as f:
for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'):
pid = oid_to_pid[oid]
pname = oid_to_name[pid]
name_to_oid[".".join((pname, name))] = oid
name_to_oid[(pname, name)] = oid
oid_to_desc[oid] = desc
def description(item):
+5 -6
View File
@@ -18,9 +18,8 @@
###############################################################################
import templates
import codegen
class EnumHeader(codegen.Base):
class EnumHeader:
def __init__(self, mapping):
enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()]))
@@ -31,9 +30,9 @@ class EnumHeader(codegen.Base):
}
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()
+4 -2
View File
@@ -1,3 +1,5 @@
# Taken from http://sourceforge.net/p/exp-engine/expresso/ci/master/tree/docs/iso-10303-11--2004.bnf
ABS = "abs" .
ABSTRACT = "abstract" .
ACOS = "acos" .
@@ -200,7 +202,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 } ] ")" .
@@ -332,7 +334,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 .
+20 -38
View File
@@ -17,13 +17,10 @@
# #
###############################################################################
import operator
import codegen
import templates
import documentation
class Header(codegen.Base):
class Header:
def __init__(self, mapping):
declarations = []
@@ -43,18 +40,15 @@ class Header(codegen.Base):
emitted_simpletypes = set()
while len(emitted_simpletypes) < len(mapping.schema.simpletypes):
for name, type in mapping.schema.simpletypes.items():
if name.lower() in emitted_simpletypes: continue
if name in emitted_simpletypes: continue
type_str = mapping.make_type_string(mapping.flatten_type_string(type))
attr_type = mapping.make_argument_type(type)
superclass = mapping.simple_type_parent(name)
if superclass is None:
superclass = "IfcUtil::IfcBaseType"
elif superclass.lower() not in emitted_simpletypes:
elif superclass not in emitted_simpletypes:
continue
else:
# Case normalize
superclass = [k for k in mapping.schema.simpletypes.keys() if k.lower() == superclass.lower()][0]
emitted_simpletypes.add(name.lower())
emitted_simpletypes.add(name)
write(templates.simpletype, name=name, type=type_str, attr_type=attr_type, superclass=superclass)
class_definitions = []
@@ -65,18 +59,15 @@ class Header(codegen.Base):
emitted_entities = set()
while len(emitted_entities) < len(mapping.schema.entities):
for name, type in mapping.schema.entities.items():
if name.lower() in emitted_entities: continue
if len(type.supertypes) == 0 or set(map(str.lower, type.supertypes)) <= emitted_entities:
if name in emitted_entities: continue
if len(type.supertypes) == 0 or set(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(".".join((name, attr.name)))])
type_str = mapping.get_parameter_type(attr, allow_optional=False, allow_entities=False)
attr_lines.extend(["/// %s"%d for d in documentation.description((name, attr.name))])
type_str = mapping.get_parameter_type(attr, allow_optional=True, allow_entities=True)
if mapping.make_argument_type(attr) != "IfcUtil::Argument_UNKNOWN":
attr_lines.append("%s %s() const;"%(type_str, attr.name))
attr_lines.append("void set%s(%s v);"%(attr.name, type_str))
attr_lines.append("void %s(%s v);"%(attr.name, type_str))
[write_method(attr) for attr in type.attributes]
@@ -93,11 +84,7 @@ class Header(codegen.Base):
inverse = "\n".join(["%s%s"%(' '*4, a) for a in inv_lines])
if len(inverse): inverse += '\n'
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']
supertypes = type.supertypes if len(type.supertypes) else ['IfcUtil::IfcBaseEntity']
superclass = ": %s "%(", ".join(["public %s"%c for c in supertypes]))
argument_count = mapping.argument_count(type)
@@ -105,23 +92,17 @@ class Header(codegen.Base):
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 ' (void)i; throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
argument_name_function_body_tail = (" return %s::getArgumentName(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcException("argument out of range"); '
argument_name_function_body = argument_name_function_body_switch_stmt + argument_name_function_body_tail
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_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return %s; '%(i+argument_start, mapping.make_argument_type(attr)) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
argument_type_function_body_tail = (" return %s::getArgumentType(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcException("argument out of range"); '
argument_type_function_body = argument_type_function_body_switch_stmt + argument_type_function_body_tail
argument_entity_function_body_switch_stmt = " switch (i) {%s}"%("".join(['case %d: return %s; '%(i+argument_start, mapping.make_argument_entity(attr)) for i, attr in enumerate(type.attributes)])) if len(type.attributes) else ""
argument_entity_function_body_tail = (" return %s::getArgumentEntity(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' (void)i; throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); '
argument_entity_function_body_tail = (" return %s::getArgumentEntity(i); "%type.supertypes[0]) if len(type.supertypes) == 1 else ' throw IfcParse::IfcException("argument out of range"); '
argument_entity_function_body = argument_entity_function_body_switch_stmt + argument_entity_function_body_tail
@@ -139,9 +120,10 @@ class Header(codegen.Base):
}
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()
+61 -86
View File
@@ -17,19 +17,15 @@
# #
###############################################################################
import codegen
import templates
from schema import OrderedCaseInsensitiveDict
class Implementation(codegen.Base):
class Implementation:
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)
@@ -47,8 +43,6 @@ class Implementation(codegen.Base):
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)
)
@@ -58,7 +52,6 @@ class Implementation(codegen.Base):
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 = []
@@ -66,27 +59,23 @@ class Implementation(codegen.Base):
write_attr = lambda str, **kwargs: attributes.append(str%kwargs)
for arg in constructor_arguments:
if not arg['is_inherited'] and not arg['is_derived']:
if arg['is_optional']:
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',
body = templates.optional_attr_stmt % {'index':arg['index']-1}
)
def find_template(arg):
simple = mapping.schema.is_simpletype(arg['list_instance_type'])
select = arg['list_instance_type'] == "IfcUtil::IfcBaseClass"
express = mapping.flatten_type_string(arg['list_instance_type']) in mapping.express_to_cpp_typemapping
if arg['is_enum']: return templates.get_attr_stmt_enum
elif arg['is_nested'] and arg['is_templated_list']: return templates.get_attr_stmt_nested_array
elif arg['is_templated_list'] and not (select or simple or express): return templates.get_attr_stmt_array
elif arg['non_optional_type'].endswith('*'): return templates.get_attr_stmt_entity
else: return templates.get_attr_stmt
express = arg['list_instance_type'] in mapping.express_to_cpp_typemapping
if arg['is_optional']:
if arg['is_enum']: return templates.get_attr_stmt_optional_enum
elif arg['is_nested']: return templates.get_attr_stmt_optional_nested_array
elif arg['is_array'] and not (select or simple or express): return templates.get_attr_stmt_optional_array
elif arg['non_optional_type'].endswith('*'): return templates.get_attr_stmt_optional_entity
else: return templates.get_attr_stmt_generic
else:
if arg['is_enum']: return templates.get_attr_stmt_enum
elif arg['is_nested']: return templates.get_attr_stmt_nested_array
elif arg['is_array'] and not (select or simple or express): return templates.get_attr_stmt_array
elif arg['non_optional_type'].endswith('*'): return templates.get_attr_stmt_entity
else: return templates.get_attr_stmt_generic
tmpl = find_template(arg)
write_attr(
@@ -94,11 +83,9 @@ class Implementation(codegen.Base):
class_name = name,
name = arg['name'],
arguments = '',
schema_name = schema_name,
schema_name_upper = schema_name_upper,
return_type = arg['non_optional_type'],
return_type = arg['full_type'],
body = tmpl % {'index': arg['index']-1,
'type' : arg['non_optional_type'].replace('::Value', ''),
'type' : arg['non_optional_type'].split('::')[0],
'list_instance_type' : arg['list_instance_type']}
)
@@ -106,37 +93,39 @@ class Implementation(codegen.Base):
simple = mapping.schema.is_simpletype(arg['list_instance_type'])
select = arg['list_instance_type'] == "IfcUtil::IfcBaseClass"
express = arg['list_instance_type'] in mapping.express_to_cpp_typemapping
if arg['is_enum']: return templates.set_attr_stmt_enum
elif arg['is_templated_list'] and not (select or simple or express): return templates.set_attr_stmt_array
else: return templates.set_attr_stmt
if arg['is_optional']:
if arg['is_enum']: return templates.set_attr_stmt_optional_enum
elif arg['is_array'] and not (select or simple or express): return templates.set_attr_stmt_optional_array
else: return templates.set_attr_stmt_optional_generic
else:
if arg['is_enum']: return templates.set_attr_stmt_enum
elif arg['is_array'] and not (select or simple or express): return templates.set_attr_stmt_array
else: return templates.set_attr_stmt_generic
tmpl = find_template(arg)
write_attr(
templates.function,
class_name = name,
name = 'set%s'%arg['name'],
arguments = '%s v'%arg['non_optional_type'],
name = arg['name'],
arguments = '%s v'%arg['full_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'].replace('::Value', '')}
'type' : arg['non_optional_type'].split('::')[0]}
)
if arg['is_derived']:
constructor_implementations.append(templates.constructor_stmt_derived % {'index' : arg['index']-1})
else:
is_optional_non_naked_ptr = arg['is_optional'] and not arg['non_optional_type'].endswith('*')
arg_name = "v%(index)d_%(name)s"%arg
deref_name = ("*%s"%arg_name) if is_optional_non_naked_ptr else arg_name
deref_name = ("*%s"%arg_name) if arg['is_optional'] else arg_name
tmpl = templates.constructor_stmt_array if arg['is_templated_list'] \
else templates.constructor_stmt_enum if arg['is_enum'] \
else templates.constructor_stmt
impl = tmpl % {'name' : deref_name,
'index' : arg['index']-1,
'type' : arg['non_optional_type'].replace('::Value', '')}
if is_optional_non_naked_ptr:
'type' : arg['non_optional_type'].split('::')[0]}
if arg['is_optional']:
impl = templates.constructor_stmt_optional%{'name' : arg_name,
'index' : arg['index']-1,
'stmt' : impl}
@@ -144,19 +133,17 @@ class Implementation(codegen.Base):
def get_attribute_index(entity, attr_name):
related_entity = mapping.schema.entities[entity]
return [a['name'].lower() for a in mapping.get_assignable_arguments(related_entity, include_derived=True)].index(attr_name.lower())
return [a['name'] for a in mapping.get_assignable_arguments(related_entity, include_derived=True)].index(attr_name)
inverse = [templates.const_function % {
'class_name' : name,
'schema_name' : schema_name,
'schema_name_upper' : schema_name_upper,
'name' : i.name,
'arguments' : '',
'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}
'return_type' : '%s::list::ptr' % i.entity,
'body' : templates.get_inverse % {'type': i.entity, 'index':get_attribute_index(i.entity, i.attribute)}
} for i in (type.inverse.elements if type.inverse else [])]
superclass = "%s((IfcEntityInstanceData*)0)" % type.supertypes[0] if len(type.supertypes) == 1 else 'IfcUtil::IfcBaseEntity()'
superclass = "%s((IfcAbstractEntity*)0)" % type.supertypes[0] if len(type.supertypes) == 1 else 'IfcUtil::IfcBaseEntity()'
write(
templates.entity_implementation,
@@ -166,12 +153,10 @@ class Implementation(codegen.Base):
constructor_implementation = cat(constructor_implementations),
attributes = nl(catnl(attributes)),
inverse = nl(catnl(inverse)),
superclass = superclass,
schema_name = schema_name,
schema_name_upper = schema_name_upper
superclass = superclass
)
selectable_simple_types = sorted(set(sum([b.values for a,b in mapping.schema.selects.items()], [])) & set(map(str, mapping.schema.types.keys())))
selectable_simple_types = sorted(set(sum([b.values for a,b in mapping.schema.selects.items()], [])) & set(mapping.schema.types.keys()))
schema_entity_statements += [templates.schema_entity_stmt%locals() for name, type in mapping.schema.simpletypes.items()]
schema_entity_statements += [templates.schema_entity_stmt%locals() for name, type in mapping.schema.entities.items()]
@@ -183,15 +168,12 @@ class Implementation(codegen.Base):
'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 = ",".join(map(str, map(get_parent_id, enumerable_types)))
parent_type_statements = [templates.parent_type_stmt % {
'name' : name,
'parent' : type.supertypes[0],
'padding' : ' ' * (max_len - len(name))
} for name, type in mapping.schema.entities.items() if type.supertypes and len(type.supertypes) == 1]
max_id = len(enumerable_types)
@@ -209,51 +191,44 @@ class Implementation(codegen.Base):
constructor = templates.constructor_single_initlist if superclass \
else templates.constructor
simpletype_impl_cast = templates.simpletype_impl_cast_templated if mapping.is_templated_list(type) \
else templates.simpletype_impl_cast
simpletype_impl_constructor = templates.simpletype_impl_constructor_templated if mapping.is_templated_list(type) \
else templates.simpletype_impl_constructor
def compose(params, schema_name=schema_name, schema_name_upper=schema_name_upper):
def compose(params):
class_name, attr_type, superclass, superclass_init, name, tmpl, return_type, args, body = params
underlying_type = mapping.list_instance_type(type)
arguments = ",".join(args)
body = body % locals()
return tmpl % locals()
simple_type_impl.append(templates.simpletype_impl_comment % {'name': class_name})
simple_type_impl.extend(map(compose, map(lambda x: (class_name, attr_type, superclass, "(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.extend(map(compose, map(lambda x: (class_name, attr_type, superclass, "(IfcAbstractEntity*)0")+x, (
('getArgumentType', templates.const_function, 'IfcUtil::ArgumentType', ('unsigned int i',), templates.simpletype_impl_argument_type ),
('getArgument', templates.const_function, 'Argument*', ('unsigned int i',), templates.simpletype_impl_argument ),
('is', templates.const_function, 'bool', ('Type::Enum v',), simpletype_impl_is ),
('type', templates.const_function, 'Type::Enum', (), templates.simpletype_impl_type ),
('Class', templates.function, 'Type::Enum', (), templates.simpletype_impl_class ),
('', constructor, '', ('IfcAbstractEntity* e',), templates.simpletype_impl_explicit_constructor),
('', constructor, '', ("%s v" % type_str,), templates.simpletype_impl_constructor ),
('', templates.cast_function, type_str, (), templates.simpletype_impl_cast )
))))
simple_type_impl.append('')
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' : schema_name_upper,
'schema_name' : schema_name,
'schema_name_upper' : mapping.schema.name.upper(),
'schema_name' : mapping.schema.name.capitalize(),
'max_id' : max_id,
'enumeration_functions' : cat(enumeration_functions),
'schema_entity_statements' : catnl(schema_entity_statements),
'type_name_strings' : type_name_strings,
'string_map_statements' : catnl(string_map_statements),
'simple_type_statement' : simple_type_statements,
'parent_type_statements' : parent_type_statements,
'parent_type_statements' : catnl(parent_type_statements),
'entity_implementations' : catnl(entity_implementations),
'simple_type_impl' : catnl(simple_type_impl),
'external_definitions' : catnl(external_definitions)
'simple_type_impl' : catnl(simple_type_impl)
}
self.schema_name = mapping.schema.name.capitalize()
self.file_name = '%s.cpp'%self.schema_name
def __repr__(self):
return self.str
def emit(self):
f = open('%s.cpp'%self.schema_name, 'w', encoding='utf-8')
f.write(str(self))
f.close()
@@ -17,11 +17,19 @@
# #
###############################################################################
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import templates
from . import ifcopenshell_wrapper
version = ifcopenshell_wrapper.version()
get_log = ifcopenshell_wrapper.get_log
class LateBoundHeader:
def __init__(self, mapping):
self.str = templates.lb_header % {
'schema_name_upper' : mapping.schema.name.upper(),
'schema_name' : mapping.schema.name.capitalize()
}
self.schema_name = mapping.schema.name.capitalize()
def __repr__(self):
return self.str
def emit(self):
f = open('%s-latebound.h'%self.schema_name, 'w', encoding='utf-8')
f.write(str(self))
f.close()
@@ -0,0 +1,119 @@
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
import templates
class LateBoundImplementation:
def __init__(self, mapping):
schema_name = mapping.schema.name.capitalize()
entity_descriptors = []
enumeration_descriptors = []
derived_field_statements = []
inverse_implementations = []
for name, type in mapping.schema.simpletypes.items():
entity_descriptors.append(templates.entity_descriptor % {
'type' : name,
'parent_statement' : '0',
'entity_descriptor_attributes' : templates.entity_descriptor_attribute_without_entity % {
'name' : 'wrappedValue',
'optional' : 'false',
'type' : mapping.make_argument_type(mapping.schema.types[name].type)
}
})
emitted_entities = set()
entities_to_emit = mapping.schema.entities.keys()
while len(emitted_entities) < len(mapping.schema.entities):
for name, type in mapping.schema.entities.items():
if name in emitted_entities: continue
if len(type.supertypes) == 0 or set(type.supertypes) < emitted_entities:
constructor_arguments = mapping.get_assignable_arguments(type, include_derived = True)
entity_descriptor_attributes = []
for arg in constructor_arguments:
if not arg['is_inherited']:
is_enumeration = arg['argument_type_enum'] == 'IfcUtil::Argument_ENUMERATION'
tmpl = templates.entity_descriptor_attribute_with_entity
entity_name = arg['argument_type'] if is_enumeration else arg['argument_entity'].split('::')[1]
entity_descriptor_attributes.append(tmpl % {
'name' : arg['name'],
'optional' : 'true' if arg['is_optional'] else 'false',
'type' : arg['argument_type_enum'],
'entity_name': entity_name
})
emitted_entities.add(name)
parent_statement = '0' if len(type.supertypes) != 1 else templates.entity_descriptor_parent % {
'type' : type.supertypes[0]
}
entity_descriptors.append(templates.entity_descriptor % {
'type' : name,
'parent_statement' : parent_statement,
'entity_descriptor_attributes' : '\n'.join(entity_descriptor_attributes)
})
for name, enum in mapping.schema.enumerations.items():
enumeration_descriptor_values = '\n'.join([templates.enumeration_descriptor_value % {
'name' : v
} for v in enum.values])
enumeration_descriptors.append(templates.enumeration_descriptor % {
'type' : name,
'enumeration_descriptor_values' : enumeration_descriptor_values
})
for name, type in mapping.schema.entities.items():
constructor_arguments = mapping.get_assignable_arguments(type, include_derived = True)
statements = ''.join(templates.derived_field_statement_attrs % (a['index']-1) for a in constructor_arguments if a['is_derived'])
if len(statements):
derived_field_statements.append(templates.derived_field_statement % {
'type' : name,
'statements' : statements
})
for name, type in mapping.schema.entities.items():
if type.inverse:
for attr in type.inverse.elements:
related_entity = mapping.schema.entities[attr.entity]
related_attrs = [a['name'] for a in mapping.get_assignable_arguments(related_entity, include_derived=True)]
inverse_implementations.append(templates.inverse_implementation % {
'type' : name,
'name' : attr.name,
'related_type' : attr.entity,
'index' : related_attrs.index(attr.attribute)
})
self.str = templates.lb_implementation % {
'schema_name_upper' : mapping.schema.name.upper(),
'schema_name' : mapping.schema.name.capitalize(),
'entity_descriptors' : '\n'.join(entity_descriptors),
'enumeration_descriptors' : '\n'.join(enumeration_descriptors),
'derived_field_statements' : '\n'.join(derived_field_statements),
'inverse_implementations' : '\n'.join(inverse_implementations)
}
self.schema_name = mapping.schema.name.capitalize()
def __repr__(self):
return self.str
def emit(self):
f = open('%s-latebound.cpp'%self.schema_name, 'w', encoding='utf-8')
f.write(str(self))
f.close()
+41 -71
View File
@@ -17,9 +17,6 @@
# #
###############################################################################
from __future__ import print_function
import sys
import nodes
import templates
@@ -31,15 +28,8 @@ class Mapping:
'integer' : 'int',
'real' : 'double',
'number' : 'double',
'string' : 'std::string',
'binary' : 'boost::dynamic_bitset<>'
'string' : 'std::string'
}
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
@@ -54,17 +44,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 str(parent) in self.express_to_cpp_typemapping else parent
return None if parent in self.express_to_cpp_typemapping else parent
def make_type_string(self, 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))
if isinstance(type, str):
return self.express_to_cpp_typemapping.get(type, type)
else:
is_list = self.schema.is_entity(type.type)
is_nested_list = isinstance(type.type, nodes.AggregationType)
tmpl = templates.list_list_type if is_nested_list else templates.list_type if is_list else templates.array_type
return tmpl % {
'instance_type' : self.make_type_string(self.flatten_type_string(type.type)),
'instance_type' : self.make_type_string(type.type),
'lower' : type.bounds.lower,
'upper' : type.bounds.upper,
}
@@ -80,76 +70,67 @@ 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 str(type) in self.express_to_cpp_typemapping: return "Type::UNDEFINED"
if type in self.express_to_cpp_typemapping or isinstance(type, nodes.BinaryType): return "Type::UNDEFINED"
else: return "Type::%s" % type
def make_argument_type(self, attr):
def _make_argument_type(type):
if self.schema.is_entity(type) or isinstance(type, nodes.SelectType):
return "ENTITY_INSTANCE"
if type in self.express_to_cpp_typemapping:
return self.express_to_cpp_typemapping.get(type, type).split('::')[-1].upper()
elif self.schema.is_entity(type):
return "ENTITY"
elif self.schema.is_type(type):
return _make_argument_type(self.schema.types[type].type.type)
elif isinstance(type, nodes.BinaryType):
return "BINARY"
elif isinstance(type, nodes.StringType):
return "STRING"
return "UNKNOWN"
elif isinstance(type, nodes.EnumerationType):
return "ENUMERATION"
elif isinstance(type, nodes.SelectType):
return "ENTITY"
elif isinstance(type, nodes.AggregationType):
ty = _make_argument_type(type.type)
if ty == "UNKNOWN": return "UNKNOWN"
return "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))
return "%s_LIST"%ty if ty.startswith("ENTITY") else ("VECTOR_%s"%ty)
else: raise ValueError
supported = {'INT', 'BOOL', 'DOUBLE', 'STRING', 'VECTOR_INT', 'VECTOR_DOUBLE', 'VECTOR_STRING', 'ENTITY', 'ENTITY_LIST', 'ENTITY_LIST_LIST', 'ENUMERATION'}
ty = _make_argument_type(attr.type if hasattr(attr, 'type') else attr)
if ty not in self.supported_argument_types:
print("Attribute %r mapped as 'unknown'" % (attr), file=sys.stderr)
ty = 'UNKNOWN'
if ty not in supported: ty = 'UNKNOWN'
return "IfcUtil::Argument_%s" % ty
def get_type_dep(self, type):
if isinstance(type, str):
return self.express_to_cpp_typemapping.get(str(type), type)
return self.express_to_cpp_typemapping.get(type, type)
else:
return self.get_type_dep(type.type)
def get_parameter_type(self, attr, allow_optional, allow_entities, allow_pointer = True):
attr_type = self.flatten_type(attr.type)
type_str = self.express_to_cpp_typemapping.get(str(attr_type), attr_type)
is_ptr = False
if self.schema.is_enumeration(attr_type):
type_str = '::%s::%s::Value' % (self.schema.name.capitalize(), attr_type)
type_str = '%s::%s'%(attr_type, attr_type)
elif isinstance(type_str, nodes.AggregationType):
is_nested_list = isinstance(attr_type.type, nodes.AggregationType)
ty = self.get_parameter_type(attr_type.type if is_nested_list else attr_type, False, allow_entities, False)
if self.schema.is_select(attr_type.type):
if True and self.schema.is_select(attr_type.type):
type_str = templates.untyped_list
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 % {
elif self.schema.is_simpletype(ty) or ty in self.express_to_cpp_typemapping.values():
type_str = templates.array_type % {
'instance_type' : ty,
'lower' : bounds[0],
'upper' : bounds[1]
'lower' : attr_type.bounds.lower,
'upper' : attr_type.bounds.upper
}
else:
tmpl = templates.list_list_type if is_nested_list else templates.list_type
type_str = tmpl % {
'instance_type': ty
}
elif (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 allow_pointer and (self.schema.is_entity(type_str) or self.schema.is_select(type_str)):
type_str += '*'
elif not allow_pointer and self.schema.is_select(type_str):
type_str = "IfcUtil::IfcBaseClass*"
is_ptr = True
if allow_optional and attr.optional and not is_ptr:
if allow_optional and attr.optional:# and not is_ptr:
type_str = "boost::optional< %s >"%type_str
return type_str
@@ -166,34 +147,23 @@ class Mapping:
return c + ([str(s) for s in t.derive.elements] if t.derive else [])
def list_instance_type(self, attr):
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)
f = lambda v : 'IfcUtil::IfcBaseClass' if self.schema.is_select(v) else v
if self.is_array(attr.type):
if not isinstance(attr.type, str) and self.is_array(attr.type.type):
if isinstance(attr.type.type, str):
return f(attr.type.type)
else: return f(attr.type.type.type)
else:
if isinstance(attr_type, str):
return f(attr_type)
else: return f(attr_type.type)
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)
if ty is None: return False
arr = self.is_array(attr_type)
arr = self.is_array(attr.type)
simple = self.schema.is_simpletype(ty)
express = self.flatten_type_string(ty) in self.express_to_cpp_typemapping
express = ty in self.express_to_cpp_typemapping
select = ty == 'IfcUtil::IfcBaseClass'
return arr and not simple and not express and not select
+10 -37
View File
@@ -21,8 +21,8 @@ import string
import collections
class Node:
def __init__(self, tokens = None):
self.tokens = tokens or []
def __init__(self, tokens):
self.tokens = tokens
self.init()
def tokens_of_type(self, cls):
return [t for t in self.tokens if isinstance(t, cls)]
@@ -44,17 +44,15 @@ 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 += "%sEntity(%s)" % ("Abstract " if self.abstract else "", self.name)
builder += "Entity(%s)" % (self.name)
if len(self.supertypes):
builder += "\n Supertypes: %s"%(",".join(self.supertypes))
if len(self.attributes):
@@ -108,20 +106,12 @@ 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):
if self.tokens[0] == 'abstract':
self.tokens = self.tokens[1:]
self.abstract = True
assert self.type == self.type_relationship
assert self.type == self.class_type
class SubTypeExpression(SubSuperTypeExpression):
type_relationship = 'subtype'
class SuperTypeExpression(SubSuperTypeExpression):
type_relationship = 'supertype'
class SubtypeExpression(SubSuperTypeExpression):
class_type = 'subtype'
class AttributeList(Node):
@@ -137,8 +127,8 @@ class AttributeList(Node):
class InverseAttribute(Node):
name = property(lambda self: self.tokens[0])
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])
type = property(lambda self: self.tokens[2])
bounds = property(lambda self: None if len(self.tokens) == 6 else self.tokens[3])
entity = property(lambda self: self.tokens[-4])
attribute = property(lambda self: self.tokens[-2])
def init(self):
@@ -159,7 +149,7 @@ class BinaryType(Node):
def init(self):
pass
def __repr__(self):
return "binary"
return "BINARY"
class BoundSpecification(Node):
@@ -180,23 +170,6 @@ 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"
+10 -48
View File
@@ -18,67 +18,29 @@
###############################################################################
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 str(v) in self.enumerations
return v in self.enumerations
def is_select(self, v):
return str(v) in self.selects
return v in self.selects
def is_simpletype(self, v):
return str(v) in self.simpletypes
return v in self.simpletypes
def is_type(self, v):
return str(v) in self.types
return v in self.types
def is_entity(self, v):
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]
return v in self.entities
def __init__(self, parsetree):
self.name = parsetree[1]
sort = lambda d: OrderedCaseInsensitiveDict(sorted(d))
sort = lambda d: collections.OrderedDict(sorted(d.items()))
self.types = sort([(t.name,t) for t in parsetree if isinstance(t, nodes.TypeDeclaration)])
self.entities = sort([(t.name,t) for t in parsetree if isinstance(t, nodes.EntityDeclaration)])
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()}
self.types = sort({t.name:t for t in parsetree if isinstance(t, nodes.TypeDeclaration)})
self.entities = sort({t.name:t for t in parsetree if isinstance(t, nodes.EntityDeclaration)})
of_type = lambda *types: sort([(a, b.type.type) for a,b in self.types.items() if any(isinstance(b.type.type, ty) for ty in types)])
of_type = lambda *types: sort({a: b.type.type for a,b in self.types.items() if any(isinstance(b.type.type, ty) for ty in types)})
self.enumerations = of_type(nodes.EnumerationType)
self.selects = of_type(nodes.SelectType)
self.simpletypes = of_type(str, nodes.AggregationType, nodes.BinaryType, nodes.StringType)
self.simpletypes = of_type(str, nodes.AggregationType)
-250
View File
@@ -1,250 +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 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
+299 -80
View File
@@ -23,24 +23,19 @@ header = """
#include <string>
#include <vector>
#include <map>
#include <boost/optional.hpp>
#include "../ifcparse/ifc_parse_api.h"
#include "../ifcparse/IfcEntityList.h"
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcSchema.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/Argument.h"
#include "../ifcparse/%(schema_name)senum.h"
struct %(schema_name)s {
#define IfcSchema %(schema_name)s
static const IfcParse::schema_definition& get_schema();
namespace %(schema_name)s {
static const char* const Identifier;
const char* const Identifier = "%(schema_name_upper)s";
// Forward definitions
%(forward_definitions)s
@@ -48,7 +43,9 @@ static const char* const Identifier;
%(declarations)s
%(class_definitions)s
};
void InitStringMap();
IfcUtil::IfcBaseClass* SchemaEntity(IfcAbstractEntity* e = 0);
}
#endif
"""
@@ -57,31 +54,97 @@ enum_header = """
#ifndef %(schema_name_upper)sENUM_H
#define %(schema_name_upper)sENUM_H
#include "../ifcparse/ifc_parse_api.h"
#define IfcSchema %(schema_name)s
#include <string>
#include <boost/optional.hpp>
namespace %(schema_name)s {
namespace Type {
typedef enum {
%(types)s, UNDEFINED
} Enum;
Enum Parent(Enum v);
Enum FromString(const std::string& s);
std::string ToString(Enum v);
bool IsSimple(Enum v);
}
}
#endif
"""
lb_header = """"""
lb_header = """
#ifndef %(schema_name_upper)sRT_H
#define %(schema_name_upper)sRT_H
#define IfcSchema %(schema_name)s
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcEntityDescriptor.h"
#include "../ifcparse/IfcWritableEntity.h"
namespace %(schema_name)s {
namespace Type {
int GetAttributeCount(Enum t);
int GetAttributeIndex(Enum t, const std::string& a);
IfcUtil::ArgumentType GetAttributeType(Enum t, unsigned char a);
Enum GetAttributeEntity(Enum t, unsigned char a);
const std::string& GetAttributeName(Enum t, unsigned char a);
bool GetAttributeOptional(Enum t, unsigned char a);
bool GetAttributeDerived(Enum t, unsigned char a);
std::pair<const char*, int> GetEnumerationIndex(Enum t, const std::string& a);
std::pair<Enum, unsigned> GetInverseAttribute(Enum t, const std::string& a);
std::set<std::string> GetInverseAttributeNames(Enum t);
void PopulateDerivedFields(IfcWrite::IfcWritableEntity* e);
}}
#endif
"""
implementation= """
#include "../ifcparse/%(schema_name)s.h"
#include "../ifcparse/IfcSchema.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcWrite.h"
#include "../ifcparse/IfcWritableEntity.h"
#include <map>
const char* const %(schema_name)s::Identifier = "%(schema_name_upper)s";
using namespace %(schema_name)s;
using namespace IfcParse;
using namespace IfcWrite;
// External definitions
%(external_definitions)s
IfcUtil::IfcBaseClass* %(schema_name)s::SchemaEntity(IfcAbstractEntity* e) {
switch(e->type()) {
%(schema_entity_statements)s
default: throw IfcException("Unable to find find keyword in schema"); break;
}
}
std::string Type::ToString(Enum v) {
if (v < 0 || v >= %(max_id)d) throw IfcException("Unable to find find keyword in schema");
const char* names[] = { %(type_name_strings)s };
return names[v];
}
static std::map<std::string,Type::Enum> string_map;
void %(schema_name)s::InitStringMap() {
%(string_map_statements)s
}
Type::Enum Type::FromString(const std::string& s) {
if (string_map.empty()) InitStringMap();
std::map<std::string,Type::Enum>::const_iterator it = string_map.find(s);
if ( it == string_map.end() ) throw IfcException("Unable to find find keyword in schema");
else return it->second;
}
Type::Enum Type::Parent(Enum v){
if (v < 0 || v >= %(max_id)d) return (Enum)-1;
%(parent_type_statements)s
return (Enum)-1;
}
bool Type::IsSimple(Enum v) {
return %(simple_type_statement)s;
}
%(enumeration_functions)s
@@ -90,7 +153,150 @@ using namespace IfcWrite;
%(entity_implementations)s
"""
lb_implementation = """"""
lb_implementation = """
#include <set>
#include "../ifcparse/%(schema_name)s.h"
#include "../ifcparse/%(schema_name)s-latebound.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcWrite.h"
#include "../ifcparse/IfcWritableEntity.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcEntityDescriptor.h"
using namespace %(schema_name)s;
using namespace IfcParse;
using namespace IfcWrite;
using namespace IfcUtil;
typedef std::map<Type::Enum,IfcEntityDescriptor*> entity_descriptor_map_t;
typedef std::map<Type::Enum,IfcEnumerationDescriptor*> enumeration_descriptor_map_t;
typedef std::map<Type::Enum, std::map<std::string, std::pair<Type::Enum, int> > > inverse_map_t;
typedef std::map<Type::Enum,std::set<int> > derived_map_t;
entity_descriptor_map_t entity_descriptor_map;
enumeration_descriptor_map_t enumeration_descriptor_map;
inverse_map_t inverse_map;
derived_map_t derived_map;
void InitDescriptorMap() {
IfcEntityDescriptor* current;
%(entity_descriptors)s
// Enumerations
IfcEnumerationDescriptor* current_enum;
std::vector<std::string> values;
%(enumeration_descriptors)s
}
void InitInverseMap() {
%(inverse_implementations)s
}
void InitDerivedMap() {
%(derived_field_statements)s
}
int Type::GetAttributeIndex(Enum t, const std::string& a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentIndex(a);
}
int Type::GetAttributeCount(Enum t) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentCount();
}
ArgumentType Type::GetAttributeType(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentType(a);
}
Type::Enum Type::GetAttributeEntity(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentEntity(a);
}
const std::string& Type::GetAttributeName(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentName(a);
}
bool Type::GetAttributeOptional(Enum t, unsigned char a) {
if (entity_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEntityDescriptor*>::const_iterator i = entity_descriptor_map.find(t);
if ( i == entity_descriptor_map.end() ) throw IfcException("Type not found");
else return i->second->getArgumentOptional(a);
}
bool Type::GetAttributeDerived(Enum t, unsigned char a) {
if (derived_map.empty()) ::InitDerivedMap();
std::map<Type::Enum,std::set<int> >::const_iterator i = derived_map.find(t);
return i != derived_map.end() && i->second.find(a) != i->second.end();
}
std::pair<const char*, int> Type::GetEnumerationIndex(Enum t, const std::string& a) {
if (enumeration_descriptor_map.empty()) ::InitDescriptorMap();
std::map<Type::Enum,IfcEnumerationDescriptor*>::const_iterator i = enumeration_descriptor_map.find(t);
if ( i == enumeration_descriptor_map.end() ) throw IfcException("Value not found");
else return i->second->getIndex(a);
}
std::pair<Type::Enum, unsigned> Type::GetInverseAttribute(Enum t, const std::string& a) {
if (inverse_map.empty()) ::InitInverseMap();
inverse_map_t::const_iterator it;
inverse_map_t::mapped_type::const_iterator jt;
while (true) {
it = inverse_map.find(t);
if (it != inverse_map.end()) {
jt = it->second.find(a);
if (jt != it->second.end()) {
return jt->second;
}
}
if ((t = Parent(t)) == -1) break;
}
throw IfcException("Attribute not found");
}
std::set<std::string> Type::GetInverseAttributeNames(Enum t) {
if (inverse_map.empty()) ::InitInverseMap();
inverse_map_t::const_iterator it;
inverse_map_t::mapped_type::const_iterator jt;
std::set<std::string> return_value;
while (true) {
it = inverse_map.find(t);
if (it != inverse_map.end()) {
for (jt = it->second.begin(); jt != it->second.end(); ++jt) {
return_value.insert(jt->first);
}
}
if ((t = Parent(t)) == -1) break;
}
return return_value;
}
void Type::PopulateDerivedFields(IfcWrite::IfcWritableEntity* e) {
std::map<Type::Enum, std::set<int> >::const_iterator i = derived_map.find(e->type());
if (i != derived_map.end()) {
for (std::set<int>::const_iterator it = i->second.begin(); it != i->second.end(); ++it) {
e->setArgumentDerived(*it);
}
}
}
"""
entity_descriptor = """ current = entity_descriptor_map[Type::%(type)s] = new IfcEntityDescriptor(Type::%(type)s,%(parent_statement)s);
%(entity_descriptor_attributes)s"""
@@ -101,7 +307,7 @@ entity_descriptor_attribute_with_entity = ' current->add("%(name)s",%(optiona
enumeration_descriptor = """ values.clear(); values.reserve(128);
%(enumeration_descriptor_values)s
enumeration_descriptor_map[Type::%(type)s] = new IfcEnumerationDescriptor(Type::%(type)s, values);"""
current_enum = enumeration_descriptor_map[Type::%(type)s] = new IfcEnumerationDescriptor(Type::%(type)s, values);"""
enumeration_descriptor_value = ' values.push_back("%(name)s");'
@@ -109,85 +315,89 @@ derived_field_statement = ' {std::set<int> idxs; %(statements)sderived_map[Ty
derived_field_statement_attrs = 'idxs.insert(%d); '
simpletype = """%(documentation)s
class IFC_PARSE_API %(name)s : public %(superclass)s {
class %(name)s : public %(superclass)s {
public:
virtual const IfcParse::type_declaration& declaration() const;
static const IfcParse::type_declaration& Class();
explicit %(name)s (IfcEntityInstanceData* e);
virtual IfcUtil::ArgumentType getArgumentType(unsigned int i) const;
virtual Argument* getArgument(unsigned int i) const;
bool is(Type::Enum v) const;
Type::Enum type() const;
static Type::Enum Class();
explicit %(name)s (IfcAbstractEntity* e);
%(name)s (%(type)s v);
operator %(type)s() const;
};
"""
simpletype_impl_comment = "// Function implementations for %(name)s"
simpletype_impl_argument_type = "if (i == 0) { return %(attr_type)s; } else { throw IfcParse::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;"
simpletype_impl_argument_type = "if (i == 0) { return %(attr_type)s; } else { throw IfcParse::IfcException(\"argument out of range\"); }"
simpletype_impl_argument = "return entity->getArgument(i);"
simpletype_impl_is_with_supertype = "return v == Type::%(class_name)s || %(superclass)s::is(v);"
simpletype_impl_is_without_supertype = "return v == %(class_name)s::Class();"
simpletype_impl_type = "return Type::%(class_name)s;"
simpletype_impl_class = "return Type::%(class_name)s;"
simpletype_impl_explicit_constructor = "entity = e;"
simpletype_impl_constructor = "IfcWritableEntity* e = new IfcWritableEntity(Type::%(class_name)s); e->setArgument(0, v); entity = e;"
simpletype_impl_cast = "return *entity->getArgument(0);"
select = """%(documentation)s
typedef IfcUtil::IfcBaseClass %(name)s;
"""
enumeration = """struct %(name)s {
enumeration = """namespace %(name)s {
%(documentation)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);
};
typedef enum {%(values)s} %(name)s;
const char* ToString(%(name)s v);
%(name)s FromString(const std::string& s);
}
"""
entity = """%(documentation)s
class IFC_PARSE_API %(name)s %(superclass)s{
class %(name)s %(superclass)s{
public:
%(attributes)s %(inverse)s virtual const IfcParse::entity& declaration() const;
static const IfcParse::entity& Class();
%(name)s (IfcEntityInstanceData* e);
%(attributes)s virtual unsigned int getArgumentCount() const { return %(argument_count)d; }
virtual IfcUtil::ArgumentType getArgumentType(unsigned int i) const {%(argument_type_function_body)s}
virtual Type::Enum getArgumentEntity(unsigned int i) const {%(argument_entity_function_body)s}
virtual const char* getArgumentName(unsigned int i) const {%(argument_name_function_body)s}
virtual Argument* getArgument(unsigned int i) const { return entity->getArgument(i); }
%(inverse)s bool is(Type::Enum v) const;
Type::Enum type() const;
static Type::Enum Class();
%(name)s (IfcAbstractEntity* e);
%(name)s (%(constructor_arguments)s);
typedef IfcTemplatedEntityList< %(name)s > list;
};
"""
enumeration_function="""
const char* %(schema_name)s::%(name)s::ToString(Value v) {
const char* %(name)s::ToString(%(name)s v) {
if ( v < 0 || v >= %(max_id)d ) throw IfcException("Unable to find find keyword in schema");
const char* names[] = { %(values)s };
return names[v];
}
%(schema_name)s::%(name)s::Value %(schema_name)s::%(name)s::FromString(const std::string& s) {
%(name)s::%(name)s %(name)s::FromString(const std::string& s) {
%(from_string_statements)s
throw IfcException("Unable to find find keyword in schema");
}
"""
entity_implementation = """// Function implementations for %(name)s
%(attributes)s
%(inverse)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 }
%(attributes)s%(inverse)sbool %(name)s::is(Type::Enum v) const { return v == Type::%(name)s%(parent_type_test)s; }
Type::Enum %(name)s::type() const { return Type::%(name)s; }
Type::Enum %(name)s::Class() { return Type::%(name)s; }
%(name)s::%(name)s(IfcAbstractEntity* e) : %(superclass)s { if (!e) return; if (!e->is(Type::%(name)s)) throw IfcException("Unable to find find keyword in schema"); entity = e; }
%(name)s::%(name)s(%(constructor_arguments)s) : %(superclass)s { IfcWritableEntity* e = new IfcWritableEntity(Class());%(constructor_implementation)s entity = e; EntityBuffer::Add(this); }
"""
optional_attribute_description = "/// Whether the optional attribute %s is defined for this %s"
function = "%(return_type)s %(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 }"
function = "%(return_type)s %(class_name)s::%(name)s(%(arguments)s) { %(body)s }"
const_function = "%(return_type)s %(class_name)s::%(name)s(%(arguments)s) const { %(body)s }"
constructor = "%(class_name)s::%(class_name)s(%(arguments)s) { %(body)s }"
constructor_single_initlist = "%(class_name)s::%(class_name)s(%(arguments)s) : %(superclass)s(%(superclass_init)s) { %(body)s }"
cast_function = "%(class_name)s::operator %(return_type)s() const { %(body)s }"
array_type = "std::vector< %(instance_type)s > /*[%(lower)s:%(upper)s]*/"
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"
@@ -196,31 +406,40 @@ 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 !data_->getArgument(%(index)d)->isNull();"
get_attr_stmt_generic = "return *entity->getArgument(%(index)d);"
get_attr_stmt_enum = "return %(type)s::FromString(*entity->getArgument(%(index)d));"
get_attr_stmt_entity = "return (%(type)s)((IfcUtil::IfcBaseClass*)(*entity->getArgument(%(index)d)));"
get_attr_stmt_array = "IfcEntityList::ptr es = *entity->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
get_attr_stmt_nested_array = "IfcEntityListList::ptr es = *entity->getArgument(%(index)d); return es->as<%(list_instance_type)s>();"
get_attr_stmt_optional = "Argument* arg = entity->getArgument(%%(index)d); if (arg->isNull()) { return boost::none; } else { %s }"
get_attr_stmt_optional_generic = get_attr_stmt_optional % "return *arg;"
get_attr_stmt_optional_enum = get_attr_stmt_optional % "return %(type)s::FromString(*arg);"
get_attr_stmt_optional_entity = get_attr_stmt_optional % "return (%(type)s)((IfcUtil::IfcBaseClass*)(*arg));"
get_attr_stmt_optional_array = get_attr_stmt_optional % "IfcEntityList::ptr es = *arg; return es->as<%(list_instance_type)s>();"
get_attr_stmt_optional_nested_array = get_attr_stmt_optional % "IfcEntityListList::ptr es = *arg; return es->as<%(list_instance_type)s>();"
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 >();"
set_attr_stmt = "IfcWritableEntity* w = entity->isWritable(); if (!w) { entity = w = new IfcWritableEntity(entity); } %s;"
set_attr_stmt_optional = "IfcWritableEntity* w = entity->isWritable(); if (!w) { entity = w = new IfcWritableEntity(entity); } if (v) { %s; } else { w->setArgument(%%(index)d); }"
set_attr_stmt_generic = set_attr_stmt % "w->setArgument(%(index)d,v)"
set_attr_stmt_enum = set_attr_stmt % "w->setArgument(%(index)d,v,%(type)s::ToString(v));"
set_attr_stmt_array = set_attr_stmt % "w->setArgument(%(index)d,v->generalize());"
set_attr_stmt_optional_generic = set_attr_stmt_optional % "w->setArgument(%(index)d,*v)"
set_attr_stmt_optional_enum = set_attr_stmt_optional % "w->setArgument(%(index)d,*v,%(type)s::ToString(*v));"
set_attr_stmt_optional_array = set_attr_stmt_optional % "w->setArgument(%(index)d,(*v)->generalize());"
get_inverse = "return data_->getInverse(%(schema_name_upper)s_%(type)s_type, %(index)d)->as<%(type)s>();"
get_inverse = "return entity->getInverse(Type::%(type)s, %(index)d)->as<%(type)s>();"
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 = "{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); }"
constructor_stmt = " e->setArgument(%(index)d,(%(name)s));"
constructor_stmt_enum = " e->setArgument(%(index)d,%(name)s,%(type)s::ToString(%(name)s));"
constructor_stmt_array = " e->setArgument(%(index)d,(%(name)s)->generalize());"
constructor_stmt_optional = " if (%(name)s) {%(stmt)s } else { e->setArgument(%(index)d); }"
constructor_stmt_derived = " e->setArgumentDerived(%(index)d);"
inverse_implementation = " inverse_map[Type::%(type)s].insert(std::make_pair(\"%(name)s\", std::make_pair(Type::%(related_type)s, %(index)d)));"
+81 -222
View File
@@ -20,14 +20,8 @@
#ifndef IFCGEOM_H
#define IFCGEOM_H
#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;
}
#define ALMOST_ZERO (1e-9)
#define ALMOST_THE_SAME(a,b) (fabs(a-b) < ALMOST_ZERO)
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
@@ -43,108 +37,70 @@ inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMO
#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/IfcBaseClass.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcgeom/IfcGeomElement.h"
#include "../ifcgeom/IfcGeomRepresentation.h"
#include "../ifcgeom/IfcRepresentationShapeItem.h"
#include "../ifcgeom/IfcGeomShapeType.h"
#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());\
#define IN_CACHE(T,E,t,e) std::map<int,t>::const_iterator it = cache.T.find(E->entity->id());\
if ( it != cache.T.end() ) { e = it->second; return true; }
#define CACHE(T,E,e) cache.T[E->data().id()] = e;
#endif
#define INCLUDE_PARENT_DIR(x) STRINGIFY(../ifcparse/x.h)
#include INCLUDE_PARENT_DIR(IfcSchema)
#define CACHE(T,E,e) cache.T[E->entity->id()] = e;
namespace IfcGeom {
class IFC_GEOM_API MAKE_TYPE_NAME(Cache) {
class Cache {
public:
#include "IfcRegisterCreateCache.h"
std::map<int, SurfaceStyle> Style;
std::map<int, TopoDS_Shape> Shape;
};
class IFC_GEOM_API MAKE_TYPE_NAME(Kernel) : public IfcGeom::Kernel {
class Kernel {
private:
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;
Cache cache;
public:
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;
}
// Tolerances and settings for various geometrical operations:
enum GeomValue {
// Specifies the deflection of the mesher
// Default: 0.001m / 1mm
GV_DEFLECTION_TOLERANCE,
// Specifies the tolerance of the wire builder, most notably for trimmed curves
// Defailt: 0.0001m / 0.1mm
GV_WIRE_CREATION_TOLERANCE,
// Specifies the minimal area of a face to be included in an IfcConnectedFaceset
// Default: 0.000001m 0.01cm2
GV_MINIMAL_FACE_AREA,
// Specifies the treshold distance under which cartesian points are deemed equal
// Default: 0.00001m / 0.01mm
GV_POINT_EQUALITY_TOLERANCE,
// Specifies maximum number of faces for a shell to be sewed. Sewing shells
// that consist of many faces is really detrimental for the performance.
// Default: 1000
GV_MAX_FACES_TO_SEW,
// By default singular faces have no explicitly defined orientation, to
// force faces to be defined CounterClockWise, set this value greater than zero.
GV_FORCE_CCW_FACE_ORIENTATION,
// The length unit used the creation of TopoDS_Shapes, primarily affects the
// interpretation of IfcCartesianPoints and IfcVector magnitudes
// DefaultL 1.0
GV_LENGTH_UNIT,
// The plane angle unit used for the creation of TopoDS_Shapes, primarily affects
// the interpretation of IfcParamaterValues of IfcTrimmedCurves
// Default: -1.0 (= not set, fist try degrees, then radians)
GV_PLANEANGLE_UNIT,
// The precision used in boolean operations, setting this value too low results
// in artefacts and potentially modelling failures
// Default: 0.00001 (obtained from IfcGeometricRepresentationContext if available)
GV_PRECISION
};
bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face);
bool convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire);
bool convert_shapes(const IfcUtil::IfcBaseClass* L, IfcRepresentationShapeItems& result);
IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseClass* L);
bool is_shape_collection(const IfcUtil::IfcBaseClass* L);
bool convert_shape(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
bool flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse);
bool convert_wire(const IfcUtil::IfcBaseClass* L, TopoDS_Wire& result);
@@ -152,40 +108,8 @@ 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);
@@ -193,133 +117,68 @@ 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_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&);
void remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
std::pair<std::string, double> initializeUnits(IfcSchema::IfcUnitAssignment*);
static IfcSchema::IfcObjectDefinition* get_decomposing_entity(IfcSchema::IfcProduct*);
IfcSchema::IfcObjectDefinition* get_decomposing_entity(IfcSchema::IfcProduct*);
template <typename P, typename PP>
IfcGeom::BRepElement<P, PP>* create_brep_for_representation_and_product(
const IteratorSettings&, IfcSchema::IfcRepresentation*, 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_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*);
const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem* representation_item);
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> _get_surface_style(const IfcSchema::IfcStyledItem* si) {
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) {
IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem();
for (IfcSchema::IfcStyledItem::list::it jt = styled_items->begin(); jt != styled_items->end(); ++jt) {
#ifdef USE_IFC4
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;
IfcUtil::IfcAbstractSelect::list::ptr style_assignments = (*jt)->Styles();
for (IfcUtil::IfcAbstractSelect::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
if (!(*kt)->is(IfcSchema::Type::IfcPresentationStyleAssignment)) {
continue;
}
IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt;
#else
IfcSchema::IfcPresentationStyleAssignment::list::ptr style_assignments = si->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 = (*jt)->Styles();
for (IfcSchema::IfcPresentationStyleAssignment::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
IfcSchema::IfcPresentationStyleAssignment* style_assignment = *kt;
#endif
IfcEntityList::ptr styles = style_assignment->Styles();
for (IfcEntityList::it lt = styles->begin(); lt != styles->end(); ++lt) {
IfcUtil::IfcBaseClass* style = *lt;
if (style->declaration().is(IfcSchema::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);
IfcEntityList::ptr styles = style_assignment->Styles();
for (IfcEntityList::it lt = styles->begin(); lt != styles->end(); ++lt) {
IfcUtil::IfcBaseClass* style = *lt;
if (style->is(IfcSchema::Type::IfcSurfaceStyle)) {
IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style;
if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) {
IfcEntityList::ptr styles_elements = surface_style->Styles();
for (IfcEntityList::it mt = styles_elements->begin(); mt != styles_elements->end(); ++mt) {
if ((*mt)->is(T::Class())) {
return std::make_pair(surface_style, (T*) *mt);
}
}
}
}
}
}
// StyledByItem is a SET [0:1] OF IfcStyledItem, so we
// break after encountering the first IfcStyledItem
break;
}
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0,0);
}
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;
}
};
IfcUtil::IfcBaseClass* MAKE_TYPE_NAME(tesselate_)(const TopoDS_Shape& shape, double deflection);
IfcUtil::IfcBaseClass* MAKE_TYPE_NAME(serialise_)(const TopoDS_Shape& shape, bool advanced);
IfcSchema::IfcProductDefinitionShape* tesselate(TopoDS_Shape& shape, double deflection, IfcEntityList::ptr es);
}
#endif
+5 -65
View File
@@ -77,23 +77,17 @@
#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);
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
return false;
}
gp_Trsf trsf;
IfcSchema::IfcAxis2Placement* placement = l->Position();
if (placement->declaration().is(IfcSchema::IfcAxis2Placement3D::Class())) {
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
} else {
gp_Trsf2d trsf2d;
@@ -108,7 +102,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);
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
return false;
}
// Open Cascade does not allow ellipses of which the minor radius
@@ -118,7 +112,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->declaration().is(IfcSchema::IfcAxis2Placement3D::Class())) {
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
} else {
gp_Trsf2d trsf2d;
@@ -141,58 +135,4 @@ 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
}
+36 -110
View File
@@ -20,14 +20,9 @@
#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 {
@@ -45,7 +40,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.get(IteratorSettings::CONVERT_BACK_UNITS)
const double matrix_value = i == 4 && settings.convert_back_units()
? trsf_value / settings.unit_magnitude()
: trsf_value;
_data.push_back(static_cast<P>(matrix_value));
@@ -58,28 +53,18 @@ namespace IfcGeom {
template <typename P>
class Transformation {
private:
ElementSettings settings_;
gp_Trsf trsf_;
Matrix<P> matrix_;
gp_Trsf trsf;
Matrix<P> _matrix;
public:
Transformation(const ElementSettings& settings, const gp_Trsf& trsf)
: settings_(settings)
, trsf_(trsf)
, matrix_(settings, trsf)
: trsf(trsf)
, _matrix(settings, trsf)
{}
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()));
}
const gp_Trsf& data() const { return trsf; }
const Matrix<P>& matrix() const { return _matrix; }
};
template <typename P = double, typename PP = P>
template <typename P>
class Element {
private:
int _id;
@@ -87,123 +72,64 @@ namespace IfcGeom {
std::string _name;
std::string _type;
std::string _guid;
std::string _context;
std::string _unique_id;
Transformation<PP> _transformation;
IfcUtil::IfcBaseEntity* product_;
std::vector<const IfcGeom::Element<P, PP>*> _parents;
Transformation<P> _transformation;
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 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();
}
const Transformation<P>& transformation() const { return _transformation; }
Element(const ElementSettings& settings, int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf)
: _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _transformation(settings, trsf)
{}
virtual ~Element() {}
};
template <typename P = double, typename PP = P>
class BRepElement : public Element<P, PP> {
template <typename P>
class BRepElement : public Element<P> {
private:
boost::shared_ptr<Representation::BRep> _geometry;
Representation::BRep* _geometry;
public:
const boost::shared_ptr<Representation::BRep>& geometry_pointer() const { return _geometry; }
const Representation::BRep& geometry() const { return *_geometry; }
BRepElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid,
const std::string& context, const gp_Trsf& trsf, const boost::shared_ptr<Representation::BRep>& geometry,
IfcUtil::IfcBaseEntity* product)
: Element<P, PP>(geometry->settings() ,id, parent_id, name, type, guid, context, trsf, product)
BRepElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const gp_Trsf& trsf, Representation::BRep* geometry)
: Element<P>(geometry->settings(),id,parent_id,name,type,guid,trsf)
, _geometry(geometry)
{}
virtual ~BRepElement() {
delete _geometry;
}
private:
BRepElement(const BRepElement& other);
BRepElement& operator=(const BRepElement& other);
};
template <typename P = double, typename PP = P>
class TriangulationElement : public Element<P, PP> {
template <typename P>
class TriangulationElement : public Element<P> {
private:
boost::shared_ptr< Representation::Triangulation<P> > _geometry;
Representation::Triangulation<P>* _geometry;
public:
const Representation::Triangulation<P>& geometry() const { return *_geometry; }
const boost::shared_ptr< Representation::Triangulation<P> >& geometry_pointer() const { return _geometry; }
TriangulationElement(const BRepElement<P, PP>& shape_model)
: 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)
TriangulationElement(const BRepElement<P>& shape_model)
: Element<P>(shape_model)
, _geometry(new Representation::Triangulation<P>(shape_model.geometry()))
{}
virtual ~TriangulationElement() {
delete _geometry;
}
private:
TriangulationElement(const TriangulationElement& other);
TriangulationElement& operator=(const TriangulationElement& other);
};
template <typename P = double, typename PP = P>
class SerializedElement : public Element<P, PP> {
template <typename P>
class SerializedElement : public Element<P> {
private:
Representation::Serialization* _geometry;
public:
const Representation::Serialization& geometry() const { return *_geometry; }
SerializedElement(const BRepElement<P, PP>& shape_model)
: Element<P, PP>(shape_model)
SerializedElement(const BRepElement<P>& shape_model)
: Element<P>(shape_model)
, _geometry(new Representation::Serialization(shape_model.geometry()))
{}
virtual ~SerializedElement() {
@@ -215,4 +141,4 @@ namespace IfcGeom {
};
}
#endif
#endif
+223 -456
View File
@@ -47,7 +47,6 @@
#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>
@@ -71,11 +70,9 @@
#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>
@@ -86,297 +83,127 @@
#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();
Handle(Geom_Surface) face_surface;
const bool is_face_surface = l->declaration().is(IfcSchema::IfcFaceSurface::Class());
if (is_face_surface) {
IfcSchema::IfcFaceSurface* fs = (IfcSchema::IfcFaceSurface*) l;
fs->FaceSurface();
// FIXME: Surfaces are interpreted as a TopoDS_Shape
TopoDS_Shape surface_shape;
if (!convert_shape(fs->FaceSurface(), surface_shape)) return false;
// FIXME: Assert this obtaines the only face
TopExp_Explorer exp(surface_shape, TopAbs_FACE);
if (!exp.More()) return false;
TopoDS_Face surface = TopoDS::Face(exp.Current());
face_surface = BRep_Tool::Surface(surface);
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();
}
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;
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)) {
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop);
delete mf;
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;
}
/*
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 ++;
} else {
return false;
}
}
if (!success) {
success = processed == num_bounds;
if (success) {
if (num_outer_bounds > 1) {
face = compound;
} else {
success = success && mf->IsDone();
if (success) {
face = mf->Face();
}
if ( 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());
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());
}
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 (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 Newell's normal does not point in the same direction
// as the topological face normal the face orientation is
// reversed
gp_Vec face_normal2(x,y,z);
if (all_reversed) {
face.Reverse();
}
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);
}
}
delete mf;
return success;
}
// 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;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, TopoDS_Shape& face) {
@@ -408,22 +235,15 @@ 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);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
gp_Trsf2d trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
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);
}
@@ -434,19 +254,12 @@ 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);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
gp_Trsf2d trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
IfcGeom::Kernel::convert(l->Position(),trsf2d);
double coords[8] = {-x,-y, x,-y, x,y, -x,y};
int fillets[4] = {0,1,2,3};
double radii[4] = {r,r,r,r};
@@ -458,14 +271,14 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l,
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d = l->WallThickness() * getValue(GV_LENGTH_UNIT);
const bool fr1 = l->hasOuterFilletRadius();
const bool fr2 = l->hasInnerFilletRadius();
const bool fr1 = l->OuterFilletRadius() ? true : false;
const bool fr2 = l->InnerFilletRadius() ? true : false;
const double r1 = fr1 ? l->OuterFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.;
const double r2 = fr2 ? l->InnerFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.;
const double r1 = fr1 ? *l->OuterFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.;
const double r2 = fr2 ? *l->InnerFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.;
if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
@@ -473,14 +286,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l,
TopoDS_Face f2;
gp_Trsf2d trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
IfcGeom::Kernel::convert(l->Position(),trsf2d);
double coords1[8] = {-x ,-y, x ,-y, x, y, -x, y };
double coords2[8] = {-x+d,-y+d, x-d,-y+d, x-d,y-d, -x+d,y-d};
double radii1[4] = {r1,r1,r1,r1};
@@ -514,19 +320,12 @@ 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);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
gp_Trsf2d trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
IfcGeom::Kernel::convert(l->Position(),trsf2d);
double coords[8] = {-x1,-y, x1,-y, dx+w-x1,y, dx-x1,y};
return profile_helper(4,coords,0,0,0,trsf2d,face);
}
@@ -537,40 +336,34 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcIShapeProfileDef* l, TopoDS_Sh
const double d1 = l->WebThickness() / 2.0f * getValue(GV_LENGTH_UNIT);
const double dy1 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
bool doFillet1 = l->hasFilletRadius();
bool doFillet1 = l->FilletRadius() ? true : false;
double f1 = 0.;
if ( doFillet1 ) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
f1 = *l->FilletRadius() * getValue(GV_LENGTH_UNIT);
}
bool doFillet2 = doFillet1;
double x2 = x1, dy2 = dy1, f2 = f1;
if (l->declaration().is(IfcSchema::IfcAsymmetricIShapeProfileDef::Class())) {
if (l->is(IfcSchema::Type::IfcAsymmetricIShapeProfileDef)) {
IfcSchema::IfcAsymmetricIShapeProfileDef* assym = (IfcSchema::IfcAsymmetricIShapeProfileDef*) l;
x2 = assym->TopFlangeWidth() / 2. * getValue(GV_LENGTH_UNIT);
doFillet2 = assym->hasTopFlangeFilletRadius();
doFillet2 = assym->TopFlangeFilletRadius() ? true : false;
if (doFillet2) {
f2 = assym->TopFlangeFilletRadius() * getValue(GV_LENGTH_UNIT);
f2 = *assym->TopFlangeFilletRadius() * getValue(GV_LENGTH_UNIT);
}
if (assym->hasTopFlangeThickness()) {
dy2 = assym->TopFlangeThickness() * getValue(GV_LENGTH_UNIT);
if (assym->TopFlangeThickness()) {
dy2 = *assym->TopFlangeThickness() * getValue(GV_LENGTH_UNIT);
}
}
if ( x1 < ALMOST_ZERO || x2 < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || dy1 < ALMOST_ZERO || dy2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
gp_Trsf2d trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
convert(l->Position(),trsf2d);
double coords[24] = {-x1,-y, x1,-y, x1,-y+dy1, d1,-y+dy1, d1,y-dy2, x2,y-dy2, x2,y, -x2,y, -x2,y-dy2, -d1,y-dy2, -d1,-y+dy1, -x1,-y+dy1};
int fillets[4] = {3,4,9,10};
@@ -584,32 +377,26 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcZShapeProfileDef* l, TopoDS_Sh
const double dx = l->WebThickness() / 2.0f * getValue(GV_LENGTH_UNIT);
const double dy = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
bool doFillet = l->hasFilletRadius();
bool doEdgeFillet = l->hasEdgeRadius();
bool doFillet = l->FilletRadius() ? true : false;
bool doEdgeFillet = l->EdgeRadius() ? true : false;
double f1 = 0.;
double f2 = 0.;
if ( doFillet ) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
f1 = *l->FilletRadius() * getValue(GV_LENGTH_UNIT);
}
if ( doEdgeFillet ) {
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
f2 = *l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
}
if ( x == 0.0f || y == 0.0f || dx == 0.0f || dy == 0.0f ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
gp_Trsf2d trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
IfcGeom::Kernel::convert(l->Position(),trsf2d);
double coords[16] = {-dx,-y, x,-y, x,-y+dy, dx,-y+dy, dx,y, -x,y, -x,y-dy, -dx,y-dy};
int fillets[4] = {2,3,6,7};
@@ -622,27 +409,21 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCShapeProfileDef* l, TopoDS_Sh
const double x = l->Width() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d1 = l->WallThickness() * getValue(GV_LENGTH_UNIT);
const double d2 = l->Girth() * getValue(GV_LENGTH_UNIT);
bool doFillet = l->hasInternalFilletRadius();
bool doFillet = l->InternalFilletRadius() ? true : false;
double f1 = 0;
double f2 = 0;
if ( doFillet ) {
f1 = l->InternalFilletRadius() * getValue(GV_LENGTH_UNIT);
f1 = *l->InternalFilletRadius() * getValue(GV_LENGTH_UNIT);
f2 = f1 + d1;
}
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
gp_Trsf2d trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
IfcGeom::Kernel::convert(l->Position(),trsf2d);
double coords[24] = {-x,-y,x,-y,x,-y+d2,x-d1,-y+d2,x-d1,-y+d1,-x+d1,-y+d1,-x+d1,y-d1,x-d1,y-d1,x-d1,y-d2,x,y-d2,x,y,-x,y};
int fillets[8] = {0,1,4,5,6,7,10,11};
@@ -651,26 +432,26 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCShapeProfileDef* l, TopoDS_Sh
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Shape& face) {
const bool hasSlope = l->hasLegSlope();
const bool doEdgeFillet = l->hasEdgeRadius();
const bool doFillet = l->hasFilletRadius();
const bool hasSlope = l->LegSlope() ? true : false;
const bool doEdgeFillet = l->EdgeRadius() ? true : false;
const bool doFillet = l->FilletRadius() ? true : false;
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double x = (l->hasWidth() ? l->Width() : l->Depth()) / 2.0f * getValue(GV_LENGTH_UNIT);
const double x = (l->Width() ? *l->Width() : l->Depth()) / 2.0f * getValue(GV_LENGTH_UNIT);
const double d = l->Thickness() * getValue(GV_LENGTH_UNIT);
const double slope = hasSlope ? (l->LegSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
const double slope = hasSlope ? (*l->LegSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
double f1 = 0.0f;
double f2 = 0.0f;
if (doFillet) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
f1 = *l->FilletRadius() * getValue(GV_LENGTH_UNIT);
}
if ( doEdgeFillet) {
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
f2 = *l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
}
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
@@ -702,7 +483,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);
Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:",l->entity);
return false;
}
@@ -711,13 +492,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Sh
}
gp_Trsf2d trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
convert(l->Position(),trsf2d);
double coords[12] = {-x,-y, x,-y, x,-y+d-dy1, xx, xy, -x+d-dx1,y, -x,y};
int fillets[3] = {2,3,4};
@@ -726,15 +501,15 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Sh
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcUShapeProfileDef* l, TopoDS_Shape& face) {
const bool doEdgeFillet = l->hasEdgeRadius();
const bool doFillet = l->hasFilletRadius();
const bool hasSlope = l->hasFlangeSlope();
const bool doEdgeFillet = l->EdgeRadius() ? true : false;
const bool doFillet = l->FilletRadius() ? true : false;
const bool hasSlope = l->FlangeSlope() ? true : false;
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double x = l->FlangeWidth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() * getValue(GV_LENGTH_UNIT);
const double d2 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
const double slope = hasSlope ? (l->FlangeSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
const double slope = hasSlope ? (*l->FlangeSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
double dy1 = 0.0f;
double dy2 = 0.0f;
@@ -742,10 +517,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcUShapeProfileDef* l, TopoDS_Sh
double f2 = 0.0f;
if (doFillet) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
f1 = *l->FilletRadius() * getValue(GV_LENGTH_UNIT);
}
if (doEdgeFillet) {
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
f2 = *l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
}
if (hasSlope) {
@@ -754,18 +529,12 @@ 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);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
gp_Trsf2d trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
convert(l->Position(),trsf2d);
double coords[16] = {-x,-y, x,-y, x,-y+d2-dy2, -x+d1,-y+d2+dy1, -x+d1,y-d2-dy1, x,y-d2+dy2, x,y, -x,y};
int fillets[4] = {2,3,4,5};
@@ -774,21 +543,21 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcUShapeProfileDef* l, TopoDS_Sh
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Shape& face) {
const bool doFlangeEdgeFillet = l->hasFlangeEdgeRadius();
const bool doWebEdgeFillet = l->hasWebEdgeRadius();
const bool doFillet = l->hasFilletRadius();
const bool hasFlangeSlope = l->hasFlangeSlope();
const bool hasWebSlope = l->hasWebSlope();
const bool doFlangeEdgeFillet = l->FlangeEdgeRadius() ? true : false;
const bool doWebEdgeFillet = l->WebEdgeRadius() ? true : false;
const bool doFillet = l->FilletRadius() ? true : false;
const bool hasFlangeSlope = l->FlangeSlope() ? true : false;
const bool hasWebSlope = l->WebSlope() ? true : false;
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double x = l->FlangeWidth() / 2.0f * getValue(GV_LENGTH_UNIT);
const double d1 = l->WebThickness() * getValue(GV_LENGTH_UNIT);
const double d2 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
const double flangeSlope = hasFlangeSlope ? (l->FlangeSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
const double webSlope = hasWebSlope ? (l->WebSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
const double flangeSlope = hasFlangeSlope ? (*l->FlangeSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
const double webSlope = hasWebSlope ? (*l->WebSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
@@ -801,13 +570,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
double f3 = 0.0f;
if (doFillet) {
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
f1 = *l->FilletRadius() * getValue(GV_LENGTH_UNIT);
}
if (doWebEdgeFillet) {
f2 = l->WebEdgeRadius() * getValue(GV_LENGTH_UNIT);
f2 = *l->WebEdgeRadius() * getValue(GV_LENGTH_UNIT);
}
if (doFlangeEdgeFillet) {
f3 = l->FlangeEdgeRadius() * getValue(GV_LENGTH_UNIT);
f3 = *l->FlangeEdgeRadius() * getValue(GV_LENGTH_UNIT);
}
double xx, xy;
@@ -836,7 +605,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);
Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:",l->entity);
return false;
}
@@ -848,13 +617,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
}
gp_Trsf2d trsf2d;
bool has_position = true;
#ifdef USE_IFC4
has_position = l->hasPosition();
#endif
if (has_position) {
IfcGeom::Kernel::convert(l->Position(), trsf2d);
}
convert(l->Position(),trsf2d);
double coords[16] = {d1/2.-dx2,-y, xx,xy, x,y-d2+dy2, x,y, -x,y, -x,y-d2+dy2, -xx,xy, -d1/2.+dx2,-y};
int fillets[6] = {0,1,2,5,6,7};
@@ -865,25 +628,17 @@ 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);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
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);
Handle(Geom_Circle) circle = new Geom_Circle(ax, r);
TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(circle);
gp_Trsf2d trsf;
convert(l->Position(),trsf);
BRepBuilderAPI_MakeWire w;
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
Handle(Geom_Circle) circle = new Geom_Circle(ax, r);
TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(circle);
w.Add(edge);
TopoDS_Face f;
@@ -897,20 +652,13 @@ 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);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
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);
gp_Trsf2d trsf;
convert(l->Position(),trsf);
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
BRepBuilderAPI_MakeWire outer;
Handle(Geom_Circle) outerCircle = new Geom_Circle(ax, r);
@@ -933,27 +681,20 @@ 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);
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity);
return false;
}
const bool rotated = ry > rx;
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_Trsf2d trsf;
convert(l->Position(),trsf);
gp_Ax2 ax = gp_Ax2();
if (rotated) {
ax.Rotate(ax.Axis(), M_PI / 2.);
std::swap(rx, ry);
}
ax.Transform(trsf2d);
ax.Transform(trsf);
BRepBuilderAPI_MakeWire w;
Handle(Geom_Ellipse) ellipse = new Geom_Ellipse(ax, rx, ry);
@@ -1023,7 +764,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)) {
@@ -1057,32 +798,20 @@ 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 IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineSurfaceWithKnots* l, TopoDS_Shape& face) {
boost::shared_ptr< IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint> > cps = l->ControlPointsList();
bool convert_surf(IfcSchema::IfcBSplineSurfaceWithKnots* l, Handle_Geom_Surface& surf) {
SHARED_PTR< IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint> > cps = l->ControlPointsList();
std::vector<double> uknots = l->UKnots();
std::vector<double> vknots = l->VKnots();
std::vector<int> umults = l->UMultiplicities();
std::vector<int> vmults = l->VMultiplicities();
TColgp_Array2OfPnt Poles (0, (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);
TColgp_Array2OfPnt Poles (0, cps->size() - 1, 0, (*cps->begin()).size() - 1);
TColStd_Array1OfReal UKnots(0, uknots.size() - 1);
TColStd_Array1OfReal VKnots(0, vknots.size() - 1);
TColStd_Array1OfInteger UMults(0, umults.size() - 1);
TColStd_Array1OfInteger VMults(0, vmults.size() - 1);
Standard_Integer UDegree = l->UDegree();
Standard_Integer VDegree = l->VDegree();
@@ -1112,13 +841,51 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineSurfaceWithKnots* l, To
for (std::vector<int>::const_iterator it = vmults.begin(); it != vmults.end(); ++it, ++i) {
VMults(i) = *it;
}
Handle_Geom_Surface surf = new Geom_BSplineSurface(Poles, UKnots, VKnots, UMults, VMults, UDegree, VDegree);
surf = new Geom_BSplineSurface(Poles, UKnots, VKnots, UMults, VMults, UDegree, VDegree);
return true;
}
#if OCC_VERSION_HEX < 0x60502
face = BRepBuilderAPI_MakeFace(surf);
#else
face = BRepBuilderAPI_MakeFace(surf, getValue(GV_PRECISION));
#endif
bool convert_surf(IfcSchema::IfcPlane* l, Handle_Geom_Surface& surf) {
gp_Pln pln;
convert(l, pln);
surf = new Geom_Plane(pln);
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAdvancedFace* l, TopoDS_Shape& face) {
IfcSchema::IfcSurface* s = l->FaceSurface();
Handle_Geom_Surface surf(0);
if (s->is(IfcSchema::Type::IfcBSplineSurfaceWithKnots)) {
convert_surf((IfcSchema::IfcBSplineSurfaceWithKnots*)s, surf);
} else if (s->is(IfcSchema::Type::IfcPlane)) {
convert_surf((IfcSchema::IfcPlane*)s, surf);
} else {
return false;
}
BRepBuilderAPI_MakeFace mf(surf, Precision::Confusion());
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
IfcSchema::IfcLoop* loop = (*it)->Bound();
TopoDS_Wire outer_wire;
if (!convert_wire(loop, outer_wire)) return false;
TopoDS_Face temp = BRepBuilderAPI_MakeFace(surf, outer_wire);
if (BRepCheck_Face(temp).OrientationOfWires() == BRepCheck_BadOrientationOfSubshape) {
outer_wire.Reverse();
ShapeFix_Face fix(BRepBuilderAPI_MakeFace(surf, outer_wire).Face());
fix.FixOrientation();
fix.Perform();
TopoDS_Face temp = fix.Face();
TopExp_Explorer exp(temp, TopAbs_WIRE);
outer_wire = TopoDS::Wire(exp.Current());
}
mf.Add(outer_wire);
}
face = mf.Face();
return true;
}
-319
View File
@@ -1,319 +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/>. *
* *
********************************************************************************/
/** @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
+41 -135
View File
@@ -77,58 +77,6 @@
#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();
@@ -166,17 +114,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement3D* l, gp_Trsf&
IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf)
gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);gp_Dir refDirection;
IfcGeom::Kernel::convert(l->Location(),o);
bool hasRef = l->hasRefDirection();
if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(),axis);
if ( hasRef ) IfcGeom::Kernel::convert(l->RefDirection(),refDirection);
bool hasRef = l->RefDirection() ? true : false;
if ( l->Axis() ) IfcGeom::Kernel::convert(*l->Axis(),axis);
if ( hasRef ) IfcGeom::Kernel::convert(*l->RefDirection(),refDirection);
gp_Ax3 ax3;
if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection);
else ax3 = gp_Ax3(o,axis);
if (!axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) {
trsf.SetTransformation(ax3, gp::XOY());
}
trsf.SetTransformation(ax3, gp_Ax3(gp_Pnt(),gp_Dir(0,0,1),gp_Dir(1,0,0)));
CACHE(IfcAxis2Placement3D,l,trsf)
return true;
}
@@ -185,7 +129,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis1Placement* l, gp_Ax1& ax)
IN_CACHE(IfcAxis1Placement,l,gp_Ax1,ax)
gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);
IfcGeom::Kernel::convert(l->Location(),o);
if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(), axis);
if ( l->Axis() ) IfcGeom::Kernel::convert(*l->Axis(), axis);
ax = gp_Ax1(o, axis);
CACHE(IfcAxis1Placement,l,ax)
return true;
@@ -198,21 +142,14 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
gp_Dir axis1 (1.,0.,0.);
gp_Dir axis2 (0.,1.,0.);
gp_Dir axis3 (0.,0.,1.);
if ( l->hasAxis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1);
if ( l->hasAxis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2);
if ( l->hasAxis3() ) IfcGeom::Kernel::convert(l->Axis3(),axis3);
if ( l->Axis1() ) IfcGeom::Kernel::convert(*l->Axis1(),axis1);
if ( l->Axis2() ) IfcGeom::Kernel::convert(*l->Axis2(),axis2);
if ( l->Axis3() ) IfcGeom::Kernel::convert(*l->Axis3(),axis3);
gp_Ax3 ax3 (origin,axis3,axis1);
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
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());
}
trsf.SetTransformation(ax3);
trsf.Invert();
if ( l->Scale() ) trsf.SetScaleFactor(*l->Scale());
CACHE(IfcCartesianTransformationOperator3D,l,trsf)
return true;
}
@@ -225,8 +162,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
gp_Dir axis2 (0.,1.,0.);
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
if ( l->hasAxis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1);
if ( l->hasAxis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2);
if ( l->Axis1() ) IfcGeom::Kernel::convert(*l->Axis1(),axis1);
if ( l->Axis2() ) IfcGeom::Kernel::convert(*l->Axis2(),axis2);
const gp_Pnt2d origin2d(origin.X(), origin.Y());
const gp_Dir2d axis12d(axis1.X(), axis1.Y());
@@ -246,12 +183,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
}
trsf.Invert();
if ( l->hasScale() && !ALMOST_THE_SAME(l->Scale(), 1.) ) trsf.SetScaleFactor(l->Scale());
if (is_identity(trsf, getValue(GV_PRECISION))) {
trsf = gp_Trsf2d();
}
if ( l->Scale() ) trsf.SetScaleFactor(*l->Scale());
CACHE(IfcCartesianTransformationOperator2D,l,trsf)
return true;
}
@@ -264,26 +196,21 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
gp_Dir axis1 (1.,0.,0.);
gp_Dir axis2 (0.,1.,0.);
gp_Dir axis3 (0.,0.,1.);
if ( l->hasAxis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1);
if ( l->hasAxis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2);
if ( l->hasAxis3() ) IfcGeom::Kernel::convert(l->Axis3(),axis3);
if ( l->Axis1() ) IfcGeom::Kernel::convert(*l->Axis1(),axis1);
if ( l->Axis2() ) IfcGeom::Kernel::convert(*l->Axis2(),axis2);
if ( l->Axis3() ) IfcGeom::Kernel::convert(*l->Axis3(),axis3);
gp_Ax3 ax3 (origin,axis3,axis1);
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
trsf.SetTransformation(ax3);
trsf.Invert();
const double scale1 = l->hasScale() ? l->Scale() : 1.0f;
const double scale2 = l->hasScale2() ? l->Scale2() : scale1;
const double scale3 = l->hasScale3() ? l->Scale3() : scale1;
const double scale1 = l->Scale() ? *l->Scale() : 1.0f;
const double scale2 = l->Scale2() ? *l->Scale2() : scale1;
const double scale3 = l->Scale3() ? *l->Scale3() : scale1;
gtrsf = gp_GTrsf();
gtrsf.SetValue(1,1,scale1);
gtrsf.SetValue(2,2,scale2);
gtrsf.SetValue(3,3,scale3);
gtrsf.PreMultiply(trsf);
if (is_identity(gtrsf, getValue(GV_PRECISION))) {
gtrsf = gp_GTrsf();
}
CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gtrsf)
return true;
}
@@ -297,8 +224,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
gp_Dir axis2 (0.,1.,0.);
IfcGeom::Kernel::convert(l->LocalOrigin(),origin);
if ( l->hasAxis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1);
if ( l->hasAxis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2);
if ( l->Axis1() ) IfcGeom::Kernel::convert(*l->Axis1(),axis1);
if ( l->Axis2() ) IfcGeom::Kernel::convert(*l->Axis2(),axis2);
const gp_Pnt2d origin2d(origin.X(), origin.Y());
const gp_Dir2d axis12d(axis1.X(), axis1.Y());
@@ -314,17 +241,12 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato
trsf.Invert();
const double scale1 = l->hasScale() ? l->Scale() : 1.0f;
const double scale2 = l->hasScale2() ? l->Scale2() : scale1;
const double scale1 = l->Scale() ? *l->Scale() : 1.0f;
const double scale2 = l->Scale2() ? *l->Scale2() : scale1;
gtrsf = gp_GTrsf2d();
gtrsf.SetValue(1,1,scale1);
gtrsf.SetValue(2,2,scale2);
gtrsf.Multiply(trsf);
if (is_identity(gtrsf, getValue(GV_PRECISION))) {
gtrsf = gp_GTrsf2d();
}
CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gtrsf)
return true;
}
@@ -334,9 +256,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPlane* pln, gp_Pln& plane) {
IfcSchema::IfcAxis2Placement3D* l = pln->Position();
gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);gp_Dir refDirection;
IfcGeom::Kernel::convert(l->Location(),o);
bool hasRef = l->hasRefDirection();
if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(),axis);
if ( hasRef ) IfcGeom::Kernel::convert(l->RefDirection(),refDirection);
bool hasRef = l->RefDirection();
if ( l->Axis() ) IfcGeom::Kernel::convert(*l->Axis(),axis);
if ( hasRef ) IfcGeom::Kernel::convert(*l->RefDirection(),refDirection);
gp_Ax3 ax3;
if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection);
else ax3 = gp_Ax3(o,axis);
@@ -349,52 +271,36 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d
IN_CACHE(IfcAxis2Placement2D,l,gp_Trsf2d,trsf)
gp_Pnt P; gp_Dir V (1,0,0);
IfcGeom::Kernel::convert(l->Location(),P);
if ( l->hasRefDirection() )
IfcGeom::Kernel::convert(l->RefDirection(),V);
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());
}
if ( l->RefDirection() )
IfcGeom::Kernel::convert(*l->RefDirection(),V);
gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()),gp_Dir2d(V.X(),V.Y()));
trsf.SetTransformation(axis,gp_Ax2d());
CACHE(IfcAxis2Placement2D,l,trsf)
return true;
}
void IfcGeom::Kernel::set_conversion_placement_rel_to(const IfcParse::declaration* type) {
placement_rel_to = type;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf) {
IN_CACHE(IfcObjectPlacement,l,gp_Trsf,trsf)
if ( ! l->declaration().is(IfcSchema::IfcLocalPlacement::Class()) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l);
if ( ! l->is(IfcSchema::Type::IfcLocalPlacement) ) {
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity);
return false;
}
IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l;
for (;;) {
while (1) {
gp_Trsf trsf2;
IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement();
if ( relplacement->declaration().is(IfcSchema::IfcAxis2Placement3D::Class()) ) {
if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2);
trsf.PreMultiply(trsf2);
}
if ( current->hasPlacementRelTo() ) {
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;
if ( current->PlacementRelTo() ) {
IfcSchema::IfcObjectPlacement* relto = *current->PlacementRelTo();
if ( relto->is(IfcSchema::Type::IfcLocalPlacement) )
current = (IfcSchema::IfcLocalPlacement*) relto;
else break;
} else break;
}
CACHE(IfcObjectPlacement,l,trsf)
return true;
}
}
+493
View File
@@ -0,0 +1,493 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) *
* and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). *
* *
* IfcGeom::Representation::Triangulation is a class that represents a *
* triangulated IfcShapeRepresentation. *
* Triangulation.verts is a 1 dimensional vector of float defining the *
* cartesian coordinates of the vertices of the triangulated shape in the *
* format of [x1,y1,z1,..,xn,yn,zn] *
* Triangulation.faces is a 1 dimensional vector of int containing the *
* indices of the triangles referencing positions in Triangulation.verts *
* Triangulation.edges is a 1 dimensional vector of int in {0,1} that dictates*
* the visibility of the edges that span the faces in Triangulation.faces *
* *
* IfcGeom::Element represents the actual IfcBuildingElements. *
* IfcGeomObject.name is the GUID of the element *
* IfcGeomObject.type is the datatype of the element e.g. IfcWindow *
* IfcGeomObject.mesh is a pointer to an IfcMesh *
* IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the *
* orientation and translation of the mesh in relation to the world origin *
* *
* IfcGeom::Iterator::findContext() *
* finds the most suitable representation contexts. Returns true iff *
* at least a single representation will process successfully *
* *
* IfcGeom::Iterator::get() *
* returns a pointer to the current IfcGeom::Element *
* *
* IfcGeom::Iterator::next() *
* returns true iff a following entity is available for a successive call to *
* IfcGeom::Iterator::get() *
* *
* IfcGeom::Iterator::progress() *
* returns an int in [0..100] that indicates the overall progress *
* *
********************************************************************************/
#ifndef IFCGEOMITERATOR_H
#define IFCGEOMITERATOR_H
#include <map>
#include <set>
#include <vector>
#include <limits>
#include <algorithm>
#include <gp_Mat.hxx>
#include <gp_Mat2d.hxx>
#include <gp_GTrsf.hxx>
#include <gp_GTrsf2d.hxx>
#include <gp_Trsf.hxx>
#include <gp_Trsf2d.hxx>
#include "../ifcparse/IfcFile.h"
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom/IfcGeomElement.h"
#include "../ifcgeom/IfcGeomMaterial.h"
#include "../ifcgeom/IfcGeomIteratorSettings.h"
#include "../ifcgeom/IfcRepresentationShapeItem.h"
namespace IfcGeom {
template <typename P>
class Iterator {
private:
Kernel kernel;
IteratorSettings settings;
IfcParse::IfcFile* ifc_file;
// A container and iterator for IfcRepresentations
IfcSchema::IfcRepresentation::list::ptr representations;
IfcSchema::IfcRepresentation::list::it representation_iterator;
// The object is fetched beforehand to be sure that get() returns a valid element
TriangulationElement<P>* current_triangulation;
BRepElement<P>* current_shape_model;
SerializedElement<P>* current_serialization;
// A container and iterator for IfcBuildingElements for the current IfcRepresentation referenced by *representation_iterator
IfcSchema::IfcProduct::list::ptr ifcproducts;
IfcSchema::IfcProduct::list::it ifcproduct_iterator;
int done;
int total;
std::string unit_name;
// double?
P unit_magnitude;
void initUnits() {
IfcSchema::IfcProject::list::ptr projects = ifc_file->entitiesByType<IfcSchema::IfcProject>();
if (projects->size() == 1) {
IfcSchema::IfcProject* project = *projects->begin();
std::pair<std::string, double> length_unit = kernel.initializeUnits(project->UnitsInContext());
unit_name = length_unit.first;
unit_magnitude = static_cast<P>(length_unit.second);
}
}
std::set<IfcSchema::Type::Enum> entities_to_include_or_exclude;
bool include_entities_in_processing;
void populate_set(const std::set<std::string>& include_or_ignore) {
entities_to_include_or_exclude.clear();
for (std::set<std::string>::const_iterator it = include_or_ignore.begin(); it != include_or_ignore.end(); ++it) {
std::string uppercase_type = *it;
for (std::string::iterator c = uppercase_type.begin(); c != uppercase_type.end(); ++c) {
*c = toupper(*c);
}
IfcSchema::Type::Enum ty;
try {
ty = IfcSchema::Type::FromString(uppercase_type);
} catch (const IfcParse::IfcException&) {
std::stringstream ss;
ss << "'" << *it << "' does not name a valid IFC entity";
throw IfcParse::IfcException(ss.str());
}
entities_to_include_or_exclude.insert(ty);
// TODO: Add child classes so that containment in set can be in O(log n)
}
}
public:
bool findContext() {
try {
initUnits();
} catch (...) {}
// Really this should only be 'Model', as per
// the standard 'Design' is deprecated. So,
// just for backwards compatibility:
std::set<std::string> context_types;
context_types.insert("model");
context_types.insert("design");
// DDS likes to output 'model view'
context_types.insert("model view");
double lowest_precision_encountered = std::numeric_limits<double>::infinity();
bool any_precision_encountered = false;
representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
IfcSchema::IfcGeometricRepresentationContext::list::it it;
IfcSchema::IfcGeometricRepresentationSubContext::list::it jt;
IfcSchema::IfcGeometricRepresentationContext::list::ptr contexts =
ifc_file->entitiesByType<IfcSchema::IfcGeometricRepresentationContext>();
IfcSchema::IfcGeometricRepresentationContext::list::ptr filtered_contexts (new IfcSchema::IfcGeometricRepresentationContext::list);
for (it = contexts->begin(); it != contexts->end(); ++it) {
IfcSchema::IfcGeometricRepresentationContext* context = *it;
if (context->is(IfcSchema::Type::IfcGeometricRepresentationSubContext)) {
// Continue, as the list of subcontexts will be considered
// by the parent's context inverse attributes.
continue;
}
if (context->ContextType()) {
std::string context_type_lc = *context->ContextType();
for (std::string::iterator c = context_type_lc.begin(); c != context_type_lc.end(); ++c) {
*c = tolower(*c);
}
if (context_types.find(context_type_lc) != context_types.end()) {
filtered_contexts->push(context);
}
}
}
if (filtered_contexts->size() == 0) {
filtered_contexts = contexts;
}
for (it = filtered_contexts->begin(); it != filtered_contexts->end(); ++it) {
IfcSchema::IfcGeometricRepresentationContext* context = *it;
representations->push(context->RepresentationsInContext());
if (context->Precision() && *context->Precision() < lowest_precision_encountered) {
lowest_precision_encountered = *context->Precision();
any_precision_encountered = true;
}
IfcSchema::IfcGeometricRepresentationSubContext::list::ptr sub_contexts = context->HasSubContexts();
for (jt = sub_contexts->begin(); jt != sub_contexts->end(); ++jt) {
representations->push((*jt)->RepresentationsInContext());
}
// There is no need for full recursion as the following is governed by the schema:
// WR31: The parent context shall not be another geometric representation sub context.
}
if (any_precision_encountered) {
// Some arbitrary factor that has proven to work better for the models in the set of test files.
lowest_precision_encountered *= 10.;
lowest_precision_encountered *= unit_magnitude;
if (lowest_precision_encountered < 1.e-7) {
Logger::Message(Logger::LOG_WARNING, "Precision lower than 0.0000001 meter not enforced");
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-7);
} else {
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, lowest_precision_encountered);
}
} else {
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-5);
}
if (representations->size() == 0) return false;
representation_iterator = representations->begin();
ifcproducts.reset();
if (!create()) {
return false;
}
done = 0;
total = representations->size();
return true;
}
int progress() {
return 100 * done / total;
}
const std::string& getUnitName() {
return unit_name;
}
const P getUnitMagnitude() {
return unit_magnitude;
}
const std::string getLog() {
return Logger::GetLog();
}
IfcParse::IfcFile* getFile() {
return ifc_file;
}
void includeEntities(const std::set<std::string>& entities) {
populate_set(entities);
include_entities_in_processing = true;
}
void excludeEntities(const std::set<std::string>& entities) {
populate_set(entities);
include_entities_in_processing = false;
}
private:
// Move to the next IfcRepresentation
void _nextShape() {
ifcproducts.reset();
++ representation_iterator;
++ done;
}
BRepElement<P>* create_shape_model_for_next_entity() {
while ( true ) {
IfcSchema::IfcRepresentation* representation;
// Have we reached the end of our list of representations?
if ( representation_iterator == representations->end() ) {
representations.reset();
return 0;
}
representation = *representation_iterator;
// Has the list of IfcProducts for this representation been initialized?
if (!ifcproducts) {
IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation();
ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list);
IfcSchema::IfcProduct::list::ptr unfiltered_products(new IfcSchema::IfcProduct::list);
for ( IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it ) {
if ( (*it)->is(IfcSchema::Type::IfcProductDefinitionShape) ) {
IfcSchema::IfcProductDefinitionShape* pds = (IfcSchema::IfcProductDefinitionShape*)*it;
unfiltered_products->push(pds->ShapeOfProduct());
} else {
// http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm
// IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards.
// It will be changed into an ABSTRACT supertype in future releases of IFC.
// IfcProductRepresentation also lacks the INVERSE relation to IfcProduct
// Let's find the IfcProducts that reference the IfcProductRepresentation anyway
unfiltered_products->push((*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>());
}
// Filter the products based on the set of entities being included or excluded for
// processing. The set is iterated over te able to filter on subtypes.
for ( IfcSchema::IfcProduct::list::it it = unfiltered_products->begin(); it != unfiltered_products->end(); ++it ) {
bool found = false;
for (std::set<IfcSchema::Type::Enum>::const_iterator jt = entities_to_include_or_exclude.begin(); jt != entities_to_include_or_exclude.end(); ++jt) {
if ((*it)->is(*jt)) {
found = true;
break;
}
}
if (found == include_entities_in_processing) {
ifcproducts->push(*it);
}
}
}
// Does this representation have any IfcProducts?
if (!ifcproducts->size()) {
_nextShape();
continue;
}
ifcproduct_iterator = ifcproducts->begin();
}
// Have we reached the end of our list of IfcProducts?
if ( ifcproduct_iterator == ifcproducts->end() ) {
_nextShape();
continue;
}
IfcSchema::IfcProduct* product = *ifcproduct_iterator;
BRepElement<P>* element = kernel.create_brep_for_representation_and_product<P>(settings, representation, product);
if ( !element ) {
_nextShape();
continue;
}
return element;
}
}
public:
bool next() {
// Free all possible representations of the current geometrical entity
delete current_triangulation;
current_triangulation = 0;
delete current_serialization;
current_serialization = 0;
delete current_shape_model;
current_shape_model = 0;
// Increment the iterator over the list of products using the current
// shape representation
if (ifcproducts) {
++ifcproduct_iterator;
}
return create();
}
Element<P>* get() {
// TODO: Test settings and throw
if (current_triangulation) return current_triangulation;
else if (current_serialization) return current_serialization;
else if (current_shape_model) return current_shape_model;
else return 0;
}
const Element<P>* getObject(int id) {
gp_Trsf trsf;
int parent_id = -1;
std::string instance_type, product_name, product_guid;
try {
const IfcUtil::IfcBaseClass* ifc_entity = ifc_file->entityById(id);
instance_type = IfcSchema::Type::ToString(ifc_entity->type());
if ( ifc_entity->is(IfcSchema::Type::IfcProduct) ) {
IfcSchema::IfcProduct* ifc_product = (IfcSchema::IfcProduct*)ifc_entity;
product_guid = ifc_product->GlobalId();
product_name = ifc_product->hasName() ? ifc_product->Name() : "";
parent_id = -1;
try {
IfcSchema::IfcObjectDefinition* parent_object = kernel.get_decomposing_entity(ifc_product);
if (parent_object) {
parent_id = parent_object->entity->id();
}
} catch (...) {}
try {
kernel.convert(ifc_product->ObjectPlacement(), trsf);
} catch (...) {}
}
} catch(...) {}
ElementSettings element_settings(settings, unit_magnitude, instance_type);
Element<P>* ifc_object = new Element<P>(element_settings, id, parent_id, product_name, instance_type, product_guid, trsf);
return ifc_object;
}
bool create() {
try {
current_shape_model = create_shape_model_for_next_entity();
} catch (...) {}
if (!current_shape_model) return false;
if (settings.use_brep_data()) {
try {
current_serialization = new SerializedElement<P>(*current_shape_model);
} catch (...) {}
return !!current_serialization;
} else if (!settings.disable_triangulation()) {
try {
current_triangulation = new TriangulationElement<P>(*current_shape_model);
} catch (...) {}
return !!current_triangulation;
} else {
return true;
}
}
private:
void initialize() {
current_triangulation = 0;
current_shape_model = 0;
current_serialization = 0;
// Upon initialisation, the (empty) set of entity names,
// should be excluded, or no products would be processed.
include_entities_in_processing = false;
unit_name = "METER";
unit_magnitude = 1.f;
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.sew_shells() ? 1000 : -1);
kernel.setValue(IfcGeom::Kernel::GV_FORCE_CCW_FACE_ORIENTATION, settings.force_ccw_face_orientation() ? 1 : -1);
}
public:
Iterator(const IteratorSettings& settings, IfcParse::IfcFile* file)
: settings(settings)
, ifc_file(file)
{
initialize();
}
Iterator(const IteratorSettings& settings, const std::string& filename)
: settings(settings)
, ifc_file(new IfcParse::IfcFile)
{
ifc_file->Init(filename);
initialize();
}
Iterator(const IteratorSettings& settings, void* data, int length)
: settings(settings)
, ifc_file(new IfcParse::IfcFile)
{
ifc_file->Init(data, length);
initialize();
}
Iterator(const IteratorSettings& settings, std::istream& filestream, int length)
: settings(settings)
, ifc_file(new IfcParse::IfcFile)
{
ifc_file->Init(filestream, length);
initialize();
}
~Iterator() {
// TODO: Correctly implement destructor for IfcFile
delete ifc_file;
delete current_triangulation;
current_triangulation = 0;
delete current_serialization;
current_serialization = 0;
delete current_shape_model;
current_shape_model = 0;
}
};
}
#endif
@@ -1,32 +0,0 @@
#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
@@ -1,758 +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::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
+139 -124
View File
@@ -20,138 +20,153 @@
#ifndef IFCGEOMITERATORSETTINGS_H
#define IFCGEOMITERATORSETTINGS_H
#include "ifc_geom_api.h"
#include <string>
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcBaseClass.h"
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;
namespace IfcGeom {
IteratorSettings()
: settings_(WELD_VERTICES) // OR options that default to true here
, deflection_tolerance_(1.e-3)
{
}
class IteratorSettings {
public:
// Enumeration of setting identifiers. These settings define the
// behaviour of various aspects of IfcOpenShell.
/// Note that this is independent of the IFC length unit, one millimeter by default.
double deflection_tolerance() const { return deflection_tolerance_; }
// 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;
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;
}
}
// End of settings enumeration.
/// 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;
}
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)
{}
/// 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 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)
{}
protected:
SettingField settings_;
double deflection_tolerance_;
};
const double& unit_magnitude() const { return _unit_magnitude; }
const std::string& element_type() const { return _element_type; }
};
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
@@ -30,6 +30,5 @@ 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::original_name() const { return style->original_name(); }
const std::string IfcGeom::Material::name() const { return style->Name(); }
bool IfcGeom::Material::operator==(const IfcGeom::Material& other) const { return style == other.style; }
@@ -22,11 +22,11 @@
#include <string>
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
#include "../ifcgeom/IfcGeomRenderStyles.h"
namespace IfcGeom {
class IFC_GEOM_API Material {
class Material {
private:
const IfcGeom::SurfaceStyle* style;
public:
@@ -41,11 +41,10 @@ namespace IfcGeom {
const double* specular() const;
double transparency() const;
double specularity() const;
const std::string &name() const;
const std::string &original_name() const;
const std::string name() const;
bool operator==(const Material& other) const;
};
}
#endif
#endif
+96 -73
View File
@@ -21,119 +21,142 @@
#include "IfcGeom.h"
namespace {
bool process_colour(IfcSchema::IfcColourRgb* colour, double* rgb) {
if (colour != 0) {
rgb[0] = colour->Red();
rgb[1] = colour->Green();
rgb[2] = colour->Blue();
}
return colour != 0;
bool process_colour(IfcSchema::IfcColourRgb* colour, std::tr1::array<double, 3>& rgb) {
if (colour != 0) {
rgb[0] = colour->Red();
rgb[1] = colour->Green();
rgb[2] = colour->Blue();
}
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;
}
}
return colour != 0;
}
#define Kernel MAKE_TYPE_NAME(Kernel)
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;
}
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::internalize_surface_style(const std::pair<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*>& shading_styles) {
bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, std::tr1::array<double, 3>& rgb) {
if (colour_or_factor == 0) {
return false;
} else if (colour_or_factor->is(IfcSchema::Type::IfcColourRgb)) {
return process_colour(static_cast<IfcSchema::IfcColourRgb*>(colour_or_factor), rgb);
} else if (colour_or_factor->is(IfcSchema::Type::IfcNormalisedRatioMeasure)) {
return process_colour(static_cast<IfcSchema::IfcNormalisedRatioMeasure*>(colour_or_factor), rgb);
} else {
return false;
}
}
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepresentationItem* item) {
std::pair<IfcSchema::IfcSurfaceStyle*, IfcSchema::IfcSurfaceStyleShading*> shading_styles = get_surface_style<IfcSchema::IfcSurfaceStyleShading>(item);
if (shading_styles.second == 0) {
return 0;
}
int surface_style_id = shading_styles.first->data().id();
std::map<int,SurfaceStyle>::const_iterator it = style_cache.find(surface_style_id);
if (it != style_cache.end()) {
int surface_style_id = shading_styles.first->entity->id();
std::map<int,SurfaceStyle>::const_iterator it = cache.Style.find(surface_style_id);
if (it != cache.Style.end()) {
return &(it->second);
}
SurfaceStyle surface_style;
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());
if (shading_styles.first->Name()) {
surface_style = SurfaceStyle(surface_style_id, *shading_styles.first->Name());
} else {
surface_style = SurfaceStyle(surface_style_id);
}
double rgb[3];
if (process_colour(shading->SurfaceColour(), rgb)) {
std::tr1::array<double, 3> rgb;
if (process_colour(shading_styles.second->SurfaceColour(), rgb)) {
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
}
if (shading_styles.second->declaration().is(IfcSchema::IfcSurfaceStyleRendering::Class())) {
if (shading_styles.second->is(IfcSchema::Type::IfcSurfaceStyleRendering)) {
IfcSchema::IfcSurfaceStyleRendering* rendering_style = static_cast<IfcSchema::IfcSurfaceStyleRendering*>(shading_styles.second);
if (rendering_style->hasDiffuseColour() && process_colour(rendering_style->DiffuseColour(), rgb)) {
if (rendering_style->DiffuseColour() && process_colour(*rendering_style->DiffuseColour(), rgb)) {
SurfaceStyle::ColorComponent diffuse = surface_style.Diffuse().get_value_or(SurfaceStyle::ColorComponent(1,1,1));
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(diffuse.R() * rgb[0], diffuse.G() * rgb[1], diffuse.B() * rgb[2]));
}
if (rendering_style->hasDiffuseTransmissionColour()) {
if (rendering_style->DiffuseTransmissionColour()) {
// Not supported
}
if (rendering_style->hasReflectionColour()) {
if (rendering_style->ReflectionColour()) {
// Not supported
}
if (rendering_style->hasSpecularColour() && process_colour(rendering_style->SpecularColour(), rgb)) {
if (rendering_style->SpecularColour() && process_colour(*rendering_style->SpecularColour(), rgb)) {
surface_style.Specular().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
}
if (rendering_style->hasSpecularHighlight()) {
IfcSchema::IfcSpecularHighlightSelect* highlight = rendering_style->SpecularHighlight();
if (highlight->declaration().is(IfcSchema::IfcSpecularRoughness::Class())) {
if (rendering_style->SpecularHighlight()) {
IfcSchema::IfcSpecularHighlightSelect* highlight = *rendering_style->SpecularHighlight();
if (highlight->is(IfcSchema::Type::IfcSpecularRoughness)) {
double roughness = *((IfcSchema::IfcSpecularRoughness*)highlight);
if (roughness >= 1e-9) {
surface_style.Specularity().reset(1.0 / roughness);
}
} else if (highlight->declaration().is(IfcSchema::IfcSpecularExponent::Class())) {
} else if (highlight->is(IfcSchema::Type::IfcSpecularExponent)) {
surface_style.Specularity().reset(*((IfcSchema::IfcSpecularExponent*)highlight));
}
}
if (rendering_style->hasTransmissionColour()) {
if (rendering_style->TransmissionColour()) {
// Not supported
}
if (rendering_style->hasTransparency()) {
const double d = rendering_style->Transparency();
if (rendering_style->Transparency()) {
const double d = *rendering_style->Transparency();
surface_style.Transparency().reset(d);
}
}
return &(style_cache[surface_style_id] = surface_style);
return &(cache.Style[surface_style_id] = surface_style);
}
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepresentationItem* item) {
return internalize_surface_style(get_surface_style<IfcSchema::IfcSurfaceStyleShading>(item));
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::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* 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);
}
return 0;
const IfcGeom::SurfaceStyle& surface_style = it->second;
return &surface_style;
}
@@ -20,20 +20,24 @@
#ifndef IFCGEOMRENDERSTYLES_H
#define IFCGEOMRENDERSTYLES_H
#include "../ifcgeom/ifc_geom_api.h"
#ifdef __GNUC__
#include <tr1/array>
#else
#include <array>
#endif
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/optional.hpp>
#include <sstream>
#ifdef USE_IFC4
#include "../ifcparse/Ifc4.h"
#else
#include "../ifcparse/Ifc2x3.h"
#endif
namespace IfcGeom {
class IFC_GEOM_API SurfaceStyle {
class SurfaceStyle {
public:
class ColorComponent {
private:
double data[3];
std::tr1::array<double, 3> data;
public:
ColorComponent(double r, double g, double b) {
data[0] = r; data[1] = g; data[2] = b;
@@ -46,27 +50,24 @@ namespace IfcGeom {
double& B() { return data[2]; }
};
private:
std::string name;
std::string original_name_;
boost::optional<std::string> name;
boost::optional<int> id;
boost::optional<ColorComponent> diffuse, specular;
boost::optional<double> transparency;
boost::optional<double> specularity;
public:
SurfaceStyle() : name("surface-style") {}
SurfaceStyle() {
this->name = "IfcSurfaceStyleShading";
}
SurfaceStyle(int id) : id(id) {
std::stringstream sstr;
sstr << "surface-style-" << id;
sstr << "IfcSurfaceStyleShading_" << id;
this->name = sstr.str();
}
SurfaceStyle(const std::string& name) : name(name), original_name_(name) {}
SurfaceStyle(int id, const std::string& name) : original_name_(name), id(id)
{
SurfaceStyle(const std::string& name) : name(name) {}
SurfaceStyle(int id, const std::string& name) : id(id) {
std::stringstream sstr;
std::string sanitized = name;
boost::to_lower(sanitized);
boost::replace_all(sanitized, " ", "-");
sstr << "surface-style-" << id << "-" << sanitized;
sstr << id << "_" << name;
this->name = sstr.str();
}
@@ -75,14 +76,16 @@ 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) {
return name == other.name;
if (name && other.name) {
return *name == *other.name;
} else if (id && other.id) {
return *id == *other.id;
} else {
return false;
}
}
/// 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 std::string& Name() const { return *name; }
const boost::optional<ColorComponent>& Diffuse() const { return diffuse; }
const boost::optional<ColorComponent>& Specular() const { return specular; }
@@ -94,7 +97,7 @@ namespace IfcGeom {
boost::optional<double>& Specularity() { return specularity; }
};
IFC_GEOM_API const SurfaceStyle* get_default_style(const std::string& ifc_type);
const SurfaceStyle* get_default_style(const std::string& ifc_type);
}
#endif
#endif
+16 -57
View File
@@ -22,6 +22,7 @@
#include <BRep_Builder.hxx>
#include <TopoDS_Compound.hxx>
#include <BRepBuilderAPI_GTransform.hxx>
#include "../ifcgeom/IfcGeom.h"
@@ -29,72 +30,30 @@
IfcGeom::Representation::Serialization::Serialization(const BRep& brep)
: Representation(brep.settings())
, id_(brep.id())
, _id(brep.getId())
{
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 = begin(); it != end(); ++it) {
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++ it) {
const TopoDS_Shape& s = it->Shape();
gp_GTrsf trsf = it->Placement();
if (settings().get(IteratorSettings::CONVERT_BACK_UNITS)) {
if (settings().convert_back_units()) {
gp_Trsf scale;
scale.SetScaleFactor(1.0 / settings().unit_magnitude());
trsf.PreMultiply(scale);
}
const TopoDS_Shape moved_shape = apply_transformation(s, trsf);
builder.Add(compound, moved_shape);
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);
}
return compound;
std::stringstream sstream;
BRepTools::Write(compound,sstream);
_brep_data = sstream.str();
}
+56 -195
View File
@@ -27,68 +27,54 @@
#include <TColgp_Array1OfPnt.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <TopoDS.hxx>
#include <BRepTools.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <GCPnts_QuasiUniformDeflection.hxx>
#include <Geom_SphericalSurface.hxx>
#include "../ifcgeom/IfcGeomIteratorSettings.h"
#include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h"
#include "../ifcgeom/IfcGeomMaterial.h"
#include "../ifcgeom/IfcRepresentationShapeItem.h"
#include <TopoDS_Compound.hxx>
namespace IfcGeom {
namespace Representation {
class IFC_GEOM_API Representation {
Representation(const Representation&); //N/A
Representation& operator =(const Representation&); //N/A
class Representation {
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 IFC_GEOM_API BRep : public Representation {
class BRep : public Representation {
private:
std::string id_;
const IfcGeom::IfcRepresentationShapeItems shapes_;
unsigned int id;
const IfcGeom::IfcRepresentationShapeItems shapes;
BRep(const BRep& other);
BRep& operator=(const BRep& other);
public:
BRep(const ElementSettings& settings, const std::string& id, const IfcGeom::IfcRepresentationShapeItems& shapes)
BRep(const ElementSettings& settings, unsigned int 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 IfcGeom::IfcRepresentationShapeItems& shapes() const { return shapes_; }
const std::string& id() const { return id_; }
TopoDS_Compound as_compound() const;
IfcGeom::IfcRepresentationShapeItems::const_iterator begin() const { return shapes.begin(); }
IfcGeom::IfcRepresentationShapeItems::const_iterator end() const { return shapes.end(); }
const unsigned int& getId() const { return id; }
};
class IFC_GEOM_API Serialization : public Representation {
class Serialization : public Representation {
private:
std::string id_;
std::string brep_data_;
std::vector<double> surface_styles_;
int _id;
std::string _brep_data;
public:
const std::string& brep_data() const { return brep_data_; }
const std::vector<double>& surface_styles() const { return surface_styles_; }
int id() const { return _id; }
const std::string& brep_data() const { return _brep_data; }
Serialization(const BRep& brep);
virtual ~Serialization() {}
const std::string& id() const { return id_; }
private:
Serialization();
Serialization(const Serialization&);
@@ -105,70 +91,69 @@ namespace IfcGeom {
typedef std::map<VertexKey, int> VertexKeyMap;
typedef std::pair<int, int> Edge;
std::string id_;
int _id;
std::vector<P> _verts;
std::vector<int> _faces;
std::vector<int> _edges;
std::vector<P> _normals;
std::vector<P> uvs_;
std::vector<int> _material_ids;
std::vector<Material> _materials;
VertexKeyMap welds;
public:
const std::string& id() const { return id_; }
int id() const { return _id; }
const std::vector<P>& verts() const { return _verts; }
const std::vector<int>& faces() const { return _faces; }
const std::vector<int>& edges() const { return _edges; }
const std::vector<P>& normals() const { return _normals; }
const std::vector<P>& uvs() const { return uvs_; }
const std::vector<int>& material_ids() const { return _material_ids; }
const std::vector<Material>& materials() const { return _materials; }
Triangulation(const BRep& shape_model)
: Representation(shape_model.settings())
, id_(shape_model.id())
, _id(shape_model.getId())
{
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++ iit ) {
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it = shape_model.begin(); it != shape_model.end(); ++ it ) {
int surface_style_id = -1;
if (iit->hasStyle()) {
Material adapter(&iit->Style());
if (it->hasStyle()) {
Material adapter(&it->Style());
std::vector<Material>::const_iterator jt = std::find(_materials.begin(), _materials.end(), adapter);
if (jt == _materials.end()) {
surface_style_id = (int)_materials.size();
surface_style_id = _materials.size();
_materials.push_back(adapter);
} else {
surface_style_id = (int)(jt - _materials.begin());
surface_style_id = jt - _materials.begin();
}
}
if (settings().get(IteratorSettings::APPLY_DEFAULT_MATERIALS) && surface_style_id == -1) {
if (settings().apply_default_materials() && surface_style_id == -1) {
Material material(IfcGeom::get_default_style(settings().element_type()));
std::vector<Material>::const_iterator mit = std::find(_materials.begin(), _materials.end(), material);
if (mit == _materials.end()) {
surface_style_id = (int)_materials.size();
std::vector<Material>::const_iterator it = std::find(_materials.begin(), _materials.end(), material);
if (it == _materials.end()) {
surface_style_id = _materials.size();
_materials.push_back(material);
} else {
surface_style_id = (int)(mit - _materials.begin());
surface_style_id = it - _materials.begin();
}
}
const TopoDS_Shape& s = iit->Shape();
const gp_GTrsf& trsf = iit->Placement();
const TopoDS_Shape& s = it->Shape();
const gp_GTrsf& trsf = it->Placement();
// Triangulate the shape
try {
BRepMesh_IncrementalMesh(s, settings().deflection_tolerance());
} catch(...) {
Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape");
// TODO: Catch outside
// Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape:",ifc_file->entityById(_id)->entity);
Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape");
continue;
}
TopExp_Explorer exp;
// Iterates over the faces of the shape
int num_faces = 0;
TopExp_Explorer exp;
for ( exp.Init(s,TopAbs_FACE); exp.More(); exp.Next(), ++num_faces ) {
for ( exp.Init(s,TopAbs_FACE); exp.More(); exp.Next() ) {
TopoDS_Face face = TopoDS::Face(exp.Current());
TopLoc_Location loc;
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face,loc);
@@ -189,9 +174,8 @@ namespace IfcGeom {
BRepGProp_Face prop(face);
std::map<int,int> dict;
// Vertex normals are only calculated if vertices are not welded and calculation is not disable explicitly.
const bool calculate_normals = !settings().get(IteratorSettings::WELD_VERTICES) &&
!settings().get(IteratorSettings::NO_NORMALS);
// Vertex normals are only calculated if vertices are not welded
const bool calculate_normals = !settings().weld_vertices();
for( int i = 1; i <= nodes.Length(); ++ i ) {
coords.push_back(nodes(i).Transformed(loc).XYZ());
@@ -204,24 +188,12 @@ 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() > 1.e-9) {
if (normal_direction.Magnitude() > ALMOST_ZERO) {
normal = gp_Dir(normal_direction.XYZ() * rotation_matrix);
} else {
Handle_Geom_Surface surf = BRep_Tool::Surface(face);
// Special case the normal at the poles of a spherical surface
if (surf->DynamicType() == STANDARD_TYPE(Geom_SphericalSurface)) {
if (fabs(fabs(uv.Y()) - M_PI / 2.) < 1.e-9) {
const bool is_top = uv.Y() > 0;
const bool is_forward = face.Orientation() == TopAbs_FORWARD;
const double z = (is_top == is_forward) ? 1. : -1.;
normal = gp_Dir(gp_XYZ(0, 0, z) * rotation_matrix);
}
}
// TODO: Do the same for conical surfaces, but they are rare in IFC.
}
_normals.push_back(static_cast<P>(normal.X()));
_normals.push_back(static_cast<P>(normal.Y()));
_normals.push_back(static_cast<P>(normal.Z()));
_normals.push_back((float)normal.X());
_normals.push_back((float)normal.Y());
_normals.push_back((float)normal.Z());
}
}
@@ -252,137 +224,26 @@ namespace IfcGeom {
_material_ids.push_back(surface_style_id);
addEdge(dict[n1], dict[n2], edgecount, edges_temp);
addEdge(dict[n2], dict[n3], edgecount, edges_temp);
addEdge(dict[n3], dict[n1], edgecount, edges_temp);
addEdge(n1,n2,edgecount,edges_temp);
addEdge(n2,n3,edgecount,edges_temp);
addEdge(n3,n1,edgecount,edges_temp);
}
for ( std::vector<std::pair<int,int> >::const_iterator 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);
}
for ( std::vector<std::pair<int,int> >::const_iterator it = edges_temp.begin(); it != edges_temp.end(); ++it ) {
_edges.push_back(edgecount[*it]==1);
}
}
}
if (!_normals.empty() && settings().get(IfcGeom::IteratorSettings::GENERATE_UVS)) {
uvs_ = box_project_uvs(_verts, _normals);
}
if (num_faces == 0) {
// Edges are only emitted if there are no faces. A mixed representation of faces
// and loose edges is discouraged by the standard. An alternative would be to use
// TopExp_Explorer texp(s, TopAbs_EDGE, TopAbs_FACE) to find edges that do not
// belong to any face.
for (TopExp_Explorer texp(s, TopAbs_EDGE); texp.More(); texp.Next()) {
BRepAdaptor_Curve crv(TopoDS::Edge(texp.Current()));
GCPnts_QuasiUniformDeflection tessellater(crv, settings().deflection_tolerance());
int n = tessellater.NbPoints();
int start = (int)_verts.size() / 3;
for (int i = 1; i <= n; ++i) {
gp_XYZ p = tessellater.Value(i).XYZ();
/*
// In case you want direction arrows on your edges
double u = tessellater.Parameter(i);
gp_XYZ p2, p3;
gp_Pnt tmp;
gp_Vec tmp2;
crv.D1(u, tmp, tmp2);
gp_Dir d1, d2, d3, d4;
d1 = tmp2;
if (texp.Current().Orientation() == TopAbs_REVERSED) {
d1 = -d1;
}
if (fabs(d1.Z()) < 0.5) {
d2 = d1.Crossed(gp::DZ());
} else {
d2 = d1.Crossed(gp::DY());
}
d3 = d1.XYZ() + d2.XYZ();
d4 = d1.XYZ() - d2.XYZ();
p2 = p - d3.XYZ() / 10.;
p3 = p - d4.XYZ() / 10.;
trsf.Transforms(p2);
trsf.Transforms(p3);
_material_ids.push_back(surface_style_id);
_material_ids.push_back(surface_style_id);
_verts.push_back(static_cast<P>(p2.X()));
_verts.push_back(static_cast<P>(p2.Y()));
_verts.push_back(static_cast<P>(p2.Z()));
_verts.push_back(static_cast<P>(p3.X()));
_verts.push_back(static_cast<P>(p3.Y()));
_verts.push_back(static_cast<P>(p3.Z()));
*/
trsf.Transforms(p);
_material_ids.push_back(surface_style_id);
_verts.push_back(static_cast<P>(p.X()));
_verts.push_back(static_cast<P>(p.Y()));
_verts.push_back(static_cast<P>(p.Z()));
if (i > 1) {
_edges.push_back(start + i - 2);
_edges.push_back(start + i - 1);
// _edges.push_back(start + 3 * (i - 2) + 2);
// _edges.push_back(start + 3 * (i - 1) + 2);
}
// _edges.push_back(start + 3 * (i - 1) + 0);
// _edges.push_back(start + 3 * (i - 1) + 2);
// _edges.push_back(start + 3 * (i - 1) + 1);
// _edges.push_back(start + 3 * (i - 1) + 2);
}
}
}
BRepTools::Clean(s);
}
}
virtual ~Triangulation() {}
/// Generates UVs for a single mesh using box projection.
/// @todo Very simple impl. Assumes that input vertices and normals match 1:1.
static std::vector<P> box_project_uvs(const std::vector<P> &vertices, const std::vector<P> &normals)
{
std::vector<P> uvs;
uvs.resize(vertices.size() / 3 * 2);
for (size_t uv_idx = 0, v_idx = 0;
uv_idx < uvs.size() && v_idx < vertices.size() && v_idx < normals.size();
uv_idx += 2, v_idx += 3) {
P n_x = normals[v_idx], n_y = normals[v_idx + 1], n_z = normals[v_idx + 2];
P v_x = vertices[v_idx], v_y = vertices[v_idx + 1], v_z = vertices[v_idx + 2];
if (std::abs(n_x) > std::abs(n_y) && std::abs(n_x) > std::abs(n_z)) {
uvs[uv_idx] = v_z;
uvs[uv_idx + 1] = v_y;
}
if (std::abs(n_y) > std::abs(n_x) && std::abs(n_y) > std::abs(n_z)) {
uvs[uv_idx] = v_x;
uvs[uv_idx + 1] = v_z;
}
if (std::abs(n_z) > std::abs(n_x) && std::abs(n_z) > std::abs(n_y)) {
uvs[uv_idx] = v_x;
uvs[uv_idx + 1] = v_y;
}
}
return uvs;
}
private:
// Welds vertices that belong to different faces
int addVertex(int material_index, const gp_XYZ& p) {
const bool convert = settings().get(IteratorSettings::CONVERT_BACK_UNITS);
const P X = static_cast<P>(convert ? (p.X() / settings().unit_magnitude()) : p.X());
const P Y = static_cast<P>(convert ? (p.Y() / settings().unit_magnitude()) : p.Y());
const P Z = static_cast<P>(convert ? (p.Z() / settings().unit_magnitude()) : p.Z());
const P X = static_cast<P>(settings().convert_back_units() ? (p.X() / settings().unit_magnitude()) : p.X());
const P Y = static_cast<P>(settings().convert_back_units() ? (p.Y() / settings().unit_magnitude()) : p.Y());
const P Z = static_cast<P>(settings().convert_back_units() ? (p.Z() / settings().unit_magnitude()) : p.Z());
int i = (int) _verts.size() / 3;
if (settings().get(IteratorSettings::WELD_VERTICES)) {
if (settings().weld_vertices()) {
const VertexKey key = std::make_pair(material_index, std::make_pair(X, std::make_pair(Y, Z)));
typename VertexKeyMap::const_iterator it = welds.find(key);
if ( it != welds.end() ) return it->second;
@@ -408,4 +269,4 @@ namespace IfcGeom {
}
}
#endif
#endif
-660
View File
@@ -1,660 +0,0 @@
#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
@@ -1,38 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef 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
File diff suppressed because it is too large Load Diff
-280
View File
@@ -1,280 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef 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
+87 -441
View File
@@ -65,8 +65,6 @@
#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>
@@ -83,174 +81,11 @@
#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);
Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l->entity);
// Temporarily pretend we do have unit information
setValue(GV_PLANEANGLE_UNIT,1.0);
@@ -264,33 +99,13 @@ 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 (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");
}
} catch (...) {}
// Now try degrees
setValue(GV_PLANEANGLE_UNIT,0.0174532925199433);
try {
succes_degrees = IfcGeom::Kernel::convert(l,wire_degrees);
} 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");
}
} catch (...) {}
// Restore to unknown unit state
setValue(GV_PLANEANGLE_UNIT,-1.0);
@@ -324,128 +139,113 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
return use_radians || use_degrees;
}
IfcSchema::IfcCompositeCurveSegment::list::ptr segments = l->Segments();
TopTools_ListOfShape converted_segments;
for (IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++it) {
BRepBuilderAPI_MakeWire w;
//TopoDS_Vertex last_vertex;
for( IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++ it ) {
IfcSchema::IfcCurve* curve = (*it)->ParentCurve();
TopoDS_Wire segment;
if (!convert_wire(curve, segment)) {
Logger::Message(Logger::LOG_ERROR, "Failed to convert curve:", curve);
TopoDS_Wire wire2;
if ( !convert_wire(curve,wire2) ) {
Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve->entity);
continue;
}
if (!(*it)->SameSense()) {
segment.Reverse();
}
if ( ! (*it)->SameSense() ) wire2.Reverse();
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(segment, getValue(GV_PRECISION), TopAbs_WIRE);
converted_segments.Append(segment);
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;
}
}
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();
wire = w.Wire();
return true;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& wire) {
IfcSchema::IfcCurve* basis_curve = l->BasisCurve();
bool isConic = basis_curve->declaration().is(IfcSchema::IfcConic::Class());
bool isConic = basis_curve->is(IfcSchema::Type::IfcConic);
double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT);
Handle(Geom_Curve) curve;
if ( !convert_curve(basis_curve,curve) ) return false;
bool trim_cartesian = l->MasterRepresentation() != IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER;
bool trim_cartesian = l->MasterRepresentation() == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN;
IfcEntityList::ptr trims1 = l->Trim1();
IfcEntityList::ptr trims2 = l->Trim2();
bool trimmed1 = false;
bool trimmed2 = false;
unsigned sense_agreement = l->SenseAgreement() ? 0 : 1;
double flts[2];
gp_Pnt pnts[2];
bool has_flts[2] = {false,false};
bool has_pnts[2] = {false,false};
BRepBuilderAPI_MakeWire w;
for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) {
IfcUtil::IfcBaseClass* i = *it;
if ( i->declaration().is(IfcSchema::IfcCartesianPoint::Class()) ) {
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] );
has_pnts[sense_agreement] = true;
} else if ( i->declaration().is(IfcSchema::IfcParameterValue::Class()) ) {
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
const double value = *((IfcSchema::IfcParameterValue*)i);
flts[sense_agreement] = value * parameterFactor;
has_flts[sense_agreement] = true;
}
}
for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) {
IfcUtil::IfcBaseClass* i = *it;
if ( i->declaration().is(IfcSchema::IfcCartesianPoint::Class()) ) {
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] );
has_pnts[1-sense_agreement] = true;
} else if ( i->declaration().is(IfcSchema::IfcParameterValue::Class()) ) {
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
const double value = *((IfcSchema::IfcParameterValue*)i);
flts[1-sense_agreement] = value * parameterFactor;
has_flts[1-sense_agreement] = true;
}
}
trim_cartesian &= has_pnts[0] && has_pnts[1];
bool trim_cartesian_failed = !trim_cartesian;
if ( trim_cartesian ) {
if ( pnts[0].Distance(pnts[1]) < 2 * getValue(GV_PRECISION) ) {
Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l);
if ( pnts[0].Distance(pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE) ) {
Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l->entity);
return false;
}
ShapeFix_ShapeTolerance FTol;
TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(pnts[0]);
TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(pnts[1]);
FTol.SetTolerance(v1, getValue(GV_PRECISION), TopAbs_VERTEX);
FTol.SetTolerance(v2, getValue(GV_PRECISION), TopAbs_VERTEX);
FTol.SetTolerance(v1, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
FTol.SetTolerance(v2, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
BRepBuilderAPI_MakeEdge e (curve,v1,v2);
if ( ! e.IsDone() ) {
BRepBuilderAPI_EdgeError err = e.Error();
if ( err == BRepBuilderAPI_PointProjectionFailed ) {
Logger::Message(Logger::LOG_WARNING,"Point projection failed for:",l);
Logger::Message(Logger::LOG_WARNING,"Point projection failed for:",l->entity);
trim_cartesian_failed = true;
}
} else {
w.Add(e.Edge());
}
}
if ( (!trim_cartesian || trim_cartesian_failed) && (has_flts[0] && has_flts[1]) ) {
// The Geom_Line is constructed from a gp_Pnt and gp_Dir, whereas the IfcLine
// is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because
// the vector is normalised when passed to Geom_Line constructor the magnitude
// needs to be factored in with the IfcParameterValue here.
if ( basis_curve->declaration().is(IfcSchema::IfcLine::Class()) ) {
if ( basis_curve->is(IfcSchema::Type::IfcLine) ) {
IfcSchema::IfcLine* line = static_cast<IfcSchema::IfcLine*>(basis_curve);
const double magnitude = line->Dir()->Magnitude();
flts[0] *= magnitude; flts[1] *= magnitude;
}
if ( basis_curve->declaration().is(IfcSchema::IfcEllipse::Class()) ) {
if ( basis_curve->is(IfcSchema::Type::IfcEllipse) ) {
IfcSchema::IfcEllipse* ellipse = static_cast<IfcSchema::IfcEllipse*>(basis_curve);
double x = ellipse->SemiAxis1() * getValue(GV_LENGTH_UNIT);
double y = ellipse->SemiAxis2() * getValue(GV_LENGTH_UNIT);
@@ -455,7 +255,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],M_PI*2.),0.) ) {
if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],(double)(M_PI*2.0)),0.0f) ) {
w.Add(BRepBuilderAPI_MakeEdge(curve));
} else {
BRepBuilderAPI_MakeEdge e (curve,flts[0],flts[1]);
@@ -464,18 +264,8 @@ 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;
@@ -493,25 +283,14 @@ 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_duplicate_points_from_loop(polygon, closed_by_proximity, eps);
remove_redundant_points_from_loop(polygon, false);
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;
}
@@ -530,22 +309,21 @@ 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);
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
return false;
}
// Remove points that are too close to one another
const double eps = getValue(GV_PRECISION) * 10;
remove_duplicate_points_from_loop(polygon, true, eps);
remove_redundant_points_from_loop(polygon, true);
int count = polygon.Length();
if (original_count - count != 0) {
std::stringstream ss; ss << (original_count - count) << " edges removed for:";
Logger::Message(Logger::LOG_WARNING, ss.str(), l);
Logger::Message(Logger::LOG_WARNING, ss.str(), l->entity);
}
if (count < 3) {
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l);
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
return false;
}
@@ -555,14 +333,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& resu
}
w.Close();
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);
}
result = w.Wire();
return true;
}
@@ -573,8 +344,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->declaration().is(IfcSchema::IfcCartesianPoint::Class()) || !pnt2->declaration().is(IfcSchema::IfcCartesianPoint::Class())) {
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l);
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;
}
@@ -593,53 +364,36 @@ 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()->declaration().is(IfcSchema::IfcBoundedCurve::Class());
const bool is_bounded = l->EdgeGeometry()->is(IfcSchema::Type::IfcBoundedCurve);
if (!is_bounded && convert_curve(l->EdgeGeometry(), crv)) {
mw.Add(BRepBuilderAPI_MakeEdge(crv, p1, p2));
result = mw;
return true;
} else if (is_bounded && convert_wire(l->EdgeGeometry(), result)) {
if (!l->SameSense()) {
result.Reverse();
}
bool first = true;
if (!l->SameSense()) std::swap(pnt1, pnt2);
TopExp_Explorer exp(result, TopAbs_EDGE);
bool first = true;
while (exp.More()) {
const TopoDS_Edge& ed = TopoDS::Edge(exp.Current());
Standard_Real u1, u2;
Handle(Geom_Curve) ecrv = BRep_Tool::Curve(ed, u1, u2);
exp.Next();
const bool last = !exp.More();
gp_Pnt a, b;
first = false;
if (first && last) {
a = p1;
b = p2;
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, p1, p2));
} else if (first) {
a = p1;
ecrv->D0(u2, b);
gp_Pnt pu;
ecrv->D0(u2, pu);
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, p1, pu));
} else if (last) {
ecrv->D0(u1, a);
b = p2;
gp_Pnt pu;
ecrv->D0(u1, pu);
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, pu, 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;
@@ -652,140 +406,32 @@ 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(*it, w)) {
mw.Add(TopoDS::Edge(TopoDS_Iterator(w).Value()));
if (convert_wire(e->EdgeElement(), w)) {
if (!e->Orientation()) w.Reverse();
mw.Add(w);
}
}
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
+12 -62
View File
@@ -18,84 +18,34 @@
********************************************************************************/
#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);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
return false;
}
IfcGeom::ShapeType IfcGeom::Kernel::shape_type(const IfcBaseClass* l) {
#include "IfcRegisterShapeType.h"
return ST_OTHER;
bool IfcGeom::Kernel::is_shape_collection(const IfcBaseClass* l) {
#include "IfcRegisterIsShapeCollection.h"
return false;
}
bool IfcGeom::Kernel::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) {
const unsigned int id = l->data().id();
const unsigned int id = l->entity->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"
} 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 ) {
if ( processed ) {
const double precision = getValue(GV_PRECISION);
apply_tolerance(r, precision);
#ifndef NO_CACHE
cache.Shape[id] = r;
#endif
} else if (!ignored) {
const char* const msg = processed
? "Failed to convert:"
: "No operation defined for:";
Logger::Message(Logger::LOG_ERROR, msg, l);
} else {
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
}
return success;
}
@@ -106,18 +56,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);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
return false;
}
bool IfcGeom::Kernel::convert_face(const IfcBaseClass* l, TopoDS_Shape& r) {
#include "IfcRegisterConvertFace.h"
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
return false;
}
bool IfcGeom::Kernel::convert_curve(const IfcBaseClass* l, Handle(Geom_Curve)& r) {
#include "IfcRegisterConvertCurve.h"
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
return false;
}
+6 -25
View File
@@ -38,36 +38,26 @@
#include <gp_Trsf.hxx>
#include <gp_Trsf2d.hxx>
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/IfcUtil.h"
#include "../ifcparse/IfcParse.h"
SHAPES(IfcShellBasedSurfaceModel);
SHAPES(IfcFaceBasedSurfaceModel);
SHAPES(IfcRepresentation);
SHAPES(IfcShapeRepresentation);
SHAPES(IfcMappedItem);
// IfcFacetedBrep included
// IfcAdvancedBrep included
// IfcFacetedBrepWithVoids included
// IfcAdvancedBrepWithVoids included
SHAPES(IfcManifoldSolidBrep);
SHAPES(IfcFacetedBrep);
SHAPES(IfcGeometricSet);
#ifdef USE_IFC4
SHAPE(IfcCylindricalSurface);
SHAPE(IfcAdvancedBrep);
// FIXME: Surfaces should have a shape type of their own
SHAPE(IfcBSplineSurfaceWithKnots);
SHAPE(IfcTriangulatedFaceSet);
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);
@@ -81,6 +71,9 @@ SHAPE(IfcRectangularTrimmedSurface);
SHAPE(IfcSurfaceCurveSweptAreaSolid);
SHAPE(IfcSweptDiskSolid);
#ifdef USE_IFC4
FACE(IfcAdvancedFace);
#endif
FACE(IfcArbitraryProfileDefWithVoids);
FACE(IfcArbitraryClosedProfileDef);
FACE(IfcRoundedRectangleProfileDef);
@@ -100,31 +93,19 @@ 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->declaration().is(IfcSchema::T::Class()) ) return convert((IfcSchema::T*)l,r);
if ( l->is(T::Class()) ) return convert((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->declaration().is(IfcSchema::T::Class()) ) return convert((IfcSchema::T*)l,r);
if ( l->is(T::Class()) ) return convert((T*)l,r);
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
+5 -14
View File
@@ -1,23 +1,14 @@
#include "IfcRegisterUndef.h"
#define SHAPE(T) \
if ( !processed && l->declaration().is(IfcSchema::T::Class()) ) { \
if ( !processed && l->is(T::Class()) ) { \
processed = true; \
try { \
if ( convert((IfcSchema::T*)l,r) ) { \
if ( convert((T*)l,r) ) { \
success = true; \
} \
} catch (const std::exception& e) { \
Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \
return false; \
} 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); \
} catch(...) { } \
if ( !success) { \
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
return false; \
} \
}
+4 -10
View File
@@ -1,16 +1,10 @@
#include "IfcRegisterUndef.h"
#define SHAPES(T) \
if ( l->declaration().is(IfcSchema::T::Class()) ) { \
if ( l->is(T::Class()) ) { \
try { \
return convert((IfcSchema::T*)l,r); \
} catch (const std::exception& e) { \
Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \
} 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 convert((T*)l,r); \
} catch (...) { } \
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
return false; \
}
#include "IfcRegisterDef.h"
+1 -1
View File
@@ -1,6 +1,6 @@
#include "IfcRegisterUndef.h"
#define WIRE(T) \
if ( l->declaration().is(IfcSchema::T::Class()) ) return convert((IfcSchema::T*)l,r);
if ( l->is(T::Class()) ) return convert((T*)l,r);
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
@@ -0,0 +1,6 @@
#include "IfcRegisterUndef.h"
#define SHAPES(T) \
if ( l->is(T::Class()) ) return true;
#include "IfcRegisterDef.h"
#include "IfcRegister.h"
-14
View File
@@ -1,14 +0,0 @@
#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"
+2 -3
View File
@@ -23,10 +23,10 @@
#include <gp_GTrsf.hxx>
#include <TopoDS_Shape.hxx>
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
#include "../ifcgeom/IfcGeomRenderStyles.h"
namespace IfcGeom {
class IFC_GEOM_API IfcRepresentationShapeItem {
class IfcRepresentationShapeItem {
private:
gp_GTrsf placement;
TopoDS_Shape shape;
@@ -46,7 +46,6 @@ 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
@@ -1,37 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef 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
@@ -1,115 +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::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
@@ -1,47 +0,0 @@
#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>;
@@ -1,75 +0,0 @@
#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
@@ -1,49 +0,0 @@
#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
@@ -1,138 +0,0 @@
#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
@@ -1,30 +0,0 @@
#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);
}
@@ -1,11 +0,0 @@
#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);
}
@@ -1,57 +0,0 @@
#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;
}
+49 -275
View File
@@ -27,43 +27,23 @@
#include <iostream>
#include <boost/cstdint.hpp>
// 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)
#if defined(_WIN32) && !defined(__CYGWIN__)
#define SET_BINARY_STREAMS
#endif
#ifdef SET_BINARY_STREAMS
#include <io.h>
#include <fcntl.h>
#endif
#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>
#include "../ifcgeom/IfcGeomIterator.h"
using namespace boost;
template <typename T>
union data_field {
char buffer[sizeof(T)];
T value;
};
template <typename T>
T sread(std::istream& s) {
data_field<T> data;
s.read(data.buffer, sizeof(T));
return data.value;
char buf[sizeof(T)];
s.read(buf, sizeof(T));
return *((T*)buf);
}
template <>
@@ -74,21 +54,10 @@ 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>
@@ -100,7 +69,7 @@ void swrite(std::ostream& s, T t) {
template <>
void swrite(std::ostream& s, std::string t) {
int32_t len = (int32_t)t.size();
int32_t len = t.size();
swrite(s, len);
s.write(t.c_str(), len);
while (len++ % 4) s.put(0);
@@ -140,8 +109,6 @@ 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:
@@ -155,7 +122,7 @@ protected:
}
public:
const std::string& string() { return str; }
Hello() : Command(HELLO), str("IfcOpenShell-" IFCOPENSHELL_VERSION "-0") {}
Hello() : Command(HELLO), str("IfcOpenShell-" IFCOPENSHELL_VERSION) {}
};
class More : public Command {
@@ -189,16 +156,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) {};
};
@@ -217,74 +184,38 @@ 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, double>* geom;
bool append_line_data;
EntityExtension* eext_;
const IfcGeom::TriangulationElement<float>* geom;
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<double>& m = geom->transformation().matrix().data();
const double matrix_array[16] = {
const std::vector<float>& m = geom->transformation().matrix().data();
const float matrix_array[16] = {
m[0], m[3], m[6], m[ 9],
m[1], m[4], m[7], m[10],
m[2], m[5], m[8], m[11],
0, 0, 0, 1
};
swrite(s, std::string((char*)matrix_array, 16 * sizeof(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*)matrix_array, 16 * sizeof(float)));
swrite<int32_t>(s, geom->geometry().id());
swrite(s, std::string((char*)geom->geometry().verts().data(), geom->geometry().verts().size() * sizeof(float)));
swrite(s, std::string((char*)geom->geometry().normals().data(), geom->geometry().normals().size() * sizeof(float)));
{
std::vector<int32_t> indices;
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<int32_t> indices;
for (std::vector<int>::const_iterator it = geom->geometry().faces().begin(); it != geom->geometry().faces().end(); ++it) {
indices.push_back(*it);
}
swrite(s, std::string((char*) indices.data(), indices.size() * sizeof(int32_t))); }
{ std::vector<float> diffuse_color_array;
for (std::vector<IfcGeom::Material>::const_iterator it = geom->geometry().materials().begin(); it != geom->geometry().materials().end(); ++it) {
const IfcGeom::Material& mat = *it;
if (mat.hasDiffuse()) {
const double* color = mat.diffuse();
const IfcGeom::Material& m = *it;
if (m.hasDiffuse()) {
const double* color = m.diffuse();
diffuse_color_array.push_back(static_cast<float>(color[0]));
diffuse_color_array.push_back(static_cast<float>(color[1]));
diffuse_color_array.push_back(static_cast<float>(color[2]));
@@ -293,8 +224,8 @@ protected:
diffuse_color_array.push_back(0.f);
diffuse_color_array.push_back(0.f);
}
if (mat.hasTransparency()) {
diffuse_color_array.push_back(static_cast<float>(1. - mat.transparency()));
if (m.hasTransparency()) {
diffuse_color_array.push_back(static_cast<float>(1. - m.transparency()));
} else {
diffuse_color_array.push_back(1.f);
}
@@ -305,155 +236,32 @@ 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, double>* geom, EntityExtension* eext = 0) : Command(ENTITY), geom(geom), append_line_data(false), eext_(eext) {};
Entity(const IfcGeom::TriangulationElement<float>* geom) : Command(ENTITY), geom(geom) {};
};
class Next : public Command {
protected:
void read_content(std::istream& /*s*/) {}
void write_content(std::ostream& /*s*/) {}
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) {};
};
class Deflection : public Command {
private:
double deflection_;
protected:
void read_content(std::istream& s) {
deflection_ = sread<double>(s);
int main (int argc, char** argv) {
if (sizeof(float) != 4 || sizeof(int32_t) != 4) {
return 1;
}
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;
@@ -468,17 +276,14 @@ int main () {
std::cin.setf(std::ios_base::binary);
#endif
double deflection = 1.e-3;
bool has_more = false;
IfcGeom::Iterator<float, double>* iterator = 0;
IfcParse::IfcFile* file = 0;
std::vector< std::pair<uint32_t, uint32_t> > setting_pairs;
IfcGeom::Iterator<float>* iterator = 0;
Hello().write(std::cout);
int exit_code = 0;
for (;;) {
while (1) {
const int32_t msg_type = sread<int32_t>(std::cin);
switch (msg_type) {
case IFC_MODEL: {
@@ -488,21 +293,13 @@ int main () {
memcpy(data, m.string().c_str(), len);
IfcGeom::IteratorSettings settings;
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);
settings.use_world_coords() = false;
settings.weld_vertices() = false;
settings.convert_back_units() = true;
settings.force_ccw_face_orientation() = true;
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();
iterator = new IfcGeom::Iterator<float>(settings, data, len);
has_more = iterator->findContext();
More(has_more).write(std::cout);
continue;
@@ -513,18 +310,15 @@ int main () {
exit_code = 1;
break;
}
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);
const IfcGeom::TriangulationElement<float>* geom = static_cast<const IfcGeom::TriangulationElement<float>*>(iterator->get());
Entity(geom).write(std::cout);
continue;
}
case NEXT: {
Next n; n.read(std::cin);
has_more = iterator->next() != 0;
has_more = iterator->next();
if (!has_more) {
delete file;
delete iterator;
file = 0;
iterator = 0;
}
More(has_more).write(std::cout);
@@ -532,7 +326,7 @@ int main () {
}
case GET_LOG: {
GetLog gl; gl.read(std::cin);
WriteLog(Logger::GetLog()).write(std::cout);
WriteLog(iterator->getLog()).write(std::cout);
continue;
}
case BYE: {
@@ -540,27 +334,7 @@ int main () {
exit_code = 0;
break;
}
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:
default:
exit_code = 1;
break;
}
-4
View File
@@ -1,4 +0,0 @@
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
@@ -1,40 +0,0 @@
################################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
################################################################################
INCLUDE_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})
+50 -89
View File
@@ -17,57 +17,49 @@
* *
********************************************************************************/
#include <map>
#include <set>
#include <Max.h>
#include <stdmat.h>
#include <istdplug.h>
#include "IfcMax.h"
#include "../ifcmax/IfcMax.h"
#include "../ifcgeom/IfcGeomIterator.h"
static const int NUM_MATERIAL_SLOTS = 24;
BOOL WINAPI DllMain(HINSTANCE /*hinstDLL*/, ULONG /*fdwReason*/, LPVOID /*lpvReserved*/) {
static int controlsInit = false;
int controlsInit = false;
BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) {
if (!controlsInit) {
controlsInit = true;
InitCommonControls();
}
return TRUE;
}
return true;
}
static class IFCImpClassDesc :public ClassDesc {
__declspec( dllexport ) const TCHAR* LibDescription() {
return _T("IfcOpenShell IFC Importer");
}
__declspec( dllexport ) int LibNumberClasses() { return 1; }
static class IFCImpClassDesc:public ClassDesc {
public:
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"); }
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");}
} IFCImpDesc;
#define DLLEXPORT __declspec(dllexport)
extern "C" {
DLLEXPORT const TCHAR* LibDescription() {
return _T("IfcOpenShell IFC Importer");
__declspec( dllexport ) ClassDesc* LibClassDesc(int i) {
return i == 0 ? &IFCImpDesc : 0;
}
DLLEXPORT int LibNumberClasses() { return 1; }
DLLEXPORT ClassDesc* LibClassDesc(int i) {
return i == 0 ? &IFCImpDesc : 0;
__declspec( dllexport ) ULONG LibVersion() {
return VERSION_3DSMAX;
}
DLLEXPORT ULONG LibVersion() {
return VERSION_3DSMAX;
}
} // extern "C"
int IFCImp::ExtCount() { return 1; }
const TCHAR * IFCImp::Ext(int n) {
@@ -87,7 +79,7 @@ const TCHAR * IFCImp::AuthorName() {
}
const TCHAR * IFCImp::CopyrightMessage() {
return _T("Copyright (c) 2011-2016 IfcOpenShell");
return _T("Copyight (c) 2011 IfcOpenShell");
}
const TCHAR * IFCImp::OtherMessage1() {
@@ -102,14 +94,13 @@ unsigned int IFCImp::Version() {
return 12;
}
// TODO Use this in IFCImp::ShowAbout() if/when wanted
//static BOOL CALLBACK AboutBoxDlgProc(HWND /*hWnd*/, UINT /*msg*/, WPARAM /*wParam*/, LPARAM /*lParam*/) {
// return TRUE;
//}
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()))
@@ -119,9 +110,8 @@ DWORD WINAPI fn(LPVOID /*arg*/) { return 0; }
# define S(x) (CStr(x.c_str()))
#endif
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* FindMaterialByName(MtlBaseLib* library, const std::string& material_name) {
const int mat_index = library->FindMtlByName(S(material_name));
Mtl* m = 0;
if (mat_index != -1) {
m = static_cast<Mtl*>((*library)[mat_index]);
@@ -129,7 +119,7 @@ static Mtl* FindMaterialByName(MtlBaseLib* library, const std::string& material_
return m;
}
static Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& slot, const IfcGeom::Material& material) {
Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& slot, const IfcGeom::Material& material) {
Mtl* m = FindMaterialByName(library, material.name());
if (m == 0) {
StdMat2* stdm = NewDefaultStdMat();
@@ -143,10 +133,10 @@ static Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface,
stdm->SetSpecular(Color(specular[0], specular[1], specular[2]),t);
}
if (material.hasSpecularity()) {
stdm->SetShininess((float)material.specularity(), t);
stdm->SetShininess(material.specularity(), t);
}
if (material.hasTransparency()) {
stdm->SetOpacity(1.0f - (float)material.transparency(), t);
stdm->SetOpacity(1.0 - material.transparency(), t);
}
m = stdm;
m->SetName(S(material.name()));
@@ -158,10 +148,7 @@ static Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface,
return m;
}
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)
{
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) {
@@ -194,7 +181,7 @@ static Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi
return i->second;
}
MultiMtl* multi_mat = NewDefaultMultiMtl();
multi_mat->SetNumSubMtls((int)material_names.size());
multi_mat->SetNumSubMtls(material_names.size());
int mtl_id = 0;
if (needs_default) {
multi_mat->SetSubMtlAndName(mtl_id ++, default_material, default_material->GetName());
@@ -211,12 +198,12 @@ static Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi
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.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false);
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, true);
settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, true);
settings.use_world_coords() = false;
settings.weld_vertices() = true;
settings.sew_shells() = true;
#ifdef _UNICODE
int fn_buffer_size = WideCharToMultiByte(CP_UTF8, 0, name, -1, 0, 0, 0, 0);
@@ -227,8 +214,8 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
#endif
IfcGeom::Iterator<float> iterator(settings, fn_mb);
delete fn_mb;
if (!iterator.initialize()) return false;
if (!iterator.findContext()) return false;
itfc->ProgressStart(_T("Importing file..."), TRUE, fn, NULL);
@@ -247,47 +234,21 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
TriObject* tri = CreateNewTriObject();
const int numVerts = (int)o->geometry().verts().size()/3;
const int numVerts = o->geometry().verts().size()/3;
tri->mesh.setNumVerts(numVerts);
for( int i = 0; i < numVerts; i ++ ) {
tri->mesh.setVert(i,o->geometry().verts()[3*i+0],o->geometry().verts()[3*i+1],o->geometry().verts()[3*i+2]);
}
const int numFaces = (int)o->geometry().faces().size()/3;
const int numFaces = o->geometry().faces().size()/3;
tri->mesh.setNumFaces(numFaces);
bool needs_default = std::find(o->geometry().material_ids().begin(), o->geometry().material_ids().end(), -1) != o->geometry().material_ids().end();
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 ++ ) {
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].setVerts(o->geometry().faces()[3*i+0],o->geometry().faces()[3*i+1],o->geometry().faces()[3*i+2]);
tri->mesh.faces[i].setEdgeVisFlags(o->geometry().edges()[3*i+0],o->geometry().edges()[3*i+1],o->geometry().edges()[3*i+2]);
MtlID mtlid = o->geometry().material_ids()[i];
if (needs_default) mtlid ++;
tri->mesh.faces[i].setMatID(mtlid);
}
@@ -320,4 +281,4 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
itfc->ProgressEnd();
return true;
}
}
+8
View File
@@ -0,0 +1,8 @@
LIBRARY ifcmax.dli
EXPORTS
LibDescription @1
LibNumberClasses @2
LibClassDesc @3
LibVersion @4
SECTIONS
.data READ WRITE
+7 -1
View File
@@ -21,6 +21,12 @@
#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();
@@ -32,7 +38,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(); // = "Copyright (c) 2011-2016 IfcOpenShell"
const TCHAR * CopyrightMessage(); // = "Copyight (c) 2011 IfcOpenShell"
const TCHAR * OtherMessage1(); // = ""
const TCHAR * OtherMessage2(); // = ""
unsigned int Version(); // = 12
+105 -50
View File
@@ -17,62 +17,117 @@
# #
###############################################################################
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import sys
import platform
import functools
import itertools
if hasattr(os, 'uname'):
platform_system = os.uname()[0].lower()
else:
platform_system = 'windows'
if sys.maxsize == (1 << 31) - 1:
platform_architecture = '32bit'
else:
platform_architecture = '64bit'
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)))
try:
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
traceback.print_exc()
print('-' * 64)
raise ImportError("IfcOpenShell not built for '%s'" % python_distribution)
from functools import reduce
from . import guid
from .file import file
from .entity_instance import entity_instance
python_distribution = os.path.join(platform.system().lower(),
platform.architecture()[0],
'python%s.%s' % platform.python_version_tuple()[:2])
sys.path.append(os.path.abspath(os.path.join(
os.path.dirname(__file__),
'lib', python_distribution)))
try:
from . import ifcopenshell_wrapper
except:
raise ImportError("IfcOpenShell not built for '%s'" % python_distribution)
class entity_instance(object):
def __init__(self, e):
super(entity_instance, self).__setattr__('wrapped_data', e)
def __getattr__(self, name):
try: return entity_instance.wrap_value(self.wrapped_data.get_argument(self.wrapped_data.get_argument_index(name)))
except:
try: return entity_instance.wrap_value(self.wrapped_data.get_inverse(name))
except: raise AttributeError("entity instance of type '%s' has no attribute '%s'"%(self.wrapped_data.is_a(), name))
@staticmethod
def map_value(v):
if isinstance(v, entity_instance): return v.wrapped_data
elif isinstance(v, (tuple, list)) and len(v):
classes = list(map(type, v))
if float in classes: return ifcopenshell_wrapper.double_vector(v)
elif int in classes: return ifcopenshell_wrapper.int_vector(v)
elif str in classes: return ifcopenshell_wrapper.string_vector(v)
elif entity_instance in classes: return list(map(lambda e: e.wrapped_data, v))
return v
@staticmethod
def wrap_value(v):
wrap = lambda e: entity_instance(e)
if isinstance(v, ifcopenshell_wrapper.entity_instance): return wrap(v)
elif isinstance(v, (tuple, list)) and len(v):
classes = list(map(type, v))
if ifcopenshell_wrapper.entity_instance in classes: return list(map(wrap, v))
return v
def attribute_type(self, attr):
attr_idx = attr if isinstance(attr, int) else self.wrapped_data.get_argument_index(attr)
return self.wrapped_data.get_argument_type(attr_idx)
def attribute_name(self, attr_idx):
return self.wrapped_data.get_argument_name(attr_idx)
def __setattr__(self, key, value):
self[self.wrapped_data.get_argument_index(key)] = value
def __getitem__(self, key):
return entity_instance.wrap_value(self.wrapped_data.get_argument(key))
def __setitem__(self, idx, value):
self.wrapped_data.set_argument(idx, entity_instance.map_value(value))
def __len__(self): return len(self.wrapped_data)
def __repr__(self): return repr(self.wrapped_data)
def is_a(self, *args): return self.wrapped_data.is_a(*args)
def id(self): return self.wrapped_data.id()
def __dir__(self):
return sorted(set(itertools.chain(
dir(type(self)),
self.wrapped_data.get_attribute_names(),
self.wrapped_data.get_inverse_attribute_names()
)))
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
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())
from .main import *
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

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