Compare commits

..

65 Commits

Author SHA1 Message Date
Thomas Krijnen 16f2b0a0d2 Renumber instances, add comments, update federate for group structure 2018-02-13 14:50:39 +01:00
Thomas Krijnen 6dd22fda82 Consistent IFC4 schema 2018-02-06 14:45:22 +01:00
Thomas Krijnen 1e772a7ea9 Inverse attributes 2018-02-06 13:31:00 +01:00
Thomas Krijnen 7e14d4389e Fixes for reading proper select types 2018-02-05 15:19:38 +01:00
Thomas Krijnen 852e3e28ee Create objects group, separate some string definitions 2018-02-02 16:44:35 +01:00
Thomas Krijnen e962872549 Only *ambiguous* selects with type path, numeric code in padded profile 2018-02-02 14:12:14 +01:00
Thomas Krijnen f16b2e59ae Fix set_unset_bitmap_value 2018-01-26 11:53:04 +01:00
Thomas Krijnen 844428fefd Fix IfcBinary default instantiation as part of select 2018-01-23 11:59:24 +01:00
Thomas Krijnen a53ffd2662 Fix padded serialization of aggregate of IfcInteger 2018-01-18 18:05:32 +01:00
Thomas Krijnen fd02665e5e Add missing ifc4 schema 2018-01-18 14:15:42 +01:00
Thomas Krijnen fa3fdcd273 Fix for IfcPropertyEnumeratedValue padded profile 2018-01-18 13:56:38 +01:00
Thomas Krijnen e6499ef3b1 gcc compatibility 2018-01-17 17:00:27 +01:00
Thomas Krijnen cf1de365e7 Fix federation example 2018-01-12 17:05:39 +01:00
Thomas Krijnen 3bdf429c30 Correct bounding boxes on LOD case 2018-01-12 12:39:39 +01:00
Thomas Krijnen 1bef19a87a Update types for LOD segmentation 2018-01-08 12:17:28 +01:00
Thomas Krijnen e07189e6b1 Work on LOD use case 2017-12-08 13:26:23 +01:00
Thomas Krijnen f851a7188f Fix set_unset mask on padded profile 2017-12-07 19:26:51 +01:00
Thomas Krijnen d8d82eb6ec Work on LOD example 2017-12-06 17:51:18 +01:00
Thomas Krijnen 89e97e5d7c Separate properties 2017-12-04 18:14:52 +01:00
Thomas Krijnen 388c717317 Work on LOD use case 2017-12-04 17:20:04 +01:00
Thomas Krijnen 20eb913b65 Work on LOD use case 2017-12-04 17:19:31 +01:00
Thomas Krijnen 6ca5c90517 Work around for H5cpp memory leak 2017-12-04 16:49:03 +01:00
Thomas Krijnen 5e2d5129bb Work on LOD use case 2017-12-01 15:38:28 +01:00
Thomas Krijnen 226a02adfc Work on LOD use case 2017-11-25 09:47:42 +01:00
Thomas Krijnen 03a82fe301 Start working on LOD example 2017-11-24 15:20:21 +01:00
Thomas Krijnen b40a21743b Separate h file 2017-11-24 15:19:58 +01:00
Thomas Krijnen 2562d6c208 Rename federation use case example 2017-11-24 13:20:46 +01:00
Thomas Krijnen cab7716bdf No mounting in federation example 2017-11-24 13:15:24 +01:00
Thomas Krijnen 83af36dc60 common prefix and postfix 2017-11-24 13:14:46 +01:00
Thomas Krijnen 34fd334fcb Check dereference error 2017-11-24 12:15:30 +01:00
Thomas Krijnen 839dd9aed6 Specify mount points from command line 2017-11-24 12:15:08 +01:00
Thomas Krijnen 0f0d060177 Option to renumber instances 2017-11-21 15:45:42 +01:00
Thomas Krijnen 6dc9ff6fa3 Mount: Create new owner history 2017-11-21 13:24:20 +01:00
Thomas Krijnen c2da3b9e82 Write populations to distinct groups 2017-11-20 14:48:40 +01:00
Thomas Krijnen 621859453a Configurable instance locator 2017-11-20 14:38:54 +01:00
Thomas Krijnen 01ab21a69a Incrementing id when enumerating arbitrary instances 2017-11-18 10:40:10 +01:00
Thomas Krijnen 9c81735cbd Begin working on some hdf5 use cases 2017-11-17 14:58:13 +01:00
Thomas Krijnen 659f05bda3 attempts to make hdf5 generation process more configurable 2017-11-17 14:57:33 +01:00
Thomas Krijnen 59020a22ee set_default() on spf header 2017-11-17 14:57:03 +01:00
Thomas Krijnen 693444d4d2 Fix traversal 2017-11-13 14:58:02 +01:00
Thomas Krijnen 93a33a8507 Quotes in comment 2017-11-12 08:30:02 +01:00
Thomas Krijnen e1b1940d83 Conversion back from hdf to spf, referenced profile 2017-11-11 09:43:45 +01:00
Thomas Krijnen 9a2e5d698a Conversion back from hdf to spf, padded profile 2017-11-09 13:49:49 +01:00
Thomas Krijnen 71dcc96ac2 Hacky support for LOGICAL 2017-10-13 14:51:09 +02:00
Thomas Krijnen 2422da4048 Run codegen 2017-10-13 13:12:43 +02:00
Thomas Krijnen f6403c81e1 Ignore line comment in express parser 2017-10-13 13:11:08 +02:00
Thomas Krijnen de78c6c5dc Map LOGICAL to separate type 2017-10-13 13:09:08 +02:00
Thomas Krijnen f24c996bc1 Backport some codegen fixes wrt unicode 2017-10-13 13:08:50 +02:00
Thomas Krijnen 3dbb52a4f3 Read and write header fields in HDF; clean-up 2017-10-13 12:19:50 +02:00
Thomas Krijnen d9c4920d37 Conversion back from hdf to spf, standard profile only ftm 2017-10-11 16:15:27 +02:00
Thomas Krijnen dcf331a78d Correct instance lookup 2017-10-09 15:43:51 +02:00
Thomas Krijnen 09679050c2 Fix iso_10303_26_data_set_names 2017-10-09 14:57:14 +02:00
Thomas Krijnen d13a7b613b Work on padded and referenced profiles 2017-10-09 13:58:29 +02:00
Thomas Krijnen 61fba3f406 Work on padded profile 2017-09-24 13:48:16 +02:00
Thomas Krijnen b8001ea05d Refactor 2017-09-20 17:08:11 +02:00
Thomas Krijnen 4163f817a6 Update win build script and cmake for HDF5 library 2017-08-18 15:29:05 +02:00
aothms 2a0471ec27 Add support for storing aggregate values in separate datasets 2016-02-24 11:26:47 +01:00
aothms 418b78cdd5 Fix wrapper code 2016-02-24 11:26:15 +01:00
aothms c1c738390f Add support for aggregate of bool 2016-02-24 11:25:45 +01:00
aothms 766d45e0cb Add missing include 2016-02-19 14:25:56 +01:00
aothms df88474bc5 Merge remote-tracking branch 'origin/master' into hdf5
Conflicts:
	src/ifcexpressparser/bootstrap.py
	src/ifcexpressparser/templates.py
	src/ifcgeom/IfcGeomFaces.cpp
	src/ifcgeom/IfcGeomFunctions.cpp
	src/ifcgeom/IfcGeomIterator.h
	src/ifcgeom/IfcGeomWires.cpp
	src/ifcparse/Ifc2x3.h
	src/ifcparse/Ifc4.h
	src/ifcparse/IfcLateBoundEntity.cpp
	src/ifcparse/IfcParse.cpp
	src/ifcparse/IfcUtil.h
2016-02-19 14:19:57 +01:00
aothms 6716423a68 Sort instances on name rather than on std::map occurrence. Add chunk-size command line argument. 2016-01-08 06:35:53 +01:00
aothms 83c4b6a642 More serialization options for HDF5 2015-11-30 22:34:48 +01:00
aothms ac8cf298fa Commit override types for efficiency 2015-11-16 10:37:02 +01:00
aothms 579d3713fd hdf5 2015-11-10 11:16:00 +01:00
773 changed files with 221173 additions and 521244 deletions
-8
View File
@@ -1,8 +0,0 @@
c14f5eeca042232025797990396232e4feab53e7
d6881e833da0b6278313870d37d42ca6ece8686a
892be5444c5bd01a601c99243ac8d3e7b2f0e779
d169a964dd7e9ab5c98b35a82bcbc76dc6229a7a
4a6ec11f6f84a3d1fed2ee9b2f85d783ac3daa9d
2c9d6a47f4d24a923069775206bf734feeb14830
8f1743ed64a2a52c201a1ef5e312b4d3a7a922cf
ad7f030344c405e10cfa7d5cf06d82c121eeb825
-3
View File
@@ -1,3 +0,0 @@
# These are supported funding model platforms
github: [aothms]
+3 -18
View File
@@ -4,22 +4,7 @@
/install*/
/win/BuildDepsCache*.txt
# IfcExpressParser residue
/src/ifcexpressparser/__pycache__
/src/ifcexpressparser/express_parser.py
# General Python residue
__pycache__
*.py.bak
# Visual Studio Code files
.vscode
# PyCharm files
.idea
# Docs
/docs/output
/docs/rst_files
/docs/doxygen
/src/ifcblenderexport/docs/_build
# gettext binary translation files
*.mo
# Vim
*.swp
# Python test residue
/test/__pycache__
-7
View File
@@ -1,7 +0,0 @@
[submodule "test/input"]
path = test/input
url = https://github.com/IfcOpenShell/files
ignore = dirty
[submodule "src/ifcopenshell-python/ifcopenshell/mvd"]
path = src/ifcopenshell-python/ifcopenshell/mvd
url = https://github.com/opensourceBIM/python-mvdxml/
-66
View File
@@ -1,66 +0,0 @@
language: cpp
compiler: gcc
os: linux
dist: bionic
sudo: required
before_install:
- "sudo add-apt-repository -y ppa:freecad-community/ppa"
- sudo apt-get update -qq
install:
- |
sudo apt-get install -y \
libocct-data-exchange-dev libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev \
libboost-system-dev libboost-program-options-dev libboost-regex-dev libboost-thread-dev libboost-date-time-dev libboost-iostreams-dev libboost-filesystem-dev \
build-essential cmake python2.7 libpython2.7-dev swig zlib1g liblzma5 opencollada-dev wget apt-transport-https
- sudo mkdir -p /usr/include/json/nlohmann/
- sudo wget https://github.com/nlohmann/json/releases/download/v3.6.1/json.hpp -O /usr/include/json/nlohmann/json.hpp
# - sudo sh -c 'curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -'
# - sudo sh -c 'curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list'
# - sudo apt-get update -qq && sudo apt-get install -y dart
# - export PATH=$PATH:/usr/lib/dart/bin:$HOME/.pub-cache/bin
# - git clone https://github.com/KhronosGroup/glTF-Validator && pushd glTF-Validator && pub get && pub global activate --source path ./ && popd
script:
- pwd
- cd cmake
- mkdir build
- cd build
- |
cmake \
-DOCC_INCLUDE_DIR=/usr/include/opencascade \
-DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
-DPYTHON_LIBRARY=/usr/lib/python2.7/config-x86_64-linux-gnu/libpython2.7.so \
-DPYTHON_INCLUDE_DIR=/usr/include/python2.7 \
-DPYTHON_EXECUTABLE=/usr/bin/python2.7 \
-DLIBXML2_INCLUDE_DIR=/usr/include/libxml2 \
-DLIBXML2_LIBRARIES="/usr/lib/x86_64-linux-gnu/libxml2.so;/lib/x86_64-linux-gnu/libz.so.1;/lib/x86_64-linux-gnu/liblzma.so.5;/usr/lib/x86_64-linux-gnu/libicuuc.so.60;/usr/lib/x86_64-linux-gnu/libicudata.so.60" \
-DGLTF_SUPPORT=On \
-DJSON_INCLUDE_DIR=/usr/include/json \
..
- sudo make -j2 install
- cd ../../test
- /usr/bin/python2.7 tests.py
- cd input
- /usr/local/bin/IfcConvert -yv acad2010_walls.ifc acad2010_walls.glb
# - gltf_validator acad2010_walls.glb
- /usr/bin/python2.7 -c "from __future__ import print_function; from io import open; import ifcopenshell; f = ifcopenshell.open('encoding.ifc'); assert list(map(ord, f[1][0])) == [39, 97, 39, 32, 49, 109, 179, 32, 8804, 32, 53, 109, 179, 32, 8805, 32, 49, 48, 109, 179]"
- |
(for i in *.ifc; do \
echo $i | tee -a log; \
timeout 1m /usr/local/bin/IfcConvert -yv "$i" "$i.dae" --validate >> log 2>&1; \
echo $i $? >> statuses; \
done) || true
- echo Failed
- grep -v 0$ statuses
- grep -v 0$ statuses | wc -l
- echo Succeeded
- grep 0$ statuses
- grep 0$ statuses | wc -l
+54 -112
View File
@@ -1,53 +1,46 @@
IfcOpenShell
============
IfcOpenShell is an open source ([LGPL]) software library for working with the Industry Foundation Classes ([IFC])
file format. Currently supported IFC releases are [IFC2x3 TC1] and [IFC4 Add2 TC1].
Open source (LGPL) software library for working with the IFC ([IFC2x3 TC1] and [IFC4]) file format.
For more information, see
* [http://ifcopenshell.org](http://ifcopenshell.org)
* [http://academy.ifcopenshell.org](http://academy.ifcopenshell.org)
[http://ifcopenshell.org](http://ifcopenshell.org)
[http://academy.ifcopenshell.org](http://academy.ifcopenshell.org)
[![Build Status](https://travis-ci.org/IfcOpenShell/IfcOpenShell.svg?branch=v0.6.0)](https://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)
=============
* Git, CMake (2.6 or newer), Visual Studio 2008 or newer with C++ toolset (Windows), or GCC (*nix, Clang untested).
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")
* Open Cascade - *optional*, but required for building IfcGeom
([official](http://www.opencascade.org/getocc/download/loadocc/) or [community edition](https://github.com/tpaviot/oce))
For converting IFC representation items into BRep solids and tesselated meshes
* [ICU](http://site.icu-project.org/) - *optional*
For handling code pages and Unicode in the parser
* [OpenCOLLADA](https://github.com/khronosGroup/OpenCOLLADA/) - *optional*
For IfcConvert to be able to write tessellated Collada (.dae) files
* [SWIG](http://www.swig.org/) and [Python](https://www.python.org/) - *optional*
* [SWIG](http://www.swig.org/), [Python](https://www.python.org/) libraries - *optional*
For building the IfcOpenShell Python interface and the Blender add-on
* [3ds Max SDK](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.
* 3ds Max SDK - *optional*
For building the 3ds Max plug-in
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
====================
Users are advised to build IfcOpenShell using the CMake file provided in
the cmake/ folder.
### 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**):
in win/ folder. **See [win/readme.md] for more information**. Instructions in a nutshell
(**assuming Visual Studio 2015 x64 environment variables set**):
> git clone https://github.com/IfcOpenShell/IfcOpenShell.git
> cd IfcOpenShell\win
> build-deps.cmd
> run-cmake.bat
NB: `build-deps.cmd` need to be ran from the directory containing it, i.e. the `./win` folder.
You can now open and build the solution file in Visual Studio:
> ..\build-vs2015-x64\IfcOpenShell.sln
@@ -56,98 +49,53 @@ As the scripts default to using the `RelWithDebInfo` configuration, and a freshl
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):
Alternatively, one can use the utility batch files to build and install the project easily from the command-line:
> install-ifcopenshell.bat
> build-ifcopenshell.cmd
> install-ifcopenshell.cmd
#### Using MSYS2 + MinGW
Alternatively, the old Visual Studio solution and project files requiring manual work can
be found from the win/sln folder.
Start the MSYS2 Shell and then:
$ cd IfcOpenShell/win
$ ./build-deps.sh
$ ./run-cmake.sh
$ ./install-ifcopenshell.sh
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.
#### Using Bash on Ubuntu on Windows
For building the IfcPython wrapper, SWIG and Python development are
required.
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.
Additionally, on Ubuntu (and possibly other linux flavors) the following steps
install some of the prerequisites:
### Compiling on *nix
The following instructions are for Ubuntu, modify as required for other operating systems. [nix/build-all.py] script
can be experimented with and studied for pointers for other operating systems, but note that this script is not currently
meant to be used for a typical IfcOpenShell workspace setup.
Note: where `make -j` is written, add a number roughly equal to the amount of CPU cores + 1.
**1)** Install most of the prerequisites and dependencies:
$ sudo apt-get install git cmake gcc g++ libboost-all-dev
**2a)** Either use an OCE package from your operating system's software repository
$ sudo apt-get install liboce-foundation-dev liboce-modeling-dev liboce-ocaf-dev liboce-visualization-dev liboce-ocaf-lite-dev
**2b)** or (if not available, or the latest code is wanted) compile OCE yourself (note that the build takes a long time):
$ sudo apt-get install libftgl-dev libtbb2 libtbb-dev libgl1-mesa-dev libfreetype6-dev
$ sudo apt-get install git swig cmake gcc g++ libftgl-dev libtbb2 libtbb-dev libboost-all-dev libgl1-mesa-dev libfreetype6-dev
$ git clone https://github.com/tpaviot/oce.git
$ cd oce
$ mkdir build && cd build
$ cmake ..
$ make -j
$ sudo make install
$ make
$ sudo make install
**2c)** or obtain and compile OCCT from http://www.opencascade.org/getocc/download/loadocc/
To build IfcOpenShell please take the following steps:
**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
$ cd /path/to/IfcOpenShell/cmake
$ mkdir build
$ cd build
Optionally:
$ OCC_INCLUDE_PATH="/path/to/OpenCASCADE/include"
$ OCC_LIBRARY_PATH="/path/to/OpenCASCADE/lib"
$ export OCC_INCLUDE_PATH
$ export OCC_LIBRARY_PATH
$ cmake ../
$ make
If all worked out correctly you can now use IfcOpenShell. See the examples below.
**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**
@@ -158,7 +106,7 @@ Usage examples
**Using the IfcOpenShell Python interface**
$ wget -O duplex.zip https://portal.nibs.org/files/wl/?id=4DsTgHFQAcOXzFetxbpRCECPbbfUqpgo
$ wget -O duplex.zip http://projects.buildingsmartalliance.org/files/?artifact_id=4278
$ unzip duplex.zip
$ python
>>> import ifcopenshell
@@ -217,12 +165,6 @@ Usage examples
>>> # Writing IFC-SPF files to disk:
>>> f.write("out.ifc")
[LGPL]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/COPYING "LGPL"
[IFC]: https://technical.buildingsmart.org/standards/ifc/ "IFC"
[IFC2x3 TC1]: https://standards.buildingsmart.org/IFC/RELEASE/IFC2x3/TC1/HTML/ "IFC2x3 TC1"
[IFC4 Add2 TC1]: https://standards.buildingsmart.org/IFC/RELEASE/IFC4/ADD2_TC1/HTML/ "IFC4 Add2 TC1"
[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"
[IFC2x3 TC1]: http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc2x3-tc1-release "IFC2x3 TC1"
[IFC4]: http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc4-release "IFC4"
+198 -453
View File
@@ -17,86 +17,22 @@
# #
################################################################################
cmake_minimum_required(VERSION 3.1.3)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON) # not necessary, but encouraged
cmake_minimum_required (VERSION 2.8.5)
project (IfcOpenShell)
foreach(max_year RANGE 2014 2030)
set(max_sdk "$ENV{ADSK_3DSMAX_SDK_${max_year}}")
if (NOT "${max_sdk}" STREQUAL "")
MESSAGE(STATUS "Autodesk 3ds Max SDK found at ${max_sdk}")
set(HAS_MAX TRUE)
endif()
endforeach()
OPTION(UNICODE_SUPPORT "Build IfcOpenShell with Unicode support (requires ICU)." ON)
OPTION(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON)
OPTION(IFCXML_SUPPORT "Build IfcParse with ifcXML support (requires libxml2)." ON)
OPTION(HDF5_SUPPORT "Enable HDF5 support (requires HDF5, zlib)" ON)
OPTION(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF)
OPTION(IFCCONVERT_DOUBLE_PRECISION "IfcConvert: Use double precision floating-point numbers." ON)
OPTION(BUILD_IFCGEOM "Build IfcGeom." ON)
OPTION(BUILD_DOCUMENTATION "Build IfcOpenShell Documentation." OFF)
#TODO OPTION(IFCCONVERT_DOUBLE_PRECISION "IfcConvert: Use double precision floating-point numbers." OFF)
OPTION(USE_IFC4 "Use IFC 4 instead of IFC 2x3 (full rebuild recommended when switching this)" OFF)
OPTION(BUILD_IFCPYTHON "Build IfcPython." ON)
OPTION(BUILD_EXAMPLES "Build example applications." ON)
OPTION(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_SHARED_LIBS "Build IfcParse and IfcGeom as shared libs (SO/DLL)." OFF)
if (${HAS_MAX})
OPTION(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." ON)
endif()
if (${BUILD_CONVERT})
OPTION(GLTF_SUPPORT "Build IfcConvert with glTF support (requires json.hpp)." OFF)
endif()
OPTION(USERSPACE_PYTHON_PREFIX "Installs IfcPython for the current user only instead of system-wide." 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)
if((BUILD_CONVERT OR BUILD_GEOMSERVER OR BUILD_IFCPYTHON) AND (NOT BUILD_IFCGEOM))
message(STATUS "'IfcGeom' is required with current outputs")
set(BUILD_IFCGEOM ON)
endif()
# Specify where to install files
IF(NOT BINDIR)
set(BINDIR bin)
ENDIF()
IF(NOT IS_ABSOLUTE ${BINDIR})
set(BINDIR ${CMAKE_INSTALL_PREFIX}/${BINDIR})
ENDIF()
MESSAGE(STATUS "BINDIR: ${BINDIR}")
IF(NOT INCLUDEDIR)
set(INCLUDEDIR include)
ENDIF()
IF(NOT IS_ABSOLUTE ${INCLUDEDIR})
set(INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/${INCLUDEDIR})
ENDIF()
MESSAGE(STATUS "INCLUDEDIR: ${INCLUDEDIR}")
IF(NOT LIBDIR)
set(LIBDIR lib)
ENDIF()
IF(NOT IS_ABSOLUTE ${LIBDIR})
set(LIBDIR ${CMAKE_INSTALL_PREFIX}/${LIBDIR})
ENDIF()
MESSAGE(STATUS "LIBDIR: ${LIBDIR}")
set(IFCOPENSHELL_LIBARY_DIR "") # for *nix rpaths
if (BUILD_SHARED_LIBS)
add_definitions(-DIFC_SHARED_BUILD)
if (MSVC)
message(WARNING "Building DLLs against the static VC run-time. This is not recommended if the DLLs are to be redistributed.")
# C4521: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
# There will be couple hundreds of these so suppress them away, https://msdn.microsoft.com/en-us/library/esew7y1w.aspx
add_definitions(-wd4251)
endif()
set(IFCOPENSHELL_LIBARY_DIR "${LIBDIR}")
endif()
# Create cache entries if absent for environment variables
MACRO(UNIFY_ENVVARS_AND_CACHE VAR)
@@ -107,286 +43,209 @@ 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(LIBXML2_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(LIBXML2_LIBRARIES)
UNIFY_ENVVARS_AND_CACHE(HDF5_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(HDF5_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(PCRE_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE)
if (GLTF_SUPPORT AND BUILD_CONVERT)
UNIFY_ENVVARS_AND_CACHE(JSON_INCLUDE_DIR)
FIND_FILE(json_hpp "json.hpp" ${JSON_INCLUDE_DIR}/nlohmann)
IF(json_hpp)
MESSAGE(STATUS "JSON for Modern C++ header file found")
ELSE()
MESSAGE(FATAL_ERROR "Unable to find JSON for Modern C++ header file, aborting")
ENDIF()
add_definitions(-DWITH_GLTF)
endif()
# Set INSTALL_RPATH for target
MACRO(SET_INSTALL_RPATHS _target _paths)
SET(${_target}_rpaths "")
FOREACH(_path ${_paths})
LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${_path}" isSystemDir)
IF("${isSystemDir}" STREQUAL "-1")
LIST(APPEND ${_target}_rpaths ${_path})
ENDIF()
ENDFOREACH()
MESSAGE(STATUS "Set INSTALL_RPATH for ${_target}: ${${_target}_rpaths}")
SET_TARGET_PROPERTIES(${_target} PROPERTIES INSTALL_RPATH "${${_target}_rpaths}")
ENDMACRO()
# Find Boost: On win32 the (hardcoded) default is to use static libraries and
# runtime, when doing running conda-build we pick what conda prepared for us.
IF(WIN32 AND ("$ENV{CONDA_BUILD}" STREQUAL ""))
# Find Boost
IF(MSVC)
SET(Boost_USE_STATIC_LIBS ON)
SET(Boost_USE_STATIC_RUNTIME ON)
SET(Boost_USE_MULTITHREADED ON)
# Disable Boost's autolinking as the libraries to be linked to are supplied
# already by CMake, and wrong libraries would be asked for when code is
# compiled with a toolset different from default.
if(MSVC)
ADD_DEFINITIONS(-DBOOST_ALL_NO_LIB)
# Necessary for boost version >= 1.67
SET(BCRYPT_LIBRARIES "bcrypt.lib")
ENDIF()
ELSE()
# Disable Boost's autolinking as the libraries to be linked to are supplied
# already by CMake, and it's going to conflict if there are multiple, as is
# the case in conda-forge's libboost feedstock.
ADD_DEFINITIONS(-DBOOST_ALL_NO_LIB)
IF(WIN32)
# Necessary for boost version >= 1.67
SET(BCRYPT_LIBRARIES "bcrypt.lib")
ENDIF()
ENDIF()
set(BOOST_COMPONENTS system program_options regex thread date_time)
if(USE_MMAP)
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()
if (IFCXML_SUPPORT)
add_definitions(-DWITH_IFCXML)
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)
# SET(SOME_LIRARIES foo bar)
# ADD_DEBUG_VARIANTS(SOME_LIRARIES "${SOME_LIRARIES}" "d")
# "foo bar" -> "optimized foo debug food optimized bar debug bard"
# or
# set(SOME_LIRARIES path/foo.lib)
# add_debug_variants(SOME_LIRARIES "${SOME_LIRARIES}" "d")
# "path/foo.lib" -> "optimized path/foo.lib debug path/food.lib"
# TODO Could be refined: take the library file extension as a parameter and
# make sure the lib variable ends with not just contains it.
function(add_debug_variants NAME LIBRARIES POSTFIX)
set(LIBRARIES_STR "${LIBRARIES}")
set(LIBRARIES "")
# the result, "optimized <lib> debug <lib>", needs to be a list instead of a string
foreach(lib ${LIBRARIES_STR})
list(APPEND LIBRARIES optimized)
if ("${lib}" MATCHES ".lib")
string(REPLACE ".lib" "" lib ${lib})
list(APPEND LIBRARIES ${lib}.lib)
else()
list(APPEND LIBRARIES ${lib})
endif()
list(APPEND LIBRARIES debug)
if ("${lib}" MATCHES ".lib")
string(REPLACE ".lib" "" lib ${lib})
list(APPEND LIBRARIES ${lib}${POSTFIX}.lib)
else()
list(APPEND LIBRARIES ${lib}${POSTFIX})
endif()
endforeach()
set(${NAME} ${LIBRARIES} PARENT_SCOPE)
endfunction()
if(BUILD_IFCGEOM)
IF(MSVC)
add_debug_variants(LIBXML2_LIBRARIES "${LIBXML2_LIBRARIES}" d)
ENDIF()
FUNCTION(ADD_DEBUG_VARIANTS NAME LIBRARIES POSTFIX)
SET(LIBRARIES_STR "${LIBRARIES}")
SET(LIBRARIES "")
FOREACH(lib ${LIBRARIES_STR})
SET(LIBRARIES "${LIBRARIES} optimized ${lib}")
SET(LIBRARIES "${LIBRARIES} debug ${lib}${POSTFIX}")
ENDFOREACH()
STRING(STRIP ${LIBRARIES} LIBRARIES) # leading and trailing whitespace cause confusion
SEPARATE_ARGUMENTS(LIBRARIES) # "optimized <lib> debug <lib>" needs to be a list instead of a string
SET(${NAME} ${LIBRARIES} PARENT_SCOPE)
ENDFUNCTION()
# Find Open CASCADE
IF("${OCC_INCLUDE_DIR}" STREQUAL "")
SET(OCC_INCLUDE_DIR "/usr/include/oce/" CACHE FILEPATH "Open CASCADE header files")
MESSAGE(STATUS "Looking for Open CASCADE include files in: ${OCC_INCLUDE_DIR}")
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}")
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
SET(OPENCASCADE_LIBRARIES
TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO
TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset TKHLR
TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset
)
IF(MSVC)
ADD_DEBUG_VARIANTS(OPENCASCADE_LIBRARIES "${OPENCASCADE_LIBRARIES}" "d")
ENDIF()
IF("${OCC_LIBRARY_DIR}" STREQUAL "")
SET(OCC_LIBRARY_DIR "/usr/lib/" CACHE FILEPATH "Open CASCADE library files")
MESSAGE(STATUS "Looking for 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}")
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 NAMES TKernel TKerneld PATHS ${OCC_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64)
IF(libTKernel)
MESSAGE(STATUS "Library files found")
ELSE()
MESSAGE(FATAL_ERROR "Unable to find library files, aborting")
ENDIF()
# 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(UNICODE_SUPPORT)
# Find ICU
IF("${ICU_INCLUDE_DIR}" STREQUAL "")
MESSAGE(STATUS "No ICU include directory specified")
ElSE()
SET(ICU_INCLUDE_DIR "${ICU_INCLUDE_DIR}" CACHE FILEPATH "ICU header files")
ENDIF()
if(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("${ICU_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No ICU library directory specified")
ElSE()
SET(ICU_LIBRARY_DIR "${ICU_LIBRARY_DIR}" CACHE FILEPATH "ICU library files")
ENDIF()
# Make sure cross-referenced symbols between static OCC libraries get
# resolved. Also add thread and rt libraries.
get_filename_component(libTKernelExt ${libTKernel} EXT)
if("${libTKernelExt}" STREQUAL ".a")
set(OCCT_STATIC ON)
endif()
FIND_LIBRARY(icu NAMES icuuc icuucd PATHS /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR})
if(OCCT_STATIC)
find_package(Threads)
# OPENCASCADE_LIBRARIES repeated three times below in order to fix cyclic dependencies - use --start-group ... --end-group instead?
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
if (NOT APPLE AND NOT WIN32)
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} "rt")
endif()
if (NOT WIN32)
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} "dl")
endif()
endif()
IF(icu)
ADD_DEFINITIONS(-DHAVE_ICU)
MESSAGE(STATUS "ICU libraries found")
# NOTE icudata appears to be icudt on Windows/MSVC and icudata on others
# dl is included to resolve dlopen and friends symbols
IF(MSVC)
SET(ICU_LIBRARIES icuuc icudt)
ADD_DEBUG_VARIANTS(ICU_LIBRARIES "${ICU_LIBRARIES}" "d")
ADD_DEFINITIONS(-DU_STATIC_IMPLEMENTATION) # required for static ICU
ELSE()
SET(ICU_LIBRARIES icuuc icudata dl)
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR "UNICODE_SUPPORT enabled, but unable to find ICU. Disable UNICODE_SUPPORT or fix ICU paths to proceed.")
ENDIF()
ENDIF()
endif(BUILD_IFCGEOM)
IF(COLLADA_SUPPORT AND BUILD_CONVERT)
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 "/usr/local/include/opencollada" CACHE FILEPATH "OpenCOLLADA header files")
ElSE()
SET(OPENCOLLADA_INCLUDE_DIR "${OPENCOLLADA_INCLUDE_DIR}" CACHE FILEPATH "OpenCOLLADA header files")
ENDIF()
IF("${OPENCOLLADA_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No OpenCOLLADA library directory specified")
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)
SET(OPENCOLLADA_LIBRARY_DIR "/usr/local/lib/opencollada" CACHE FILEPATH "OpenCOLLADA library files")
ElSE()
SET(OPENCOLLADA_LIBRARY_DIR "${OPENCOLLADA_LIBRARY_DIR}" CACHE FILEPATH "OpenCOLLADA library files")
ENDIF()
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
SET(OPENCOLLADA_LIBRARIES
GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader
OpenCOLLADAStreamWriter UTF buffer ftoa
OpenCOLLADAStreamWriter UTF buffer ftoa pcre
)
# 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)
IF(NOT "${PCRE_LIBRARY_DIR}" STREQUAL "")
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()
ENDIF()
IF(MSVC)
add_debug_variants(OPENCOLLADA_LIBRARIES "${OPENCOLLADA_LIBRARIES}" d)
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.")
MESSAGE(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find OpenCOLLADA. Disable COLLADA_SUPPORT or fix OpenCOLLADA paths to proceed.")
ENDIF()
ENDIF()
if(HDF5_SUPPORT)
IF("${HDF5_INCLUDE_DIR}" STREQUAL "")
MESSAGE(STATUS "No HDF5 include directory specified")
ElSE()
SET(HDF5_INCLUDE_DIR "${HDF5_INCLUDE_DIR}" CACHE FILEPATH "HDF5 header files")
ENDIF()
IF("${HDF5_LIBRARY_DIR}" STREQUAL "")
MESSAGE(STATUS "No HDF5 library directory specified")
ElSE()
SET(HDF5_LIBRARY_DIR "${HDF5_LIBRARY_DIR}" CACHE FILEPATH "HDF5 library files")
ENDIF()
IF(WIN32)
# An additional lib- prefix is added by HDF5 to denote static libraries
SET(HDF5_LIBRARIES libhdf5_cpp libhdf5 libzlib)
ELSE()
SET(HDF5_LIBRARIES hdf5_cpp hdf5 z szip)
ENDIF()
endif()
# TODO Are these needed on other platforms still or can these be removed for good?
IF (NOT WIN32)
INCLUDE(CheckIncludeFileCXX)
MACRO(CHECK_ADD_OCE_OCC_DEF INCLUDE)
STRING(REPLACE . _ STR ${INCLUDE})
STRING(TOUPPER ${STR} STR)
CHECK_INCLUDE_FILE_CXX("${INCLUDE}" FOUND_${STR})
IF(FOUND_${STR})
ADD_DEFINITIONS(-DOCE_HAVE_${STR})
ADD_DEFINITIONS(-DHAVE_${STR})
ENDIF(FOUND_${STR})
ENDMACRO()
CHECK_ADD_OCE_OCC_DEF(limits)
CHECK_ADD_OCE_OCC_DEF(climits)
CHECK_ADD_OCE_OCC_DEF(limits.h)
CHECK_ADD_OCE_OCC_DEF(fstream)
CHECK_ADD_OCE_OCC_DEF(fstream.h)
CHECK_ADD_OCE_OCC_DEF(iomanip)
CHECK_ADD_OCE_OCC_DEF(iomanip.h)
CHECK_ADD_OCE_OCC_DEF(iostream)
CHECK_ADD_OCE_OCC_DEF(iostream.h)
ENDIF()
IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE "Release")
ENDIF()
# NOTE: RelWithDebInfo and Release use O2 (= /Ox /Gl /Gy/ = Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy) by default,
# with the exception with RelWithDebInfo has /Ob1 instead. /Ob2 has been observed to improve the performance
# of IfcConvert significantly.
# TODO Setting of /GL and /LTCG don't seem to apply for static libraries (IfcGeom, IfcParse)
if(ENABLE_BUILD_OPTIMIZATIONS)
if(MSVC)
# 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")
@@ -398,18 +257,12 @@ if(ENABLE_BUILD_OPTIMIZATIONS)
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")
#TODO GCC (& Clang?) optimizations
message(STATUS "ENABLE_BUILD_OPTIMIZATIONS not implemented for GCC/non-MSVC compilers.)")
endif()
endif()
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()
IF(USE_VLD)
ADD_DEFINITIONS(-DUSE_VLD)
ENDIF()
@@ -424,13 +277,7 @@ IF(MSVC)
# Disable overeager and false positives causing C4458 ("declaration of 'indentifier' hides class member"), at least for now.
ADD_DEFINITIONS(-wd4458)
ENDIF()
# Enforce standards-conformance on VS > 2015, older Boost versions fail to compile with this
if (MSVC_VERSION GREATER 1900 AND (Boost_MAJOR_VERSION GREATER 1 OR Boost_MINOR_VERSION GREATER 66))
add_definitions(-permissive-)
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)
@@ -441,50 +288,38 @@ IF(MSVC)
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)
else()
add_definitions(-Wno-maybe-uninitialized)
endif()
# -fPIC is not relevant on Windows and creates pointless warnings
if (UNIX)
add_definitions(-fPIC)
endif()
ADD_DEFINITIONS(-fPIC -Wno-non-virtual-dtor)
ENDIF()
if (IFCCONVERT_DOUBLE_PRECISION)
SET(CONVERT_PRECISION "-DIFCCONVERT_DOUBLE_PRECISION")
endif()
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS} ${LIBXML2_INCLUDE_DIR} ${JSON_INCLUDE_DIR}
${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${HDF5_INCLUDE_DIR}
)
if(NOT WIN32)
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} /usr/inc /usr/local/inc /usr/local/include/oce)
endif()
function(files_for_ifc_version IFC_VERSION RESULT_NAME)
set(IFC_PARSE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcparse)
set(${RESULT_NAME}
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.h
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}enum.h
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}-latebound.h
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.cpp
PARENT_SCOPE
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}-latebound.cpp
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}-schema.cpp
PARENT_SCOPE
)
endfunction()
set(SCHEMA_VERSIONS "2x3" "4" "4x1" "4x2" "4x3_rc1")
if(COMPILE_SCHEMA)
# @todo, this appears to be untested at the moment
find_package(PythonInterp)
IF(NOT PYTHONINTERP_FOUND)
MESSAGE(FATAL_ERROR "A Python interpreter is necessary when COMPILE_SCHEMA is enabled. Disable COMPILE_SCHEMA or fix Python paths to proceed.")
ENDIF()
set(IFC_RELEASE_NOT_USED ${SCHEMA_VERSIONS})
set(IFC_RELEASE_NOT_USED "2x3" "4")
# Install pyparsing if necessary
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST)
@@ -525,142 +360,85 @@ if(COMPILE_SCHEMA)
OUTPUT_VARIABLE COMPILED_SCHEMA_NAME)
# Prevent the schema that had just been compiled from being excluded
foreach(s ${SCHEMA_VERSIONS})
if("${COMPILED_SCHEMA_NAME}" STREQUAL "${s}")
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "${s}")
endif()
endforeach()
endif()
# Boost >= 1.58 requires BOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE to build on some Linux distros.
if(NOT Boost_VERSION LESS 105800)
add_definitions(-DBOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE)
endif()
set(IFCOPENSHELL_LIBRARIES IfcParse)
if (BUILD_IFCGEOM)
foreach(s ${SCHEMA_VERSIONS})
set(IFCGEOM_SCHEMA_LIBRARIES ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom_ifc${s})
endforeach()
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES})
endif()
if (BUILD_CONVERT)
foreach(s ${SCHEMA_VERSIONS})
set(SERIALIZER_SCHEMA_LIBRARIES ${SERIALIZER_SCHEMA_LIBRARIES} Serializers_ifc${s})
endforeach()
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} Serializers ${SERIALIZER_SCHEMA_LIBRARIES})
if("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC2X3")
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "2x3")
add_definitions(-DUSE_IFC2x3)
elseif("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC4")
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "4")
add_definitions(-DUSE_IFC4)
endif()
else()
if(USE_IFC4)
add_definitions(-DUSE_IFC4)
set(IFC_RELEASE_NOT_USED "2x3")
else()
add_definitions(-DUSE_IFC2x3) # TODO Make all caps? i.e. USE_IFC2X3
set(IFC_RELEASE_NOT_USED "4")
endif()
endif()
# IfcParse
file(GLOB IFCPARSE_H_FILES ../src/ifcparse/*.h)
file(GLOB IFCPARSE_CPP_FILES ../src/ifcparse/*.cpp)
foreach(IFC_RELEASE ${IFC_RELEASE_NOT_USED})
files_for_ifc_version(${IFC_RELEASE} SOURCE_FILES_NOT_USED)
foreach(SOURCE_FILE ${SOURCE_FILES_NOT_USED})
list(REMOVE_ITEM IFCPARSE_CPP_FILES ${SOURCE_FILE})
list(REMOVE_ITEM IFCPARSE_H_FILES ${SOURCE_FILE})
endforeach()
endforeach()
set(IFCPARSE_FILES ${IFCPARSE_CPP_FILES} ${IFCPARSE_H_FILES})
add_library(IfcParse ${IFCPARSE_FILES})
set_target_properties(IfcParse PROPERTIES COMPILE_FLAGS -DIFC_PARSE_EXPORTS VERSION "0.6.0" SOVERSION "0.6")
ADD_LIBRARY(IfcParse STATIC ${IFCPARSE_FILES})
TARGET_LINK_LIBRARIES(IfcParse ${Boost_LIBRARIES} ${BCRYPT_LIBRARIES} ${LIBXML2_LIBRARIES})
IF(UNICODE_SUPPORT)
TARGET_LINK_LIBRARIES(IfcParse ${ICU_LIBRARIES})
ENDIF()
if (BUILD_IFCGEOM)
if(HDF5_SUPPORT)
TARGET_LINK_LIBRARIES(IfcParse ${HDF5_LIBRARIES})
endif()
# IfcGeom
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/*.h)
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp)
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES})
ADD_LIBRARY(IfcGeom STATIC ${IFCGEOM_FILES})
foreach(s ${SCHEMA_VERSIONS})
add_library(IfcGeom_ifc${s} STATIC ${IFCGEOM_FILES})
set_target_properties(IfcGeom_ifc${s} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${s}")
TARGET_LINK_LIBRARIES(IfcGeom_ifc${s} IfcParse ${OPENCASCADE_LIBRARIES})
endforeach()
TARGET_LINK_LIBRARIES(IfcGeom IfcParse)
# IfcGeom (schema agnostic)
file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom_schema_agnostic/*.h)
file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom_schema_agnostic/*.cpp)
set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES})
add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES})
set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS VERSION "0.6.0" SOVERSION "0.6")
if (UNIX)
find_package(Threads)
LINK_DIRECTORIES(${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} ${OPENCOLLADA_LIBRARY_DIR}
${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS} ${HDF5_LIBRARY_DIR}
)
if(NOT WIN32)
LINK_DIRECTORIES(${LINK_DIRECTORIES} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64)
endif()
TARGET_LINK_LIBRARIES(IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
endif(BUILD_IFCGEOM)
if (BUILD_CONVERT)
# Serializers
file(GLOB SERIALIZERS_H_FILES ../src/serializers/*.h)
file(GLOB SERIALIZERS_CPP_FILES ../src/serializers/*.cpp)
set(SERIALIZERS_FILES ${SERIALIZERS_H_FILES} ${SERIALIZERS_CPP_FILES})
file(GLOB SERIALIZERS_S_H_FILES ../src/serializers/schema_dependent/*.h)
file(GLOB SERIALIZERS_S_CPP_FILES ../src/serializers/schema_dependent/*.cpp)
set(SERIALIZERS_S_FILES ${SERIALIZERS_S_H_FILES} ${SERIALIZERS_S_CPP_FILES})
foreach(s ${SCHEMA_VERSIONS})
add_library(Serializers_ifc${s} STATIC ${SERIALIZERS_S_FILES})
set_target_properties(Serializers_ifc${s} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${s} ${CONVERT_PRECISION}")
TARGET_LINK_LIBRARIES(Serializers_ifc${s} IfcGeom ${OPENCASCADE_LIBRARIES})
endforeach()
add_library(Serializers ${SERIALIZERS_FILES})
set_target_properties(Serializers PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS ${CONVERT_PRECISION}" VERSION "0.6.0" SOVERSION "0.6")
TARGET_LINK_LIBRARIES(Serializers ${SERIALIZER_SCHEMA_LIBRARIES})
# IfcConvert
file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp)
file(GLOB IFCCONVERT_H_FILES ../src/ifcconvert/*.h)
set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES})
ADD_EXECUTABLE(IfcConvert ${IFCCONVERT_FILES})
set_target_properties(IfcConvert PROPERTIES COMPILE_FLAGS "${CONVERT_PRECISION}")
TARGET_LINK_LIBRARIES(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES})
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
# Only set RPATHs when building shared libraries (i.e. IfcParse and
# IfcGeom are dynamically linked). Not necessarily a perfect solution
# but probably a good indication of whether RPATHs are necessary.
SET_INSTALL_RPATHS(IfcConvert "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS};${OPENCOLLADA_LIBRARY_DIR}")
# Make sure cross-referenced symbols between static OCC libraries get
# resolved. Also add thread and rt libraries.
get_filename_component(libTKernelExt ${libTKernel} EXT)
if("${libTKernelExt}" STREQUAL ".a")
find_package(Threads)
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} rt dl)
endif()
INSTALL(TARGETS IfcConvert
ARCHIVE DESTINATION ${LIBDIR}
LIBRARY DESTINATION ${LIBDIR}
RUNTIME DESTINATION ${BINDIR}
)
endif(BUILD_CONVERT)
TARGET_LINK_LIBRARIES(IfcConvert IfcParse IfcGeom ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${ICU_LIBRARIES})
# 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})
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
SET_INSTALL_RPATHS(IfcGeomServer "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS}")
endif()
INSTALL(TARGETS IfcGeomServer
ARCHIVE DESTINATION ${LIBDIR}
LIBRARY DESTINATION ${LIBDIR}
RUNTIME DESTINATION ${BINDIR}
)
endif()
# Documentation
IF(BUILD_DOCUMENTATION)
set(CMAKE_MODULE_PATH "../docs/cmake")
ADD_SUBDIRECTORY(../docs docs)
ENDIF()
TARGET_LINK_LIBRARIES(IfcGeomServer IfcParse IfcGeom ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBRARIES})
IF(BUILD_IFCPYTHON)
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
@@ -670,49 +448,16 @@ IF(BUILD_EXAMPLES)
ADD_SUBDIRECTORY(../src/examples examples)
ENDIF()
IF(BUILD_IFCMAX)
ADD_SUBDIRECTORY(../src/ifcmax ifcmax)
IF(HDF5_SUPPORT)
ADD_SUBDIRECTORY(../src/hdf5_usecases hdf5_usecases)
ENDIF()
if(NOT MSVC)
add_definitions(-std=c++14)
endif()
# CMake installation targets
INSTALL(FILES ${IFCPARSE_H_FILES}
DESTINATION ${INCLUDEDIR}/ifcparse
)
INSTALL(TARGETS IfcParse
ARCHIVE DESTINATION ${LIBDIR}
LIBRARY DESTINATION ${LIBDIR}
RUNTIME DESTINATION ${BINDIR}
)
if(BUILD_IFCGEOM)
INSTALL(FILES ${IFCGEOM_H_FILES}
DESTINATION ${INCLUDEDIR}/ifcgeom
)
INSTALL(FILES ${SCHEMA_AGNOSTIC_H_FILES}
DESTINATION ${INCLUDEDIR}/ifcgeom_schema_agnostic
)
INSTALL(TARGETS ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom
ARCHIVE DESTINATION ${LIBDIR}
LIBRARY DESTINATION ${LIBDIR}
RUNTIME DESTINATION ${BINDIR}
)
endif()
if(BUILD_CONVERT)
INSTALL(TARGETS Serializers ${SERIALIZER_SCHEMA_LIBRARIES}
ARCHIVE DESTINATION ${LIBDIR}
LIBRARY DESTINATION ${LIBDIR}
RUNTIME DESTINATION ${BINDIR}
)
INSTALL(FILES ${SERIALIZERS_FILES}
DESTINATION ${INCLUDEDIR}/serializers/
)
INSTALL(FILES ${SERIALIZERS_S_FILES}
DESTINATION ${INCLUDEDIR}/serializers/schema_dependent
)
endif()
INSTALL(FILES ${IFCPARSE_H_FILES} DESTINATION include/ifcparse)
INSTALL(FILES ${IFCGEOM_H_FILES} DESTINATION include/ifcgeom)
INSTALL(TARGETS IfcConvert IfcGeomServer DESTINATION bin)
INSTALL(TARGETS IfcParse IfcGeom DESTINATION lib)
-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
-40
View File
@@ -1,40 +0,0 @@
#Look for an executable called sphinx-build
find_program(SPHINX_EXECUTABLE
NAMES sphinx-build
DOC "Path to sphinx-build executable")
include(FindPackageHandleStandardArgs)
#Handle standard arguments to find_package like REQUIRED and QUIET
find_package_handle_standard_args(Sphinx
"Failed to find sphinx-build executable"
SPHINX_EXECUTABLE)
find_package(Doxygen REQUIRED)
#find_package(Sphinx REQUIRED)
set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR})
set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/docs/sphinx)
MESSAGE(STATUS "SPHINX BUILD ${CMAKE_CURRENT_BINARY_DIR}")
file(MAKE_DIRECTORY ./output/doxygen)
if (DOXYGEN_FOUND)
add_custom_target(Sphinx ALL
COMMAND
${SPHINX_EXECUTABLE} -v -T -b html
${SPHINX_SOURCE} ${CMAKE_CURRENT_SOURCE_DIR}/output
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/output
COMMENT "Generating documentation with Sphinx")
# add_custom_target(ifcopenshell_python_docs ALL
# COMMAND make html
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcblenderexport/docs
# OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcblenderexport/docs
# COMMENT "Generating documentation with Sphinx")
else (DOXYGEN_FOUND)
message("Doxygen need to be installed to generate the doxygen documentation")
endif (DOXYGEN_FOUND)
-2531
View File
File diff suppressed because it is too large Load Diff
-11
View File
@@ -1,11 +0,0 @@
#Look for an executable called sphinx-build
find_program(SPHINX_EXECUTABLE
NAMES sphinx-build
DOC "Path to sphinx-build executable")
include(FindPackageHandleStandardArgs)
#Handle standard arguments to find_package like REQUIRED and QUIET
find_package_handle_standard_args(Sphinx
"Failed to find sphinx-build executable"
SPHINX_EXECUTABLE)
-11
View File
@@ -1,11 +0,0 @@
#Look for an executable called sphinx-build
find_program(SPHINX_EXECUTABLE
NAMES sphinx-build
DOC "Path to sphinx-build executable")
include(FindPackageHandleStandardArgs)
#Handle standard arguments to find_package like REQUIRED and QUIET
find_package_handle_standard_args(Sphinx
"Failed to find sphinx-build executable"
SPHINX_EXECUTABLE)
-48
View File
@@ -1,48 +0,0 @@
import textwrap
# The `extensions` list should already be in here from `sphinx-quickstart`
extensions = [
# there may be others here already, e.g. 'sphinx.ext.mathjax'
'breathe',
'exhale',
'sphinx.ext.intersphinx'
]
project = 'IfcOpenShell'
copyright = '2020, IfcOpenShell'
author = ''
# Setup the breathe extension
breathe_projects = {
"My Project": "./output/doxygen/xml"
}
breathe_default_project = "My Project"
# Setup the exhale extension
exhale_args = {
# These arguments are required
"containmentFolder": "./rst_files",
"rootFileName": "library_root.rst",
"rootFileTitle": "IfcOpenShell",
"doxygenStripFromPath": "..",
# Suggested optional arguments
"createTreeView": True,
# TIP: if using the sphinx-bootstrap-theme, you need
# "treeViewIsBootstrap": True,
"exhaleExecutesDoxygen": True,
# "exhaleDoxygenStdin": "INPUT = ../src/serializers/ ../src/ifcgeom",
"exhaleUseDoxyfile": True
}
# html_theme = 'sphinx_rtd_theme'
# # Tell sphinx what the primary language being documented is.
# primary_domain = 'cpp'
# # Tell sphinx what the pygments highlight language should be.
# highlight_language = 'cpp'
-52
View File
@@ -1,52 +0,0 @@
# This program requires doxygen, sphinx, breathe and exhale.
import os
import os.path
import subprocess
from sys import platform
def copy_content(content, container):
with open(content) as f:
with open(container, "w") as f1:
for line in f:
f1.write(line)
conf_path = "./conf.py"
index_path = "./index.rst"
if not os.path.isdir("./output/doxygen/xml"):
os.makedirs("output/doxygen/xml")
if os.path.isfile(conf_path) and not os.path.isfile(index_path):
os.remove(conf_path)
if os.path.isfile(index_path) and not os.path.isfile(conf_path):
os.remove(index_path)
if not (os.path.isfile(conf_path) and os.path.isfile(index_path)):
subprocess.run(["sphinx-quickstart", "-q", "-p", "IfcOpenShell"])
conf_copy = ["./conf_to_copy.py", "./conf.py"]
index_copy = ["./index_to_copy.rst", "./index.rst"]
copy_content(conf_copy[0], conf_copy[1])
copy_content(index_copy[0], index_copy[1])
if platform == "linux" or platform == "linux2":
subprocess.run(["make", "html"])
if not os.path.isdir("/output/_build"):
subprocess.run(["cd","../src/ifcblenderexport/docs"])
subprocess.run(["make", "html"])
subprocess.run(["cd", "../../../docs"])
subprocess.run(["mv" "../src/ifcblenderexport/docs/_build", "./output"])
elif platform == "win32" or platform == "win64":
subprocess.run(["make.bat", "html"])
Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

-240
View File
@@ -1,240 +0,0 @@
APPLY_DEFAULT_MATERIALS
-----------------------
Given the command invocation:
Duplex_A_20110907_optimized.ifc d.dae -yv --include attribute GlobalId 3bXiCStxP6Fgxdej$yc50U
You will find log messages along the lines of
[Warning] {3bXiCStxP6Fgxdej$yc50U} No material and surface styles for:
#333=IfcCovering('3bXiCStxP6Fgxdej$yc50U',#1,'Compound Ceiling:Gypsum Board:187483',$,'Compound Ceiling:Gypsum Board',#17840,#17052,'187483',.CEILING.)
This means that there is no IfcStyledItem associated to the representation items and that the element does not have an IfcMaterial association with IfcMaterialRepresentation from which we can derive a style (colour) for the element.
The interactive session below shows how with this setting enabled you will get a default generated material from the IFC element entity type and material indices of 0 pointing to that. With this setting disabled the material index would be -1 to indicate a missing style. Note that there is one material index for every triangle in the list of `shp.geometry.faces`.
>>> import ifcopenshell, ifcopenshell.geom
>>> f = ifcopenshell.open("Duplex_A_20110907_optimized.ifc")
>>> s = ifcopenshell.geom.settings()
>>> c = f["3bXiCStxP6Fgxdej$yc50U"]
>>>
>>> shp = ifcopenshell.geom.create_shape(s, c)
>>> shp.geometry.material_ids
(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
>>> [(m.name, m.diffuse) for m in shp.geometry.materials]
[]
>>>
>>> s.set(s.APPLY_DEFAULT_MATERIALS, True)
>>> shp = ifcopenshell.geom.create_shape(s, c)
>>> shp.geometry.material_ids
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
>>> [(m.name, m.diffuse) for m in shp.geometry.materials]
[('IfcCovering', (0.7, 0.7, 0.7))]
This is enabled by default for the IfcConvert serializers as they will not gracefully handle -1 material indices and allows users to quickly assign colours based on entity types in their modelling applications.
APPLY_LAYERSETS
---------------
This setting is available in IfcConvert as `--enable-layerset-slicing`.
For IfcWall and IfcSlab elements, takes the associated IfcMaterialLayerSet and builds a set of surfaces to segment the building element geometry.
Note that enabling this settings is computationally intensive as it involves 3D Boolean operations.
Duplex_A_20110907_optimized.ifc d1.dae -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
![Image of d1.dae](images/settings-1.png)
Duplex_A_20110907_optimized.ifc d2.dae --enable-layerset-slicing -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
![Image of d2.dae](images/settings-2.png)
BUILDING_LOCAL_PLACEMENT
------------------------
This setting is available in IfcConvert using `--building-local-placement`.
In the typical IfcSite > IfcBuilding > IfcBuildingStorey > ... hierarchy of elements, don't incorporate the ObjectPlacement of the IfcBuilding and above in the placement of elements in the output. This is useful when there is a large offset in this placement that reduces precision in further processing.
CONVERT_BACK_UNITS
------------------
This setting is available in IfcConvert using `--convert-back-units`.
Internally IfcOpenShell uses meters as the global length unit to do calculations. This setting restores the coordinate positions after conversion by multiplying the factor of the IfcUnit with UnitType=LENGTHUNIT into the output geometry coordinate values.
DISABLE_OPENING_SUBTRACTIONS
----------------------------
This setting is available in IfcConvert using `--disable-opening-subtraction`.
As in most viewer applications, IfcOpeningElement geometry is subtracted from their host elements. This setting disables this behavior.
Duplex_A_20110907_optimized.ifc d1.dae -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
![Image of d1.dae](images/settings-1.png)
Duplex_A_20110907_optimized.ifc d3.dae --disable-opening-subtraction -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
![Image of d3.dae](images/settings-3.png)
Note that disabling this settings will reduce processing time and improve robustness as it involves 3D Boolean operations.
DISABLE_TRIANGULATION
---------------------
To be used in conjunction with `USE_BREP_DATA`. Do not apply the triangulation and - when `USE_BREP_DATA` is set - return a OpenCASCADE serialized TopoDS_Shape from `create_shape()` and `iterator`.
>>> import ifcopenshell, ifcopenshell.geom
>>> s = ifcopenshell.geom.settings()
>>> s.set(s.DISABLE_TRIANGULATION, True)
>>> s.set(s.USE_BREP_DATA, True)
>>> f = ifcopenshell.open("Duplex_A_20110907_optimized.ifc")
>>> c = f["3bXiCStxP6Fgxdej$yc50U"]
>>> shp = ifcopenshell.geom.create_shape(s, c)
>>> print(shp.geometry.brep_data)
CASCADE Topology V1, (c) Matra-Datavision
Locations 0
Curve2ds 0
Curves 12
1 4.6750000000000034 -8.0749999999999904 2.657 -2.0455514041918775e-15 -1 0
1 4.6750000000000034 -8.0749999999999904 2.657 1 -3.435893306383461e-15 0
1 6.2260000000000044 -8.0749999999999957 2.657 -2.0455514041918724e-15 -1 0
1 6.226 -10.246000000000031 2.657 -1 6.8717866127669219e-15 0
...
EDGE_ARROWS
-----------
When `INCLUDE_CURVES` is true and geometric elements include curves (such as the wall axis), add arrow heads to the edges to indicate direction of the curve.
Duplex_A_20110907_optimized.ifc d4.dae --model --plan --edge-arrows -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
![Image of d4.dae](images/settings-4.png)
EXCLUDE_SOLIDS_AND_SURFACES
---------------------------
Exclude faces, shells and solids from geometrical output. Implied when using `--plan` without `--model` in IfcConvert.
FASTER_BOOLEANS
---------------
NOTE: Only applicable when using OCCT 6.9 and earlier.
This setting is available in IfcConvert using `--merge-boolean-operands`.
Fuse the collection of all boolean operands into a single union before applying the boolean subtraction, as opposed to doing individual subtractions. This likely improves performance. From OCCT 7.0 onwards the boolean operations with multiple arguments is used.
GENERATE_UVS
------------
This setting is available in IfcConvert using `--generate-uvs`.
Applies a box projection on the generated geometry for the element to obtain UV coordinates. This is purely generated, it does not involve texture coordinates stored in the IFC model.
Duplex_A_20110907_optimized.ifc d5.dae --generate-uvs -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
![Image of d5.dae with a UV grid applied in Blender](images/settings-5.png)
INCLUDE_CURVES
--------------
This setting is available in IfcConvert using `--plan`.
Include edge and wire geometries in the geometric output.
LAYERSET_FIRST
--------------
This setting is available in IfcConvert using `--layerset-first`.
When not using APPLY_LAYERSETS, take the first material layer from the set to use as the material for the overall element.
NO_NORMALS
----------
This setting is available in IfcConvert using `--no-normals`.
Do not emit normals on geometric output
SEARCH_FLOOR
------------
Note: Only applicable to Collada .DAE output when used from IfcConvert.
This setting is available in IfcConvert using `--use-element-hierarchy`.
Include the spatial hierarchy in the elements.
SEW_SHELLS
----------
This setting is available in IfcConvert using `--orient-shells`.
Re-orient or sew connected face sets to have a consistent outwards orientation.
SITE_LOCAL_PLACEMENT
--------------------
This setting is available in IfcConvert using `--site-local-placement`.
See `BUILDING_LOCAL_PLACEMENT`, but exclude also the ObjectPlacement of the IfcSite.
USE_BREP_DATA
-------------
See `DISABLE_TRIANGULATION`.
USE_PYTHON_OPENCASCADE
----------------------
Note: Only available when an import of `OCC.Core.BRepTools` or `OCC.BRepTools` succeeds.
This implies `USE_WORLD_COORDS` `USE_BREP_DATA` and `DISABLE_TRIANGULATION`. The serialized TopoDS_Shape of `USE_BREP_DATA` is deserialized by Python OpenCASCADE.
USE_WORLD_COORDS
----------------
Apply the ObjectPlacement of the building elements to the geometric output. This is implied when using the Wavefront .OBJ output in IfcConvert. Note that this also eliminates the possibility for geometric elements to point to the same interpreted geometry result.
VALIDATE_QUANTITIES
-------------------
This setting is available in IfcConvert using `--validate`.
Running IfcConvert with `--validate` will set a non-zero exit code when ever a log message with severity equal or greater than ERROR has been emitted.
Currently for internal use only. For every building element geometry converted, looks for an associated quantity set where the OwnerHistory's organization name is IfcOpenShell. And looks for the quantities "Total Surface Area", "Volume", "Shape Validation Properties.Surface Genus" and validates these according to the interpreted geometry definition. Emit Logger::Error when calculated values are outside of the tolerance range for the value stored in the model.
WELD_VERTICES
-------------
Note: In Python, this setting is *on* by default.
Note: This setting only affects triangulated output.
This setting is available in IfcConvert using `--weld-vertices`.
Discards normals and joins vertices solely based on position. This is useful when output is to be modified in a modeling application.
>>> import ifcopenshell, ifcopenshell.geom
>>> s = ifcopenshell.geom.settings()
>>> s.set(s.WELD_VERTICES, False)
>>> f = ifcopenshell.open("Duplex_A_20110907_optimized.ifc")
>>> c = f["3bXiCStxP6Fgxdej$yc50U"]
>>> shp = ifcopenshell.geom.create_shape(s, c)
>>> shp.geometry.verts
(4.675000000000003, -8.07499999999999, 2.657, 4.674999999999999, -10.24600000000002, 2.657, 6.226000000000004, -8.074999999999996, 2.657, 6.226, -10.24600000000003, 2.657, 4.675000000000003, -8.07499999999999, 2.6, 4.674999999999999, -10.24600000000002, 2.6, 6.226000000000004, -8.074999999999996, 2.6, 6.226, -10.24600000000003, 2.6, 4.674999999999999, -10.24600000000002, 2.657, 4.674999999999999, -10.24600000000002, 2.6, 4.675000000000003, -8.07499999999999, 2.657, 4.675000000000003, -8.07499999999999, 2.6, 6.226, -10.24600000000003, 2.657, 4.674999999999999, -10.24600000000002, 2.657, 6.226, -10.24600000000003, 2.6, 4.674999999999999, -10.24600000000002, 2.6, 6.226000000000004, -8.074999999999996, 2.657, 6.226, -10.24600000000003, 2.657, 6.226000000000004, -8.074999999999996, 2.6, 6.226, -10.24600000000003, 2.6, 4.675000000000003, -8.07499999999999, 2.657, 4.675000000000003, -8.07499999999999, 2.6, 6.226000000000004, -8.074999999999996, 2.657, 6.226000000000004, -8.074999999999996, 2.6)
>>> shp.geometry.normals
(3.059754518198021e-17, 0.0, -1.0, 3.059754518198021e-17, 0.0, -1.0, 3.059754518198021e-17, 0.0, -1.0, 3.059754518198021e-17, 0.0, -1.0, 2.110175529791737e-16, 0.0, -1.0, 2.110175529791737e-16, 0.0, -1.0, 2.110175529791737e-16, 0.0, -1.0, 2.110175529791737e-16, 0.0, -1.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, 6.8717866127669046e-15, 1.0, 0.0, 6.8717866127669046e-15, 1.0, 0.0, 6.8717866127669046e-15, 1.0, 0.0, 6.8717866127669046e-15, 1.0, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, 3.4358933063834523e-15, 1.0, 0.0, 3.4358933063834523e-15, 1.0, 0.0, 3.4358933063834523e-15, 1.0, 0.0, 3.4358933063834523e-15, 1.0, 0.0)
>>>
>>> s.set(s.WELD_VERTICES, True)
>>> shp = ifcopenshell.geom.create_shape(s, c)
>>> shp.geometry.verts
(4.675000000000003, -8.07499999999999, 2.657, 4.674999999999999, -10.24600000000002, 2.657, 6.226000000000004, -8.074999999999996, 2.657, 6.226, -10.24600000000003, 2.657, 4.675000000000003, -8.07499999999999, 2.6, 4.674999999999999, -10.24600000000002, 2.6, 6.226000000000004, -8.074999999999996, 2.6, 6.226, -10.24600000000003, 2.6)
>>> shp.geometry.normals
()
-10
View File
@@ -1,10 +0,0 @@
IfcOpenShell
============
.. toctree::
:maxdepth: 3
rst_files/library_root
`ifcopenshell-python documentation <_build/html/index.html>`_
-10
View File
@@ -1,10 +0,0 @@
IfcOpenShell
============
.. toctree::
:maxdepth: 3
rst_files/library_root
`ifcopenshell-python documentation <_build/html/index.html>`_
-784
View File
@@ -1,784 +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: #
# * cmake * git * bzip2 * tar * c(++) compilers * yacc * autoconf #
# #
# if building with USE_OCCT additionally: #
# * freetype * glx.h #
# #
# if building with OCCT 7.4.0 additionally: #
# * libfontconfig1-dev #
# #
# if building with -shared #
# * libgl1-mesa-dev libxext-dev libxmu-dev libxmu-headers libxi-dev #
# #
# for python37 to install correctly additionally: #
# * libffi(-dev[el]) #
# #
# on debian 7.8 these can be obtained with: #
# $ apt-get install git gcc g++ autoconf bison bzip2 cmake #
# libfreetype6-dev mesa-common-dev libffi-dev libfontconfig1-dev #
# #
# on ubuntu 14.04: #
# $ apt-get install git gcc g++ autoconf bison make cmake #
# libfreetype6-dev mesa-common-dev libffi-dev libfontconfig1-dev #
# #
# on OS X El Capitan with homebrew: #
# $ brew install git bison autoconf automake freetype libffi cmake #
# #
###############################################################################
from __future__ import print_function
import logging
import os
import sys
import subprocess as sp
import shutil
import time
import tarfile
import multiprocessing
PYTHON_MAJOR = sys.version_info[0]
if PYTHON_MAJOR >= 3:
from urllib.request import urlretrieve
else:
# Not Python 3 - today, it is most likely to be Python 2
# But note that this might need an update when Python 4
# might be around one day
from urllib import urlretrieve
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
logger.addHandler(ch)
PROJECT_NAME="IfcOpenShell"
PYTHON_VERSIONS=["2.7.16", "3.2.6", "3.3.6", "3.4.6", "3.5.3", "3.6.2", "3.7.3", "3.8.6", "3.9.1"]
JSON_VERSION="v3.6.1"
OCE_VERSION="0.18"
# OCCT_VERSION="7.1.0"
# OCCT_HASH="89aebde"
# OCCT_VERSION="7.2.0"
# OCCT_HASH="88af392"
OCCT_VERSION="7.3.0p3"
BOOST_VERSION="1.71.0"
#PCRE_VERSION="8.39"
PCRE_VERSION="8.41"
#LIBXML2_VERSION="2.9.3"
LIBXML2_VERSION="2.9.9"
SWIG_VERSION="3.0.12"
#SWIG_VERSION="4.0.0"
#OPENCOLLADA_VERSION="v1.6.63"
OPENCOLLADA_VERSION="v1.6.68"
# binaries
cp="cp"
bash="bash"
uname="uname"
git="git"
bunzip2="bunzip2"
tar="tar"
cc="cc"
cplusplus="c++"
autoconf="autoconf"
automake="automake"
yacc="yacc"
make="make"
date = "date"
curl="curl"
wget="wget"
strip="strip"
# Helper function for coloured printing
NO_COLOR="\033[0m" # <ref>http://stackoverflow.com/questions/5947742/how-to-change-the-output-color-of-echo-in-linux</ref>
BLACK_ON_WHITE="\033[0;30;107m"
RED="\033[31m"
GREEN="\033[32m"
YELLOW="\033[33m"
MAGENTA="\033[35m"
def cecho(message, color=NO_COLOR):
"""Logs message `message` in color `color`."""
logger.info("%s%s\033[0m" % (color, message))
def which(cmd):
for path in os.environ["PATH"].split(":"):
if os.path.exists(path) and cmd in os.listdir(path):
return cmd
return None
def get_os():
ret_value = sp.check_output([uname, "-s"]).strip()
return ret_value
def to_pystring(x):
""" Python 2 & 3 compatibility function for strings handling
(to solve TypeError "Can't mix strings and bytes in path components" for Python 3).
Reference https://github.com/hugsy/gef/issues/382 """
res = str(x, encoding="utf-8") if PYTHON_MAJOR == 3 else x
substs = [("\n","\\n"), ("\r","\\r"), ("\t","\\t"), ("\v","\\v"), ("\b","\\b"), ]
for x,y in substs: res = res.replace(x,y)
return res
# Set defaults for missing empty environment variables
USE_OCCT = os.environ.get("USE_OCCT", "true").lower() == "true"
TOOLSET = None
if get_os() == "Darwin":
# C++11 features used in OCCT 7+ need a more recent stdlib
TOOLSET = "10.9" if USE_OCCT else "10.6"
# python 3.4 doesn't seem to build anymore on recent versions of clang
if get_os() == "Darwin":
try:
PYTHON_VERSIONS.remove("3.4.6")
except ValueError as e:
pass
try:
IFCOS_NUM_BUILD_PROCS = os.environ["IFCOS_NUM_BUILD_PROCS"]
except KeyError:
IFCOS_NUM_BUILD_PROCS=multiprocessing.cpu_count() + 1
try:
TARGET_ARCH = os.environ["TARGET_ARCH"]
except KeyError:
TARGET_ARCH = sp.check_output([uname, "-m"]).strip()
CMAKE_DIR=os.path.realpath(os.path.join("..", "cmake"))
try:
DEPS_DIR = os.environ["DEPS_DIR"]
except KeyError:
path = [b"..", b"build", sp.check_output(uname).strip(), TARGET_ARCH]
if TOOLSET:
path.append(TOOLSET)
DEPS_DIR = to_pystring(os.path.realpath(os.path.join(*path)))
if not os.path.exists(DEPS_DIR):
os.makedirs(DEPS_DIR)
try:
BUILD_CFG=os.environ["BUILD_CFG"]
except KeyError:
BUILD_CFG="RelWithDebInfo"
# Print build configuration information
cecho ("""This script fetches and builds %s and its dependencies
""" % (PROJECT_NAME,), BLACK_ON_WHITE)
cecho("""Script configuration:
""", GREEN)
cecho("""* Target Architecture = %s""" % (TARGET_ARCH,), MAGENTA)
cecho(" - Whether 32-bit (i686) or 64-bit (x86_64) will be built.")
cecho("""* USE_OCCT = %r""" % (USE_OCCT,), MAGENTA)
if USE_OCCT:
cecho(" - Compiling against official Open Cascade")
else:
cecho(" - Compiling against Open Cascade Community Edition")
cecho("* Dependency Directory = %s" % (DEPS_DIR,), MAGENTA)
cecho(" - The directory where %s dependencies are installed." % (PROJECT_NAME,))
cecho("* Build Config Type = %s" % (BUILD_CFG,), MAGENTA)
cecho(""" - The used build configuration type for the dependencies.
Defaults to RelWithDebInfo if not specified.""")
if BUILD_CFG == "MinSizeRel":
cecho(" WARNING: MinSizeRel build can suffer from a significant performance loss.", RED)
cecho("* IFCOS_NUM_BUILD_PROCS = %s" % (IFCOS_NUM_BUILD_PROCS,), MAGENTA)
cecho(""" - How many compiler processes may be run in parallel.
""")
dependency_tree = {
'IfcParse': ('boost', 'libxml2'),
'IfcGeom': ('IfcParse', 'occ'),
'IfcConvert': ('IfcGeom', 'OpenCOLLADA', 'json'),
'OpenCOLLADA': ('libxml2', 'pcre'),
'IfcGeomServer': ('IfcGeom',),
'IfcOpenShell-Python': ('python', 'swig', 'IfcGeom'),
'swig': ('pcre',),
'boost': (),
'libxml2': (),
'python': (),
'occ': (),
'pcre': (),
'json': ()
}
def v(dep):
yield dep
for d in dependency_tree[dep]:
for x in v(d):
yield x
tgts = [s for s in sys.argv[1:] if not s.startswith("-")]
flags = set(s for s in sys.argv[1:] if s.startswith("-"))
BUILD_STATIC = not "-shared" in flags
ENABLE_FLAG = "--enable-static" if BUILD_STATIC else "--enable-shared"
DISABLE_FLAG = "--disable-shared" if BUILD_STATIC else "--disable-static"
LINK_TYPE = "static" if BUILD_STATIC else "shared"
LINK_TYPE_UCFIRST = LINK_TYPE[0].upper() + LINK_TYPE[1:]
LIBRARY_EXT = "a" if BUILD_STATIC else "so"
PIC = "-fPIC" if BUILD_STATIC else ""
if len(tgts):
targets = set(sum((list(v(target)) for target in tgts), []))
else:
targets = set(dependency_tree.keys())
print("Building:", *sorted(targets, key=lambda t: len(list(v(t)))))
# Check that required tools are in PATH
for cmd in [git, bunzip2, tar, cc, cplusplus, autoconf, automake, yacc, make, "patch", "cmake"]:
if which(cmd) is None:
raise ValueError("Required tool '%s' not installed or not added to PATH" % (cmd,))
# identifiers for the download tool (could be less memory consuming as ints, but are more verbose as strings)
download_tool_default = download_tool_py = "py"
download_tool_git = "git"
# Create log directory and file
log_dir = os.path.join(DEPS_DIR, "logs")
if not os.path.exists(log_dir):
os.makedirs(log_dir)
LOG_FILE="%s.log" % (os.path.join(log_dir, to_pystring(sp.check_output([date, "+%Y%m%d"]).strip())),)
if not os.path.exists(LOG_FILE):
open(LOG_FILE, "w").close()
logger.info("using command log file '%s'" % (LOG_FILE,))
def run(cmds, cwd=None):
"""
Wraps `subprocess.Popen.communicate()` and logs the command being executed,
sets up logging `stderr` to `LOG_FILE` (in append mode) and returns stdout
with leading and trailing whitespace removed.
"""
logger.debug("running command %r in directory %r" % (" ".join(cmds), cwd))
log_file_handle = open(LOG_FILE, "ab")
proc = sp.Popen(cmds, cwd=cwd, stdout=sp.PIPE, stderr=sp.PIPE)
stdout, stderr = proc.communicate()
log_file_handle.write(stdout)
log_file_handle.write(stderr)
log_file_handle.close()
logger.debug("command returned %r" % proc.returncode)
if proc.returncode != 0:
print("-" * 70)
print(stderr)
print("-" * 70)
raise Exception("Command `%s` returned exit code %d" % (" ".join(cmds), proc.returncode))
return stdout.strip()
BOOST_VERSION_UNDERSCORE=BOOST_VERSION.replace(".", "_")
OCE_LOCATION="https://github.com/tpaviot/oce/archive/OCE-%s.tar.gz" % (OCE_VERSION,)
BOOST_LOCATION="https://dl.bintray.com/boostorg/release/%s/source/" % (BOOST_VERSION,)
# 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):
run([bash, "./autogen.sh"], cwd=os.path.realpath(os.path.join(cwd, ".."))) # only run autogen.sh in the directory it is located and use cwd to achieve that in order to not mess up things
# Using `sh` over `bash` fixes issues with building swig
run(["/bin/sh", "../configure"]+configure_args+["--prefix=%s" % (os.path.realpath("%s/install/%s" % (DEPS_DIR, arg1)),)], cwd=cwd)
def run_cmake(arg1, cmake_args, cmake_dir=None, cwd=None):
if cmake_dir is None:
P=".."
else:
P=cmake_dir
run(["cmake", P]+cmake_args+["-DCMAKE_BUILD_TYPE=%s" % (BUILD_CFG,)], cwd=cwd)
def git_clone_or_pull_repository(clone_url, target_dir, revision=None):
"""Lazily clones the `git` repository denoted by `clone_url` into
the `target_dir` or pulls latest changes if the `target_dir` exists (naively assumes
that a working clone exists there) and optionally checks out a revision
`revision` after cloning or in the existing clone if `revision` is not
`None`."""
if not os.path.exists(target_dir):
logger.info("cloning '%s' into '%s'" % (clone_url, target_dir))
run([git, "clone", clone_url, target_dir])
else:
logger.info("directory '%s' already cloned. Pulling latest changes." % (target_dir,))
# detect whether we are on a branch and pull
if run([git, "rev-parse", "--abbrev-ref", "HEAD"], cwd=target_dir) != "HEAD":
run([git, "pull", clone_url], cwd=target_dir)
if revision != None:
run([git, "checkout", revision], cwd=target_dir)
def build_dependency(name, mode, build_tool_args, download_url, download_name, download_tool=download_tool_default, revision=None, patch=None, additional_files={}, no_append_name=False):
"""Handles building of dependencies with different tools (which are
distinguished with the `mode` argument. `build_tool_args` is expected to be
a list which is necessary in order to not mess up quoting of compiler and
linker flags."""
check_dir = os.path.join(DEPS_DIR, "install", name)
if os.path.exists(check_dir):
logger.info( "Found existing %s, skipping" % (name,))
return
build_dir = os.path.join(DEPS_DIR, "build")
if not os.path.exists(build_dir):
os.makedirs(build_dir)
logger.info("\rFetching %s... " % (name,))
if download_tool == download_tool_py:
if no_append_name:
url = download_url
else:
url = os.path.join(download_url, download_name)
download_path = os.path.join(build_dir, download_name)
if not os.path.exists(download_path):
urlretrieve(url, os.path.join(build_dir, download_path))
else:
logger.info("Download '%s' already exists, assuming it's an undamaged download and that it has been extracted if possible, skipping" % (download_path,))
elif download_tool == download_tool_git:
logger.info("\rChecking %s... " % (name,))
git_clone_or_pull_repository(download_url, target_dir=os.path.join(build_dir, download_name), revision=revision)
else:
raise ValueError("download tool '%s' is not supported" % (download_tool,))
download_dir = os.path.join(build_dir, download_name)
if os.path.isdir(download_dir):
extract_dir_name=download_name
extract_dir = os.path.join(build_dir, extract_dir_name)
else:
download_tarfile_path = os.path.join(build_dir, download_name)
if download_name.endswith(".tar.gz") or download_name.endswith(".tgz"):
compr = "gz"
elif download_name.endswith(".tar.bz2"):
compr = "bz2"
else:
raise RuntimeError("fix source for new download type")
download_tarfile = tarfile.open(name=download_tarfile_path, mode="r:%s" % (compr,))
extract_dir_name= os.path.commonprefix(download_tarfile.getnames()) # tarfile seriously doesn't have a function to retrieve the root directory more easily
#run([tar, "--exclude=\"*/*\"", "-tf", download_name], cwd=build_dir).strip() no longer works
if extract_dir_name is None:
extract_dir_name= run([bash, "-c", "tar -tf %s 2> /dev/null | head -n 1 | cut -f1 -d /" % (download_name,)], cwd=build_dir)
extract_dir = os.path.join(build_dir, extract_dir_name)
if not os.path.exists(extract_dir):
run([tar, "-xf", download_name], cwd=build_dir)
for path, url in additional_files.items():
if not os.path.exists(path):
urlretrieve(url, os.path.join(extract_dir, path))
if patch is not None:
patch_abs = os.path.abspath(os.path.join(os.path.dirname(__file__), patch))
if os.path.exists(patch_abs):
try: run(["patch", "-p1", "--batch", "--forward", "-i", patch_abs], cwd=extract_dir)
except Exception as e:
# Assert that the patch has already been applied
run(["patch", "-p1", "--batch", "--reverse", "--dry-run", "-i", patch_abs], cwd=extract_dir)
if mode != "bjam":
extract_build_dir = os.path.join(extract_dir, "build")
if os.path.exists(extract_build_dir):
shutil.rmtree(extract_build_dir)
os.makedirs(extract_build_dir)
logger.info("\rConfiguring %s..." % (name,))
if mode == "autoconf":
run_autoconf(name, build_tool_args, cwd=extract_build_dir)
elif mode == "cmake":
run_cmake(name, build_tool_args, cwd=extract_build_dir)
else:
raise ValueError()
logger.info("\rBuilding %s... " % (name,))
run([make, "-j%s" % (IFCOS_NUM_BUILD_PROCS,), "VERBOSE=1"], cwd=extract_build_dir)
logger.info( "\rInstalling %s... " % (name,))
run([make, "install"], cwd=extract_build_dir)
logger.info( "\rInstalled %s \n" % (name,))
else:
logger.info( "\rConfiguring %s..." % (name,))
run([bash, "./bootstrap.sh"], cwd=extract_dir)
logger.info("\rBuilding %s... " % (name,))
run(["./b2", "-j%s" % (IFCOS_NUM_BUILD_PROCS,)]+build_tool_args, cwd=extract_dir)
logger.info("\rInstalling %s... " % (name,))
shutil.copytree(os.path.join(extract_dir, "boost"), os.path.join(DEPS_DIR, "install", "boost-%s" % BOOST_VERSION, "boost"))
logger.info("\rInstalled %s \n" % (name,))
cecho("Collecting dependencies:", GREEN)
# Set compiler flags for 32bit builds on 64bit system
# TODO: This is untested
ADDITIONAL_ARGS=[]
BOOST_ADDRESS_MODEL=[]
if TARGET_ARCH == "i686" and run([uname, "-m"]).strip() == "x86_64":
if get_os() == "Darwin":
ADDITIONAL_ARGS=["-m32", "-arch i386"]
else:
ADDITIONAL_ARGS=["-m32"]
BOOST_ADDRESS_MODEL=["architecture=x86", "address-model=32"]
if get_os() == "Darwin":
ADDITIONAL_ARGS=["-mmacosx-version-min=%s" % TOOLSET]+ADDITIONAL_ARGS
# If the linker supports GC sections, set it up to reduce binary file size
# -fPIC is required for the shared libraries to work
CXXFLAGS=os.environ.get("CXXFLAGS", "")
CFLAGS=os.environ.get("CFLAGS", "")
LDFLAGS=os.environ.get("LDFLAGS", "")
if sp.call([bash, "-c", "ld --gc-sections 2>&1 | grep -- --gc-sections &> /dev/null"]) != 0:
CXXFLAGS_MINIMAL="%s %s %s" % (CXXFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
CFLAGS_MINIMAL="%s %s %s" % (CFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
if BUILD_STATIC:
CXXFLAGS="%s %s -fdata-sections -ffunction-sections -fvisibility=hidden -fvisibility-inlines-hidden %s" % (CXXFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
CFLAGS="%s %s -fdata-sections -ffunction-sections -fvisibility=hidden %s"% (CFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
else:
CXXFLAGS=CXXFLAGS_MINIMAL
CFLAGS=CFLAGS_MINIMAL
LDFLAGS="%s -Wl,--gc-sections %s" % (LDFLAGS, str.join(" ", ADDITIONAL_ARGS))
else:
CXXFLAGS_MINIMAL="%s %s %s" % (CXXFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
CFLAGS_MINIMAL="%s %s %s" % (CFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
if BUILD_STATIC:
CXXFLAGS="%s %s -fvisibility=hidden -fvisibility-inlines-hidden %s" % (CXXFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
CFLAGS="%s %s -fvisibility=hidden -fvisibility-inlines-hidden %s" % (CFLAGS, PIC, str.join(" ", ADDITIONAL_ARGS))
else:
CXXFLAGS=CXXFLAGS_MINIMAL
CFLAGS=CFLAGS_MINIMAL
LDFLAGS="%s %s" % (LDFLAGS, str.join(" ", ADDITIONAL_ARGS))
os.environ["CXXFLAGS"] = CXXFLAGS
os.environ["CFLAGS"] = CFLAGS
os.environ["LDFLAGS"] = LDFLAGS
# Some dependencies need a more recent CMake version than most distros provide
# @tfk: this is no longer needed
# 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,))
if "json" in targets:
json_url = "https://github.com/nlohmann/json/releases/download/{JSON_VERSION}/json.hpp".format(**locals())
json_install_path = "{DEPS_DIR}/install/json/nlohmann/json.hpp".format(**locals())
if not os.path.exists(os.path.dirname(json_install_path)):
os.makedirs(os.path.dirname(json_install_path))
if not os.path.exists(json_install_path):
urlretrieve(json_url, json_install_path)
if "pcre" in targets:
build_dependency(
name="pcre-{PCRE_VERSION}".format(**locals()),
mode="autoconf",
build_tool_args=[DISABLE_FLAG],
download_url="https://downloads.sourceforge.net/project/pcre/pcre/{PCRE_VERSION}/".format(**locals()),
download_name="pcre-{PCRE_VERSION}.tar.bz2".format(**locals())
)
# An issue exists with swig-1.3 and python >= 3.2
# Therefore, build a recent copy from source
if "swig" in targets:
build_dependency(
name="swig",
mode="autoconf",
build_tool_args=["--disable-ccache", "--with-pcre-prefix={DEPS_DIR}/install/pcre-{PCRE_VERSION}".format(**locals())],
download_url="https://github.com/swig/swig.git",
download_name="swig",
download_tool=download_tool_git,
revision="rel-{SWIG_VERSION}".format(**locals())
)
if USE_OCCT and "occ" in targets:
build_dependency(
name="occt-{OCCT_VERSION}".format(**locals()),
mode="cmake",
build_tool_args=[
"-DINSTALL_DIR={DEPS_DIR}/install/occt-{OCCT_VERSION}".format(**locals()),
"-DBUILD_LIBRARY_TYPE={LINK_TYPE_UCFIRST}".format(**locals()),
"-DBUILD_MODULE_Draw=0",
"-DBUILD_RELEASE_DISABLE_EXCEPTIONS=Off"
],
download_url = "https://git.dev.opencascade.org/repos/occt.git",
download_name = "occt",
download_tool=download_tool_git,
patch=None if OCCT_VERSION >= "7.4" else "./patches/occt/enable-exception-handling.patch",
revision="V" + OCCT_VERSION.replace('.', '_')
)
elif "occ" in targets:
build_dependency(
name="oce-{OCE_VERSION}".format(**locals()),
mode="cmake",
build_tool_args=[
"-DOCE_DISABLE_TKSERVICE_FONT=ON",
"-DOCE_TESTING=OFF",
"-DOCE_BUILD_SHARED_LIB=OFF",
"-DOCE_DISABLE_X11=ON",
"-DOCE_VISUALISATION=OFF",
"-DOCE_OCAF=OFF",
"-DOCE_INSTALL_PREFIX={DEPS_DIR}/install/oce-{OCE_VERSION}".format(**locals())
],
download_url="https://github.com/tpaviot/oce/archive/",
download_name="OCE-{OCE_VERSION}.tar.gz".format(**locals())
)
if "libxml2" in targets:
build_dependency(
"libxml2-{LIBXML2_VERSION}".format(**locals()),
"autoconf",
build_tool_args=[
"--without-python",
ENABLE_FLAG,
DISABLE_FLAG,
"--without-zlib",
"--without-iconv",
"--without-lzma"
],
download_url="ftp://xmlsoft.org/libxml2/",
download_name="libxml2-{LIBXML2_VERSION}.tar.gz".format(**locals())
)
if "OpenCOLLADA" in targets:
build_dependency(
"OpenCOLLADA",
"cmake",
build_tool_args=[
"-DLIBXML2_INCLUDE_DIR={DEPS_DIR}/install/libxml2-{LIBXML2_VERSION}/include/libxml2".format(**locals()),
"-DLIBXML2_LIBRARIES={DEPS_DIR}/install/libxml2-{LIBXML2_VERSION}/lib/libxml2.{LIBRARY_EXT}".format(**locals()),
"-DPCRE_INCLUDE_DIR={DEPS_DIR}/install/pcre-{PCRE_VERSION}/include".format(**locals()),
"-DPCRE_PCREPOSIX_LIBRARY={DEPS_DIR}/install/pcre-{PCRE_VERSION}/lib/libpcreposix.{LIBRARY_EXT}".format(**locals()),
"-DPCRE_PCRE_LIBRARY={DEPS_DIR}/install/pcre-{PCRE_VERSION}/lib/libpcre.{LIBRARY_EXT}".format(**locals()),
"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/OpenCOLLADA/".format(**locals())
],
download_url="https://github.com/KhronosGroup/OpenCOLLADA.git",
download_name="OpenCOLLADA",
download_tool=download_tool_git,
patch="./patches/opencollada/pr622_and_disable_subdirs.patch",
revision=OPENCOLLADA_VERSION
)
if "python" in targets:
# Python should not be built with -fvisibility=hidden, from experience that introduces segfaults
OLD_CXX_FLAGS=os.environ["CXXFLAGS"]
OLD_C_FLAGS=os.environ["CFLAGS"]
os.environ["CXXFLAGS"]=CXXFLAGS_MINIMAL
os.environ["CFLAGS"]=CFLAGS_MINIMAL
# On OSX a dynamic python library is built or it would not be compatible
# with the system python because of some threading initialization
PYTHON_CONFIGURE_ARGS=[]
if get_os() == "Darwin":
PYTHON_CONFIGURE_ARGS=["--disable-static", "--enable-shared"]
def get_python_unicode_confs(py_ver):
if py_ver < "3.3":
return [("--enable-unicode=ucs2",""), ("--enable-unicode=ucs4","u")]
else: return [("","")]
def PYTHON_VERSION_CONFS():
for v in PYTHON_VERSIONS:
for unicode_conf, abi_tag in get_python_unicode_confs(v):
yield v, unicode_conf, abi_tag
for PYTHON_VERSION, unicode_conf, abi_tag in PYTHON_VERSION_CONFS():
try:
build_dependency(
"python-{PYTHON_VERSION}{abi_tag}".format(**locals()),
"autoconf",
PYTHON_CONFIGURE_ARGS + [unicode_conf],
"http://www.python.org/ftp/python/{PYTHON_VERSION}/".format(**locals()),
"Python-{PYTHON_VERSION}.tgz".format(**locals())
)
except Exception as e:
pyver2 = PYTHON_VERSION[:PYTHON_VERSION.rfind('.')]
if os.path.exists("{DEPS_DIR}/install/python-{PYTHON_VERSION}{abi_tag}/bin/python{pyver2}".format(**locals())):
print("Installation partially failed")
else: raise e
os.environ["CXXFLAGS"]=OLD_CXX_FLAGS
os.environ["CFLAGS"]=OLD_C_FLAGS
if "boost" in targets:
str_concat = lambda prefix: lambda postfix: "" if postfix.strip() == "" else "=".join((prefix, postfix.strip()))
build_dependency(
"boost-{BOOST_VERSION}".format(**locals()),
mode="bjam",
build_tool_args=[
"--stagedir={DEPS_DIR}/install/boost-{BOOST_VERSION}".format(**locals()),
"--with-system",
"--with-program_options",
"--with-regex",
"--with-thread",
"--with-date_time",
"--with-iostreams",
"link={LINK_TYPE}".format(**locals())
] + \
BOOST_ADDRESS_MODEL + \
list(map(str_concat("cxxflags"), CXXFLAGS.strip().split(' '))) + \
list(map(str_concat("linkflags"), LDFLAGS.strip().split(' '))) + \
["stage", "-s", "NO_BZIP2=1"],
download_url=BOOST_LOCATION,
download_name="boost_{BOOST_VERSION_UNDERSCORE}.tar.bz2".format(**locals())
)
cecho("Building IfcOpenShell:", GREEN)
IFCOS_DIR=os.path.join(DEPS_DIR, "build", "ifcopenshell")
if os.path.exists(IFCOS_DIR):
shutil.rmtree(IFCOS_DIR)
os.makedirs(IFCOS_DIR)
executables_dir = os.path.join(IFCOS_DIR, "executables")
if not os.path.exists(executables_dir):
os.makedirs(executables_dir)
logger.info("\rConfiguring executables...")
OFF_ON = ["OFF", "ON"]
cmake_args=[
"-DUSE_MMAP=" "OFF",
"-DBUILD_EXAMPLES=" "OFF",
"-DBUILD_IFCPYTHON=" "OFF",
"-DBUILD_SHARED_LIBS=" +OFF_ON[not BUILD_STATIC],
"-DBUILD_IFCGEOM=" +OFF_ON["IfcGeom" in targets],
"-DBUILD_GEOMSERVER=" +OFF_ON["IfcGeomServer" in targets],
"-DBUILD_CONVERT=" +OFF_ON["IfcConvert" in targets],
"-DCMAKE_INSTALL_PREFIX=" "{DEPS_DIR}/install/ifcopenshell".format(**locals()),
"-DBOOST_ROOT=" "{DEPS_DIR}/install/boost-{BOOST_VERSION}".format(**locals()),
"-DGLTF_SUPPORT=" "ON",
"-DJSON_INCLUDE_DIR=" "{DEPS_DIR}/install/json".format(**locals()),
"-DBoost_NO_BOOST_CMAKE=" "On"
]
if "occ" in targets and USE_OCCT:
occ_include_dir = "{DEPS_DIR}/install/occt-{OCCT_VERSION}/include/opencascade".format(**locals())
occ_library_dir = "{DEPS_DIR}/install/occt-{OCCT_VERSION}/lib".format(**locals())
cmake_args.extend([
"-DOCC_INCLUDE_DIR=" +occ_include_dir,
"-DOCC_LIBRARY_DIR=" +occ_library_dir
])
elif "occ" in targets:
occ_include_dir = "{DEPS_DIR}/install/oce-{OCE_VERSION}/include/oce".format(**locals())
occ_library_dir = "{DEPS_DIR}/install/oce-{OCE_VERSION}/lib"
cmake_args.extend([
"-DOCC_INCLUDE_DIR=" +occ_include_dir,
"-DOCC_LIBRARY_DIR=" +occ_library_dir
])
if "OpenCOLLADA" in targets:
cmake_args.extend([
"-DOPENCOLLADA_INCLUDE_DIR=" "{DEPS_DIR}/install/OpenCOLLADA/include/opencollada".format(**locals()),
"-DOPENCOLLADA_LIBRARY_DIR=" "{DEPS_DIR}/install/OpenCOLLADA/lib/opencollada".format(**locals())
])
if "pcre" in targets:
cmake_args.append(
"-DPCRE_LIBRARY_DIR=" "{DEPS_DIR}/install/pcre-{PCRE_VERSION}/lib".format(**locals())
)
if "libxml2" in targets:
cmake_args.extend([
"-DLIBXML2_INCLUDE_DIR=" "{DEPS_DIR}/install/libxml2-{LIBXML2_VERSION}/include/libxml2".format(**locals()),
"-DLIBXML2_LIBRARIES=" "{DEPS_DIR}/install/libxml2-{LIBXML2_VERSION}/lib/libxml2.{LIBRARY_EXT}".format(**locals())
])
run_cmake("", cmake_args, cmake_dir=CMAKE_DIR, cwd=executables_dir)
logger.info("\rBuilding executables... ")
run([make, "-j{IFCOS_NUM_BUILD_PROCS}".format(**locals())], cwd=executables_dir)
run([make, "install/strip" if BUILD_CFG == "Release" else "install"], cwd=executables_dir)
if "IfcOpenShell-Python" in targets:
# On OSX the actual Python library is not linked against.
ADDITIONAL_ARGS=""
if get_os() == "Darwin":
ADDITIONAL_ARGS="-Wl,-flat_namespace,-undefined,suppress"
os.environ["CXXFLAGS"]="%s %s" % (CXXFLAGS_MINIMAL, ADDITIONAL_ARGS)
os.environ["CFLAGS"]="%s %s" % (CFLAGS_MINIMAL, ADDITIONAL_ARGS)
os.environ["LDFLAGS"]="%s %s" % (LDFLAGS, ADDITIONAL_ARGS)
for PYTHON_VERSION, _, TAG in PYTHON_VERSION_CONFS():
logger.info("\rConfiguring python {PYTHON_VERSION}{TAG} wrapper...".format(**locals()))
# python_dir = os.path.join(IFCOS_DIR, "python-{PYTHON_VERSION}{TAG}".format(**locals()))
python_dir = os.path.join(IFCOS_DIR, "pythonwrapper")
if not os.path.exists(python_dir):
os.makedirs(python_dir)
cache_path = os.path.join(python_dir, "CMakeCache.txt")
if os.path.exists(cache_path):
os.unlink(cache_path)
PYTHON_LIBRARY=run([bash, "-c", "ls {DEPS_DIR}/install/python-{PYTHON_VERSION}{TAG}/lib/libpython*.*".format(**locals())])
PYTHON_INCLUDE=run([bash, "-c", "ls -d {DEPS_DIR}/install/python-{PYTHON_VERSION}{TAG}/include/python*".format(**locals())])
PYTHON_EXECUTABLE=os.path.join(DEPS_DIR, "install", "python-{PYTHON_VERSION}{TAG}".format(**locals()), "bin", "python{PYTHON_VERSION[0]}".format(**locals()))
os.environ["PYTHON_LIBRARY_BASENAME"]=os.path.basename(PYTHON_LIBRARY)
run_cmake("",
cmake_args=[
"-DBUILD_SHARED_LIBS=" "OFF" if BUILD_STATIC else "ON",
"-DBOOST_ROOT=" "{DEPS_DIR}/install/boost-{BOOST_VERSION}".format(**locals()),
"-DOCC_INCLUDE_DIR=" +occ_include_dir,
"-DOCC_LIBRARY_DIR=" +occ_library_dir,
"-DPYTHON_LIBRARY=" +PYTHON_LIBRARY,
"-DPYTHON_EXECUTABLE=" +PYTHON_EXECUTABLE,
"-DPYTHON_INCLUDE_DIR=" +PYTHON_INCLUDE,
"-DSWIG_EXECUTABLE=" "{DEPS_DIR}/install/swig/bin/swig".format(**locals()),
"-DCMAKE_INSTALL_PREFIX=" "{DEPS_DIR}/install/ifcopenshell/tmp".format(**locals()),
"-DLIBXML2_INCLUDE_DIR=" "{DEPS_DIR}/install/libxml2-{LIBXML2_VERSION}/include/libxml2".format(**locals()),
"-DLIBXML2_LIBRARIES=" "{DEPS_DIR}/install/libxml2-{LIBXML2_VERSION}/lib/libxml2.{LIBRARY_EXT}".format(**locals()),
"-DCOLLADA_SUPPORT=OFF"
], cmake_dir=CMAKE_DIR, cwd=python_dir)
logger.info("\rBuilding python %s%s wrapper... " % (PYTHON_VERSION, TAG))
run([make, "-j%s" % (IFCOS_NUM_BUILD_PROCS,), "_ifcopenshell_wrapper"], cwd=python_dir)
run([make, "install/local"], cwd=os.path.join(python_dir, "ifcwrap"))
module_dir = os.path.dirname(run([PYTHON_EXECUTABLE, "-c", "from __future__ import print_function; import inspect, ifcopenshell; print(inspect.getfile(ifcopenshell))"]))
if get_os() != "Darwin":
# TODO: This symbol name depends on the Python version?
run([strip, "-s", "-K", "PyInit__ifcopenshell_wrapper", "_ifcopenshell_wrapper.so"], cwd=module_dir)
run([cp, "-R", module_dir, os.path.join(DEPS_DIR, "install", "ifcopenshell", "python-%s%s" % (PYTHON_VERSION, TAG))])
logger.info("\rBuilt IfcOpenShell...\n\n")
+372
View File
@@ -0,0 +1,372 @@
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
###############################################################################
# #
# This script builds IfcOpenShell and its dependencies #
# #
# Prerequisites for this script to function correctly: #
# * git * bzip2 * tar * c(++) compilers * yacc * autoconf #
# on debian 7.8 these can be obtained with: #
# $ apt-get install git bzip2 bizon autoconf gcc g++ #
# #
###############################################################################
set -e
PROJECT_NAME=IfcOpenShell
OCE_VERSION=0.16
PYTHON_VERSIONS=(2.7.9 3.3.6 3.4.2)
BOOST_VERSION=1.55.0
PCRE_VERSION=8.38
LIBXML_VERSION=2.9.3
CMAKE_VERSION=3.4.1
ICU_VERSION=56.1
# Helper function for coloured printing
BLACK_ON_WHITE="\033[0;30;107m"
RED="\033[31m"
GREEN="\033[32m"
YELLOW="\033[33m"
MAGENTA="\033[35m"
function cecho {
printf "$1$2\033[0m\n"
}
# Set defaults for missing empty environment variables
if [ -z "$IFCOS_NUM_BUILD_PROCS" ]; then
IFCOS_NUM_BUILD_PROCS=$(expr $(sysctl -n hw.ncpu 2> /dev/null || cat /proc/cpuinfo | grep processor | wc -l) + 1)
fi
if [ -z "$TARGET_ARCH" ]; then
TARGET_ARCH="$(uname -m)"
fi
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
CMAKE_DIR="$SCRIPT_DIR/../../cmake/"
if [ -z "$DEPS_DIR" ]; then
DEPS_DIR="$SCRIPT_DIR/../../build/$(uname)/"
[ -d $DEPS_DIR ] || mkdir -p $DEPS_DIR
DEPS_DIR=`readlink -f $DEPS_DIR`
fi
if [ -z "$BUILD_CFG" ]; then
BUILD_CFG="RelWithDebInfo"
fi
if [ -z "$BUILD_TYPE" ]; then
BUILD_TYPE=Build
fi
# Print build configuration information
cecho $BLACK_ON_WHITE "This script fetches and builds $PROJECT_NAME and its dependencies"
echo ""
cecho $GREEN "Script configuration:"
cecho $MAGENTA "* Target Architecture = $TARGET_ARCH"
echo " - Whether 32-bit (i686) or 64-bit (x86_64) will be built."
cecho $MAGENTA "* Dependency Directory = $DEPS_DIR"
echo " - The directory where $PROJECT_NAME dependencies are installed."
cecho $MAGENTA "* Build Config Type = $BUILD_CFG"
echo " - The used build configuration type for the dependencies."
echo " Defaults to RelWithDebInfo if not specified."
if [ "$BUILD_CFG" = "MinSizeRel" ]; then
cecho $RED " WARNING: MinSizeRel build can suffer from a significant performance loss."
fi
cecho $MAGENTA "* IFCOS_NUM_BUILD_PROCS = $IFCOS_NUM_BUILD_PROCS"
echo " - How many compiler processes may be run in parallel."
echo ""
# Check that required tools are in PATH
for cmd in git bunzip2 tar cc c++ autoconf yacc
do
which $cmd > /dev/null || { cecho $RED "Required tool '$cmd' not installed or not added to PATH" ; exit 1 ; }
done
which curl > /dev/null && DOWNLOAD="curl -sLO"
which wget > /dev/null && DOWNLOAD="wget -q --no-check-certificate"
if [ -z "$DOWNLOAD" ]; then
cecho $RED "No download application found, tried: curl, wget"
exit 1
fi
# Create log directory and file
mkdir -p $DEPS_DIR/logs
LOG_FILE=$DEPS_DIR/logs/`date +"%Y%m%d"`.log
BOOST_VERSION_UNDERSCORE=${BOOST_VERSION//./_}
ICU_VERSION_UNDERSCORE=${ICU_VERSION//./_}
CMAKE_VERSION_2=${CMAKE_VERSION:0:3}
OCE_LOCATION=https://github.com/tpaviot/oce/archive/OCE-$OCE_VERSION.tar.gz
BOOST_LOCATION=http://downloads.sourceforge.net/project/boost/boost/$BOOST_VERSION/boost_$BOOST_VERSION_UNDERSCORE.tar.bz2
OPENCOLLADA_LOCATION=https://github.com/KhronosGroup/OpenCOLLADA.git
OPENCOLLADA_COMMIT=f99d59e73e565a41715eaebc00c7664e1ee5e628
# Helper functions
function download {
[ -f $2 ] || $DOWNLOAD $1$2
}
function run_autoconf {
if [ ! -f configure ]; then
pushd . >>$LOG_FILE 2>&1
cd ..
./autogen.sh >>$LOG_FILE 2>&1
popd >>$LOG_FILE 2>&1
fi
../configure $2 --prefix=$DEPS_DIR/install/$1 >>$LOG_FILE 2>&1
}
function run_cmake {
if [ -z "$3" ]; then
P=..
else
P=$3
fi
$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake $P $2 -DCMAKE_BUILD_TYPE=$BUILD_TYPE >>$LOG_FILE 2>&1
}
function run_icu {
PLATFORM=`uname -s`
if [ $PLATFORM == "Darwin" ]; then
PLATFORM=MacOSX
fi
../source/runConfigureICU $PLATFORM $2 --prefix=$DEPS_DIR/install/$1 >>$LOG_FILE 2>&1
}
function git_clone {
[ -d $2 ] || git clone $1 >>$LOG_FILE 2>&1
if [ ! -z "$3" ]; then
cd $2
git checkout $3
cd ..
fi
}
function build_dependency {
if [ -e $DEPS_DIR/install/$1 ]; then
echo "Found existing $1"
return
fi
mkdir -p $DEPS_DIR/build/
cd $DEPS_DIR/build/
printf "\rFetching $1... "
$6 $4 $5 $7
if [ -d $5 ]; then
DEP_NAME=$5
else
DEP_NAME=`tar --exclude="*/*" -tf $5`
[ -z $DEP_NAME ] && DEP_NAME=`tar -tf $5 2> /dev/null | head -n 1 | cut -f1 -d /`
[ -d $DEP_NAME ] || tar -xf $5
fi
cd $DEP_NAME
if [ "$2" != "bjam" ]; then
[ -d build ] && rm -rf build
mkdir build
cd build
printf "\rConfiguring $1..."
run_$2 $1 "$3"
printf "\rBuilding $1... "
make -j$IFCOS_NUM_BUILD_PROCS >>$LOG_FILE 2>&1
printf "\rInstalling $1... "
make install >>$LOG_FILE 2>&1
printf "\rInstalled $1 \n"
else
printf "\rConfiguring $1..."
./bootstrap.sh >>$LOG_FILE 2>&1
printf "\rBuilding $1... "
./b2 $3 >>$LOG_FILE 2>&1
printf "\rInstalling $1... "
cp -R boost $DEPS_DIR/install/boost-$BOOST_VERSION/ >>$LOG_FILE 2>&1
printf "\rInstalled $1 \n"
fi
}
cecho $GREEN "Collecting dependencies:"
# Set compiler flags for 32bit builds on 64bit system
if [ "$TARGET_ARCH" == "i686" ] && [ "$(uname -m)" == "x86_64" ]; then
ADDITIONAL_ARGS="-m32 -arch i386"
fi
if [ "$(uname)" == "Darwin" ]; then
ADDITIONAL_ARGS="-macosx_version_min 10.6 $ADDITIONAL_ARGS"
fi
# If the linker supports GC sections, set it up to reduce binary file size
# -fPIC is required for the shared libraries to work
if man ld 2> /dev/null | grep gc-sections &> /dev/null; then
export CXXFLAGS="$CXXFLAGS -fPIC -fdata-sections -ffunction-sections -fvisibility=hidden -fvisibility-inlines-hidden $ADDITIONAL_ARGS"
export CFLAGS="$CFLAGS -fPIC -fdata-sections -ffunction-sections -fvisibility=hidden $ADDITIONAL_ARGS"
export LDFLAGS="$LDFLAGS -Wl,--gc-sections $ADDITIONAL_ARGS"
export CXXFLAGS_MINIMAL="$CXXFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
export CFLAGS_MINIMAL="$CFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
else
export CXXFLAGS="$CXXFLAGS -fPIC -fvisibility=hidden -fvisibility-inlines-hidden $ADDITIONAL_ARGS"
export CFLAGS="$CFLAGS -fPIC -fvisibility=hidden -fvisibility-inlines-hidden $ADDITIONAL_ARGS"
export LDFLAGS="$LDFLAGS -s -death_code $ADDITIONAL_ARGS"
export CXXFLAGS_MINIMAL="$CXXFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
export CFLAGS_MINIMAL="$CFLAGS_MINIMAL -fPIC $ADDITIONAL_ARGS"
fi
# Some dependencies need a more recent CMake version than most distros provide
build_dependency cmake-$CMAKE_VERSION autoconf "" https://cmake.org/files/v$CMAKE_VERSION_2/ cmake-$CMAKE_VERSION.tar.gz download
# Extract compiler flags from CMake to harmonize settings with other autoconf dependencies
CMAKE_FLAG_EXTRACT_DIR=ifcopenshell_cmake_test_`cat /dev/urandom | env LC_CTYPE=C tr -dc 'a-zA-Z0-9' | head -c 32`
[ -e $CMAKE_FLAG_EXTRACT_DIR ] && rm -rf $CMAKE_FLAG_EXTRACT_DIR
mkdir $CMAKE_FLAG_EXTRACT_DIR
cd $CMAKE_FLAG_EXTRACT_DIR
BUILD_CFG_UPPER=${BUILD_CFG^^}
for FL in C CXX LD; do
echo "
message(\"\${CMAKE_${FL}_FLAGS_${BUILD_CFG_UPPER}}\")
" > CMakeLists.txt
declare ${FL}FLAGS="`$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake . 2>&1 >/dev/null`"
declare ${FL}FLAGS_MINIMAL="`$DEPS_DIR/install/cmake-$CMAKE_VERSION/bin/cmake . 2>&1 >/dev/null`"
done
cd ..
rm -rf $CMAKE_FLAG_EXTRACT_DIR
build_dependency pcre-$PCRE_VERSION autoconf "--disable-shared" ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ pcre-$PCRE_VERSION.tar.bz2 download
# An issue exists with swig-1.3 and python >= 3.2
# Therefore, build a recent copy from source
build_dependency swig autoconf "--with-pcre-prefix=$DEPS_DIR/install/pcre-$PCRE_VERSION" https://github.com/swig/swig.git swig git_clone rel-3.0.8
build_dependency oce-$OCE_VERSION cmake "-DOCE_DISABLE_TKSERVICE_FONT=ON -DOCE_TESTING=OFF -DOCE_BUILD_SHARED_LIB=OFF -DOCE_DISABLE_X11=ON -DOCE_VISUALISATION=OFF -DOCE_OCAF=OFF -DOCE_INSTALL_PREFIX=$DEPS_DIR/install/oce-$OCE_VERSION/" https://github.com/tpaviot/oce/archive/ OCE-$OCE_VERSION.tar.gz download
build_dependency libxml2-$LIBXML_VERSION autoconf "--without-python --disable-shared" ftp://xmlsoft.org/libxml2/ libxml2-$LIBXML_VERSION.tar.gz download
build_dependency OpenCOLLADA cmake "
-DLIBXML2_INCLUDE_DIR=$DEPS_DIR/install/libxml2-$LIBXML_VERSION/include/libxml2
-DLIBXML2_LIBRARIES=$DEPS_DIR/install/libxml2-$LIBXML_VERSION/lib/libxml2.a
-DPCRE_INCLUDE_DIR=$DEPS_DIR/install/pcre-$PCRE_VERSION/include
-DPCRE_PCREPOSIX_LIBRARY=$DEPS_DIR/install/pcre-$PCRE_VERSION/lib/libpcreposix.a
-DPCRE_PCRE_LIBRARY=$DEPS_DIR/install/pcre-$PCRE_VERSION/lib/libpcre.a
-DCMAKE_INSTALL_PREFIX=$DEPS_DIR/install/OpenCOLLADA/" https://github.com/KhronosGroup/OpenCOLLADA.git OpenCOLLADA git_clone
# Python should not be built with -fvisibility=hidden, from experience that introduces segfaults
OLD_CXX_FLAGS=$CXXFLAGS
OLD_C_FLAGS=$CFLAGS
OLD_LD_FLAGS=$LDFLAGS
export CXXFLAGS=$CXXFLAGS_MINIMAL
export CFLAGS=$CFLAGS_MINIMAL
export LDFLAGS=$LDFLAGS_MINIMAL
for PYTHON_VERSION in "${PYTHON_VERSIONS[@]}"; do
build_dependency python-$PYTHON_VERSION autoconf "" http://www.python.org/ftp/python/$PYTHON_VERSION/ Python-$PYTHON_VERSION.tgz download
done
export CXXFLAGS=$OLD_CXX_FLAGS
export CFLAGS=$OLD_C_FLAGS
export LDFLAGS=$OLD_LD_FLAGS
if [ "$(uname)" == "Darwin" ] && [ "$1" == "32" ]; then
BOOST_ADDRESS_MODEL="toolset=darwin architecture=x86 target-os=darwin address-model=32"
fi
build_dependency boost-$BOOST_VERSION bjam "--stagedir=$DEPS_DIR/install/boost-$BOOST_VERSION --with-program_options link=static $BOOST_ADDRESS_MODEL stage" http://downloads.sourceforge.net/project/boost/boost/$BOOST_VERSION/ boost_$BOOST_VERSION_UNDERSCORE.tar.bz2 download
build_dependency icu-$ICU_VERSION icu "--enable-static --disable-shared" http://download.icu-project.org/files/icu4c/$ICU_VERSION/ icu4c-${ICU_VERSION_UNDERSCORE}-src.tgz download
cecho $GREEN "Building IfcOpenShell:"
IFCOS_DIR=$DEPS_DIR/build/ifcopenshell
[ -d $IFCOS_DIR ] && rm -rf $IFCOS_DIR
mkdir -p $IFCOS_DIR
cd $IFCOS_DIR
mkdir -p executables
cd executables
printf "\rConfiguring executables..."
run_cmake "" "
-DBOOST_ROOT=$DEPS_DIR/install/boost-$BOOST_VERSION
-DOCC_INCLUDE_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/include/oce
-DOCC_LIBRARY_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/lib
-DOPENCOLLADA_INCLUDE_DIR=$DEPS_DIR/install/OpenCOLLADA/include/opencollada
-DOPENCOLLADA_LIBRARY_DIR=$DEPS_DIR/install/OpenCOLLADA/lib/opencollada
-DICU_INCLUDE_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/include
-DICU_LIBRARY_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/lib
-DPCRE_LIBRARY_DIR=$DEPS_DIR/install/pcre-$PCRE_VERSION/lib
-DBUILD_IFCPYTHON=OFF
" $CMAKE_DIR
printf "\rBuilding executables... "
make -j$IFCOS_NUM_BUILD_PROCS >>$LOG_FILE 2>&1
strip -s IfcConvert IfcGeomServer
cd ..
for PYTHON_VERSION in "${PYTHON_VERSIONS[@]}"; do
printf "\rConfiguring python $PYTHON_VERSION wrapper..."
mkdir -p python-$PYTHON_VERSION
cd python-$PYTHON_VERSION
PYTHON_LIBRARY=`ls $DEPS_DIR/install/python-$PYTHON_VERSION/lib/libpython*.a`
PYTHON_INCLUDE=`ls -d $DEPS_DIR/install/python-$PYTHON_VERSION/include/python*`
PYTHON_EXECUTABLE=$DEPS_DIR/install/python-$PYTHON_VERSION/bin/python
export PYTHON_LIBRARY_BASENAME=`basename $PYTHON_LIBRARY`
run_cmake "" "
-DBOOST_ROOT=$DEPS_DIR/install/boost-$BOOST_VERSION
-DOCC_INCLUDE_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/include/oce
-DOCC_LIBRARY_DIR=$DEPS_DIR/install/oce-$OCE_VERSION/lib
-DOPENCOLLADA_INCLUDE_DIR=$DEPS_DIR/install/OpenCOLLADA/include/opencollada
-DOPENCOLLADA_LIBRARY_DIR=$DEPS_DIR/install/OpenCOLLADA/lib/opencollada
-DICU_INCLUDE_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/include
-DICU_LIBRARY_DIR=$DEPS_DIR/install/icu-$ICU_VERSION/lib
-DPYTHON_LIBRARY=$PYTHON_LIBRARY
-DPYTHON_EXECUTABLE=$PYTHON_EXECUTABLE
-DPYTHON_INCLUDE_DIR=$PYTHON_INCLUDE
-DSWIG_EXECUTABLE=$DEPS_DIR/install/swig/bin/swig
" $CMAKE_DIR
# This still needs to be tested
# test "$(uname)" == "Darwin" && sed -i~ "s/-o/-flat_namespace -undefined suppress -o/" ifcwrap/CMakeFiles/_ifcopenshell_wrapper.dir/link.txt
printf "\rBuilding python $PYTHON_VERSION wrapper... "
make -j$IFCOS_NUM_BUILD_PROCS _ifcopenshell_wrapper >>$LOG_FILE 2>&1
strip -s \
-K PyInit__ifcopenshell_wrapper \
ifcwrap/_ifcopenshell_wrapper.so
done
printf "\rBuilt IfcOpenShell... \n\n"
-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);
}
@@ -1,17 +0,0 @@
Description: Enable exception handling
Upstream defaults to no exception handling for performance reasons,
but in OCCT's role as a shared library it's better for Debian to
enable it.
Author: Kurt Kremitzki <kkremitzki@gmail.com>
Last-Update: 2018-06-10
--- a/adm/cmake/occt_defs_flags.cmake
+++ b/adm/cmake/occt_defs_flags.cmake
@@ -138,5 +138,5 @@
set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s")
endif()
-set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNo_Exception")
-set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNo_Exception")
+#set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNo_Exception")
+#set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNo_Exception")
@@ -1,29 +0,0 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 95abbe21..293c951c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -284,10 +284,10 @@ add_subdirectory(COLLADASaxFrameworkLoader)
add_subdirectory(COLLADAStreamWriter)
# building COLLADAValidator app
-add_subdirectory(COLLADAValidator)
+# add_subdirectory(COLLADAValidator)
# DAE validator app
-add_subdirectory(DAEValidator)
+# add_subdirectory(DAEValidator)
# Library export
install(EXPORT LibraryExport DESTINATION ${OPENCOLLADA_INST_CMAKECONFIG} FILE OpenCOLLADATargets.cmake)
diff --git a/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp b/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp
index 1f9a3eef..dd6f5c59 100644
--- a/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp
+++ b/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp
@@ -10,6 +10,7 @@
#include "GeneratedSaxParserUtils.h"
#include <math.h>
+#include <cmath>
#include <memory>
#include <string.h>
#include <limits>
-22
View File
@@ -1,22 +0,0 @@
From a0deb4ce8b43cf3c8b8c0a4225c6be5296446dbd Mon Sep 17 00:00:00 2001
From: Adam Eri <adam.eri@blackmirror.media>
Date: Tue, 3 Sep 2019 23:30:20 +0200
Subject: [PATCH] Resolves compile error on macOS
Resolves "no member named 'isnan' in namespace 'std'" on macOS
---
GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp b/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp
index 1f9a3eef..dd6f5c59 100644
--- a/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp
+++ b/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp
@@ -10,6 +10,7 @@
#include "GeneratedSaxParserUtils.h"
#include <math.h>
+#include <cmath>
#include <memory>
#include <string.h>
#include <limits>
-2
View File
@@ -1,2 +0,0 @@
[tool.black]
line-length = 120
-64
View File
@@ -1,64 +0,0 @@
# ****************************************************************************
# line endings
# to suppress line ending changes in github, add ?w=1 at link end of a diff
# for more information see
# FreeCAD source code src/Mod/.gitattributes
# FreeCAD forum topic https://forum.freecadweb.org/viewtopic.php?f=17&t=41117
# FreeCAD pull request https://github.com/FreeCAD/FreeCAD/pull/2752
# get all used file types
# in a directory in a bash use
# find . -type f -name '*.*' | sed 's|.*\.||' | sort -u
# search for a specific file ending
# find . -type f -name '*.ico'
# normalize the line endings of the following files
*.cpp text
*.css text
*.csv text
*.feature text
*.gitattributes text
*.gitignore text
*.gitkeep
*.h text
*.html text
*.ifc text
*.json text
*.md text
*.po text
*.pot text
*.py text
*.txt text
# files not normalized ATM
# bat
# bnf
# blend
# i
# ico
# mo
# mpass
# png
# pth
# pyc
# rst
# svg
# ttf
# xsd
# line endings of all directories will be normalized
# to exclude a directory from being normalized add it here
# example: to exclude dirctory ifcbimtester use the following line without #
# ifcbimtester/** -text
# use git to manually correct the file endings
# git add --renormalize .
-59
View File
@@ -1,59 +0,0 @@
# bcf
A simple Python implementation of BCF. The data model is described in `data.py`.
Manipulation of BCF-XML is available via `bcfxml.py` and manipulation of BCF-API
is available via `bcfapi.py`.
Currently supports BCF version 2.1.
## bcfxml
The `bcfxml` module lets you interact with the BCF-XML standard.
```
from bcf.bcfxml import BcfXml
bcfxml = BcfXml()
# Load a project
project = bcfxml.get_project("/path/to/file.bcf")
# The project is also stored in the module
# project == bcfxml.project
print(project.name)
# To edit a project, just modify the object directly
bcfxml.project.name = "New name"
bcfxml.edit_project()
# The BCF file is extracted to this temporary directory
print(bcfxml.filepath)
# Get a dictionary of topics
topics = bcfxml.get_topics()
# Note: topics == bcfxml.topics
for guid, topic in bcfxml.topics.items():
print("Topic guid is", guid)
print("Topic guid is", topic.guid)
print("Topic title is", topic.title)
# Fetch extra data about a topic
header = bcfxml.get_header(guid)
comments = bcfxml.get_comments(guid)
viewpoints = bcfxml.get_viewpoints(guid)
# Note: comments == topic.comments, and so on
for comment_guid, comment in comments.items():
print(comment_guid)
print(comment.comment)
print(comment.author)
# Get a particular topic
topic = bcfxml.get_topic(guid)
# Modify a topic
topic.title = "New title"
bcfxml.edit_topic(topic)
```
-762
View File
@@ -1,762 +0,0 @@
import os
import uuid
import shutil
import zipfile
import logging
import tempfile
import bcf.data
from datetime import datetime
from xml.dom import minidom
from xmlschema import XMLSchema
from contextlib import contextmanager
from shutil import copyfile
cwd = os.path.dirname(os.path.realpath(__file__))
@contextmanager
def cd(newdir):
prevdir = os.getcwd()
os.chdir(os.path.expanduser(newdir))
try:
yield
finally:
os.chdir(prevdir)
class BcfXml:
def __init__(self):
self.filepath = None
self.logger = logging.getLogger("bcfxml")
self.author = "john@doe.com"
self.project = bcf.data.Project()
self.version = "2.1"
self.topics = {}
def new_project(self):
self.project.project_id = str(uuid.uuid4())
self.project.name = "New Project"
self.topics = {}
if self.filepath:
self.close_project()
self.filepath = tempfile.mkdtemp()
self.edit_project()
self.edit_version()
def get_project(self, filepath=None):
if not filepath:
return self.project
zip_file = zipfile.ZipFile(filepath)
self.filepath = tempfile.mkdtemp()
zip_file.extractall(self.filepath)
data = self._read_xml("project.bcfp", "project.xsd")
self.project.project_id = data["Project"]["@ProjectId"]
self.project.name = data["Project"]["Name"]
return self.project
def edit_project(self):
self.document = minidom.Document()
root = self._create_element(self.document, "ProjectExtension")
project = self._create_element(root, "Project", {"ProjectId": self.project.project_id})
self._create_element(project, "Name", text=self.project.name)
self._create_element(root, "ExtensionSchema", text="extensions.xsd")
with open(os.path.join(self.filepath, "project.bcfp"), "wb") as f:
f.write(self.document.toprettyxml(encoding="utf-8"))
def save_project(self, filepath):
with cd(self.filepath):
zip_file = zipfile.ZipFile(filepath, "w", zipfile.ZIP_DEFLATED)
for root, dirs, files in os.walk("./"):
for file in files:
zip_file.write(os.path.join(root, file))
zip_file.close()
def get_version(self):
data = self._read_xml("bcf.version", "version.xsd")
self.version = data["@VersionId"]
return self.version
def edit_version(self):
self.document = minidom.Document()
root = self._create_element(self.document, "Version", {"VersionId": self.version})
version = self._create_element(root, "DetailedVersion", text=self.version)
with open(os.path.join(self.filepath, "bcf.version"), "wb") as f:
f.write(self.document.toprettyxml(encoding="utf-8"))
def get_topics(self):
self.topics = {}
topics = []
subdirs = []
for (dirpath, dirnames, filenames) in os.walk(self.filepath):
subdirs = dirnames
break
for subdir in subdirs:
self.topics[subdir] = self.get_topic(subdir)
return self.topics
def get_header(self, guid):
data = self._read_xml(os.path.join(guid, "markup.bcf"), "markup.xsd")
if "Header" not in data:
return
header = bcf.data.Header()
for item in data["Header"]["File"]:
header_file = bcf.data.HeaderFile()
optional_keys = {
"filename": "Filename",
"date": "Date",
"reference": "Reference",
"ifc_project": "@IfcProject",
"ifc_spatial_structure_element": "@IfcSpatialStructureElement",
"is_external": "@isExternal",
}
for key, value in optional_keys.items():
if value in item:
setattr(header_file, key, item[value])
header.files.append(header_file)
self.topics[guid].header = header
return header
def get_topic(self, guid):
if guid in self.topics:
return self.topics[guid]
data = self._read_xml(os.path.join(guid, "markup.bcf"), "markup.xsd")
topic = bcf.data.Topic()
self.topics[guid] = topic
mandatory_keys = {
"guid": "@Guid",
"title": "Title",
"creation_date": "CreationDate",
"creation_author": "CreationAuthor",
}
for key, value in mandatory_keys.items():
setattr(topic, key, data["Topic"][value])
optional_keys = {
"priority": "Priority",
"index": "Index",
"labels": "Labels",
"reference_links": "ReferenceLink",
"modified_date": "ModifiedDate",
"modified_author": "ModifiedAuthor",
"due_date": "DueDate",
"assigned_to": "AssignedTo",
"stage": "Stage",
"description": "Description",
"topic_status": "@TopicStatus",
"topic_type": "@TopicType",
}
for key, value in optional_keys.items():
if value in data["Topic"]:
setattr(topic, key, data["Topic"][value])
if "BimSnippet" in data["Topic"]:
bim_snippet = bcf.data.BimSnippet()
keys = {
"snippet_type": "@SnippetType",
"is_external": "@IsExternal",
"reference": "Reference",
"reference_schema": "ReferenceSchema",
}
for key, value in keys.items():
if value in data["Topic"]["BimSnippet"]:
setattr(bim_snippet, key, data["Topic"]["BimSnippet"][value])
topic.bim_snippet = bim_snippet
if "DocumentReference" in data["Topic"]:
for item in data["Topic"]["DocumentReference"]:
document_reference = bcf.data.DocumentReference()
keys = {
"referenced_document": "ReferencedDocument",
"is_external": "@IsExternal",
"guid": "@Guid",
"description": "Description",
}
for key, value in keys.items():
if value in item:
setattr(document_reference, key, item[value])
topic.document_references.append(document_reference)
if "RelatedTopic" in data["Topic"]:
for item in data["Topic"]["RelatedTopic"]:
related_topic = bcf.data.RelatedTopic()
related_topic.guid = item["@Guid"]
topic.related_topics.append(related_topic)
return topic
def add_topic(self, topic=None):
if topic is None:
topic = bcf.data.Topic()
if not topic.guid:
topic.guid = str(uuid.uuid4())
if not topic.title:
topic.title = "New Topic"
os.mkdir(os.path.join(self.filepath, topic.guid))
self.edit_topic(topic)
return topic
def edit_topic(self, topic):
if not topic.creation_date:
topic.creation_date = datetime.utcnow().isoformat()
topic.creation_author = self.author
else:
topic.modified_date = datetime.utcnow().isoformat()
topic.modified_author = self.author
self.document = minidom.Document()
root = self._create_element(self.document, "Markup")
self.write_header(topic.header, root)
topic_el = self._create_element(
root,
"Topic",
{
"Guid": topic.guid,
"TopicType": topic.topic_type,
"TopicStatus": topic.topic_status,
},
)
for reference_link in topic.reference_links:
self._create_element(topic_el, "ReferenceLink", text=reference_link)
text_map = {
"Title": topic.title,
"Priority": topic.priority,
"Index": topic.index,
}
for key, value in text_map.items():
if value:
self._create_element(topic_el, key, text=value)
for label in topic.labels:
self._create_element(topic_el, "Labels", text=label)
text_map = {
"CreationDate": topic.creation_date,
"CreationAuthor": topic.creation_author,
"ModifiedDate": topic.modified_date,
"ModifiedAuthor": topic.modified_author,
"DueDate": topic.due_date,
"AssignedTo": topic.assigned_to,
"Stage": topic.stage,
"Description": topic.description,
}
for key, value in text_map.items():
if value:
self._create_element(topic_el, key, text=value)
if topic.bim_snippet:
bim_snippet = self._create_element(
topic_el,
"BimSnippet",
{"SnippetType": topic.bim_snippet.snippet_type, "isExternal": topic.bim_snippet.is_external},
)
self._create_element(bim_snippet, "Reference", text=topic.bim_snippet.reference)
self._create_element(bim_snippet, "ReferenceSchema", text=topic.bim_snippet.reference_schema)
for reference in topic.document_references:
reference_el = self._create_element(
topic_el, "DocumentReference", {"Guid": reference.guid, "isExternal": reference.is_external}
)
self._create_element(reference_el, "ReferencedDocument", text=reference.referenced_document)
self._create_element(reference_el, "Description", text=reference.description)
for related_topic in topic.related_topics:
self._create_element(topic_el, "RelatedTopic", {"Guid": related_topic.guid})
self.write_comments(topic.comments, root)
self.write_viewpoints(topic.viewpoints, root, topic)
with open(os.path.join(self.filepath, topic.guid, "markup.bcf"), "wb") as f:
f.write(self.document.toprettyxml(encoding="utf-8"))
def write_header(self, header, root):
if not header or not header.files:
return
header_el = self._create_element(root, "Header")
for f in header.files:
file_el = self._create_element(
header_el,
"File",
{
"IfcProject": f.ifc_project,
"IfcSpatialStructureElement": f.ifc_spatial_structure_element,
"isExternal": f.is_external,
},
)
self._create_element(file_el, "Filename", text=f.filename)
self._create_element(file_el, "Date", text=f.date)
self._create_element(file_el, "Reference", text=f.reference)
def write_comments(self, comments, root):
for comment in comments.values():
comment_el = self._create_element(root, "Comment", {"Guid": comment.guid})
text_map = {
"Date": comment.date,
"Author": comment.author,
"Comment": comment.comment,
"ModifiedDate": comment.modified_date,
"ModifiedAuthor": comment.modified_author,
}
for key, value in text_map.items():
if value:
self._create_element(comment_el, key, text=value)
if comment.viewpoint:
self._create_element(comment_el, "Viewpoint", {"Guid": comment.viewpoint.guid})
def add_comment(self, topic, comment=None):
if comment is None:
comment = bcf.data.Comment()
if not comment.guid:
comment.guid = str(uuid.uuid4())
if not comment.comment:
comment.comment = "'Free software' is a matter of liberty, not price. To understand the concept, you should think of 'free' as in 'free speech,' not as in 'free beer'."
topic.comments[comment.guid] = comment
self.edit_comment(comment, topic)
def edit_comment(self, comment, topic):
if not comment.date:
comment.date = datetime.utcnow().isoformat()
comment.author = self.author
else:
comment.modified_date = datetime.utcnow().isoformat()
comment.modified_author = self.author
self.edit_topic(topic)
def delete_comment(self, guid, topic):
if guid in topic.comments:
del topic.comments[guid]
self.edit_topic(topic)
def delete_topic(self, guid):
if guid in self.topics:
del self.topics[guid]
shutil.rmtree(os.path.join(self.filepath, guid))
def write_viewpoints(self, viewpoints, root, topic):
for viewpoint in viewpoints.values():
viewpoint_el = self._create_element(root, "Viewpoints", {"Guid": viewpoint.guid})
text_map = {"Viewpoint": viewpoint.viewpoint, "Snapshot": viewpoint.snapshot, "Index": viewpoint.index}
for key, value in text_map.items():
if value:
self._create_element(viewpoint_el, key, text=value)
self.write_viewpoint(viewpoint, topic)
def write_viewpoint(self, viewpoint, topic):
document = minidom.Document()
root = self._create_element(document, "VisualizationInfo", {"Guid": viewpoint.guid})
self.write_viewpoint_components(viewpoint, root)
self.write_viewpoint_orthogonal_camera(viewpoint, root)
self.write_viewpoint_perspective_camera(viewpoint, root)
self.write_viewpoint_lines(viewpoint, root)
self.write_viewpoint_clipping_planes(viewpoint, root)
self.write_viewpoint_bitmaps(viewpoint, root)
with open(os.path.join(self.filepath, topic.guid, viewpoint.viewpoint), "wb") as f:
f.write(document.toprettyxml(encoding="utf-8"))
def write_viewpoint_components(self, viewpoint, parent):
if not viewpoint.components:
return
components_el = self._create_element(parent, "Components")
if viewpoint.components.view_setup_hints:
view_setup_hints = self._create_element(
components_el,
"ViewSetupHints",
{
"SpacesVisible": viewpoint.components.view_setup_hints.spaces_visible,
"SpaceBoundariesVisible": viewpoint.components.view_setup_hints.space_boundaries_visible,
"OpeningsVisible": viewpoint.components.view_setup_hints.openings_visible,
},
)
if viewpoint.components.selection:
selection_el = self._create_element(components_el, "Selection")
for selection in viewpoint.components.selection:
self.write_component(selection, selection_el)
visibility = self._create_element(
components_el, "Visibility", {"DefaultVisibility": viewpoint.components.visibility.default_visibility}
)
if viewpoint.components.visibility.exceptions:
exceptions_el = self._create_element(visibility, "Exceptions")
for exception in viewpoint.components.visibility.exceptions:
self.write_component(exception, exceptions_el)
if viewpoint.components.coloring:
coloring_el = self._create_element(components_el, "Coloring")
for color in viewpoint.components.coloring:
color_el = self._create_element(coloring_el, "Color", {"Color": color.color})
for component in color.components:
self.write_component(component, color_el)
def write_viewpoint_orthogonal_camera(self, viewpoint, parent):
if not viewpoint.orthogonal_camera:
return
camera = viewpoint.orthogonal_camera
camera_el = self._create_element(parent, "OrthogonalCamera")
camera_view_point = self._create_element(camera_el, "CameraViewPoint")
self.write_vector(camera_view_point, camera.camera_view_point)
camera_direction = self._create_element(camera_el, "CameraDirection")
self.write_vector(camera_direction, camera.camera_direction)
camera_up_vector = self._create_element(camera_el, "CameraUpVector")
self.write_vector(camera_up_vector, camera.camera_up_vector)
self._create_element(camera_el, "ViewToWorldScale", text=camera.view_to_world_scale)
def write_viewpoint_perspective_camera(self, viewpoint, parent):
if not viewpoint.perspective_camera:
return
camera = viewpoint.perspective_camera
camera_el = self._create_element(parent, "PerspectiveCamera")
camera_view_point = self._create_element(camera_el, "CameraViewPoint")
self.write_vector(camera_view_point, camera.camera_view_point)
camera_direction = self._create_element(camera_el, "CameraDirection")
self.write_vector(camera_direction, camera.camera_direction)
camera_up_vector = self._create_element(camera_el, "CameraUpVector")
self.write_vector(camera_up_vector, camera.camera_up_vector)
self._create_element(camera_el, "FieldOfView", text=camera.field_of_view)
def write_viewpoint_lines(self, viewpoint, parent):
if not viewpoint.lines:
return
lines_el = self._create_element(parent, "Lines")
for line in viewpoint.lines:
line_el = self._create_element(lines_el, "Line")
start_point_el = self._create_element(line_el, "StartPoint")
self.write_vector(start_point_el, line.start_point)
end_point_el = self._create_element(line_el, "EndPoint")
self.write_vector(end_point_el, line.end_point)
def write_viewpoint_clipping_planes(self, viewpoint, parent):
if not viewpoint.clipping_planes:
return
planes_el = self._create_element(parent, "ClippingPlanes")
for plane in viewpoint.clipping_planes:
plane_el = self._create_element(planes_el, "ClippingPlane")
location_el = self._create_element(plane_el, "Location")
self.write_vector(location_el, plane.location)
direction_el = self._create_element(plane_el, "Direction")
self.write_vector(direction_el, plane.direction)
def write_viewpoint_bitmaps(self, viewpoint, parent):
if not viewpoint.bitmaps:
return
for bitmap in viewpoint.bitmaps:
bitmap_el = self._create_element(parent, "Bitmap")
text_map = {"Bitmap": bitmap.bitmap_type, "Reference": bitmap.reference}
for key, value in text_map.items():
self._create_element(bitmap_el, key, text=value)
location_el = self._create_element(bitmap_el, "Location")
self.write_vector(location_el, bitmap.location)
normal_el = self._create_element(bitmap_el, "Normal")
self.write_vector(normal_el, bitmap.normal)
up_el = self._create_element(bitmap_el, "Up")
self.write_vector(up_el, bitmap.up)
self._create_element(bitmap_el, "Height", text=bitmap.height)
def write_vector(self, parent, from_obj):
self._create_element(parent, "X", text=from_obj.x)
self._create_element(parent, "Y", text=from_obj.y)
self._create_element(parent, "Z", text=from_obj.z)
def write_component(self, data, parent):
component_el = self._create_element(parent, "Component", {"IfcGuid": data.ifc_guid})
text_map = {"OriginatingSystem": data.originating_system, "AuthoringToolId": data.authoring_tool_id}
for key, value in text_map.items():
if value:
self._create_element(component_el, key, text=value)
def add_viewpoint(self, topic, viewpoint=None):
if not viewpoint:
viewpoint = bcf.data.Viewpoint()
if not viewpoint.guid:
viewpoint.guid = str(uuid.uuid4())
if not viewpoint.viewpoint:
viewpoint.viewpoint = f"{viewpoint.guid}.bcfv"
if viewpoint.snapshot:
topic_filepath = os.path.join(self.filepath, topic.guid)
filepath = os.path.join(topic_filepath, viewpoint.snapshot)
if not os.path.exists(filepath):
filename = viewpoint.guid + os.path.splitext(viewpoint.snapshot)[-1]
copyfile(viewpoint.snapshot, os.path.join(topic_filepath, filename))
viewpoint.snapshot = filename
topic.viewpoints[viewpoint.guid] = viewpoint
self.edit_topic(topic)
def delete_viewpoint(self, guid, topic):
if guid not in topic.viewpoints:
return
viewpoint = topic.viewpoints[guid]
if viewpoint.snapshot:
filepath = os.path.join(self.filepath, topic.guid, viewpoint.snapshot)
if os.path.exists(filepath):
os.remove(filepath)
if viewpoint.viewpoint:
filepath = os.path.join(self.filepath, topic.guid, viewpoint.viewpoint)
if os.path.exists(filepath):
os.remove(filepath)
for bitmap in viewpoint.bitmaps:
if not bitmap.reference:
continue
filepath = os.path.join(self.filepath, topic.guid, bitmap.reference)
if os.path.exists(filepath):
os.remove(filepath)
del topic.viewpoints[guid]
self.edit_topic(topic)
def delete_file(self, topic, index):
if not topic.header:
return
f = topic.header.files.pop(index)
filepath = os.path.join(self.filepath, topic.guid, f.reference)
if not f.is_external and os.path.exists(filepath):
os.remove(filepath)
self.edit_topic(topic)
def delete_bim_snippet(self, topic):
if not topic.bim_snippet:
return
if topic.bim_snippet.reference and not topic.bim_snippet.is_external:
filepath = os.path.join(self.filepath, topic.guid, topic.bim_snippet.reference)
if os.path.exists(filepath):
os.remove(filepath)
topic.bim_snippet = None
self.edit_topic(topic)
def delete_document_reference(self, topic, index):
document_reference = topic.document_references[index]
if document_reference.referenced_document and not document_reference.is_external:
filepath = os.path.join(self.filepath, topic.guid, document_reference.referenced_document)
if os.path.exists(filepath):
os.remove(filepath)
del topic.document_references[index]
self.edit_topic(topic)
def add_document_reference(self, topic, document_reference):
if os.path.exists(document_reference.referenced_document):
topic_filepath = os.path.join(self.filepath, topic.guid)
filename = os.path.basename(document_reference.referenced_document)
copyfile(document_reference.referenced_document, os.path.join(topic_filepath, filename))
document_reference.referenced_document = filename
document_reference.is_external = False
else:
document_reference.is_external = True
if not document_reference.guid:
document_reference.guid = str(uuid.uuid4())
topic.document_references.append(document_reference)
self.edit_topic(topic)
def add_bim_snippet(self, topic, bim_snippet):
if topic.bim_snippet:
self.delete_bim_snippet(topic)
if os.path.exists(bim_snippet.reference):
topic_filepath = os.path.join(self.filepath, topic.guid)
filename = os.path.basename(bim_snippet.reference)
copyfile(bim_snippet.reference, os.path.join(topic_filepath, filename))
bim_snippet.reference = filename
bim_snippet.is_external = False
else:
bim_snippet.is_external = True
topic.bim_snippet = bim_snippet
self.edit_topic(topic)
def add_file(self, topic, header_file):
if os.path.exists(header_file.reference):
topic_filepath = os.path.join(self.filepath, topic.guid)
header_file.filename = os.path.basename(header_file.reference)
copyfile(header_file.reference, os.path.join(topic_filepath, header_file.filename))
header_file.reference = header_file.filename
header_file.is_external = False
header_file.date = datetime.utcnow().isoformat()
if not topic.header:
topic.header = bcf.data.Header()
topic.header.files.append(header_file)
self.edit_topic(topic)
def get_comments(self, guid):
comments = {}
data = self._read_xml(os.path.join(guid, "markup.bcf"), "markup.xsd")
if "Comment" not in data:
return comments
for item in data["Comment"]:
comment = bcf.data.Comment()
mandatory_keys = {"guid": "@Guid", "date": "Date", "author": "Author", "comment": "Comment"}
for key, value in mandatory_keys.items():
setattr(comment, key, item[value])
optional_keys = {"modified_date": "ModifiedDate", "modified_author": "ModifiedAuthor"}
for key, value in optional_keys.items():
if value in item:
setattr(comment, key, item[value])
if "Viewpoint" in item:
viewpoint = bcf.data.Viewpoint()
viewpoint.guid = item["Viewpoint"]["@Guid"]
comment.viewpoint = viewpoint
comments[comment.guid] = comment
self.topics[guid].comments = comments
return comments
def get_viewpoints(self, guid):
viewpoints = {}
data = self._read_xml(os.path.join(guid, "markup.bcf"), "markup.xsd")
if "Viewpoints" not in data:
return viewpoints
for item in data["Viewpoints"]:
viewpoint = self.get_viewpoint(item, guid)
viewpoints[viewpoint.guid] = viewpoint
self.topics[guid].viewpoints = viewpoints
return viewpoints
def get_viewpoint(self, data, topic_guid):
viewpoint = bcf.data.Viewpoint()
viewpoint.guid = data["@Guid"]
optional_keys = {"viewpoint": "Viewpoint", "snapshot": "Snapshot", "index": "Index"}
for key, value in optional_keys.items():
if value in data:
setattr(viewpoint, key, data[value])
visinfo = self._read_xml(os.path.join(topic_guid, viewpoint.viewpoint), "visinfo.xsd")
viewpoint.components = self.get_viewpoint_components(visinfo)
viewpoint.orthogonal_camera = self.get_viewpoint_orthogonal_camera(visinfo)
viewpoint.perspective_camera = self.get_viewpoint_perspective_camera(visinfo)
viewpoint.lines = self.get_viewpoint_lines(visinfo)
viewpoint.clipping_planes = self.get_viewpoint_clipping_planes(visinfo)
viewpoint.bitmaps = self.get_viewpoint_bitmaps(visinfo)
return viewpoint
def get_viewpoint_components(self, visinfo):
if "Components" not in visinfo:
return None
components = bcf.data.Components()
data = visinfo["Components"]
if "ViewSetupHints" in data:
view_setup_hints = bcf.data.ViewSetupHints()
optional_keys = {
"spaces_visible": "@SpacesVisible",
"space_boundaries_visible": "@SpaceBoundariesVisible",
"openings_visible": "@OpeningsVisible",
}
for key, value in optional_keys.items():
if value in data["ViewSetupHints"]:
setattr(view_setup_hints, key, data["ViewSetupHints"][value])
components.view_setup_hints = view_setup_hints
if "Selection" in data and "Component" in data["Selection"]:
for item in data["Selection"]["Component"]:
components.selection.append(self.get_component(item))
if "Visibility" in data:
component_visibility = bcf.data.ComponentVisibility()
if "@DefaultVisibility" in data["Visibility"]:
component_visibility.default_visibility = data["Visibility"]["@DefaultVisibility"]
if "Exceptions" in data["Visibility"] and "Component" in data["Visibility"]["Exceptions"]:
for item in data["Visibility"]["Exceptions"]["Component"]:
component_visibility.exceptions.append(self.get_component(item))
components.visibility = component_visibility
if "Coloring" in data and "Color" in data["Coloring"]:
for item in data["Coloring"]["Color"]:
color = bcf.data.Color()
color.color = item["@Color"]
for item2 in item["Component"]:
color.components.append(self.get_component(item2))
components.coloring.append(color)
return components
def get_viewpoint_orthogonal_camera(self, visinfo):
if "OrthogonalCamera" not in visinfo:
return None
camera = bcf.data.OrthogonalCamera()
data = visinfo["OrthogonalCamera"]
self.set_vector(camera.camera_view_point, data["CameraViewPoint"])
self.set_vector(camera.camera_direction, data["CameraDirection"])
self.set_vector(camera.camera_up_vector, data["CameraUpVector"])
camera.view_to_world_scale = data["ViewToWorldScale"]
return camera
def get_viewpoint_perspective_camera(self, visinfo):
if "PerspectiveCamera" not in visinfo:
return None
camera = bcf.data.PerspectiveCamera()
data = visinfo["PerspectiveCamera"]
self.set_vector(camera.camera_view_point, data["CameraViewPoint"])
self.set_vector(camera.camera_direction, data["CameraDirection"])
self.set_vector(camera.camera_up_vector, data["CameraUpVector"])
camera.field_of_view = data["FieldOfView"]
return camera
def get_viewpoint_lines(self, visinfo):
if "Lines" not in visinfo:
return []
lines = []
for item in visinfo["Lines"]["Line"]:
line = bcf.data.Line()
self.set_vector(line.start_point, item["StartPoint"])
self.set_vector(line.end_point, item["EndPoint"])
lines.append(line)
return lines
def get_viewpoint_clipping_planes(self, visinfo):
if "ClippingPlanes" not in visinfo:
return []
planes = []
for item in visinfo["ClippingPlanes"]["ClippingPlane"]:
plane = bcf.data.ClippingPlane()
self.set_vector(plane.location, item["Location"])
self.set_vector(plane.direction, item["Direction"])
planes.append(plane)
return planes
def get_viewpoint_bitmaps(self, visinfo):
if "Bitmap" not in visinfo:
return []
bitmaps = []
for item in visinfo["Bitmap"]:
bitmap = bcf.data.Bitmap()
bitmap.reference = item["Reference"]
bitmap.bitmap_type = item["Bitmap"].upper()
self.set_vector(bitmap.location, item["Location"])
self.set_vector(bitmap.normal, item["Normal"])
self.set_vector(bitmap.up, item["Up"])
bitmap.height = item["Height"]
bitmaps.append(bitmap)
return bitmaps
def set_vector(self, to_obj, from_xml):
to_obj.x = from_xml["X"]
to_obj.y = from_xml["Y"]
to_obj.z = from_xml["Z"]
def get_component(self, data):
component = bcf.data.Component()
optional_keys = {
"originating_system": "OriginatingSystem",
"authoring_tool_id": "AuthoringToolId",
"ifc_guid": "@IfcGuid",
}
for key, value in optional_keys.items():
if value in data:
setattr(component, key, data[value])
return component
def close_project(self):
shutil.rmtree(self.filepath)
def _read_xml(self, filename, xsd):
schema = XMLSchema(os.path.join(cwd, "xsd", xsd))
filepath = os.path.join(self.filepath, filename)
(data, errors) = schema.to_dict(filepath, validation="lax")
for error in errors:
self.logger.error(error)
return data
def _create_element(self, parent, name, attributes={}, text=None):
element = self.document.createElement(name)
for key, value in attributes.items():
if isinstance(value, bool):
element.setAttribute(key, str(value).lower())
elif value:
element.setAttribute(key, value)
if text is not None:
text = self.document.createTextNode(str(text))
element.appendChild(text)
parent.appendChild(element)
return element
def __del__(self):
self.close_project()
-178
View File
@@ -1,178 +0,0 @@
class Project:
def __init__(self):
self.project_id = ""
self.name = ""
class BimSnippet:
def __init__(self):
self.snippet_type = None
self.is_external = False
self.reference = None
self.reference_schema = None
class DocumentReference:
def __init__(self):
self.referenced_document = None
self.description = None
self.guid = None
self.is_external = False
class RelatedTopic:
def __init__(self):
self.guid = None
class HeaderFile:
def __init__(self):
self.filename = None
self.date = None
self.reference = None
self.ifc_project = None
self.ifc_spatial_structure_element = None
self.is_external = True
class Header:
def __init__(self):
self.files = []
class Topic:
def __init__(self):
self.reference_links = []
self.title = ""
self.priority = None
self.index = None # Deprecated, stored, but ignored
self.labels = []
self.creation_date = None
self.creation_author = None
self.modified_date = None
self.modified_author = None
self.due_date = None
self.assigned_to = None
self.stage = None
self.description = None
self.bim_snippet = None
self.document_references = []
self.related_topics = []
self.topic_status = None
self.topic_type = None
self.guid = None
self.header = None
self.comments = {}
self.viewpoints = {}
class Comment:
def __init__(self):
self.guid = None
self.date = None
self.author = None
self.comment = None
self.viewpoint = None
self.modified_date = None
self.modified_author = None
self.topic_guid = None # Part of BCF-API
class ViewSetupHints:
def __init__(self):
self.spaces_visible = False
self.space_boundaries_visible = False
self.openings_visible = False
class Component:
def __init__(self):
self.originating_system = None
self.authoring_tool_id = None
self.ifc_guid = None
class ComponentVisibility:
def __init__(self):
self.exceptions = []
self.default_visibility = False
class Color:
def __init__(self):
self.color = None
self.components = []
class Components:
def __init__(self):
self.view_setup_hints = None
self.selection = []
self.visibility = None
self.coloring = []
class Point:
def __init__(self):
self.x = 0
self.y = 0
self.z = 0
class Direction(Point):
pass
class OrthogonalCamera:
def __init__(self):
self.camera_view_point = Point()
self.camera_direction = Direction()
self.camera_up_vector = Direction()
self.view_to_world_scale = 1.0
class PerspectiveCamera:
def __init__(self):
self.camera_view_point = Point()
self.camera_direction = Direction()
self.camera_up_vector = Direction()
self.field_of_view = 60.0
class Line:
def __init__(self):
self.start_point = Point()
self.end_point = Point()
class ClippingPlane:
def __init__(self):
self.location = Point()
self.direction = Direction()
class Bitmap:
def __init__(self):
self.reference = "" # Only in BCF-XML
self.bitmap_data = None # Only in BCF-API
self.bitmap_type = "PNG" # Enum of png or jpg
self.location = Point()
self.normal = Direction()
self.up = Direction()
self.height = 1.0
class Viewpoint:
def __init__(self):
self.guid = None
self.viewpoint = None
self.snapshot = None
self.index = None
self.components = None # It's not a list, despite the plural name
self.orthogonal_camera = None
self.perspective_camera = None
self.lines = []
self.clipping_planes = []
self.bitmaps = []
-154
View File
@@ -1,154 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Mit XMLSpy v2011 rel. 2 sp1 (http://www.altova.com) von Klaus Linhard (IABI e.V.) bearbeitet -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Markup">
<xs:complexType>
<xs:sequence>
<xs:element name="Header" type="Header" minOccurs="0"/>
<xs:element name="Topic" type="Topic"/>
<xs:element name="Comment" type="Comment" minOccurs="0" maxOccurs="unbounded"/>
<!-- ISG Jira issue BCF-9. Add support for several viewpoints and snapshots per issue -->
<xs:element name="Viewpoints" type="ViewPoint" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="Header">
<xs:sequence>
<xs:element name="File" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Filename" type="xs:string" minOccurs="0"/>
<xs:element name="Date" type="xs:dateTime" minOccurs="0"/>
<!-- Reference (URL) of the file -->
<xs:element name="Reference" type="xs:string" minOccurs="0"/>
</xs:sequence>
<xs:attributeGroup ref="FileAttributes"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<!-- ISG Jira issue BCF-9. Add support for several viewpoints and snapshots per issue -->
<xs:complexType name="ViewPoint">
<xs:sequence>
<!-- viewpoint file (xml) -->
<xs:element name="Viewpoint" type="xs:string" minOccurs="0"/>
<!-- the snapshot png -->
<xs:element name="Snapshot" type="xs:string" minOccurs="0"/>
<!-- the viewpoint index (sort order) -->
<xs:element name="Index" type="xs:int" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="Guid" type="Guid" use="required"/>
<!-- Guid of the viewpoint -->
</xs:complexType>
<!-- BimSnippet -->
<xs:complexType name="BimSnippet">
<xs:sequence>
<!--
Name of the file in the topic folder containing the snippet or a URL.
E.G.- Expresscode containing p.e Issue, Request
// Maybe some header infos ?? // IfcEntites // Geometry
-->
<!-- Reference (name) to the snippet file -->
<xs:element name="Reference" type="xs:string"/>
<xs:element name="ReferenceSchema" type="xs:string"/>
</xs:sequence>
<xs:attribute name="SnippetType" type="xs:string" use="required"/>
<xs:attribute name="isExternal" type="xs:boolean" default="false"/>
<!-- This flag is true when the reference is a URL pointing outside of the BCF file-->
</xs:complexType>
<xs:complexType name="Topic">
<xs:sequence>
<xs:element name="ReferenceLink" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="Title" type="xs:string"/>
<xs:element name="Priority" type="Priority" minOccurs="0"/>
<!-- ISG Jira issue BCF-8 Add a way save order the topics -->
<xs:element name="Index" type="xs:int" minOccurs="0"/>
<xs:element name="Labels" type="TopicLabel" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="CreationDate" type="xs:dateTime" minOccurs="1"/>
<xs:element name="CreationAuthor" type="UserIdType" minOccurs="1"/>
<xs:element name="ModifiedDate" type="xs:dateTime" minOccurs="0"/>
<xs:element name="ModifiedAuthor" type="UserIdType" minOccurs="0"/>
<xs:element name="DueDate" type="xs:dateTime" minOccurs="0"/>
<xs:element name="AssignedTo" type="UserIdType" minOccurs="0"/>
<xs:element name="Stage" type="Stage" minOccurs="0"/>
<xs:element name="Description" type="xs:string" minOccurs="0"/>
<xs:element name="BimSnippet" type="BimSnippet" minOccurs="0"/>
<!-- Name of the file in the topic folder or url -->
<xs:element name="DocumentReference" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<!-- Name of the file in the topic folder or url -->
<xs:element name="ReferencedDocument" type="xs:string" minOccurs="0"/>
<!-- Human readable name of the document -->
<xs:element name="Description" type="xs:string" minOccurs="0"/>
</xs:sequence>
<xs:attributeGroup ref="DocumentReference"/>
</xs:complexType>
</xs:element>
<xs:element name="RelatedTopic" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="Guid" type="Guid" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="Guid" type="Guid" use="required"/>
<xs:attribute name="TopicType" type="TopicType"/>
<xs:attribute name="TopicStatus" type="TopicStatus"/>
</xs:complexType>
<!-- Reference to a document inside of the topic folder or a url pointing to the web -->
<xs:attributeGroup name="DocumentReference">
<!-- Guid of the DocumentReference -->
<xs:attribute name="Guid" type="Guid"/>
<!-- A flag that is true when the ReferencedDocument points outside of the BCF file (a URL) -->
<xs:attribute name="isExternal" type="xs:boolean" default="false"/>
</xs:attributeGroup>
<xs:complexType name="Comment">
<xs:sequence>
<xs:element name="Date" type="xs:dateTime"/>
<xs:element name="Author" type="UserIdType"/>
<xs:element name="Comment" type="xs:string"/>
<xs:element name="Viewpoint" minOccurs="0">
<xs:complexType>
<xs:attribute name="Guid" type="Guid" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="ModifiedDate" type="xs:dateTime" minOccurs="0"/>
<xs:element name="ModifiedAuthor" type="UserIdType" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="Guid" type="Guid" use="required"/>
</xs:complexType>
<xs:simpleType name="TopicStatus">
<xs:restriction base="xs:string"/>
</xs:simpleType>
<xs:simpleType name="TopicType">
<xs:restriction base="xs:string"/>
</xs:simpleType>
<xs:simpleType name="TopicLabel">
<xs:restriction base="xs:string"/>
</xs:simpleType>
<xs:simpleType name="Priority">
<xs:restriction base="xs:string"/>
</xs:simpleType>
<xs:simpleType name="UserIdType">
<xs:restriction base="xs:string"/>
</xs:simpleType>
<xs:simpleType name="Stage">
<xs:restriction base="xs:string"/>
</xs:simpleType>
<xs:simpleType name="Guid">
<xs:restriction base="xs:string">
<xs:pattern value="[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="IfcGuid">
<xs:restriction base="xs:string">
<xs:length value="22"/>
<xs:pattern value="[0-9,A-Z,a-z,_$]*"/>
</xs:restriction>
</xs:simpleType>
<xs:attributeGroup name="FileAttributes">
<xs:attribute name="IfcProject" type="IfcGuid"/>
<xs:attribute name="IfcSpatialStructureElement" type="IfcGuid"/>
<xs:attribute name="isExternal" type="xs:boolean" default="true"/>
</xs:attributeGroup>
</xs:schema>
-18
View File
@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Mit XMLSpy v2011 rel. 2 sp1 (http://www.altova.com) von Klaus Linhard (IABI e.V.) bearbeitet -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="ProjectExtension">
<xs:complexType>
<xs:sequence>
<xs:element name="Project" type="Project" minOccurs="0"/>
<xs:element name="ExtensionSchema" type="xs:anyURI"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="Project">
<xs:sequence>
<xs:element name="Name" type="xs:string" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="ProjectId" type="xs:string" use="required"/>
</xs:complexType>
</xs:schema>
-12
View File
@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Mit XMLSpy v2011 rel. 3 (http://www.altova.com) von Klaus Linhard (IABI e.V.) bearbeitet -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Version">
<xs:complexType>
<xs:sequence>
<xs:element name="DetailedVersion" type="xs:string" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="VersionId" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:schema>
-191
View File
@@ -1,191 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Mit XMLSpy v2011 rel. 2 sp1 (http://www.altova.com) von Klaus Linhard (IABI e.V.) bearbeitet -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="VisualizationInfo">
<xs:annotation>
<xs:documentation>VisualizationInfo documentation</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="Components" type="Components" minOccurs="0"/>
<xs:element name="OrthogonalCamera" type="OrthogonalCamera" minOccurs="0"/>
<xs:element name="PerspectiveCamera" type="PerspectiveCamera" minOccurs="0"/>
<xs:element name="Lines" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="Line" type="Line" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="ClippingPlanes" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="ClippingPlane" type="ClippingPlane" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<!-- ISG Jira issue BCF-17: Add support for text in the viewpoints -->
<xs:element name="Bitmap" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Bitmap" type="BitmapFormat"/>
<!-- Name of the bitmap file in the topic folder -->
<xs:element name="Reference" type="xs:string"/>
<!-- Location of the center of the bitmap -->
<xs:element name="Location" type="Point"/>
<!-- Normal of the bitmap -->
<xs:element name="Normal" type="Direction"/>
<!-- Upvector of the bitmap -->
<xs:element name="Up" type="Direction"/>
<!-- Height of the bitmap -->
<xs:element name="Height" type="xs:double"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<!-- Guid of the viewpoint -->
<xs:attribute name="Guid" type="Guid" use="required"/>
</xs:complexType>
</xs:element>
<xs:complexType name="OrthogonalCamera">
<xs:sequence>
<xs:element name="CameraViewPoint" type="Point"/>
<xs:element name="CameraDirection" type="Direction"/>
<xs:element name="CameraUpVector" type="Direction"/>
<xs:element name="ViewToWorldScale" type="xs:double">
<xs:annotation>
<xs:documentation>view's visible size in meters</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="PerspectiveCamera">
<xs:sequence>
<xs:element name="CameraViewPoint" type="Point"/>
<xs:element name="CameraDirection" type="Direction"/>
<xs:element name="CameraUpVector" type="Direction"/>
<xs:element name="FieldOfView" type="FieldOfView">
<xs:annotation>
<xs:documentation>
It is currently limited to a value between 45 and 60 degrees.
This limitation will be dropped in the next release and viewers
should be expect values outside this range in current implementations.
</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Point">
<xs:sequence>
<xs:element name="X" type="xs:double"/>
<xs:element name="Y" type="xs:double"/>
<xs:element name="Z" type="xs:double"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Direction">
<xs:sequence>
<xs:element name="X" type="xs:double"/>
<xs:element name="Y" type="xs:double"/>
<xs:element name="Z" type="xs:double"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="FieldOfView">
<xs:restriction base="xs:double">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="170"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="Components">
<xs:sequence>
<xs:element name="ViewSetupHints" type="ViewSetupHints" minOccurs="0" />
<!-- Components with relevance to the viewpoint. They should be displayed highlighted or selected in a viewer -->
<xs:element name="Selection" type="ComponentSelection" minOccurs="0" />
<xs:element name="Visibility" type="ComponentVisibility" minOccurs="1" />
<xs:element name="Coloring" type="ComponentColoring" minOccurs="0" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="ViewSetupHints">
<xs:attribute name="SpacesVisible" type="xs:boolean"/>
<xs:attribute name="SpaceBoundariesVisible" type="xs:boolean"/>
<xs:attribute name="OpeningsVisible" type="xs:boolean"/>
</xs:complexType>
<xs:complexType name="ComponentSelection">
<xs:sequence>
<xs:element name="Component" type="Component" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ComponentVisibility">
<xs:sequence>
<xs:element name="Exceptions" minOccurs="0">
<!-- List Components that are different than the DefaultVisibility. E.g. if DefaultVisibility = false then list
Components that should be visible -->
<xs:complexType>
<xs:sequence>
<xs:element name="Component" type="Component" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="DefaultVisibility" type="xs:boolean"/>
</xs:complexType>
<xs:complexType name="ComponentColoring">
<xs:sequence>
<xs:element name="Color" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Component" type="Component" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute ref="Color"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Component">
<xs:sequence>
<xs:element name="OriginatingSystem" type="xs:string" minOccurs="0"/>
<xs:element name="AuthoringToolId" type="xs:string" minOccurs="0"/>
</xs:sequence>
<xs:attribute ref="IfcGuid"/>
<!-- ISG Jira Issue BCF-14 -->
</xs:complexType>
<xs:attribute name="Color">
<xs:simpleType>
<xs:restriction base="xs:normalizedString">
<!-- Should either match 3 or 4 hex bytes , e.g. "FF00FF" or "FF00FF99" -->
<xs:pattern value="[0-9,a-f,A-F]{6}([0-9,a-f,A-F]{2})?"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="IfcGuid">
<xs:simpleType>
<xs:restriction base="xs:normalizedString">
<xs:length value="22"/>
<xs:pattern value="[0-9,A-Z,a-z,_$]*"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:complexType name="Line">
<xs:sequence>
<xs:element name="StartPoint" type="Point"/>
<xs:element name="EndPoint" type="Point"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ClippingPlane">
<xs:sequence>
<xs:element name="Location" type="Point"/>
<xs:element name="Direction" type="Direction"/>
</xs:sequence>
</xs:complexType>
<!-- ISG Jira issue BCF-17: Add support for text in the viewpoints -->
<xs:simpleType name="BitmapFormat">
<xs:restriction base="xs:string">
<xs:enumeration value="PNG"/>
<xs:enumeration value="JPG"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="Guid">
<xs:restriction base="xs:string">
<xs:pattern value="[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
+1 -7
View File
@@ -19,12 +19,6 @@
ADD_EXECUTABLE(IfcParseExamples IfcParseExamples.cpp)
TARGET_LINK_LIBRARIES(IfcParseExamples IfcParse)
set_target_properties(IfcParseExamples PROPERTIES FOLDER Examples)
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 ${OPENCASCADE_LIBRARIES})
-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
}
+15 -36
View File
@@ -28,23 +28,18 @@
#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>
@@ -63,7 +58,7 @@ 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;
IfcHierarchyHelper file;
file.header().file_name().name("IfcOpenHouse.ifc");
// Start by adding a wall to the file, initially leaving most attributes blank.
@@ -245,7 +240,7 @@ int main() {
file.addBuildingProduct(west_wall);
// The west wall is assigned an opening element we created for the south wall, opening elements are
// not shared across building elements, even if they share the same representation. Hence, the east
// not shared accross building elements, even if they share the same representation. Hence, the east
// wall will not feature this opening.
// NB: an Opening Element can only be used to create a single void within a single Element, as per:
// http://www.buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcproductextension/lexical/ifcfeatureelementsubtraction.htm
@@ -267,30 +262,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>();
IfcEntityList::ptr geometrical_entities(new IfcEntityList);
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::tesselate(shape, 100., geometrical_entities);
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) {
file.addEntities(geometrical_entities);
IfcSchema::IfcShapeRepresentation::list::ptr ground_reps = geometrical_entities->as<IfcSchema::IfcShapeRepresentation>();
for (IfcSchema::IfcShapeRepresentation::list::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
(*it)->setContextOfItems(file.getRepresentationContext("Model"));
}
file.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 +320,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);
@@ -398,7 +377,7 @@ int main() {
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;
}
}
@@ -419,7 +398,7 @@ int main() {
// Therefore we will construct the window as a decomposition of beams and a plate, in which
// only the plate will have a transparent material assigned.
// The window frame will consists of four separate beams.
// The window frame will consists of four seperate beams.
// AutoCAD Architecture will create an internal window type for the IfcWindow created.
// Therefore the OverallWidth and OverallHeight of the window attributes will need to
// match the bounding box of the representation. Furthermore, the window placement needs
@@ -470,10 +449,10 @@ int main() {
);
file.addBuildingProduct(window);
// Initialize a list of parts for the window to be composed of
// Initalize a list of parts for the window to be composed of
IfcSchema::IfcObjectDefinition::list::ptr window_parts(new IfcTemplatedEntityList<IfcSchema::IfcObjectDefinition>());
// The placements for the beams are not shared across the different windows because every
// The placements for the beams are not shared accross the different windows because every
// beam is placed relative to its parent window entity.
IfcSchema::IfcLocalPlacement::list::ptr frame_placements (new IfcTemplatedEntityList<IfcSchema::IfcLocalPlacement>());
frame_placements->push(file.addLocalPlacement(storey_placement, 930,45));
+12 -13
View File
@@ -17,16 +17,14 @@
* *
********************************************************************************/
// 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) {
if ( argc != 2 ) {
@@ -38,8 +36,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,18 +58,19 @@ 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()) {
if ( element->is(IfcWindow::Class()) ) {
const IfcWindow* window = (IfcWindow*)element;
if ( window->hasOverallWidth() && window->hasOverallHeight() ) {
const double area = window->OverallWidth()*window->OverallHeight();
std::cout << "The area of this window is " << area << std::endl;
}
-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;
}
+22 -28
View File
@@ -1,30 +1,24 @@
###############################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
################################################################################
# #
# 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/>. #
# #
################################################################################
set -e
ADD_EXECUTABLE(hdf5_federate federate.cpp)
TARGET_LINK_LIBRARIES(hdf5_federate IfcParse ${ICU_LIBRARIES} ${Boost_LIBRARIES})
export PATH=/mingw64/bin/:$PATH
if [ -z "$IFCOS_NUM_BUILD_PROCS" ]; then
IFCOS_NUM_BUILD_PROCS=$(expr $(sysctl -n hw.ncpu 2> /dev/null || cat /proc/cpuinfo | grep processor | wc -l) + 1)
fi
pushd ../build-msys
make install -j$IFCOS_NUM_BUILD_PROCS
popd
ADD_EXECUTABLE(hdf5_lod lod.cpp)
TARGET_LINK_LIBRARIES(hdf5_lod IfcParse IfcGeom ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBRARIES})
+361
View File
@@ -0,0 +1,361 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include "../../../src/ifcparse/IfcHdf5File.h"
#include "../../../src/ifcparse/IfcWritableEntity.h"
#include <boost/lexical_cast.hpp>
#include <set>
#include <algorithm>
#include "multifile_instance_locator.h"
#pragma warning(disable:4100)
// A comparison operator that is used to isolate the shared hierarchy
class ifc_inst_cmp {
public:
// For these we simply assume that only a single instance exists
bool operator()(IfcSchema::IfcSite* a, IfcSchema::IfcSite* b) const { return false; }
bool operator()(IfcSchema::IfcProject* a, IfcSchema::IfcProject* b) const { return false; }
bool operator()(IfcSchema::IfcBuilding* a, IfcSchema::IfcBuilding* b) const { return false; }
bool operator()(IfcSchema::IfcPostalAddress* a, IfcSchema::IfcPostalAddress* b) const { return false; }
bool operator()(IfcSchema::IfcUnitAssignment* a, IfcSchema::IfcUnitAssignment* b) const { return false; }
bool operator()(IfcSchema::IfcConversionBasedUnit* a, IfcSchema::IfcConversionBasedUnit* b) const {
return a->Name() < b->Name();
}
bool operator()(IfcSchema::IfcDimensionalExponents* a, IfcSchema::IfcDimensionalExponents* b) const {
// For every attribute (which are all integers) check equality
unsigned num_attrs = a->data().getArgumentCount();
for (unsigned i = 0; i < num_attrs; ++i) {
const int v1 = *a->data().getArgument(i);
const int v2 = *b->data().getArgument(i);
if (v1 != v2) {
return v1 < v2;
}
}
return false;
}
bool operator()(IfcSchema::IfcMeasureWithUnit* a, IfcSchema::IfcMeasureWithUnit* b) const {
// Assume the value component is enough to differentiate
double v1 = *a->ValueComponent()->data().getArgument(0);
double v2 = *b->ValueComponent()->data().getArgument(0);
return v1 < v2;
}
bool operator()(IfcSchema::IfcGeometricRepresentationSubContext* a, IfcSchema::IfcGeometricRepresentationSubContext* b) const {
return a->ContextType() < b->ContextType();
}
bool operator()(IfcSchema::IfcGeometricRepresentationContext* a, IfcSchema::IfcGeometricRepresentationContext* b) const {
return a->ContextType() < b->ContextType();
}
bool operator()(IfcSchema::IfcSIUnit* a, IfcSchema::IfcSIUnit* b) const {
// Assume same units accross files
return a->UnitType() < b->UnitType();
}
bool operator()(IfcSchema::IfcBuildingStorey* a, IfcSchema::IfcBuildingStorey* b) const {
return a->Name() < b->Name();
}
bool operator()(IfcSchema::IfcCartesianPoint* a, IfcSchema::IfcCartesianPoint* b) const {
return a->Coordinates() < b->Coordinates();
}
bool operator()(IfcSchema::IfcDirection* a, IfcSchema::IfcDirection* b) const {
return a->DirectionRatios() < b->DirectionRatios();
}
bool operator()(IfcSchema::IfcAxis2Placement3D* a, IfcSchema::IfcAxis2Placement3D* b) const {
if (a->Location()->Coordinates() != b->Location()->Coordinates()) {
return (*this)(a->Location(), b->Location());
}
if (b->hasAxis()) {
if (!a->hasAxis()) {
return true;
} else {
return (*this)(a->Axis(), b->Axis());
}
}
if (b->hasRefDirection()) {
if (!a->hasRefDirection()) {
return true;
} else {
return (*this)(a->RefDirection(), b->RefDirection());
}
}
return false;
}
bool operator()(IfcSchema::IfcLocalPlacement* a, IfcSchema::IfcLocalPlacement* b) const {
if (b->hasPlacementRelTo()) {
if (!a->hasPlacementRelTo()) {
return true;
} else {
return (*this)(a->PlacementRelTo(), b->PlacementRelTo());
}
}
return (*this)(a->RelativePlacement(), b->RelativePlacement());
}
bool operator()(IfcUtil::IfcBaseClass* a, IfcUtil::IfcBaseClass* b) const {
if (a->declaration().type() != b->declaration().type()) {
return a->declaration().type() < b->declaration().type();
// throw std::runtime_error("Types not matching");
}
if (a->declaration().type() == IfcSchema::Type::IfcSite) { return (*this)((IfcSchema::IfcSite*) a, (IfcSchema::IfcSite*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcConversionBasedUnit) { return (*this)((IfcSchema::IfcConversionBasedUnit*) a, (IfcSchema::IfcConversionBasedUnit*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcDimensionalExponents) { return (*this)((IfcSchema::IfcDimensionalExponents*) a, (IfcSchema::IfcDimensionalExponents*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcMeasureWithUnit) { return (*this)((IfcSchema::IfcMeasureWithUnit*) a, (IfcSchema::IfcMeasureWithUnit*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcProject) { return (*this)((IfcSchema::IfcProject*) a, (IfcSchema::IfcProject*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcBuilding) { return (*this)((IfcSchema::IfcBuilding*) a, (IfcSchema::IfcBuilding*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcPostalAddress) { return (*this)((IfcSchema::IfcPostalAddress*) a, (IfcSchema::IfcPostalAddress*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcUnitAssignment) { return (*this)((IfcSchema::IfcUnitAssignment*) a, (IfcSchema::IfcUnitAssignment*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcGeometricRepresentationSubContext) { return (*this)((IfcSchema::IfcGeometricRepresentationSubContext*) a, (IfcSchema::IfcGeometricRepresentationSubContext*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcGeometricRepresentationContext) { return (*this)((IfcSchema::IfcGeometricRepresentationContext*) a, (IfcSchema::IfcGeometricRepresentationContext*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcSIUnit) { return (*this)((IfcSchema::IfcSIUnit*) a, (IfcSchema::IfcSIUnit*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcBuildingStorey) { return (*this)((IfcSchema::IfcBuildingStorey*) a, (IfcSchema::IfcBuildingStorey*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcCartesianPoint) { return (*this)((IfcSchema::IfcCartesianPoint*) a, (IfcSchema::IfcCartesianPoint*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcDirection) { return (*this)((IfcSchema::IfcDirection*) a, (IfcSchema::IfcDirection*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcAxis2Placement3D) { return (*this)((IfcSchema::IfcAxis2Placement3D*) a, (IfcSchema::IfcAxis2Placement3D*) b); }
if (a->declaration().type() == IfcSchema::Type::IfcLocalPlacement) { return (*this)((IfcSchema::IfcLocalPlacement*) a, (IfcSchema::IfcLocalPlacement*) b); }
// Should these be removed if an owner history is created manually?
if (a->declaration().type() == IfcSchema::Type::IfcPerson) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
if (a->declaration().type() == IfcSchema::Type::IfcOrganization) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
if (a->declaration().type() == IfcSchema::Type::IfcPersonAndOrganization) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
if (a->declaration().type() == IfcSchema::Type::IfcOwnerHistory) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
if (a->declaration().type() == IfcSchema::Type::IfcApplication) { return (a->data().id() & 0x1000000) < (b->data().id() & 0x1000000); }
std::cerr << "Unexpected type: " + IfcSchema::Type::ToString(a->declaration().type()) << std::endl;
throw std::runtime_error("Unexpected type: " + IfcSchema::Type::ToString(a->declaration().type()));
}
};
// Usage: hdf5_federate Office_A_20110811_optimized.ifc Office_S_20110811_optimized.ifc Office_MEP_20110811_optimized.ifc
int main(int argc, char** argv) {
// A set of datatypes for the shared hierarchy
std::set<IfcSchema::Type::Enum> shared {
IfcSchema::Type::IfcSite,
IfcSchema::Type::IfcConversionBasedUnit,
IfcSchema::Type::IfcDimensionalExponents,
IfcSchema::Type::IfcMeasureWithUnit,
IfcSchema::Type::IfcProject,
IfcSchema::Type::IfcBuilding,
IfcSchema::Type::IfcPostalAddress,
IfcSchema::Type::IfcUnitAssignment,
IfcSchema::Type::IfcGeometricRepresentationSubContext,
IfcSchema::Type::IfcGeometricRepresentationContext,
IfcSchema::Type::IfcSIUnit,
IfcSchema::Type::IfcBuildingStorey
};
// Open the set of input files
std::vector<IfcParse::IfcFile*> files;
for (int i = 1; i < argc; ++i) {
files.push_back(new IfcParse::IfcFile());
files.back()->Init(argv[i]);
}
// Detect shared instances
std::set<IfcUtil::IfcBaseClass*> shared_instances;
for (auto& ty : shared) {
std::cout << IfcSchema::Type::ToString(ty) << std::endl;
for (auto& file : files) {
IfcEntityList::ptr insts = file->entitiesByType(ty);
std::vector<IfcUtil::IfcBaseClass*> no_subtypes;
std::copy_if(insts->begin(), insts->end(), std::back_inserter(no_subtypes), [ty](IfcUtil::IfcBaseClass* inst) {
return inst->declaration().type() == ty;
});
std::set<IfcUtil::IfcBaseClass*, ifc_inst_cmp> insts_unique(no_subtypes.begin(), no_subtypes.end());
if (insts_unique.size() != no_subtypes.size()) {
throw std::runtime_error("Non-unique instances encountered within file");
}
shared_instances.insert(insts_unique.begin(), insts_unique.end());
}
}
// Follow forward references for shared instances
std::set<IfcUtil::IfcBaseClass*> shared_instances_and_refs;
for (auto& inst : shared_instances) {
IfcEntityList::ptr insts = inst->data().file->traverse(inst);
// Filter out simple types
std::vector<IfcUtil::IfcBaseClass*> insts_without_types;
std::copy_if(insts->begin(), insts->end(), std::back_inserter(insts_without_types), [](IfcUtil::IfcBaseClass* inst) {
return inst->declaration().as_entity() != nullptr;
});
shared_instances_and_refs.insert(insts_without_types.begin(), insts_without_types.end());
}
time_t now_;
time(&now_);
int now = (int)now_;
// Create a novel ownerhistory for the shared hierarchy
IfcSchema::IfcPerson* person = new IfcSchema::IfcPerson(std::string("tfk"), std::string("Krijnen"), std::string("Thomas"), boost::none, boost::none, boost::none, boost::none, boost::none);
IfcSchema::IfcOrganization* org = new IfcSchema::IfcOrganization(std::string("TU/e"), "Eindhoven University of Technology", boost::none, boost::none, boost::none);
IfcSchema::IfcPersonAndOrganization* pando = new IfcSchema::IfcPersonAndOrganization(person, org, boost::none);
IfcSchema::IfcApplication* appl = new IfcSchema::IfcApplication(org, "v1", "IfcOpenShell-HDF5", "IfcOpenShell-HDF5");
IfcSchema::IfcOwnerHistory* owner_history = new IfcSchema::IfcOwnerHistory(pando, appl, IfcSchema::IfcStateEnum::IfcState_READONLY, IfcSchema::IfcChangeActionEnum::IfcChangeAction_ADDED, now, pando, appl, now);
std::vector<IfcUtil::IfcBaseClass*> replacements{ person, org, pando, appl, owner_history};
std::vector<IfcUtil::IfcBaseClass*> shared_instances_and_refs_vector(shared_instances_and_refs.begin(), shared_instances_and_refs.end());
IfcParse::IfcFile temp;
for (int i = 0; i < 0x1000001; ++i) temp.FreshId();
std::for_each(replacements.begin(), replacements.end(), [&shared_instances_and_refs_vector, &temp](IfcUtil::IfcBaseClass* new_inst) {
temp.addEntity(new_inst);
shared_instances_and_refs_vector.erase(
std::remove_if(shared_instances_and_refs_vector.begin(), shared_instances_and_refs_vector.end(), [new_inst](IfcUtil::IfcBaseClass* orig_inst) {
return orig_inst->declaration().type() == new_inst->declaration().type();
}),
shared_instances_and_refs_vector.end()
);
shared_instances_and_refs_vector.push_back(new_inst);
});
shared_instances_and_refs.clear();
shared_instances_and_refs.insert(shared_instances_and_refs_vector.begin(), shared_instances_and_refs_vector.end());
// Assign the new ownerhistory to rooted elements in the shared hierarchy
std::for_each(shared_instances_and_refs.begin(), shared_instances_and_refs.end(), [owner_history](IfcUtil::IfcBaseClass* inst) {
const IfcParse::entity* e = inst->declaration().as_entity();
if (e) {
auto attributes = e->all_attributes();
int index = 0;
std::for_each(attributes.begin(), attributes.end(), [&index, inst, owner_history](const IfcParse::entity::attribute* attr) {
const IfcParse::named_type* nt = attr->type_of_attribute()->as_named_type();
if (nt) {
const IfcParse::entity* e2 = nt->declared_type()->as_entity();
if (e2 && e2->type() == IfcSchema::Type::IfcOwnerHistory) {
IfcWrite::IfcWritableEntity* writable = new IfcWrite::IfcWritableEntity(&inst->data());
writable->setArgument(index, owner_history);
inst->data(writable);
}
}
index++;
});
}
});
std::set<IfcUtil::IfcBaseClass*, ifc_inst_cmp> shared_instances_and_refs_unique(shared_instances_and_refs.begin(), shared_instances_and_refs.end());
// Serialize models into different groups
IfcParse::Hdf5Settings settings;
settings.profile() = IfcParse::Hdf5Settings::standard_referenced;
settings.compress() = true;
settings.chunk_size() = 1024;
std::vector<std::string> names;
std::vector<std::pair<std::string::const_iterator, std::string::const_iterator>> fixes;
std::string common_prefix, common_postfix;
for (int i = 1; i < argc; ++i) {
names.push_back(argv[i]);
fixes.push_back({ names.back().begin(), names.back().end() - 1 });
}
while (true) {
std::vector<char> chars;
std::transform(fixes.begin(), fixes.end(), std::back_inserter(chars), [](auto& pair) {
if (pair.first == pair.second) return '\0';
return (*pair.first++);
});
auto pred = std::bind(std::equal_to<char>(), std::placeholders::_1, chars.front());
if (chars.front() != 0 && std::all_of(chars.begin()+1, chars.end(), pred)) {
common_prefix.push_back(chars.front());
} else {
break;
}
}
while (true) {
std::vector<char> chars;
std::transform(fixes.begin(), fixes.end(), std::back_inserter(chars), [](auto& pair) {
if (pair.first == pair.second) return '\0';
return (*pair.second--);
});
auto pred = std::bind(std::equal_to<char>(), std::placeholders::_1, chars.front());
if (chars.front() != 0 && std::all_of(chars.begin() + 1, chars.end(), pred)) {
common_postfix.insert(common_postfix.begin(), chars.front());
} else {
break;
}
}
H5::H5File file(common_prefix + common_postfix + ".hdf", H5F_ACC_TRUNC);
H5::Group group1 = file.createGroup("population");
IfcParse::IfcHdf5File ifc_hdf5(file, get_schema(), settings);
IfcParse::IfcSpfHeader header;
header.set_default();
IfcParse::instance_enumerator shared_insts_enum(&header, shared_instances_and_refs_unique.begin(), shared_instances_and_refs_unique.end());
multifile_instance_locator* locator = new multifile_instance_locator(file, group1, [&shared_instances_and_refs_unique](IfcUtil::IfcBaseClass* inst) {
auto it = shared_instances_and_refs_unique.find(inst);
if (it == shared_instances_and_refs_unique.end()) {
return inst;
} else {
return *it;
}
}, shared_instances_and_refs_unique.begin(), shared_instances_and_refs_unique.end());
ifc_hdf5.write_schema();
ifc_hdf5.write_population(group1, shared_insts_enum, locator);
int n = 0;
for (auto f : files) {
auto filename = argv[n++ + 1];
H5::Group discipline_group = file.createGroup(filename);
H5::Group child_group = discipline_group.createGroup("population");
locator->next(filename, child_group, f);
IfcParse::instance_enumerator inst_enum(&f->header(), locator->full_begin(), locator->full_end());
ifc_hdf5.write_population(child_group, inst_enum, locator);
}
return 0;
}
+472
View File
@@ -0,0 +1,472 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include "../../../src/ifcparse/IfcHdf5File.h"
#include "../../../src/ifcgeom/IfcGeom.h"
#include "../../../src/ifcparse/IfcWritableEntity.h"
#include <Bnd_Box.hxx>
#include <BRepBndLib.hxx>
#include <BRep_Builder.hxx>
#include <TopoDS_Compound.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepBuilderAPI_GTransform.hxx>
#include <algorithm>
#include "multifile_instance_locator.h"
void generate_bounding_boxes(IfcParse::IfcFile& f, const std::string& fn) {
IfcGeom::Kernel kernel;
auto unit_factor = kernel.initializeUnits(*f.entitiesByType<IfcSchema::IfcUnitAssignment>()->begin());
IfcGeom::IteratorSettings settings;
settings.convert_back_units() = true;
settings.disable_triangulation() = true;
settings.disable_opening_subtractions() = true;
IfcSchema::IfcProductDefinitionShape::list::ptr defs_ = f.entitiesByType<IfcSchema::IfcProductDefinitionShape>();
std::vector<IfcSchema::IfcProductDefinitionShape*> defs(defs_->begin(), defs_->end());
// Make sure to sort by id to have new definitions lining up in the same order
std::sort(defs.begin(), defs.end(), [](IfcSchema::IfcProductDefinitionShape* a, IfcSchema::IfcProductDefinitionShape* b) {
return a->data().id() < b->data().id();
});
std::ofstream str(fn.c_str(), std::ios_base::binary);
int N = defs.size(), n = 0;
std::cerr << "boxes:" << std::endl;
// In newer versions of IfcOpenShell this is a method Kernel::apply_transformation()
auto apply_transformation = [](const TopoDS_Shape& s, const gp_GTrsf& gt) {
if (gt.Form() == gp_Other) {
return BRepBuilderAPI_GTransform(s, gt, true).Shape();
}
gp_Trsf t = gt.Trsf();
if (t.Form() == gp_Identity) {
return s;
} else {
/// @todo set to 1. and exactly 1. or use epsilon?
if (t.ScaleFactor() != 1.) {
return BRepBuilderAPI_Transform(s, t, true).Shape();
} else {
return s.Moved(t);
}
}
};
// In newer versions of IfcOpenShell this is a method BRep::as_compound()
auto brep_as_compound = [&apply_transformation](const IfcGeom::Representation::BRep& brep) {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++it) {
const TopoDS_Shape& s = it->Shape();
gp_GTrsf trsf = it->Placement();
if (brep.settings().convert_back_units()) {
gp_Trsf scale;
scale.SetScaleFactor(1.0 / brep.settings().unit_magnitude());
trsf.PreMultiply(scale);
}
const TopoDS_Shape moved_shape = apply_transformation(s, trsf);
builder.Add(compound, moved_shape);
}
return compound;
};
// Generate non-aa bounding boxes in local coordinates as a tuple of six doubles from existing IfcProductDefinitionShape instances
std::for_each(defs.begin(), defs.end(), [&kernel, &brep_as_compound, &str, N, &n, &settings](IfcSchema::IfcProductDefinitionShape* def) {
Bnd_Box box;
auto prods = def->data().getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>();
if (prods->size() != 1) return;
IfcSchema::IfcProduct* prod = *prods->begin();
auto reps = def->Representations();
std::for_each(reps->begin(), reps->end(), [&kernel, &brep_as_compound, &settings, &box, prod](auto rep) {
if (rep->RepresentationIdentifier() == "Body") {
IfcGeom::BRepElement<double>* elem = kernel.create_brep_for_representation_and_product<double>(settings, rep, prod);
BRepBndLib::AddClose(brep_as_compound(elem->geometry()), box);
delete elem;
}
});
const size_t name = def->data().id();
double xyz[6];
box.Get(xyz[0], xyz[1], xyz[2], xyz[3], xyz[4], xyz[5]);
str.write((char*)&name, sizeof(size_t));
str.write((char*)xyz, sizeof(double) * 6);
if (n++ % 1000 == 0) {
std::cerr << "\r" << n * 100 / N << std::flush;
}
});
std::cerr << std::endl;
}
void find_geometric_types(IfcParse::IfcFile& f, const std::string& tfn) {
std::ofstream str(tfn.c_str(), std::ios_base::binary);
IfcSchema::IfcProductDefinitionShape::list::ptr defs_ = f.entitiesByType<IfcSchema::IfcProductDefinitionShape>();
std::vector<IfcSchema::IfcProductDefinitionShape*> defs(defs_->begin(), defs_->end());
// Make sure to sort by id to have new definitions lining up in the same order
std::sort(defs.begin(), defs.end(), [](IfcSchema::IfcProductDefinitionShape* a, IfcSchema::IfcProductDefinitionShape* b) {
return a->data().id() < b->data().id();
});
// Initial choice of geometric types
std::set<IfcSchema::Type::Enum> geometric_types{
IfcSchema::Type::IfcStyledItem, IfcSchema::Type::IfcMaterialDefinitionRepresentation, IfcSchema::Type::IfcStyledRepresentation,
IfcSchema::Type::IfcSurfaceStyleRendering, IfcSchema::Type::IfcSurfaceStyle, IfcSchema::Type::IfcPresentationLayerAssignment,
IfcSchema::Type::IfcPresentationStyleAssignment, IfcSchema::Type::IfcColourRgb
};
std::set<IfcSchema::Type::Enum> other_types;
// Find all instances
std::set<IfcUtil::IfcBaseClass*> geometric_instances;
for (auto ty : geometric_types) {
auto insts = f.entitiesByType(ty);
std::for_each(insts->begin(), insts->end(), [&geometric_instances](IfcUtil::IfcBaseClass* inst) {
geometric_instances.insert(inst);
});
}
int N, n;
// Not referenced. Revit generates unused IfcExtrudedAreaSolids some times.
auto repitems = f.entitiesByType(IfcSchema::Type::IfcRepresentationItem);
std::for_each(repitems->begin(), repitems->end(), [&f, &geometric_instances](IfcUtil::IfcBaseClass* inst) {
auto invs = f.getInverse(inst->data().id(), IfcSchema::Type::UNDEFINED, -1);
if (invs->size() == 0) {
auto refs = f.traverse(inst);
std::for_each(refs->begin(), refs->end(), [&geometric_instances](IfcUtil::IfcBaseClass* inst2) {
if (inst2->declaration().as_entity()) {
geometric_instances.insert(inst2);
}
});
}
});
// Recurse over forward attributes
auto vist_geometric = [&f, &geometric_types, &geometric_instances, &N, &n](IfcUtil::IfcBaseEntity* def) {
auto refs = f.traverse(def);
geometric_instances.insert(refs->begin(), refs->end());
std::for_each(refs->begin(), refs->end(), [&geometric_types](IfcUtil::IfcBaseClass* inst) {
if (inst->declaration().as_entity()) {
geometric_types.insert(inst->declaration().type());
}
});
if (n++ % 1000 == 0) {
std::cerr << "\r" << (n * 100 / N) << std::flush;
}
};
n = 0;
N = defs.size();
std::for_each(defs.begin(), defs.end(), vist_geometric);
// Include connection geometry (e.g space boundaries) as well
auto connection_geom = f.entitiesByType<IfcSchema::IfcConnectionGeometry>();
n = 0;
N = connection_geom->size();
std::for_each(connection_geom->begin(), connection_geom->end(), vist_geometric);
// Traverse again all instances, but now to detect which geometric types are fully and only shared by geometric instances
std::function<void(IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*)> fn;
fn = [&f, &geometric_instances, &other_types, &fn](IfcUtil::IfcBaseClass* root, IfcUtil::IfcBaseClass* inst) {
if (geometric_instances.find(inst) == geometric_instances.end()) {
auto ty = inst->declaration().type();
other_types.insert(ty);
auto refs = f.traverse(inst, 1);
std::for_each(refs->begin() + 1, refs->end(), [&fn, root](IfcUtil::IfcBaseClass* inst) {
if (inst->declaration().as_entity()) {
fn(root, inst);
}
});
}
};
N = std::distance(f.begin(), f.end());
n = 0;
std::for_each(f.begin(), f.end(), [&fn, N, &n](const auto& pair) {
fn(pair.second, pair.second);
if (n++ % 1000 == 0) {
std::cerr << "\r" << n * 100 / N << std::flush;
}
});
std::set<IfcSchema::Type::Enum> only_geometric;
std::set_difference(geometric_types.begin(), geometric_types.end(),
other_types.begin(), other_types.end(),
std::inserter(only_geometric, only_geometric.begin()));
only_geometric.erase(IfcSchema::Type::IfcGeometricRepresentationContext);
only_geometric.erase(IfcSchema::Type::IfcGeometricRepresentationSubContext);
std::cerr << "\nOnly geometric:" << std::endl;
for (auto ty : only_geometric) {
std::cerr << IfcSchema::Type::ToString(ty) << std::endl;
const size_t name = ty;
str.write((char*)&name, sizeof(size_t));
}
}
int main(int argc, char** argv) {
const std::string cache_fn = argv[1] + std::string(".boxes.bin");
const std::string types_fn = argv[1] + std::string(".types.bin");
if (argc == 2 && !ifstream(cache_fn).good()) {
std::string command = std::string("\"\"") + argv[0] + "\" \"" + argv[1] + "\" -b\"";
if (system(command.c_str()) != 0) {
return 1;
}
}
if (argc == 2 && !ifstream(types_fn).good()) {
std::string command = std::string("\"\"") + argv[0] + "\" \"" + argv[1] + "\" -t\"";
if (system(command.c_str()) != 0) {
return 1;
}
}
IfcParse::IfcFile f;
f.Init(argv[1]);
if (argc == 3 && std::string(argv[2]) == "-b") {
generate_bounding_boxes(f, cache_fn);
return 0;
}
if (argc == 3 && std::string(argv[2]) == "-t") {
find_geometric_types(f, types_fn);
return 0;
}
std::set<IfcSchema::Type::Enum> only_geometric;
{
std::ifstream str(types_fn.c_str(), std::ios_base::binary);
while (!str.eof()) {
size_t name;
str.read((char*)&name, sizeof(size_t));
only_geometric.insert((IfcSchema::Type::Enum) name);
}
}
std::set<IfcSchema::Type::Enum> property_types {
IfcSchema::Type::IfcRelDefines,
IfcSchema::Type::IfcPropertySetDefinition,
IfcSchema::Type::IfcTypeObject,
IfcSchema::Type::IfcProperty,
IfcSchema::Type::IfcPhysicalQuantity,
IfcSchema::Type::IfcRelAssociatesClassification,
IfcSchema::Type::IfcClassification,
IfcSchema::Type::IfcClassificationReference,
IfcSchema::Type::IfcRelAssociatesMaterial,
IfcSchema::Type::IfcMaterialList,
IfcSchema::Type::IfcMaterialLayerSetUsage,
IfcSchema::Type::IfcMaterialLayerSet,
IfcSchema::Type::IfcMaterialLayer,
IfcSchema::Type::IfcMaterial
};
std::vector<IfcUtil::IfcBaseClass*> new_defs, old_defs, old_prop_defs, old_geom_defs, old_box_defs, all_old_defs, all_defs;
std::for_each(only_geometric.begin(), only_geometric.end(), [&f, &old_geom_defs](IfcSchema::Type::Enum t) {
auto insts = f.entitiesByType(t);
std::for_each(insts->begin(), insts->end(), [t, &old_geom_defs](IfcUtil::IfcBaseClass* inst) {
if (inst->declaration().type() == t) {
old_geom_defs.push_back(inst);
}
});
});
std::for_each(f.begin(), f.end(), [&only_geometric, &old_defs, &old_prop_defs, &property_types](const auto& pair) {
IfcUtil::IfcBaseClass* inst = pair.second;
// This is checked the other way around to include subtypes
bool is_property = false;
for (auto pty : property_types) {
if (inst->declaration().is(pty)) {
is_property = true;
break;
}
}
auto ty = inst->declaration().type();
if (is_property) {
old_prop_defs.push_back(inst);
} else if (only_geometric.find(ty) == only_geometric.end()) {
old_defs.push_back(inst);
}
});
IfcSchema::IfcRepresentationContext* context = 0;
auto reps = (*f.entitiesByType<IfcSchema::IfcProductDefinitionShape>()->begin())->Representations();
std::for_each(reps->begin(), reps->end(), [&context](auto rep) {
IfcGeom::IfcRepresentationShapeItems items;
if (rep->RepresentationIdentifier() == "Body") {
context = rep->ContextOfItems();
}
});
auto id = f.FreshId();
int num_points_added = 0;
// Create bounding box representation from the 6-tuple definitions
{
std::ifstream str(cache_fn.c_str(), std::ios_base::binary);
while (!str.eof()) {
size_t name;
double xyz[6];
str.read((char*)&name, sizeof(size_t));
str.read((char*)xyz, sizeof(double) * 6);
IfcSchema::IfcCartesianPoint* corner = new IfcSchema::IfcCartesianPoint(std::vector<double>{xyz[0], xyz[1], xyz[2]});;
IfcSchema::IfcBoundingBox* bbox = new IfcSchema::IfcBoundingBox(corner, xyz[3] - xyz[0], xyz[4] - xyz[1], xyz[5] - xyz[2]);
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
items->push(bbox);
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(context, std::string("Body"), std::string("BoundingBox"), items);
IfcSchema::IfcRepresentation::list::ptr new_reps(new IfcSchema::IfcRepresentation::list);
new_reps->push(rep);
IfcSchema::IfcProductDefinitionShape* new_def = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, new_reps);
corner->data().isWritable()->setId(id++);
// NB: Corner is added to existing definitions
old_defs.push_back(corner); ++num_points_added;
new_defs.push_back(bbox);
new_defs.push_back(rep);
new_defs.push_back(new_def);
}
}
std::for_each(new_defs.begin(), new_defs.end(), [&id](auto new_def) {
new_def->data().isWritable()->setId(id++);
});
auto iden = [](IfcUtil::IfcBaseClass* inst) { return inst; };
std::set<IfcSchema::Type::Enum> old_new_geom_types;
std::vector<std::vector<IfcUtil::IfcBaseClass*>*> all_vectors = std::vector<std::vector<IfcUtil::IfcBaseClass*>*>{ &new_defs, &old_prop_defs, &old_defs, &old_geom_defs };
for (auto vec_ : all_vectors) {
auto& vec = *vec_;
for (auto& inst : vec) {
old_new_geom_types.insert(inst->declaration().type());
}
}
// Generate proper buckets of data and serialize
all_old_defs.insert(all_old_defs.end(), old_defs.begin(), old_defs.end());
all_old_defs.insert(all_old_defs.end(), old_prop_defs.begin(), old_prop_defs.end());
all_old_defs.insert(all_old_defs.end(), old_geom_defs.begin(), old_geom_defs.end());
all_defs.insert(all_defs.end(), all_old_defs.begin(), all_old_defs.end());
all_defs.insert(all_defs.end(), new_defs.begin(), new_defs.end());
old_box_defs.insert(old_box_defs.end(), old_defs.begin(), old_defs.end());
old_box_defs.insert(old_box_defs.end(), new_defs.begin(), new_defs.end());
auto contexts = f.entitiesByType<IfcSchema::IfcRepresentationContext>();
old_box_defs.insert(old_box_defs.end(), contexts->begin(), contexts->end());
{
int num_insts1 = std::distance(all_old_defs.begin(), all_old_defs.end());
int num_insts2 = std::distance(f.begin(), f.end());
if ((num_insts1 - num_points_added) != num_insts2) {
std::cerr << "Missign instances " << num_insts1 << " - " << num_points_added << " != " << num_insts2 << std::endl;
abort();
}
}
multifile_instance_locator* locator = new multifile_instance_locator(
old_new_geom_types.begin(), old_new_geom_types.end(),
all_old_defs.begin(), all_old_defs.end());
IfcParse::Hdf5Settings settings;
settings.profile() = IfcParse::Hdf5Settings::padded;
settings.compress() = true;
settings.chunk_size() = 1024;
H5::H5File hdf(argv[1] + std::string(".hdf"), H5F_ACC_TRUNC);
H5::H5File geom_hdf(argv[1] + std::string("-geometry.hdf"), H5F_ACC_TRUNC);
H5::H5File box_hdf(argv[1] + std::string("-bounding-boxes.hdf"), H5F_ACC_TRUNC);
H5::H5File prop_hdf(argv[1] + std::string("-properties.hdf"), H5F_ACC_TRUNC);
hdf.createGroup("geometry").close();
hdf.createGroup("bounding-boxes").close();
hdf.createGroup("properties").close();
hdf.mount("geometry", geom_hdf, H5::PropList::DEFAULT);
hdf.mount("bounding-boxes", box_hdf, H5::PropList::DEFAULT);
hdf.mount("properties", prop_hdf, H5::PropList::DEFAULT);
H5::Group main_population = hdf.createGroup("population");
H5::Group geom_population = hdf.createGroup("geometry/population");
H5::Group box_population = hdf.createGroup("bounding-boxes/population");
H5::Group prop_population = hdf.createGroup("properties/population");
{
IfcParse::IfcHdf5File ifc_hdf5(hdf, get_schema(), settings);
IfcParse::instance_categorizer categorizer(all_defs.begin(), all_defs.end());
ifc_hdf5.write_schema(&categorizer);
{
IfcParse::instance_enumerator enumerator(&f.header(), old_defs.begin(), old_defs.end());
ifc_hdf5.write_population(main_population, enumerator, locator);
}
{
IfcParse::instance_enumerator enumerator(&f.header(), old_geom_defs.begin(), old_geom_defs.end());
ifc_hdf5.write_population(geom_population, enumerator, locator);
}
{
IfcParse::instance_enumerator enumerator(&f.header(), old_prop_defs.begin(), old_prop_defs.end());
ifc_hdf5.write_population(prop_population, enumerator, locator);
}
{
// locator is setup with all_old_defs, need to switch to new_defs + old_defs for the cartesian points
// NB: also geom rep context
locator->next(box_population, old_box_defs.begin(), old_box_defs.end());
IfcParse::instance_enumerator enumerator(&f.header(), new_defs.begin(), new_defs.end());
ifc_hdf5.write_population(box_population, enumerator, locator);
}
}
}
@@ -0,0 +1,275 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
class multifile_instance_locator : public IfcParse::abstract_instance_locator {
public:
typedef std::function<IfcUtil::IfcBaseClass*(IfcUtil::IfcBaseClass*)> mapping_t;
typedef std::pair<
std::vector<IfcSchema::Type::Enum>,
std::vector< std::vector<IfcUtil::IfcBaseEntity*> >
> population_t;
typedef std::vector<IfcUtil::IfcBaseClass*>::const_iterator full_const_iterator;
private:
H5::H5File* root_file_;
mapping_t mapping_;
std::set<IfcUtil::IfcBaseClass*> initial_population_set_;
std::set<IfcSchema::Type::Enum> initial_types_included_set_;
population_t initial_population_;
population_t subsequent_population_;
std::vector<IfcUtil::IfcBaseClass*> subsequent_minus_initial_;
H5::Group* initial_group_;
H5::Group* subsequent_group_;
H5::H5File* subsequent_file_;
std::string root_;
public:
template <typename ForwardIterator>
multifile_instance_locator(H5::H5File& root_file, H5::Group& group, mapping_t mapping, ForwardIterator b, ForwardIterator e)
: root_file_(&root_file)
, mapping_(mapping)
, initial_group_(&group)
, subsequent_group_(nullptr)
{
initial_population_set_.insert(b, e);
std::set<IfcSchema::Type::Enum> names_set;
std::for_each(b, e, [this, &names_set](IfcUtil::IfcBaseClass* inst) {
IfcSchema::Type::Enum ty = inst->declaration().type();
if (names_set.find(ty) == names_set.end()) {
initial_population_.first.push_back(ty);
names_set.insert(ty);
}
});
std::sort(initial_population_.first.begin(), initial_population_.first.end());
std::for_each(this->begin(), this->end(), [this, &b, &e](IfcSchema::Type::Enum t) {
std::vector<IfcUtil::IfcBaseEntity*> by_type;
std::for_each(b, e, [t,&by_type](IfcUtil::IfcBaseClass* inst) {
if (inst->declaration().type() == t && inst->declaration().as_entity()) {
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
}
});
std::sort(by_type.begin(), by_type.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
return i1->data().id() < i2->data().id();
});
initial_population_.second.emplace_back(by_type);
});
}
template <typename ForwardIteratorTypes, typename ForwardIteratorInsts>
multifile_instance_locator(ForwardIteratorTypes types_all_begin, ForwardIteratorTypes types_all_end, ForwardIteratorInsts insts_begin, ForwardIteratorInsts insts_end)
: subsequent_group_(nullptr)
{
initial_population_.first.assign(types_all_begin, types_all_end);
std::sort(initial_population_.first.begin(), initial_population_.first.end());
std::for_each(this->begin(), this->end(), [this, &insts_begin, &insts_end](IfcSchema::Type::Enum t) {
std::vector<IfcUtil::IfcBaseEntity*> by_type;
std::for_each(insts_begin, insts_end, [t, &by_type](IfcUtil::IfcBaseClass* inst) {
if (inst->declaration().type() == t && inst->declaration().as_entity()) {
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
}
});
std::sort(by_type.begin(), by_type.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
return i1->data().id() < i2->data().id();
});
initial_population_.second.emplace_back(by_type);
});
}
const_iterator begin() const {
if (subsequent_group_) {
return subsequent_population_.first.begin();
} else {
return initial_population_.first.begin();
}
}
const_iterator end() const {
if (subsequent_group_) {
return subsequent_population_.first.end();
} else {
return initial_population_.first.end();
}
}
full_const_iterator full_begin() const {
return subsequent_minus_initial_.begin();
}
full_const_iterator full_end() const {
return subsequent_minus_initial_.end();
}
const std::vector<IfcUtil::IfcBaseEntity*>& instances(IfcSchema::Type::Enum t) {
if (subsequent_group_) {
return subsequent_population_.second[std::lower_bound(begin(), end(), t) - begin()];
} else {
return initial_population_.second[std::lower_bound(begin(), end(), t) - begin()];
}
}
std::pair<int, int> operator()(IfcUtil::IfcBaseClass* v) {
if (IfcSchema::Type::IsSimple(v->declaration().type())) {
throw std::exception("Simple type not expected here");
}
IfcSchema::Type::Enum t = v->declaration().type();
// This remains constant for subsequent model serializations?
auto& dataset_names = initial_population_.first;
auto tt = std::lower_bound(dataset_names.begin(), dataset_names.end(), t);
int a = std::distance(dataset_names.begin(), tt);
int b;
const std::vector<IfcUtil::IfcBaseEntity*>& insts = instances(t);
auto it = std::lower_bound(insts.begin(), insts.end(), v, [](IfcUtil::IfcBaseClass* other, IfcUtil::IfcBaseClass* val) {
// An ordering based on ID is not equivalent to an ordering based on pointer address!
return other->data().id() < val->data().id();
});
if (it == insts.end()) {
throw std::runtime_error("Unable to find instance");
}
b = std::distance(insts.begin(), it);
return std::make_pair(a, b);
}
void make_reference(IfcUtil::IfcBaseClass* v, void*& ptr) {
v = mapping_(v);
IfcSchema::Type::Enum t = v->declaration().type();
population_t* pop;
H5::Group* group;
boost::optional<std::string> current_root;
if (initial_population_set_.find(v) != initial_population_set_.end()) {
pop = &initial_population_;
group = initial_group_;
current_root = boost::none;
} else {
pop = &subsequent_population_;
group = subsequent_group_;
current_root = root_;
}
int a = std::lower_bound(pop->first.begin(), pop->first.end(), t) - pop->first.begin();
auto& vec = pop->second[a];
hsize_t coord = std::lower_bound(vec.begin(), vec.end(), v, [](IfcUtil::IfcBaseClass* other, IfcUtil::IfcBaseClass* val) {
return other->data().id() < val->data().id();
}) - vec.begin();
hsize_t dims = instances(v->declaration().type()).size();
H5::DataSpace space(1, &dims);
space.selectElements(H5S_SELECT_SET, 1, &coord);
const std::string path = IfcSchema::Type::ToString(pop->first[a]);
std::string full_path = group->getObjName() + "/" + path + "_objects" + "/" + path + "_instances";
root_file_->reference(ptr, full_path, space);
ptr = static_cast<uint8_t*>(ptr) + sizeof(hdset_reg_ref_t);
}
template <typename ForwardIt>
void next(H5::Group& group, ForwardIt insts_begin, ForwardIt insts_end) {
subsequent_group_ = &group;
subsequent_population_.first = initial_population_.first;
subsequent_population_.second.clear();
std::for_each(this->begin(), this->end(), [this, &insts_begin, &insts_end](IfcSchema::Type::Enum t) {
std::vector<IfcUtil::IfcBaseEntity*> by_type;
std::for_each(insts_begin, insts_end, [t, &by_type](IfcUtil::IfcBaseClass* inst) {
if (inst->declaration().type() == t && inst->declaration().as_entity()) {
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
}
});
std::sort(by_type.begin(), by_type.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
return i1->data().id() < i2->data().id();
});
subsequent_population_.second.emplace_back(by_type);
});
}
void next(const std::string& name, H5::Group& group, IfcParse::IfcFile* f) {
subsequent_group_ = &group;
root_ = name;
subsequent_population_.first.clear();
subsequent_population_.second.clear();
subsequent_minus_initial_.clear();
auto f_begin = f->begin();
auto f_end = f->end();
std::set<IfcSchema::Type::Enum> names_set;
std::for_each(f_begin, f_end, [this, &names_set](auto& pair) {
IfcUtil::IfcBaseClass* inst = mapping_(pair.second);
if (initial_population_set_.find(inst) == initial_population_set_.end()) {
IfcSchema::Type::Enum ty = inst->declaration().type();
if (names_set.find(ty) == names_set.end()) {
subsequent_population_.first.push_back(ty);
names_set.insert(ty);
}
subsequent_minus_initial_.push_back(inst);
}
});
auto& names = subsequent_population_.first;
std::sort(names.begin(), names.end());
auto& vecs = subsequent_population_.second;
vecs.resize(names.size());
std::for_each(f_begin, f_end, [this, &names, &vecs](auto& pair) {
IfcUtil::IfcBaseClass* inst = mapping_(pair.second);
if (initial_population_set_.find(inst) == initial_population_set_.end() && inst->declaration().as_entity()) {
IfcSchema::Type::Enum ty = inst->declaration().type();
auto a = std::lower_bound(names.begin(), names.end(), ty) - names.begin();
auto& by_type = vecs[a];
by_type.push_back((IfcUtil::IfcBaseEntity*) inst);
}
});
std::for_each(vecs.begin(), vecs.end(), [](auto& vec) {
std::sort(vec.begin(), vec.end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) {
return i1->data().id() < i2->data().id();
});
});
}
};
-17
View File
@@ -1,17 +0,0 @@
# ifc2ca
Files and scripts for the use of [`Code_Aster`](https://code-aster.org) in IFC-driven FEM analyses
### File Organisation
#### Scripts:
- [`ifc2ca.py`](ifc2ca.py): a python script to extract and create a `json` file from an `ifc` file
- [`scriptSalome.py`](scriptSalome.py): a python script to run in the [`Salome-Meca`](https://www.code-aster.org/spip.php?article303) environment. Creates the geometry and the mesh of the structure
- [`scriptCodeAster.py`](scriptCodeAster.py): a python script to create the input file (`.comm`) for Code_Aster
#### Analysis Models
A number of analysis models with all the relative input/output and script files are provided in [this repository](https://github.com/IfcOpenShell/analysis-models) within the IfcOpenShell Organization
---
### Current Status
Read [Change Log](changelog.md)
-504
View File
@@ -1,504 +0,0 @@
import json
import ifcopenshell
import os
class CA2IFC:
def __init__(self, inputFilename, outputFilename):
self.inputFilename = inputFilename
self.outputFilename = outputFilename
self.data = None
self.f = None
self.reps = {}
self.origin = None
self.xAxis = None
self.yAxis = None
self.zAxis = None
def convert(self):
# load json file
with open(self.inputFilename) as dataFile:
self.data = json.load(dataFile)
# initiate ifc file
self.f = ifcopenshell.file()
# create header
self.create_header()
# create global axes
globalAxes = self.create_global_axes()
localPlacement = self.f.createIfcLocalPlacement(None, globalAxes)
# TODO: create units
lengthUnit = self.f.createIfcSIUnit(None, "LENGTHUNIT", None, "METRE")
unitAssignment = self.f.createIfcUnitAssignment((lengthUnit,))
# create owner history
ownerHistory = self.create_owner_history()
# create representations and subrepresentations
self.reps = self.create_reference_subrep(globalAxes)
# create project and model
project = self.f.createIfcProject(
self.guid(), ownerHistory, "A Project", None, None, None, None, (self.reps["model"],), unitAssignment
)
model = self.f.createIfcStructuralAnalysisModel(
self.guid(),
ownerHistory,
self.data["name"],
None,
None,
"NOTDEFINED",
globalAxes,
None,
None,
localPlacement,
)
self.f.createIfcRelDeclares(self.guid(), ownerHistory, None, None, project, (model,))
# create materials
ifcMaterials = [None for _ in range(len(self.data["db"]["materials"]))]
for i, material in enumerate(self.data["db"]["materials"]):
ifcMaterials[i] = self.create_material(material)
# create profiles
ifcProfiles = [None for _ in range(len(self.data["db"]["profiles"]))]
for i, profile in enumerate(self.data["db"]["profiles"]):
ifcProfiles[i] = self.create_profile(profile)
# create material-profile sets
mpSets = list(
set([el["material"] + "-" + el["profile"] for el in self.data["elements"] if el["geometryType"] == "line"])
)
ifcMaterialProfileSets = [None for _ in range(len(mpSets))]
for i, mpSet in enumerate(mpSets):
materialIndex = [mat["ifcName"] for mat in self.data["db"]["materials"]].index(mpSet.split("-")[0])
profileIndex = [prof["ifcName"] for prof in self.data["db"]["profiles"]].index(mpSet.split("-")[1])
material = ifcMaterials[materialIndex]
profile = ifcProfiles[profileIndex]
matProf = self.f.createIfcMaterialProfile(
self.data["db"]["materials"][materialIndex]["name"]
+ " | "
+ self.data["db"]["profiles"][profileIndex]["profileName"],
None,
material,
profile,
)
ifcMaterialProfileSets[i] = self.f.createIfcMaterialProfileSet(None, None, (matProf,))
# create structural elements
ifcElements = [None for _ in range(len(self.data["elements"]))]
for i, el in enumerate(self.data["elements"]):
# geometry - product definition shape
prodDefShape = self.create_geometry(el)
if el["geometryType"] == "line":
# z axis TODO: group by elements
localZAxis = self.f.createIfcDirection(tuple(el["orientation"][2]))
# element
ifcElements[i] = self.f.createIfcStructuralCurveMember(
self.guid(),
ownerHistory,
el["name"],
None,
None,
localPlacement,
prodDefShape,
el["predefinedType"],
localZAxis,
)
if el["geometryType"] == "surface":
ifcElements[i] = self.f.createIfcStructuralSurfaceMember(
self.guid(),
ownerHistory,
el["name"],
None,
None,
localPlacement,
prodDefShape,
el["predefinedType"],
el["thickness"],
)
# create structural point connections
ifcConnections = [None for _ in range(len(self.data["connections"]))]
for i, conn in enumerate(self.data["connections"]):
# geometry - product definition shape
prodDefShape = self.create_geometry(conn)
# boundary conditions
if conn["appliedCondition"]:
bc = self.create_applied_conditions(conn["appliedCondition"], conn["geometryType"])
if conn["geometryType"] == "point":
appliedCondition = self.f.createIfcBoundaryNodeCondition(
None, bc["dx"], bc["dy"], bc["dz"], bc["drx"], bc["dry"], bc["drz"]
)
if conn["geometryType"] == "line":
appliedCondition = self.f.createIfcBoundaryEdgeCondition(
None, bc["dx"], bc["dy"], bc["dz"], bc["drx"], bc["dry"], bc["drz"]
)
if conn["geometryType"] == "surface":
appliedCondition = self.f.createIfcBoundaryFaceCondition(None, bc["dx"], bc["dy"], bc["dz"])
else:
appliedCondition = None
if conn["geometryType"] == "point":
# local axes
localAxes = self.create_orientation(conn["orientation"])
# connection
ifcConnections[i] = self.f.createIfcStructuralPointConnection(
self.guid(),
ownerHistory,
conn["name"],
None,
None,
localPlacement,
prodDefShape,
appliedCondition,
localAxes,
)
if conn["geometryType"] == "line":
# z axis TODO: group by elements
localZAxis = self.f.createIfcDirection(tuple(conn["orientation"][2]))
# connection
ifcConnections[i] = self.f.createIfcStructuralCurveConnection(
self.guid(),
ownerHistory,
conn["name"],
None,
None,
localPlacement,
prodDefShape,
appliedCondition,
localZAxis,
)
if conn["geometryType"] == "surface":
ifcConnections[i] = self.f.createIfcStructuralSurfaceConnection(
self.guid(), ownerHistory, conn["name"], None, None, localPlacement, prodDefShape, appliedCondition
)
# assign material-profile-sets
for i, mpSet in enumerate(mpSets):
groupOfElements = []
for j, el in enumerate(self.data["elements"]):
if el["geometryType"] == "line" and el["material"] + "-" + el["profile"] == mpSet:
groupOfElements.append(ifcElements[j])
if groupOfElements:
self.f.createIfcRelAssociatesMaterial(
self.guid(), ownerHistory, None, None, tuple(groupOfElements), ifcMaterialProfileSets[i]
)
# assign materials
for i, mat in enumerate(self.data["db"]["materials"]):
groupOfElements = []
for j, el in enumerate(self.data["elements"]):
if el["geometryType"] == "surface" and el["material"] == mat["ifcName"]:
groupOfElements.append(ifcElements[j])
if groupOfElements:
self.f.createIfcRelAssociatesMaterial(
self.guid(), ownerHistory, None, None, tuple(groupOfElements), ifcMaterials[i]
)
# create connections with elements
for i, el in enumerate(self.data["elements"]):
for conn in el["connections"]:
j = [c["ifcName"] for c in self.data["connections"]].index(conn["relatedConnection"])
geometryType = self.data["connections"][j]["geometryType"]
if conn["appliedCondition"]:
bc = self.create_applied_conditions(conn["appliedCondition"], geometryType)
if geometryType == "point":
appliedCondition = self.f.createIfcBoundaryNodeCondition(
None, bc["dx"], bc["dy"], bc["dz"], bc["drx"], bc["dry"], bc["drz"]
)
if geometryType == "line":
appliedCondition = self.f.createIfcBoundaryEdgeCondition(
None, bc["dx"], bc["dy"], bc["dz"], bc["drx"], bc["dry"], bc["drz"]
)
if geometryType == "surface":
appliedCondition = self.f.createIfcBoundaryFaceCondition(None, bc["dx"], bc["dy"], bc["dz"])
else:
appliedCondition = None
# local axes
localAxes = self.create_orientation(conn["orientation"])
if geometryType == "point":
if not conn["eccentricity"]:
self.f.createIfcRelConnectsStructuralMember(
self.guid(),
ownerHistory,
None,
None,
ifcElements[i],
ifcConnections[j],
appliedCondition,
None,
None,
localAxes,
)
else:
pointOnElement = self.f.createIfcCartesianPoint(tuple(conn["eccentricity"]["pointOnElement"]))
vector = conn["eccentricity"]["vector"]
connPointEcc = self.f.createIfcConnectionPointEccentricity(
pointOnElement, None, vector[0], vector[1], vector[2]
)
self.f.createIfcRelConnectsWithEccentricity(
self.guid(),
ownerHistory,
None,
None,
ifcElements[i],
ifcConnections[j],
appliedCondition,
None,
None,
localAxes,
connPointEcc,
)
if geometryType in ["line", "surface"]:
self.f.createIfcRelConnectsStructuralMember(
self.guid(),
ownerHistory,
None,
None,
ifcElements[i],
ifcConnections[j],
appliedCondition,
None,
None,
localAxes,
)
# assign elements and connections to group
self.f.createIfcRelAssignsToGroup(
self.guid(), ownerHistory, None, None, tuple(ifcElements + ifcConnections), None, model
)
# finalize ifc file
self.f.write(self.outputFilename)
def guid(self):
return ifcopenshell.guid.new()
def create_header(self):
self.f.wrapped_data.header.file_name.name = os.path.basename(self.outputFilename)
def create_global_axes(self):
self.xAxis = self.f.createIfcDirection((1.0, 0.0, 0.0))
self.yAxis = self.f.createIfcDirection((0.0, 1.0, 0.0))
self.zAxis = self.f.createIfcDirection((0.0, 0.0, 1.0))
self.origin = self.f.createIfcCartesianPoint((0.0, 0.0, 0.0))
axes = self.f.createIfcAxis2Placement3D(self.origin, self.zAxis, self.xAxis)
return axes
def create_orientation(self, orientation):
xAxis = self.f.createIfcDirection(tuple(orientation[0]))
zAxis = self.f.createIfcDirection(tuple(orientation[2]))
axes = self.f.createIfcAxis2Placement3D(self.origin, zAxis, xAxis)
return axes
def create_owner_history(self):
actor = self.f.createIfcActorRole("ENGINEER", None, None)
person = self.f.createIfcPerson("Christovasilis", None, "Ioannis", None, None, None, (actor,))
organization = self.f.createIfcOrganization(
None,
"IfcOpenShell",
"IfcOpenShell, an open source (LGPL) software library that helps users and software developers to work with the IFC file format.",
)
p_o = self.f.createIfcPersonAndOrganization(person, organization)
application = self.f.createIfcApplication(organization, "v0.0.x", "IFC2CA", "IFC2CA")
ownerHistory = self.f.createIfcOwnerHistory(p_o, application, "READWRITE", None, None, p_o, application)
return ownerHistory
def create_reference_subrep(self, globalAxes):
modelRep = self.f.createIfcGeometricRepresentationContext(None, "Model", 3, 1.0e-05, globalAxes, None)
bodySubRep = self.f.createIfcGeometricRepresentationSubContext(
"Body", "Model", None, None, None, None, modelRep, None, "MODEL_VIEW", None
)
refSubRep = self.f.createIfcGeometricRepresentationSubContext(
"Reference", "Model", None, None, None, None, modelRep, None, "GRAPH_VIEW", None
)
return {"model": modelRep, "body": bodySubRep, "reference": refSubRep}
def create_material(self, material):
ifcMaterial = self.f.createIfcMaterial(material["name"], None, material["category"])
mechProps = []
if "youngModulus" in material["mechProps"]:
youngModulus = self.f.createIfcPropertySingleValue(
"YoungModulus", None, self.f.createIfcModulusOfElasticityMeasure(material["mechProps"]["youngModulus"])
)
mechProps.append(youngModulus)
if "shearModulus" in material["mechProps"]:
shearModulus = self.f.createIfcPropertySingleValue(
"ShearModulus", None, self.f.createIfcModulusOfElasticityMeasure(material["mechProps"]["shearModulus"])
)
mechProps.append(shearModulus)
if "poissonRatio" in material["mechProps"]:
poissonRatio = self.f.createIfcPropertySingleValue(
"PoissonRatio", None, self.f.createIfcPositiveRatioMeasure(material["mechProps"]["poissonRatio"])
)
mechProps.append(poissonRatio)
if mechProps:
self.f.createIfcMaterialProperties(
"Pset_MaterialMechanical", material["name"], tuple(mechProps), ifcMaterial
)
commonProps = []
if "massDensity" in material["commonProps"]:
massDensity = self.f.createIfcPropertySingleValue(
"MassDensity", None, self.f.createIfcMassDensityMeasure(material["commonProps"]["massDensity"])
)
commonProps.append(massDensity)
if commonProps:
self.f.createIfcMaterialProperties("Pset_MaterialCommon", material["name"], tuple(commonProps), ifcMaterial)
return ifcMaterial
def create_profile(self, profile):
if profile["profileShape"] == "rectangular":
ifcProfile = self.f.createIfcRectangleProfileDef(
profile["profileType"], profile["profileName"], None, profile["xDim"], profile["yDim"]
)
if profile["profileShape"] == "iSymmetrical":
ifcProfile = self.f.createIfcIShapeProfileDef(
profile["profileType"],
profile["profileName"],
None,
profile["commonProps"]["overallWidth"],
profile["commonProps"]["overallDepth"],
profile["commonProps"]["webThickness"],
profile["commonProps"]["flangeThickness"],
profile["commonProps"]["filletRadius"],
)
mechProps = []
if "massPerLength" in profile["mechProps"]:
massPerLength = self.f.createIfcPropertySingleValue(
"MassPerLength", None, self.f.createIfcMassPerLengthMeasure(profile["mechProps"]["massPerLength"])
)
mechProps.append(massPerLength)
if "crossSectionArea" in profile["mechProps"]:
crossSectionArea = self.f.createIfcPropertySingleValue(
"CrossSectionArea", None, self.f.createIfcAreaMeasure(profile["mechProps"]["crossSectionArea"])
)
mechProps.append(crossSectionArea)
if "momentOfInertiaY" in profile["mechProps"]:
momentOfInertiaY = self.f.createIfcPropertySingleValue(
"MomentOfInertiaY",
None,
self.f.createIfcMomentOfInertiaMeasure(profile["mechProps"]["momentOfInertiaY"]),
)
mechProps.append(momentOfInertiaY)
if "momentOfInertiaZ" in profile["mechProps"]:
momentOfInertiaZ = self.f.createIfcPropertySingleValue(
"MomentOfInertiaZ",
None,
self.f.createIfcMomentOfInertiaMeasure(profile["mechProps"]["momentOfInertiaZ"]),
)
mechProps.append(momentOfInertiaZ)
if "torsionalConstantX" in profile["mechProps"]:
torsionalConstantX = self.f.createIfcPropertySingleValue(
"TorsionalConstantX",
None,
self.f.createIfcMomentOfInertiaMeasure(profile["mechProps"]["torsionalConstantX"]),
)
mechProps.append(torsionalConstantX)
if mechProps:
self.f.createIfcProfileProperties(
"Pset_ProfileMechanical", profile["profileName"], tuple(mechProps), ifcProfile
)
return ifcProfile
def create_geometry(self, object):
if object["geometryType"] == "point":
point = self.f.createIfcCartesianPoint(tuple(object["geometry"]))
vertex = self.f.createIfcVertexPoint(point)
vertexTopologyRep = self.f.createIfcTopologyRepresentation(
self.reps["reference"], "Reference", "Vertex", (vertex,)
)
vertexProdDefShape = self.f.createIfcProductDefinitionShape(None, None, (vertexTopologyRep,))
return vertexProdDefShape
if object["geometryType"] == "line":
startPoint = self.f.createIfcCartesianPoint(tuple(object["geometry"][0]))
startVertex = self.f.createIfcVertexPoint(startPoint)
endPoint = self.f.createIfcCartesianPoint(tuple(object["geometry"][1]))
endVertex = self.f.createIfcVertexPoint(endPoint)
edge = self.f.createIfcEdge(startVertex, endVertex)
edgeTopologyRep = self.f.createIfcTopologyRepresentation(
self.reps["reference"], "Reference", "Edge", (edge,)
)
edgeProdDefShape = self.f.createIfcProductDefinitionShape(None, None, (edgeTopologyRep,))
return edgeProdDefShape
if object["geometryType"] == "surface":
verts = [None for _ in range(len(object["geometry"]))]
for i, p in enumerate(object["geometry"]):
point = self.f.createIfcCartesianPoint(tuple(p))
verts[i] = self.f.createIfcVertexPoint(point)
orientedEdges = [None for _ in range(len(object["geometry"]))]
for i, v in enumerate(verts):
v2Index = (i + 1) if i < len(verts) - 1 else 0
edge = self.f.createIfcEdge(v, verts[v2Index])
orientedEdges[i] = self.f.createIfcOrientedEdge(None, None, edge, True)
edgeLoop = self.f.createIfcEdgeLoop(tuple(orientedEdges))
localAxes = self.create_orientation(object["orientation"])
plane = self.f.createIfcPlane(localAxes)
faceBound = self.f.createIfcFaceBound(edgeLoop, True)
face = self.f.createIfcFaceSurface((faceBound,), plane, True)
faceTopologyRep = self.f.createIfcTopologyRepresentation(
self.reps["reference"], "Reference", "Face", (face,)
)
faceProdDefShape = self.f.createIfcProductDefinitionShape(None, None, (faceTopologyRep,))
return faceProdDefShape
def create_applied_conditions(self, bc, geometryType):
for dof in ["dx", "dy", "dz"]:
if isinstance(bc[dof], bool):
bc[dof] = self.f.createIfcBoolean(bc[dof])
else:
if geometryType == "point":
bc[dof] = self.f.createIfcLinearStiffnessMeasure(bc[dof])
if geometryType == "line":
bc[dof] = self.f.createIfcModulusOfLinearSubgradeReactionMeasure(bc[dof])
if geometryType == "surface":
bc[dof] = self.f.createIfcModulusOfSubgradeReactionMeasure(bc[dof])
for dof in ["drx", "dry", "drz"]:
if isinstance(bc[dof], bool):
bc[dof] = self.f.createIfcBoolean(bc[dof])
else:
if geometryType == "point":
bc[dof] = self.f.createIfcRotationalStiffnessMeasure(bc[dof])
if geometryType == "line":
bc[dof] = self.f.createIfcModulusOfRotationalSubgradeReactionMeasure(bc[dof])
return bc
if __name__ == "__main__":
inputFilename = "structure_01.json"
outputFilename = "structure_01.ifc"
ca2ifc = CA2IFC(inputFilename, outputFilename)
ca2ifc.convert()
-34
View File
@@ -1,34 +0,0 @@
## A change log of the ifc2ca files
##### 14/10/20
- Add curve connections betweeen elements and as supports according to the defined orientation - stiffness is not yet considered
##### 17/08/20
- Add rigid links for point connection to elements
##### 14/07/20
- Add internal springs for point connection to elements according to the defined orientation
- Add external springs for point connections according to the defined orientation
##### 27/05/20
- Add orientation for point, curve and surface geometries
- Calculate final geometry and orientation based on object placement transformation
- Add warnings in the json file to show any corrections considered while parsing the ifc file from ETABS with a model with rigid links
- Reduce file size by adding material and profile db in the json file and referencing them in the element objects
- Implement internal releases for curve-to-point connections with any arbitrary orientation
##### 22/03/20
- Calculation of section properties for I symmetric profile if not provided (assuming fillet radius is zero)
- Added geometry of planar structural surface members
- Refactored the ifc2ca.py script
- Added support for rigid links
- Added advanced meshing script to correctly simulate connections and independent meshing of structural elements (no common nodes)
##### 26/02/20
- Changed section to profile and added I profile
- Modified material and profile schema with mechanical and common properties
- Added geometry identification for point connection from representation
- Added connections along with supports based on the number of elements a connection is applied to
##### 09/02/20
- First implementation for straight structural curve elements and point connections
-547
View File
@@ -1,547 +0,0 @@
from __future__ import division
from __future__ import print_function
import json
import ifcopenshell
import numpy as np
class IFC2CA:
def __init__(self, filename):
self.filename = filename
self.file = None
self.result = {}
self.warnings = []
self.tol = 1e-06
def convert(self):
self.file = ifcopenshell.open(self.filename)
for model in self.file.by_type("IfcStructuralAnalysisModel"):
elements = self.get_structural_items(model, item_type="IfcStructuralMember")
connections = self.get_structural_items(model, item_type="IfcStructuralConnection")
materialdb = []
materials = list(dict.fromkeys([e["material"] for e in elements]))
for mat in [mat for mat in materials if mat]:
id = int(mat.split("|")[1])
material = self.get_material_properties(self.file.by_id(id))
material["relatedElements"] = [
e["ifcName"] for e in elements if "material" in e and e["material"] == mat
]
materialdb.append(material)
profiledb = []
profiles = list(dict.fromkeys([e["profile"] for e in elements if "profile" in e]))
for prof in [prof for prof in profiles if prof]:
id = int(prof.split("|")[1])
profile = self.get_profile_properties(self.file.by_id(id))
profile["relatedElements"] = [e["ifcName"] for e in elements if "profile" in e and e["profile"] == prof]
profiledb.append(profile)
self.result = {
"ifcName": model.is_a() + "|" + str(model.id()),
"name": model.Name,
"id": model.GlobalId,
"elements": elements,
"connections": connections,
"db": {"materials": materialdb, "profiles": profiledb},
"warnings": self.warnings,
}
print('Model "%s" converted' % model.Name)
print("Number of elements: ", len(elements))
print("Number of connections: ", len(connections))
print("Number of materials: ", len(materialdb))
print("Number of profiles: ", len(profiledb))
print("")
break
def get_structural_items(self, model, item_type="IfcStructuralItem"):
items = []
for group in model.IsGroupedBy:
for item in group.RelatedObjects:
if not item.is_a(item_type):
continue
data = self.get_item_data(item)
if data:
items.append(data)
return items
def get_item_data(self, item):
transformation = self.get_transformation(item.ObjectPlacement)
if item.is_a("IfcStructuralCurveMember"):
representation = self.get_representation(item, "Edge")
material_profile = self.get_material_profile(item)
if not representation:
self.warnings.append(
"No representation defined for %s. Member excluded" % (item.is_a() + "|" + str(item.id()))
)
return
if not material_profile:
self.warnings.append("No material defined for in %s" % (item.is_a() + "|" + str(item.id())))
self.warnings.append("No profile defined for in %s" % (item.is_a() + "|" + str(item.id())))
materialId = None
profileId = None
else:
material = material_profile.Material
materialId = material.is_a() + "|" + str(material.id())
profile = material_profile.Profile
profileId = profile.is_a() + "|" + str(profile.id())
geometry = self.get_geometry(representation)
orientation = self.get_1D_orientation(geometry, item.Axis)
connections = self.get_connection_data(item.ConnectedBy)
for conn in connections:
if not conn["orientation"]:
conn["orientation"] = orientation
# --> Correct pointOnElement for eccentricity connection for ETABS files
length = np.linalg.norm(np.array(geometry[1]) - np.array(geometry[0]))
for c in connections:
if c["eccentricity"]:
if np.linalg.norm(np.array(c["eccentricity"]["pointOnElement"])) > length + self.tol:
print(np.linalg.norm(np.array(c["eccentricity"]["pointOnElement"])), ">", length)
self.warnings.append("Eccentricity in %s corrected" % (item.is_a() + "|" + str(item.id())))
c["eccentricity"]["pointOnElement"][0] = length
# End <--
if transformation:
geometry = self.transform_vectors(geometry, transformation)
orientation = self.transform_vectors(orientation, transformation, include_translation=False)
for c in connections:
c["orientation"] = self.transform_vectors(
c["orientation"], transformation, include_translation=False
)
if c["eccentricity"]:
c["eccentricity"]["vector"] = self.transform_vectors(
c["eccentricity"]["vector"], transformation, include_translation=False
)
return {
"ifcName": item.is_a() + "|" + str(item.id()),
"name": item.Name,
"id": item.GlobalId,
"geometryType": "line",
"predefinedType": item.PredefinedType,
"geometry": geometry,
"orientation": orientation,
"material": materialId,
"profile": profileId,
"connections": connections,
}
elif item.is_a("IfcStructuralSurfaceMember"):
representation = self.get_representation(item, "Face")
material = self.get_material_profile(item)
if not representation:
self.warnings.append(
"No representation defined for %s. Member excluded" % (item.is_a() + "|" + str(item.id()))
)
return
if not material:
self.warnings.append("No material defined for in %s" % (item.is_a() + "|" + str(item.id())))
materialId = None
else:
materialId = material.is_a() + "|" + str(material.id())
geometry = self.get_geometry(representation)
orientation = self.get_2D_orientation(representation)
connections = self.get_connection_data(item.ConnectedBy)
for conn in connections:
if not conn["orientation"]:
conn["orientation"] = orientation
if transformation:
geometry = self.transform_vectors(geometry, transformation)
orientation = self.transform_vectors(orientation, transformation, include_translation=False)
for c in connections:
c["orientation"] = self.transform_vectors(
c["orientation"], transformation, include_translation=False
)
return {
"ifcName": item.is_a() + "|" + str(item.id()),
"name": item.Name,
"id": item.GlobalId,
"geometryType": "surface",
"predefinedType": item.PredefinedType,
"thickness": item.Thickness,
"geometry": geometry,
"orientation": orientation,
"material": materialId,
"connections": connections,
}
elif item.is_a("IfcStructuralPointConnection"):
representation = self.get_representation(item, "Vertex")
if not representation:
self.warnings.append(
"No representation defined for %s. Connection excluded" % (item.is_a() + "|" + str(item.id()))
)
return
geometry = self.get_geometry(representation)
orientation = self.get_0D_orientation(item.ConditionCoordinateSystem)
if not orientation:
orientation = np.eye(3).tolist()
if transformation:
geometry = self.transform_vectors(geometry, transformation)
orientation = self.transform_vectors(orientation, transformation, include_translation=False)
return {
"ifcName": item.is_a() + "|" + str(item.id()),
"name": item.Name,
"id": item.GlobalId,
"geometryType": "point",
"geometry": geometry,
"orientation": orientation,
"appliedCondition": self.get_connection_input(item, "point"),
"relatedElements": [con.is_a() + "|" + str(con.id()) for con in item.ConnectsStructuralMembers],
}
elif item.is_a("IfcStructuralCurveConnection"):
representation = self.get_representation(item, "Edge")
if not representation:
self.warnings.append(
"No representation defined for %s. Connection excluded" % (item.is_a() + "|" + str(item.id()))
)
return
geometry = self.get_geometry(representation)
orientation = self.get_1D_orientation(geometry, item.Axis)
if not orientation:
orientation = np.eye(3).tolist()
if transformation:
geometry = self.transform_vectors(geometry, transformation)
orientation = self.transform_vectors(orientation, transformation, include_translation=False)
return {
"ifcName": item.is_a() + "|" + str(item.id()),
"name": item.Name,
"id": item.GlobalId,
"geometryType": "line",
"geometry": geometry,
"orientation": orientation,
"appliedCondition": self.get_connection_input(item, "line"),
"relatedElements": [con.is_a() + "|" + str(con.id()) for con in item.ConnectsStructuralMembers],
}
def get_transformation(self, placement):
if not placement:
return None
if placement.is_a("IfcLocalPlacement"):
if placement.PlacementRelTo:
print("Warning! Object Placement with PlacementRelTo attribute is not supported and will be neglected")
axes = placement.RelativePlacement
location = np.array(self.get_coordinate(axes.Location))
if axes.Axis and axes.RefDirection:
xAxis = np.array(axes.RefDirection.DirectionRatios) # this can be not accurate (in the xz plane)
zAxis = np.array(axes.Axis.DirectionRatios)
zAxis /= np.linalg.norm(zAxis)
yAxis = np.cross(zAxis, xAxis)
yAxis /= np.linalg.norm(yAxis)
xAxis = np.cross(yAxis, zAxis)
xAxis /= np.linalg.norm(xAxis)
else:
if np.allclose(location, np.array([0.0, 0.0, 0.0])):
return None
xAxis = np.array([1.0, 0.0, 0.0])
yAxis = np.array([0.0, 1.0, 0.0])
zAxis = np.array([0.0, 0.0, 1.0])
if (
np.allclose(location, np.array([0.0, 0.0, 0.0]))
and np.allclose(xAxis, np.array([1.0, 0.0, 0.0]))
and np.allclose(yAxis, np.array([0.0, 1.0, 0.0]))
and np.allclose(zAxis, np.array([0.0, 0.0, 1.0]))
):
return None
return {"location": location, "rotationMatrix": np.array([xAxis, yAxis, zAxis]).transpose()}
else:
print(
"Warning! Object Placement is of type %s, which is not supported. Default considered" % placement.is_a()
)
return None
def get_representation(self, element, rep_type):
if not element.Representation:
return None
for representation in element.Representation.Representations:
rep = self.get_specific_representation(representation, "Reference", rep_type)
if rep:
return rep
else:
# print('Trying without rep identifier')
for representation in element.Representation.Representations:
rep = self.get_specific_representation(representation, None, rep_type)
if rep:
return rep
def get_specific_representation(self, representation, rep_id, rep_type):
if (
representation.RepresentationIdentifier == rep_id or rep_id is None
) and representation.RepresentationType == rep_type:
return representation
if representation.RepresentationType == "MappedRepresentation":
return self.get_specific_representation(
representation.Items[0].MappingSource.MappedRepresentation, rep_id, rep_type
)
def get_geometry(self, representation):
# Maybe IfcOpenShell can use create_shape here to simplify this, but
# supposedly structural models are very simple anyway, so perhaps we
# can do without it.
item = representation.Items[0]
if item.is_a("IfcEdge"):
return [
self.get_coordinate(item.EdgeStart.VertexGeometry),
self.get_coordinate(item.EdgeEnd.VertexGeometry),
]
elif item.is_a("IfcFaceSurface"):
edges = item.Bounds[0].Bound.EdgeList
coords = []
for edge in edges:
coords.append(self.get_coordinate(edge.EdgeElement.EdgeStart.VertexGeometry))
return coords
elif item.is_a("IfcVertexPoint"):
return self.get_coordinate(item.VertexGeometry)
def get_coordinate(self, point):
if point.is_a("IfcCartesianPoint"):
return list(point.Coordinates)
def get_0D_orientation(self, axes):
if axes and axes.Axis and axes.RefDirection:
xAxis = np.array(
axes.RefDirection.DirectionRatios
) # this can be not strictly perpendicular (in the xz plane)
zAxis = np.array(axes.Axis.DirectionRatios)
zAxis /= np.linalg.norm(zAxis)
yAxis = np.cross(zAxis, xAxis)
yAxis /= np.linalg.norm(yAxis)
xAxis = np.cross(yAxis, zAxis)
xAxis /= np.linalg.norm(xAxis)
return [xAxis.tolist(), yAxis.tolist(), zAxis.tolist()]
else: # return None and copy the elements orientation
return None
def get_1D_orientation(self, geometry, zAxis):
xAxis = np.array(geometry[1]) - np.array(geometry[0])
xAxis /= np.linalg.norm(xAxis)
zAxis = np.array(zAxis.DirectionRatios) # this can be not strictly perpendicular (in the xz plane)
yAxis = np.cross(zAxis, xAxis)
yAxis /= np.linalg.norm(yAxis)
zAxis = np.cross(xAxis, yAxis)
zAxis /= np.linalg.norm(zAxis)
return [xAxis.tolist(), yAxis.tolist(), zAxis.tolist()]
def get_2D_orientation(self, representation):
item = representation.Items[0]
if item.is_a("IfcFaceSurface"):
item.SameSense
axes = item.FaceSurface.Position
orientation = self.get_0D_orientation(axes)
if not item.SameSense:
orientation = [[-v for v in vec] for vec in orientation]
return orientation
def transform_vectors(self, geometry, trsf, include_translation=True):
if not any(isinstance(el, list) for el in geometry): # single point which contains no list
geometry = [geometry]
globalGeometry = []
for p in geometry:
gp = trsf["rotationMatrix"].dot(np.array(p))
if include_translation:
gp += trsf["location"]
globalGeometry.append(gp.tolist())
if len(globalGeometry) == 1: # single point
globalGeometry = globalGeometry[0]
return globalGeometry
def get_material_profile(self, element):
if not element.HasAssociations:
return None
for association in element.HasAssociations:
if not association.is_a("IfcRelAssociatesMaterial"):
continue
material = association.RelatingMaterial
if material.is_a("IfcMaterialProfileSet"):
# For now, we only deal with a single profile
return material.MaterialProfiles[0]
if material.is_a("IfcMaterialProfileSetUsage"):
return material.ForProfileSet.MaterialProfiles[0]
if material.is_a("IfcMaterial"):
return material
def get_material_properties(self, material):
psets = material.HasProperties
if self.get_pset_properties(psets, "Pset_MaterialMechanical"):
mechProps = self.get_pset_properties(psets, "Pset_MaterialMechanical")
else:
mechProps = self.get_pset_properties(psets, None)
if self.get_pset_properties(psets, "Pset_MaterialCommon"):
commonProps = self.get_pset_properties(psets, "Pset_MaterialCommon")
else:
commonProps = self.get_pset_properties(psets, None)
return {
"ifcName": material.is_a() + "|" + str(material.id()),
"name": material.Name,
"category": material.Category,
"mechProps": mechProps,
"commonProps": commonProps,
}
def get_pset_property(self, psets, pset_name, prop_name):
for pset in psets:
if pset.Name == pset_name or pset_name is None:
for prop in pset.Properties:
if prop.Name == prop_name:
return prop.NominalValue.wrappedValue
def get_pset_properties(self, psets, pset_name):
for pset in psets:
if pset.Name == pset_name or pset_name is None:
d = {}
for prop in pset.Properties:
propName = prop.Name[0].lower() + prop.Name[1:]
d[propName] = prop.NominalValue.wrappedValue
return d
def get_profile_properties(self, profile):
if profile.is_a("IfcRectangleProfileDef"):
return {
"ifcName": profile.is_a() + "|" + str(profile.id()),
"profileName": profile.ProfileName,
"profileType": profile.ProfileType,
"profileShape": "rectangular",
"xDim": profile.XDim,
"yDim": profile.YDim,
}
if profile.is_a("IfcIShapeProfileDef"):
psets = profile.HasProperties
if self.get_pset_properties(psets, "Pset_ProfileMechanical"):
mechProps = self.get_pset_properties(psets, "Pset_ProfileMechanical")
else:
mechProps = self.get_i_section_properties(profile, "iSymmetrical")
return {
"ifcName": profile.is_a() + "|" + str(profile.id()),
"profileName": profile.ProfileName,
"profileType": profile.ProfileType,
"profileShape": "iSymmetrical",
"mechProps": mechProps,
"commonProps": {
"flangeThickness": profile.FlangeThickness,
"webThickness": profile.WebThickness,
"overallDepth": profile.OverallDepth,
"overallWidth": profile.OverallWidth,
"filletRadius": profile.FilletRadius,
},
}
def get_connection_data(self, itemList):
return [
{
"ifcName": rel.is_a() + "|" + str(rel.id()),
"id": rel.GlobalId,
"relatingElement": rel.RelatingStructuralMember.is_a() + "|" + str(rel.RelatingStructuralMember.id()),
"relatedConnection": rel.RelatedStructuralConnection.is_a()
+ "|"
+ str(rel.RelatedStructuralConnection.id()),
"orientation": self.get_0D_orientation(rel.ConditionCoordinateSystem),
"appliedCondition": self.get_connection_input(
rel, self.get_geometry_type_from_connection(rel.RelatedStructuralConnection)
),
"eccentricity": None
if not rel.is_a("IfcRelConnectsWithEccentricity")
else {
"vector": [
0.0
if not rel.ConnectionConstraint.EccentricityInX
else rel.ConnectionConstraint.EccentricityInX,
0.0
if not rel.ConnectionConstraint.EccentricityInY
else rel.ConnectionConstraint.EccentricityInY,
0.0
if not rel.ConnectionConstraint.EccentricityInZ
else rel.ConnectionConstraint.EccentricityInZ,
],
"pointOnElement": self.get_coordinate(rel.ConnectionConstraint.PointOnRelatingElement),
},
}
for rel in itemList
]
def get_geometry_type_from_connection(self, connection):
if connection.is_a("IfcStructuralPointConnection"):
return "point"
if connection.is_a("IfcStructuralCurveConnection"):
return "line"
if connection.is_a("IfcStructuralSurfaceConnection"):
return "surface"
def get_connection_input(self, connection, geometryType):
if connection.AppliedCondition:
if geometryType == "point":
return {
"dx": connection.AppliedCondition.TranslationalStiffnessX.wrappedValue,
"dy": connection.AppliedCondition.TranslationalStiffnessY.wrappedValue,
"dz": connection.AppliedCondition.TranslationalStiffnessZ.wrappedValue,
"drx": connection.AppliedCondition.RotationalStiffnessX.wrappedValue,
"dry": connection.AppliedCondition.RotationalStiffnessY.wrappedValue,
"drz": connection.AppliedCondition.RotationalStiffnessZ.wrappedValue,
}
if geometryType == "line":
return {
"dx": connection.AppliedCondition.TranslationalStiffnessByLengthX.wrappedValue,
"dy": connection.AppliedCondition.TranslationalStiffnessByLengthY.wrappedValue,
"dz": connection.AppliedCondition.TranslationalStiffnessByLengthZ.wrappedValue,
"drx": connection.AppliedCondition.RotationalStiffnessByLengthX.wrappedValue,
"dry": connection.AppliedCondition.RotationalStiffnessByLengthY.wrappedValue,
"drz": connection.AppliedCondition.RotationalStiffnessByLengthZ.wrappedValue,
}
if geometryType == "surface":
return {
"dx": connection.AppliedCondition.TranslationalStiffnessByAreaX.wrappedValue,
"dy": connection.AppliedCondition.TranslationalStiffnessByAreaY.wrappedValue,
"dz": connection.AppliedCondition.TranslationalStiffnessByAreaZ.wrappedValue,
}
return connection.AppliedCondition
def get_i_section_properties(self, profile, profileShape):
if profileShape == "iSymmetrical":
tf = profile.FlangeThickness
tw = profile.WebThickness
h = profile.OverallDepth
b = profile.OverallWidth
A = b * h - (b - tw) * (h - 2 * tf)
Iy = b * (h ** 3) / 12 - (b - tw) * ((h - 2 * tf) ** 3) / 12
Iz = (2 * tf) * (b ** 3) / 12 + (h - 2 * tf) * (tw ** 3) / 12
Jx = 1 / 3 * ((h - tf) * (tw ** 3) + 2 * b * (tf ** 3))
return {"crossSectionArea": A, "momentOfInertiaY": Iy, "momentOfInertiaZ": Iz, "torsionalConstantX": Jx}
if __name__ == "__main__":
fileNames = ["cantilever_01", "portal_01", "grid_of_beams", "slab_01", "structure_01"]
files = fileNames
for fileName in files:
BASE_PATH = "/home/jesusbill/Dev-Projects/github.com/IfcOpenShell/analysis-models/ifcFiles/"
ifc2ca = IFC2CA(BASE_PATH + fileName + ".ifc")
ifc2ca.convert()
with open(BASE_PATH + fileName + ".json", "w") as f:
f.write(json.dumps(ifc2ca.result, indent=4))
-903
View File
@@ -1,903 +0,0 @@
import json
import numpy as np
import itertools
flatten = itertools.chain.from_iterable
class COMMANDFILE:
def __init__(self, dataFilename, asterFilename):
self.dataFilename = dataFilename
self.asterFilename = asterFilename
self.create()
def getGroupName(self, name):
info = name.split("|")
sortName = "".join(c for c in info[0] if c.isupper())
return str(sortName + "_" + info[1])
def create(self):
AccelOfGravity = 9.806 # m/sec^2
# Read data from input file
with open(self.dataFilename) as dataFile:
data = json.load(dataFile)
elements = data["elements"]
connections = data["connections"]
# --> Delete this reference data and repopulate it with the objects
# while going through elements
for conn in connections:
conn["relatedElements"] = []
self.calculateRestraints(conn)
for el in elements:
for rel in el["connections"]:
conn = [c for c in connections if c["ifcName"] == rel["relatedConnection"]][0]
rel["conn_string"] = None
if conn["geometryType"] == "point":
rel["conn_string"] = "_0DC_"
rel["springGroupName"] = (
self.getGroupName(rel["relatingElement"])
+ "_1DS_"
+ self.getGroupName(rel["relatedConnection"])
)
if conn["geometryType"] == "line":
rel["conn_string"] = "_1DC_"
rel["springGroupName"] = None
if conn["geometryType"] == "surface":
rel["conn_string"] = "_2DC_"
rel["springGroupName"] = None
rel["groupName1"] = (
self.getGroupName(rel["relatingElement"])
+ rel["conn_string"]
+ self.getGroupName(rel["relatedConnection"])
)
if rel["eccentricity"]:
rel["groupName2"] = (
self.getGroupName(rel["relatedConnection"])
+ "_0DC_"
+ self.getGroupName(rel["relatingElement"])
)
rel["index"] = len(conn["relatedElements"]) + 1
rel["unifiedGroupName"] = self.getGroupName(rel["relatedConnection"]) + "_0DC_%g" % rel["index"]
else:
rel["groupName2"] = self.getGroupName(rel["relatedConnection"])
self.calculateConstraints(rel)
conn["relatedElements"].append(rel)
# End <--
materials = data["db"]["materials"]
profiles = data["db"]["profiles"]
edgeGroupNames = tuple([self.getGroupName(el["ifcName"]) for el in elements if el["geometryType"] == "line"])
faceGroupNames = tuple([self.getGroupName(el["ifcName"]) for el in elements if el["geometryType"] == "surface"])
point0DGroupNames = tuple(
[self.getGroupName(el["ifcName"]) + "_0D" for el in connections if el["geometryType"] == "point"]
)
spring1DGroupNames = tuple(
flatten(
[[rel["springGroupName"] for rel in el["connections"] if rel["springGroupName"]] for el in elements]
)
)
point1DGroupNames = tuple(
[self.getGroupName(el["ifcName"]) + "_0D" for el in connections if el["geometryType"] == "line"]
)
unifiedConnection = False
rigidLinkGroupNames = []
for conn in connections:
conn["unifiedGroupNames"] = [
rel["unifiedGroupName"] for rel in conn["relatedElements"] if rel["eccentricity"]
]
# if not conn['appliedCondition'] and len(conn['unifiedGroupNames']) == 1:
# conn['appliedCondition'] = {
# 'dx': True,
# 'dy': True,
# 'dz': True
# }
if len(conn["unifiedGroupNames"]) >= 1:
conn["unifiedGroupNames"].insert(0, self.getGroupName(conn["ifcName"]))
conn["unifiedGroupNames"] = tuple(conn["unifiedGroupNames"])
unifiedConnection = True
rigidLinkGroupNames.extend(
[
self.getGroupName(rel["relatingElement"]) + "_1DR_" + self.getGroupName(conn["ifcName"])
for rel in conn["relatedElements"]
if rel["eccentricity"]
]
)
rigidLinkGroupNames = tuple(rigidLinkGroupNames)
# Define file to write command file for code_aster
f = open(self.asterFilename, "w")
f.write("# Command file generated by IfcOpenShell/ifc2ca scripts\n")
f.write("\n")
f.write("# Linear Static Analysis With Self-Weight\n")
f.write(
"""
# STEP: INITIALIZE STUDY
DEBUT(
PAR_LOT = 'NON'
)
"""
)
f.write(
"""
# STEP: READ MED FILE
mesh = LIRE_MAILLAGE(
FORMAT = 'MED',
UNITE = 20
)
"""
)
f.write(
"""
# STEP: DEFINE MODEL
model = AFFE_MODELE(
MAILLAGE = mesh,
AFFE = (
_F(
TOUT = 'OUI',
PHENOMENE = 'MECANIQUE',
MODELISATION = '3D'
),"""
)
if faceGroupNames:
template = """
_F(
GROUP_MA = {groupNames},
PHENOMENE = 'MECANIQUE',
MODELISATION = 'DKT'
),"""
context = {"groupNames": faceGroupNames}
f.write(template.format(**context))
if edgeGroupNames:
template = """
_F(
GROUP_MA = {groupNames},
PHENOMENE = 'MECANIQUE',
MODELISATION = 'POU_D_E'
),"""
context = {"groupNames": edgeGroupNames}
f.write(template.format(**context))
if point0DGroupNames:
template = """
_F(
GROUP_MA = {groupNames},
PHENOMENE = 'MECANIQUE',
MODELISATION = 'DIS_TR'
),"""
context = {"groupNames": tuple(flatten([point0DGroupNames, spring1DGroupNames]))}
f.write(template.format(**context))
if point1DGroupNames:
template = """
_F(
GROUP_MA = {groupNames},
PHENOMENE = 'MECANIQUE',
MODELISATION = 'DIS_TR'
),"""
context = {"groupNames": point1DGroupNames}
f.write(template.format(**context))
if rigidLinkGroupNames:
template = """
_F(
GROUP_MA = {groupNames},
PHENOMENE = 'MECANIQUE',
MODELISATION = 'POU_D_E'
),"""
context = {"groupNames": rigidLinkGroupNames}
f.write(template.format(**context))
f.write(
"""
)
)\n
"""
)
f.write("# STEP: DEFINE MATERIALS")
for i, material in enumerate(materials):
template = """
{matNameID} = DEFI_MATERIAU(
ELAS = _F(
E = {youngModulus},
NU = {poissonRatio},
RHO = {massDensity}
)
)
"""
if "poissonRatio" in material["mechProps"]:
poissonRatio = material["mechProps"]["poissonRatio"]
else:
if "shearModulus" in material["mechProps"]:
poissonRatio = (
material["mechProps"]["youngModulus"] / 2.0 / material["mechProps"]["shearModulus"]
) - 1
else:
poissonRatio = 0.0
context = {
"matNameID": "mat" + "_%s" % i,
"youngModulus": float(material["mechProps"]["youngModulus"]),
"poissonRatio": float(poissonRatio),
"massDensity": float(material["commonProps"]["massDensity"]),
}
f.write(template.format(**context))
f.write(
"""
material = AFFE_MATERIAU(
MAILLAGE = mesh,
AFFE = ("""
)
for i, material in enumerate(materials):
template = """
_F(
GROUP_MA = {groupNames},
MATER = {matNameID},
),"""
context = {
"groupNames": tuple([self.getGroupName(rel) for rel in material["relatedElements"]]),
"matNameID": "mat" + "_%s" % i,
}
f.write(template.format(**context))
if rigidLinkGroupNames:
template = """
_F(
GROUP_MA = {groupNames},
MATER = {matNameID},
),"""
context = {"groupNames": rigidLinkGroupNames, "matNameID": "mat_0"}
f.write(template.format(**context))
f.write(
"""
)
)
"""
)
f.write(
"""
# STEP: DEFINE ELEMENTS
element = AFFE_CARA_ELEM(
MODELE = model,
POUTRE = ("""
)
for profile in profiles:
if profile["profileShape"] == "rectangular" and profile["profileType"] == "AREA":
template = """
_F(
GROUP_MA = {groupNames},
SECTION = 'RECTANGLE',
CARA = ('HY', 'HZ'),
VALE = {profileDimensions}
),"""
context = {
"groupNames": tuple([self.getGroupName(rel) for rel in profile["relatedElements"]]),
"profileDimensions": (profile["xDim"], profile["yDim"]),
}
f.write(template.format(**context))
elif profile["profileShape"] == "iSymmetrical" and profile["profileType"] == "AREA":
template = """
_F(
GROUP_MA = {groupNames},
SECTION = 'GENERALE',
CARA = ('A', 'IY', 'IZ', 'JX'),
VALE = {profileProperties}
),"""
context = {
"groupNames": tuple([self.getGroupName(rel) for rel in profile["relatedElements"]]),
"profileProperties": (
profile["mechProps"]["crossSectionArea"],
profile["mechProps"]["momentOfInertiaY"],
profile["mechProps"]["momentOfInertiaZ"],
profile["mechProps"]["torsionalConstantX"],
),
}
f.write(template.format(**context))
if rigidLinkGroupNames:
template = """
_F(
GROUP_MA = {groupNames},
SECTION = 'RECTANGLE',
CARA = ('HY', 'HZ'),
VALE = {profileDimensions}
),"""
context = {"groupNames": rigidLinkGroupNames, "profileDimensions": (1, 1)}
f.write(template.format(**context))
f.write(
"""
),
COQUE = ("""
)
for el in [el for el in elements if el["geometryType"] == "surface"]:
template = """
_F(
GROUP_MA = '{groupName}',
EPAIS = {thickness},
VECTEUR = {localAxisX}
),"""
context = {
"groupName": self.getGroupName(el["ifcName"]),
"thickness": el["thickness"],
"localAxisX": tuple(el["orientation"][0]),
}
f.write(template.format(**context))
f.write(
"""
),"""
)
f.write(
"""
DISCRET = ("""
)
for conn in [conn for conn in connections if conn["geometryType"] == "point"]:
template = """
_F(
GROUP_MA = '{groupName}',
CARA = 'K_TR_D_N',
VALE = {stiffnesses},
REPERE = 'LOCAL'
),"""
context = {"groupName": self.getGroupName(conn["ifcName"]) + "_0D", "stiffnesses": conn["stiffnesses"]}
f.write(template.format(**context))
for rel in conn["relatedElements"]:
template = """
_F(
GROUP_MA = '{groupName}',
CARA = 'K_TR_D_L',
VALE = {stiffnesses},
REPERE = 'LOCAL'
),"""
context = {"groupName": rel["springGroupName"], "stiffnesses": rel["stiffnesses"]}
f.write(template.format(**context))
for conn in [conn for conn in connections if conn["geometryType"] == "line"]:
template = """
_F(
GROUP_MA = '{groupName}',
CARA = 'K_TR_D_N',
VALE = {stiffnesses},
REPERE = 'LOCAL'
),"""
context = {"groupName": self.getGroupName(conn["ifcName"]) + "_0D", "stiffnesses": conn["stiffnesses"]}
f.write(template.format(**context))
f.write(
"""
),"""
)
f.write(
"""
ORIENTATION = ("""
)
for el in [el for el in elements if el["geometryType"] == "line"]:
template = """
_F(
GROUP_MA = '{groupName}',
CARA = 'VECT_Y',
VALE = {localAxisY}
),"""
context = {"groupName": self.getGroupName(el["ifcName"]), "localAxisY": tuple(el["orientation"][1])}
f.write(template.format(**context))
for conn in [conn for conn in connections if conn["geometryType"] == "point"]:
template = """
_F(
GROUP_MA = '{groupName}',
CARA = 'VECT_X_Y',
VALE = {localAxesXY}
),"""
context = {
"groupName": self.getGroupName(conn["ifcName"]) + "_0D",
"localAxesXY": tuple(conn["orientation"][0] + conn["orientation"][1]),
}
f.write(template.format(**context))
for rel in conn["relatedElements"]:
template = """
_F(
GROUP_MA = '{groupName}',
CARA = 'VECT_X_Y',
VALE = {localAxesXY}
),"""
context = {
"groupName": rel["springGroupName"],
"localAxesXY": tuple(rel["orientation"][0] + rel["orientation"][1]),
}
f.write(template.format(**context))
for conn in [conn for conn in connections if conn["geometryType"] == "line"]:
template = """
_F(
GROUP_MA = '{groupName}',
CARA = 'VECT_X_Y',
VALE = {localAxesXY}
),"""
context = {
"groupName": self.getGroupName(conn["ifcName"]) + "_0D",
"localAxesXY": tuple(conn["orientation"][0] + conn["orientation"][1]),
}
f.write(template.format(**context))
f.write(
"""
),"""
)
f.write(
"""
)\n
"""
)
f.write("# STEP: DEFINE SUPPORTS AND CONSTRAINTS")
f.write(
"""
liaisons = AFFE_CHAR_MECA(
MODELE = model,
LIAISON_DDL = ("""
)
for conn in [conn for conn in connections if conn["geometryType"] == "point"]:
if conn["appliedCondition"]:
for i in range(len(conn["liaisons"]["coeffs"])):
template = """
_F(
GROUP_NO = {groupNames},
DDL = {dofs},
COEF_MULT = {coeffs},
COEF_IMPO = 0.0
),"""
context = {
"groupNames": conn["liaisons"]["groupNames"],
"dofs": conn["liaisons"]["dofs"][i],
"coeffs": conn["liaisons"]["coeffs"][i],
}
f.write(template.format(**context))
for rel in conn["relatedElements"]:
for i in range(len(rel["liaisons"]["coeffs"])):
template = """
_F(
GROUP_NO = {groupNames},
DDL = {dofs},
COEF_MULT = {coeffs},
COEF_IMPO = 0.0
),"""
context = {
"groupNames": rel["liaisons"]["groupNames"],
"dofs": rel["liaisons"]["dofs"][i],
"coeffs": rel["liaisons"]["coeffs"][i],
}
f.write(template.format(**context))
f.write(
"""
),"""
)
f.write(
"""
LIAISON_GROUP = ("""
)
for conn in [conn for conn in connections if conn["geometryType"] == "line"]:
if conn["appliedCondition"]:
for i in range(len(conn["liaisons"]["coeffs"])):
template = """
_F(
GROUP_NO_1 = {groupName_1},
GROUP_NO_2 = {groupName_1},
DDL_1 = {dofs},
DDL_2 = {dofs},
COEF_MULT_1 = {coeffs},
COEF_MULT_2 = (0.0, 0.0, 0.0),
COEF_IMPO = 0.0
),"""
context = {
"groupName_1": tuple([conn["liaisons"]["groupNames"][0]]),
"dofs": conn["liaisons"]["dofs"][i],
"coeffs": conn["liaisons"]["coeffs"][i],
}
f.write(template.format(**context))
for rel in conn["relatedElements"]:
for i in range(len(rel["liaisons"]["coeffs"])):
template = """
_F(
GROUP_NO_1 = {groupName_1},
GROUP_NO_2 = {groupName_2},
DDL_1 = {dofs},
DDL_2 = {dofs},
COEF_MULT_1 = {coeffs_1},
COEF_MULT_2 = {coeffs_2},
COEF_IMPO = 0.0
),"""
context = {
"groupName_1": tuple([rel["liaisons"]["groupNames"][0]]),
"groupName_2": tuple([rel["liaisons"]["groupNames"][3]]),
"dofs": tuple(list(rel["liaisons"]["dofs"][i])[:3]),
"coeffs_1": tuple(list(rel["liaisons"]["coeffs"][i])[:3]),
"coeffs_2": tuple(list(rel["liaisons"]["coeffs"][i])[3:]),
}
f.write(template.format(**context))
f.write(
"""
),"""
)
if unifiedConnection:
f.write(
"""
LIAISON_UNIF = ("""
)
for conn in [conn for conn in connections if len(conn["unifiedGroupNames"]) > 1]:
template = """
_F(
GROUP_NO = {groupNames},
DDL = ('DX', 'DY', 'DZ', 'DRX', 'DRY', 'DRZ')
),"""
context = {"groupNames": conn["unifiedGroupNames"]}
f.write(template.format(**context))
f.write(
"""
),"""
)
if rigidLinkGroupNames:
f.write(
"""
LIAISON_SOLIDE = ("""
)
for groupName in rigidLinkGroupNames:
template = """
_F(
GROUP_MA = '{groupName}'
),"""
context = {"groupName": groupName}
f.write(template.format(**context))
f.write(
"""
),"""
)
f.write(
"""
)
"""
)
template = """
# STEP: DEFINE LOAD
gravLoad = AFFE_CHAR_MECA(
MODELE = model,
PESANTEUR = _F(
GRAVITE = {AccelOfGravity},
DIRECTION = (0.0, 0.0, -1.0)
)
)
"""
context = {
"AccelOfGravity": AccelOfGravity,
}
f.write(template.format(**context))
f.write(
"""
# STEP: RUN ANALYSIS
res_Bld = MECA_STATIQUE(
MODELE = model,
CHAM_MATER = material,
CARA_ELEM = element,
EXCIT = (
_F(
CHARGE = liaisons
),
_F(
CHARGE = gravLoad
)
)
)
"""
)
# f.write(
# '''
# # STEP: POST-PROCESSING
# res_Bld = CALC_CHAMP(
# reuse = res_Bld,
# RESULTAT = res_Bld,
# # CONTRAINTE = ('SIEF_ELNO', 'SIGM_ELNO', 'EFGE_ELNO',),
# FORCE = ('REAC_NODA', 'FORC_NODA',)
# )
# '''
# )
#
# template = \
# '''
# # STEP: MASS EXTRACTION FOR EACH ASSEMBLE
# FaceMass = POST_ELEM(
# TITRE = 'TotMass',
# MODELE = model,
# CARA_ELEM = element,
# CHAM_MATER = material,
# MASS_INER = _F(
# GROUP_MA = {massList},
# ),
# )\n'''
#
# context = {
# 'massList': massList,
# }
#
# f.write(template.format(**context))
#
# f.write(
# '''
# IMPR_TABLE(
# UNITE = 10,
# TABLE = FaceMass,
# SEPARATEUR = ',',
# NOM_PARA = ('LIEU', 'MASSE', 'CDG_X', 'CDG_Y', 'CDG_Z'),
# # FORMAT_R = '1PE15.6',
# )
# '''
# )
#
# template = \
# '''
# # STEP: REACTION EXTRACTION AT THE BASE
# Reacs = POST_RELEVE_T(
# ACTION = _F(
# INTITULE = 'sumReac',
# GROUP_NO = {groupNames},
# RESULTAT = res_Bld,
# NOM_CHAM = 'REAC_NODA',
# RESULTANTE = ('DX','DY','DZ',),
# MOMENT = ('DRX','DRY','DRZ',),
# POINT = (0,0,0,),
# OPERATION = 'EXTRACTION'
# )
# )
# '''
#
# context = {
# 'groupNames': point0DGroupNames,
# }
#
# f.write(template.format(**context))
#
# f.write(
# '''
# IMPR_TABLE(
# UNITE = 10,
# TABLE = Reacs,
# SEPARATEUR = ',',
# # NOM_PARA = ('INTITULE', 'RESU', 'NOM_CHAM', 'INST', 'DX','DY','DZ'),
# FORMAT_R = '1PE12.3',
# )
# '''
# )
#
f.write(
"""
# STEP: DEFORMED SHAPE EXTRACTION
IMPR_RESU(
FORMAT = 'MED',
UNITE = 80,
RESU = _F(
RESULTAT = res_Bld,
NOM_CHAM = ('DEPL',), # 'REAC_NODA', 'FORC_NODA',
NOM_CHAM_MED = ('Bld_DISP',), # 'Bld_REAC', 'Bld_FORC'
)
)
"""
)
f.write(
"""
# STEP: CONCLUDE STUDY
FIN()
"""
)
f.close()
def calculateConstraints(self, rel):
gr1 = rel["groupName1"]
gr2 = rel["groupName2"]
o = np.array(rel["orientation"]).transpose().tolist()
liaisons = {"groupNames": (gr1, gr1, gr1, gr2, gr2, gr2), "coeffs": [], "dofs": []}
stiffnesses = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
if not rel["appliedCondition"]:
rel["appliedCondition"] = {"dx": True, "dy": True, "dz": True, "drx": True, "dry": True, "drz": True}
if isinstance(rel["appliedCondition"]["dx"], bool) and rel["appliedCondition"]["dx"]:
liaisons["coeffs"].append((o[0][0], o[1][0], o[2][0], -o[0][0], -o[1][0], -o[2][0]))
liaisons["dofs"].append(("DX", "DY", "DZ", "DX", "DY", "DZ"))
elif isinstance(rel["appliedCondition"]["dx"], float) and rel["appliedCondition"]["dx"] > 0:
stiffnesses[0] = rel["appliedCondition"]["dx"]
if isinstance(rel["appliedCondition"]["dy"], bool) and rel["appliedCondition"]["dy"]:
liaisons["coeffs"].append((o[0][1], o[1][1], o[2][1], -o[0][1], -o[1][1], -o[2][1]))
liaisons["dofs"].append(("DX", "DY", "DZ", "DX", "DY", "DZ"))
elif isinstance(rel["appliedCondition"]["dy"], float) and rel["appliedCondition"]["dy"] > 0:
stiffnesses[1] = rel["appliedCondition"]["dy"]
if isinstance(rel["appliedCondition"]["dz"], bool) and rel["appliedCondition"]["dz"]:
liaisons["coeffs"].append((o[0][2], o[1][2], o[2][2], -o[0][2], -o[1][2], -o[2][2]))
liaisons["dofs"].append(("DX", "DY", "DZ", "DX", "DY", "DZ"))
elif isinstance(rel["appliedCondition"]["dz"], float) and rel["appliedCondition"]["dz"] > 0:
stiffnesses[2] = rel["appliedCondition"]["dz"]
if isinstance(rel["appliedCondition"]["drx"], bool) and rel["appliedCondition"]["drx"]:
liaisons["coeffs"].append((o[0][0], o[1][0], o[2][0], -o[0][0], -o[1][0], -o[2][0]))
liaisons["dofs"].append(("DRX", "DRY", "DRZ", "DRX", "DRY", "DRZ"))
elif isinstance(rel["appliedCondition"]["drx"], float) and rel["appliedCondition"]["drx"] > 0:
stiffnesses[3] = rel["appliedCondition"]["drx"]
if isinstance(rel["appliedCondition"]["dry"], bool) and rel["appliedCondition"]["dry"]:
liaisons["coeffs"].append((o[0][1], o[1][1], o[2][1], -o[0][1], -o[1][1], -o[2][1]))
liaisons["dofs"].append(("DRX", "DRY", "DRZ", "DRX", "DRY", "DRZ"))
elif isinstance(rel["appliedCondition"]["dry"], float) and rel["appliedCondition"]["dry"] > 0:
stiffnesses[4] = rel["appliedCondition"]["dry"]
if isinstance(rel["appliedCondition"]["drz"], bool) and rel["appliedCondition"]["drz"]:
liaisons["coeffs"].append((o[0][2], o[1][2], o[2][2], -o[0][2], -o[1][2], -o[2][2]))
liaisons["dofs"].append(("DRX", "DRY", "DRZ", "DRX", "DRY", "DRZ"))
elif isinstance(rel["appliedCondition"]["drz"], float) and rel["appliedCondition"]["drz"] > 0:
stiffnesses[5] = rel["appliedCondition"]["drz"]
rel["liaisons"] = liaisons
rel["stiffnesses"] = tuple(stiffnesses)
def calculateRestraints(self, conn):
group = self.getGroupName(conn["ifcName"])
o = np.array(conn["orientation"]).transpose().tolist()
liaisons = {"groupNames": (group, group, group), "coeffs": [], "dofs": []}
stiffnesses = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
if not conn["appliedCondition"]:
conn["liaisons"] = liaisons
conn["stiffnesses"] = tuple(stiffnesses)
return
if isinstance(conn["appliedCondition"]["dx"], bool) and conn["appliedCondition"]["dx"]:
liaisons["coeffs"].append((o[0][0], o[1][0], o[2][0]))
liaisons["dofs"].append(("DX", "DY", "DZ"))
elif isinstance(conn["appliedCondition"]["dx"], float) and conn["appliedCondition"]["dx"] > 0:
stiffnesses[0] = conn["appliedCondition"]["dx"]
if isinstance(conn["appliedCondition"]["dy"], bool) and conn["appliedCondition"]["dy"]:
liaisons["coeffs"].append((o[0][1], o[1][1], o[2][1]))
liaisons["dofs"].append(("DX", "DY", "DZ"))
elif isinstance(conn["appliedCondition"]["dy"], float) and conn["appliedCondition"]["dy"] > 0:
stiffnesses[1] = conn["appliedCondition"]["dy"]
if isinstance(conn["appliedCondition"]["dz"], bool) and conn["appliedCondition"]["dz"]:
liaisons["coeffs"].append((o[0][2], o[1][2], o[2][2]))
liaisons["dofs"].append(("DX", "DY", "DZ"))
elif isinstance(conn["appliedCondition"]["dz"], float) and conn["appliedCondition"]["dz"] > 0:
stiffnesses[2] = conn["appliedCondition"]["dz"]
if isinstance(conn["appliedCondition"]["drx"], bool) and conn["appliedCondition"]["drx"]:
liaisons["coeffs"].append((o[0][0], o[1][0], o[2][0]))
liaisons["dofs"].append(("DRX", "DRY", "DRZ"))
elif isinstance(conn["appliedCondition"]["drx"], float) and conn["appliedCondition"]["drx"] > 0:
stiffnesses[3] = conn["appliedCondition"]["drx"]
if isinstance(conn["appliedCondition"]["dry"], bool) and conn["appliedCondition"]["dry"]:
liaisons["coeffs"].append((o[0][1], o[1][1], o[2][1]))
liaisons["dofs"].append(("DRX", "DRY", "DRZ"))
elif isinstance(conn["appliedCondition"]["dry"], float) and conn["appliedCondition"]["dry"] > 0:
stiffnesses[4] = conn["appliedCondition"]["dry"]
if isinstance(conn["appliedCondition"]["drz"], bool) and conn["appliedCondition"]["drz"]:
liaisons["coeffs"].append((o[0][2], o[1][2], o[2][2]))
liaisons["dofs"].append(("DRX", "DRY", "DRZ"))
elif isinstance(conn["appliedCondition"]["drz"], float) and conn["appliedCondition"]["drz"] > 0:
stiffnesses[5] = conn["appliedCondition"]["drz"]
conn["liaisons"] = liaisons
conn["stiffnesses"] = tuple(stiffnesses)
if __name__ == "__main__":
fileNames = ["cantilever_01", "portal_01", "grid_of_beams", "slab_01", "structure_01"]
files = fileNames
for fileName in files:
BASE_PATH = "/home/jesusbill/Dev-Projects/github.com/IfcOpenShell/analysis-models/models/"
DATAFILENAME = BASE_PATH + fileName + "/" + fileName + ".json"
ASTERFILENAME = BASE_PATH + fileName + "/" + fileName + ".comm"
COMMANDFILE(DATAFILENAME, ASTERFILENAME)
-467
View File
@@ -1,467 +0,0 @@
from __future__ import division
from __future__ import print_function
import os
import time
import json
import salome
import salome_notebook
import salome_version
import numpy as np
import itertools
flatten = itertools.chain.from_iterable
class MODEL:
def __init__(self, dataFilename, medFilename, meshSize):
self.dataFilename = dataFilename
self.medFilename = medFilename
self.meshSize = meshSize
self.tolLoc = 0
self.mesh = None
self.meshNodes = None
self.create()
def getGroupName(self, name):
info = name.split("|")
sortName = "".join(c for c in info[0] if c.isupper())
return str(sortName + "_" + info[1])
def makePoint(self, pl):
"""Function to define a Point from
a polyline (list of 1 point)"""
(x, y, z) = pl
return self.geompy.MakeVertex(x, y, z)
def makeLine(self, pl):
"""Function to define a Line from
a polyline (list of 2 points)"""
(x, y, z) = pl[0]
P1 = self.geompy.MakeVertex(x, y, z)
(x, y, z) = pl[1]
P2 = self.geompy.MakeVertex(x, y, z)
return self.geompy.MakeLineTwoPnt(P1, P2)
def makeFace(self, pl):
"""Function to define a Face from
a polyline (list of points)"""
pointList = [None for _ in range(len(pl))]
for ip, (x, y, z) in enumerate(pl):
pointList[ip] = self.geompy.MakeVertex(x, y, z)
LineList = [None for _ in range(len(pl))]
for ip, P2 in enumerate(pointList):
P1 = pointList[ip - 1]
LineList[ip] = self.geompy.MakeLineTwoPnt(P1, P2)
return self.geompy.MakeFaceWires(LineList, 1)
def makeObject(self, geometry, geometryType):
if geometryType == "point":
return self.makePoint(geometry)
if geometryType == "line":
return self.makeLine(geometry)
if geometryType == "surface":
return self.makeFace(geometry)
def makePartition(self, objects, geometryType):
if geometryType == "point":
shapeType = "VERTEX"
if geometryType == "line":
shapeType = "EDGE"
if geometryType == "surface":
shapeType = "FACE"
return self.geompy.MakePartition(objects, [], [], [], self.geompy.ShapeType[shapeType], 0, [], 1)
def getLinkGeometry(self, ecc, orientation, finalPoint):
vector = np.array(orientation).transpose().dot(ecc["vector"])
initialPoint = (np.array(finalPoint) - vector).tolist()
return [initialPoint, finalPoint]
def length(self, geometry):
return (
(geometry[1][0] - geometry[0][0]) ** 2
+ (geometry[1][1] - geometry[0][1]) ** 2
+ (geometry[1][2] - geometry[0][2]) ** 2
) ** 0.5
def create(self):
# Read data from input file
with open(self.dataFilename) as dataFile:
data = json.load(dataFile)
elements = data["elements"]
connections = data["connections"]
# --> Delete this reference data and repopulate it with the objects
# while going through elements
for conn in connections:
conn["relatedElements"] = []
# End <--
meshSize = self.meshSize
dec = 7 # 4 decimals for length in mm
tol = 10 ** (-dec - 3 + 1)
self.tolLoc = tol * 10 * 2
tolLoc = self.tolLoc
NEW_SALOME = int(salome_version.getVersion()[0]) >= 9
salome.salome_init()
theStudy = salome.myStudy
notebook = salome_notebook.NoteBook(theStudy)
###
### GEOM component
###
import GEOM
from salome.geom import geomBuilder
import math
import SALOMEDS
gg = salome.ImportComponentGUI("GEOM")
if NEW_SALOME:
geompy = geomBuilder.New()
else:
geompy = geomBuilder.New(theStudy)
self.geompy = geompy
O = geompy.MakeVertex(0, 0, 0)
OX = geompy.MakeVectorDXDYDZ(1, 0, 0)
OY = geompy.MakeVectorDXDYDZ(0, 1, 0)
OZ = geompy.MakeVectorDXDYDZ(0, 0, 1)
geompy.addToStudy(O, "O")
geompy.addToStudy(OX, "OX")
geompy.addToStudy(OY, "OY")
geompy.addToStudy(OZ, "OZ")
if len([e for e in elements if e["geometryType"] == "line"]) > 0:
buildingShapeType = "EDGE"
if len([e for e in elements if e["geometryType"] == "surface"]) > 0:
buildingShapeType = "FACE"
### Define entities ###
start_time = time.time()
print("Defining Object Geometry")
init_time = start_time
# Loop 1
for el in elements:
el["elemObj"] = self.makeObject(el["geometry"], el["geometryType"])
el["connObjs"] = [None for _ in el["connections"]]
el["linkObjs"] = [None for _ in el["connections"]]
el["linkPointObjs"] = [[None, None] for _ in el["connections"]]
for j, rel in enumerate(el["connections"]):
conn = [c for c in connections if c["ifcName"] == rel["relatedConnection"]][0]
if rel["eccentricity"]:
rel["index"] = len(conn["relatedElements"]) + 1
conn["relatedElements"].append(rel)
if not rel["eccentricity"]:
el["connObjs"][j] = self.makeObject(conn["geometry"], conn["geometryType"])
else:
if conn["geometryType"] == "point":
geometry = self.getLinkGeometry(rel["eccentricity"], el["orientation"], conn["geometry"])
el["connObjs"][j] = self.makeObject(geometry[0], conn["geometryType"])
el["linkPointObjs"][j][0] = self.geompy.MakeVertex(
geometry[0][0], geometry[0][1], geometry[0][2]
)
el["linkPointObjs"][j][1] = self.geompy.MakeVertex(
geometry[1][0], geometry[1][1], geometry[1][2]
)
el["linkObjs"][j] = self.geompy.MakeLineTwoPnt(
el["linkPointObjs"][j][0], el["linkPointObjs"][j][1]
)
else:
print("Eccentricity defined for a %s geometryType" % conn["geometryType"])
el["partObj"] = self.makePartition([el["elemObj"]] + el["connObjs"], el["geometryType"])
el["elemObj"] = geompy.GetInPlace(el["partObj"], el["elemObj"])
for j, rel in enumerate(el["connections"]):
el["connObjs"][j] = geompy.GetInPlace(el["partObj"], el["connObjs"][j])
for conn in connections:
conn["connObj"] = self.makeObject(conn["geometry"], conn["geometryType"])
# Make assemble of Building Object
bldObjs = []
bldObjs.extend([el["partObj"] for el in elements])
bldObjs.extend(flatten([[link for link in el["linkObjs"] if link] for el in elements]))
bldObjs.extend([conn["connObj"] for conn in connections])
bldComp = geompy.MakeCompound(bldObjs)
# bldComp = geompy.MakePartition(bldObjs, [], [], [], self.geompy.ShapeType[buildingShapeType], 0, [], 1)
geompy.addToStudy(bldComp, "bldComp")
# Loop 2
for el in elements:
# geompy.addToStudy(el['partObj'], self.getGroupName(el['ifcName']))
geompy.addToStudyInFather(el["partObj"], el["elemObj"], self.getGroupName(el["ifcName"]))
for j, rel in enumerate(el["connections"]):
conn = [c for c in connections if c["ifcName"] == rel["relatedConnection"]][0]
rel["conn_string"] = None
if conn["geometryType"] == "point":
rel["conn_string"] = "_0DC_"
if conn["geometryType"] == "line":
rel["conn_string"] = "_1DC_"
if conn["geometryType"] == "surface":
rel["conn_string"] = "_2DC_"
geompy.addToStudyInFather(
el["partObj"],
el["connObjs"][j],
self.getGroupName(el["ifcName"]) + rel["conn_string"] + self.getGroupName(rel["relatedConnection"]),
)
if rel["eccentricity"]:
pass
# geompy.addToStudy(el['linkObjs'][j], self.getGroupName(el['ifcName']) + '_1DR_' + self.getGroupName(rel['relatedConnection']))
# geompy.addToStudyInFather(el['linkObjs'][j], el['linkPointObjs'][j][0], self.getGroupName(rel['relatedConnection']) + '_0DC_' + self.getGroupName(el['ifcName']))
# geompy.addToStudyInFather(el['linkObjs'][j], el['linkPointObjs'][j][0], self.getGroupName(rel['relatedConnection']) + '_0DC_%g' % rel['index'])
for conn in connections:
# geompy.addToStudy(conn['connObj'], self.getGroupName(conn['ifcName']))
geompy.addToStudyInFather(conn["connObj"], conn["connObj"], self.getGroupName(conn["ifcName"]))
elapsed_time = time.time() - init_time
init_time += elapsed_time
print("Building Geometry Defined in %g sec" % (elapsed_time))
if len([e for e in elements if e["geometryType"] == "line"]) > 0:
buildingShapeType = "EDGE"
if len([e for e in elements if e["geometryType"] == "surface"]) > 0:
buildingShapeType = "FACE"
# Define and add groups for all curve and surface members
if len([e for e in elements if e["geometryType"] == "line"]) > 0:
# Make compound of requested group
compoundTemp = geompy.MakeCompound([e["elemObj"] for e in elements if e["geometryType"] == "line"])
# Define group object and add to study
curveCompound = geompy.GetInPlace(bldComp, compoundTemp)
geompy.addToStudyInFather(bldComp, curveCompound, "CurveMembers")
if len([e for e in elements if e["geometryType"] == "surface"]) > 0:
# Make compound of requested group
compoundTemp = geompy.MakeCompound([e["elemObj"] for e in elements if e["geometryType"] == "surface"])
# Define group object and add to study
surfaceCompound = geompy.GetInPlace(bldComp, compoundTemp)
geompy.addToStudyInFather(bldComp, surfaceCompound, "SurfaceMembers")
# Loop 3
for el in elements:
# el['partObj'] = geompy.RestoreGivenSubShapes(bldComp, [el['partObj']], GEOM.FSM_GetInPlace, False, False)[0]
geompy.addToStudyInFather(bldComp, el["elemObj"], self.getGroupName(el["ifcName"]))
for j, rel in enumerate(el["connections"]):
geompy.addToStudyInFather(
bldComp,
el["connObjs"][j],
self.getGroupName(el["ifcName"]) + rel["conn_string"] + self.getGroupName(rel["relatedConnection"]),
)
if rel["eccentricity"]: # point geometry
geompy.addToStudyInFather(
bldComp,
el["linkObjs"][j],
self.getGroupName(el["ifcName"]) + "_1DR_" + self.getGroupName(rel["relatedConnection"]),
)
geompy.addToStudyInFather(
bldComp,
el["linkPointObjs"][j][0],
self.getGroupName(rel["relatedConnection"]) + "_0DC_" + self.getGroupName(el["ifcName"]),
)
geompy.addToStudyInFather(
bldComp,
el["linkPointObjs"][j][1],
self.getGroupName(rel["relatedConnection"]) + "_0DC_%g" % rel["index"],
)
for conn in connections:
# conn['connObj'] = geompy.RestoreGivenSubShapes(bldComp, [conn['connObj']], GEOM.FSM_GetInPlace, False, False)[0]
geompy.addToStudyInFather(bldComp, conn["connObj"], self.getGroupName(conn["ifcName"]))
elapsed_time = time.time() - init_time
init_time += elapsed_time
print("Building Geometry Groups Defined in %g sec" % (elapsed_time))
###
### SMESH component
###
import SMESH
from salome.smesh import smeshBuilder
print("Defining Mesh Components")
if NEW_SALOME:
smesh = smeshBuilder.New()
else:
smesh = smeshBuilder.New(theStudy)
bldMesh = smesh.Mesh(bldComp)
Regular_1D = bldMesh.Segment()
Local_Length_1 = Regular_1D.LocalLength(meshSize, None, tolLoc)
if buildingShapeType == "FACE":
NETGEN2D_ONLY = bldMesh.Triangle(algo=smeshBuilder.NETGEN_2D)
NETGEN2D_Pars = NETGEN2D_ONLY.Parameters()
NETGEN2D_Pars.SetMaxSize(meshSize)
NETGEN2D_Pars.SetOptimize(1)
NETGEN2D_Pars.SetFineness(2)
NETGEN2D_Pars.SetMinSize(meshSize / 5.0)
NETGEN2D_Pars.SetUseSurfaceCurvature(1)
NETGEN2D_Pars.SetQuadAllowed(1)
NETGEN2D_Pars.SetSecondOrder(0)
NETGEN2D_Pars.SetFuseEdges(254)
isDone = bldMesh.Compute()
## Set names of Mesh objects
smesh.SetName(Regular_1D.GetAlgorithm(), "Regular_1D")
smesh.SetName(Local_Length_1, "Local_Length_1")
if buildingShapeType == "FACE":
smesh.SetName(NETGEN2D_ONLY.GetAlgorithm(), "NETGEN2D_ONLY")
smesh.SetName(NETGEN2D_Pars, "NETGEN2D_Pars")
smesh.SetName(bldMesh.GetMesh(), "bldMesh")
elapsed_time = time.time() - init_time
init_time += elapsed_time
print("Meshing Operations Completed in %g sec" % (elapsed_time))
# Define and add groups for all curve and surface members
if len([e for e in elements if e["geometryType"] == "line"]) > 0:
tempgroup = bldMesh.GroupOnGeom(curveCompound, "CurveMembers", SMESH.EDGE)
smesh.SetName(tempgroup, "CurveMembers")
if len([e for e in elements if e["geometryType"] == "surface"]) > 0:
tempgroup = bldMesh.GroupOnGeom(surfaceCompound, "SurfaceMembers", SMESH.FACE)
smesh.SetName(tempgroup, "SurfaceMembers")
# Define groups in Mesh
for el in elements:
if el["geometryType"] == "line":
shapeType = SMESH.EDGE
if el["geometryType"] == "surface":
shapeType = SMESH.FACE
tempgroup = bldMesh.GroupOnGeom(el["elemObj"], self.getGroupName(el["ifcName"]), shapeType)
smesh.SetName(tempgroup, self.getGroupName(el["ifcName"]))
for j, rel in enumerate(el["connections"]):
tempgroup = bldMesh.GroupOnGeom(
el["connObjs"][j],
self.getGroupName(el["ifcName"]) + rel["conn_string"] + self.getGroupName(rel["relatedConnection"]),
SMESH.NODE,
)
smesh.SetName(
tempgroup,
self.getGroupName(el["ifcName"]) + rel["conn_string"] + self.getGroupName(rel["relatedConnection"]),
)
rel["node"] = (bldMesh.GetIDSource(tempgroup.GetNodeIDs(), SMESH.NODE)).GetIDs()[0]
if rel["eccentricity"]:
tempgroup = bldMesh.GroupOnGeom(
el["linkObjs"][j],
self.getGroupName(el["ifcName"]) + "_1DR_" + self.getGroupName(rel["relatedConnection"]),
SMESH.EDGE,
)
smesh.SetName(
tempgroup,
self.getGroupName(el["ifcName"]) + "_1DR_" + self.getGroupName(rel["relatedConnection"]),
)
tempgroup = bldMesh.GroupOnGeom(
el["linkPointObjs"][j][0],
self.getGroupName(rel["relatedConnection"]) + "_0DC_" + self.getGroupName(el["ifcName"]),
SMESH.NODE,
)
smesh.SetName(
tempgroup,
self.getGroupName(rel["relatedConnection"]) + "_0DC_" + self.getGroupName(el["ifcName"]),
)
rel["eccNode"] = (bldMesh.GetIDSource(tempgroup.GetNodeIDs(), SMESH.NODE)).GetIDs()[0]
tempgroup = bldMesh.GroupOnGeom(
el["linkPointObjs"][j][1],
self.getGroupName(rel["relatedConnection"])
+ "_0DC_"
+ self.getGroupName(rel["relatedConnection"]),
SMESH.NODE,
)
smesh.SetName(tempgroup, self.getGroupName(rel["relatedConnection"]) + "_0DC_%g" % rel["index"])
for conn in connections:
tempgroup = bldMesh.GroupOnGeom(conn["connObj"], self.getGroupName(conn["ifcName"]), SMESH.NODE)
smesh.SetName(tempgroup, self.getGroupName(conn["ifcName"]))
nodesId = bldMesh.GetIDSource(tempgroup.GetNodeIDs(), SMESH.NODE)
tempgroup = bldMesh.Add0DElementsToAllNodes(nodesId, self.getGroupName(conn["ifcName"]))
smesh.SetName(tempgroup, self.getGroupName(conn["ifcName"] + "_0D"))
if conn["geometryType"] == "point":
conn["node"] = nodesId.GetIDs()[0]
if conn["geometryType"] == "line":
tempgroup = bldMesh.GroupOnGeom(conn["connObj"], self.getGroupName(conn["ifcName"]), SMESH.EDGE)
smesh.SetName(tempgroup, self.getGroupName(conn["ifcName"]))
if conn["geometryType"] == "surface":
tempgroup = bldMesh.GroupOnGeom(conn["connObj"], self.getGroupName(conn["ifcName"]), SMESH.FACE)
smesh.SetName(tempgroup, self.getGroupName(conn["ifcName"]))
# create 1D SEG2 spring elements
for el in elements:
for j, rel in enumerate(el["connections"]):
conn = [c for c in connections if c["ifcName"] == rel["relatedConnection"]][0]
if conn["geometryType"] == "point":
grpName = bldMesh.CreateEmptyGroup(
SMESH.EDGE,
self.getGroupName(el["ifcName"]) + "_1DS_" + self.getGroupName(rel["relatedConnection"]),
)
smesh.SetName(
grpName,
self.getGroupName(el["ifcName"]) + "_1DS_" + self.getGroupName(rel["relatedConnection"]),
)
if not rel["eccentricity"]:
conn = [conn for conn in connections if conn["ifcName"] == rel["relatedConnection"]][0]
grpName.Add([bldMesh.AddEdge([conn["node"], rel["node"]])])
else:
grpName.Add([bldMesh.AddEdge([rel["eccNode"], rel["node"]])])
self.mesh = bldMesh
self.meshNodes = bldMesh.GetNodesId()
elapsed_time = time.time() - init_time
init_time += elapsed_time
print("Mesh Groups Defined in %g sec" % (elapsed_time))
try:
if NEW_SALOME:
bldMesh.ExportMED(
self.medFilename, auto_groups=0, minor=40, overwrite=1, meshPart=None, autoDimension=0
)
else:
bldMesh.ExportMED(self.medFilename, 0, SMESH.MED_V2_2, 1, None, 0)
except:
print("ExportMED() failed. Invalid file name?")
if salome.sg.hasDesktop():
if NEW_SALOME:
salome.sg.updateObjBrowser()
else:
salome.sg.updateObjBrowser(1)
elapsed_time = init_time - start_time
print("ALL Operations Completed in %g sec" % (elapsed_time))
if __name__ == "__main__":
fileNames = ["structure_01"]
files = fileNames
meshSize = 0.1
for fileName in files:
BASE_PATH = "/home/jesusbill/Dev-Projects/github.com/IfcOpenShell/analysis-models/models/"
DATAFILENAME = BASE_PATH + fileName + "/" + fileName + ".json"
MEDFILENAME = BASE_PATH + fileName + "/" + fileName + ".med"
model = MODEL(DATAFILENAME, MEDFILENAME, meshSize)
-3
View File
@@ -1,3 +0,0 @@
# Dependency and build folders created by the build scripts
/build/
/dist/
-122
View File
@@ -1,122 +0,0 @@
# BIMTester
BIMTester lets you specify a set of exchange requirements, and automatically check whether or not BIM data, typically an
IFC file, complies with the requirements. You can run it automatically from a server, integrate it to your own
application, or use a GUI. It can generate reports in various formats including:
* HTML
* JSON
* XUnit
* BCF
* Zoom Smart View
Your exchange requirements are written in plain language which you can use to communicate to project teams and include
in contracts. Multiple languages are supported. A series of exchange requirement templates are provided to get started,
but you can, and are encouraged to, write your own tailored to your project. An example of a requirement looks like
this:
```
Feature: Project setup
In order to view the BIM data
As any interested stakeholder
We need an IFC file
Scenario: Receiving a file
* IFC data must use the IFC4 schema
```
Languages supported include (in alphabetical order):
* Dutch
* English
* French
* German
* Italian
If you are not a developer, we highly recommend simply installing an integrated version of BIMTester.
* If you use Blender, install the [BlenderBIM Add-on](https://blenderbim.org)
* If you use FreeCAD, install the [FreeCAD BIMTester Workbench](https://github.com/bimtester/bimtesterfc)
If you are a developer, read on!
## Installation
The following packages are required for BIMTester to function:
* behave
* pystache
* ifcopenshell
* PySide2 (optional: needed for GUI)
The repository does not contain translation files. You can generate them as shown.
```
cd IfcOpenShell/src/ifcbimtester/bimtester/locale
pybabel compile -d .
```
## CLI Usage
BIMTester has a command line application. Check it out:
```
$ python cli.py -h
usage: cli.py [-h] [-a ACTION] [--advanced-arguments ADVANCED_ARGUMENTS] [-c]
-f FEATURE -i IFC [-p PATH] [-r REPORT] [--lang LANG]
Runs unit tests for BIM data
optional arguments:
-h, --help show this help message and exit
-a ACTION, --action ACTION
Action to perform, from run/purge
--advanced-arguments ADVANCED_ARGUMENTS
Specify arguments to Behave
-c, --console Show results in the console
-f FEATURE, --feature FEATURE
Specify a feature file to test
-i IFC, --ifc IFC Specify a ifc file
-p PATH, --path PATH Define a path for use in tests
-r REPORT, --report REPORT
Specify an output file for a HTML report
--lang LANG Specify a language
```
You can turn it into a regular command by symlinking it to your bin folder.
```
$ ln -s /path/to/IfcOpenShell/src/ifcbimtester/cli.py /usr/local/bin/bimtester
$ bimtester -h
```
To run a test, we need an IFC to check and a feature file filled with requirements. The feature file is plaintext. Feel
free to copy the minimal example above.
```
# To see output in the console
$ bimtester -i test.ifc -f test.feature -c
# Or, if you want to generate a HTML report
$ bimtester -i test.ifc -f test.feature -r report.html
```
```
python ./gui.py
```
## Create a binary out of the Python package
TODO: Check if this works
Unix:
```
$ pyinstaller --onefile --clean --icon=icon.ico --add-data "features:features" bimtester.py
```
Windows:
```
$ pyinstaller --onefile --clean --icon=icon.ico --add-data "features;features" bimtester.py
```
-5
View File
@@ -1,5 +0,0 @@
from os.path import dirname
from os.path import realpath
package_path = dirname(realpath(__file__))
-47
View File
@@ -1,47 +0,0 @@
import ifcopenshell
import os
from pathlib import Path
class TestPurger:
def __init__(self):
self.file = None
def purge(self):
filenames = []
if os.path.exists("features"):
for filename in Path("features/").glob("*.feature"):
filenames.append(filename)
for f in os.listdir("."):
if f.endswith(".feature"):
filenames.append(f)
for filename in filenames:
with open(filename, "r") as feature_file:
old_file = feature_file.readlines()
with open(filename, "w") as new_file:
for line in old_file:
is_purged = False
if 'The IFC file "' in line and '" must be provided' in line:
filename = line.split('"')[1]
print("Loading file {} ...".format(filename))
self.file = ifcopenshell.open(filename)
if line.strip()[0:2] == "* ":
words = line.strip().split()
for word in words:
if self.is_a_global_id(word):
if not self.does_global_id_exist(word):
print("Test for {} purged ...".format(word))
is_purged = True
if not is_purged:
new_file.write(line)
def is_a_global_id(self, word):
return word[0] in ["0", "1", "2", "3"] and len(word) == 22
def does_global_id_exist(self, global_id):
try:
self.file.by_guid(global_id)
return True
except Exception:
return False
@@ -1,54 +0,0 @@
import os
from behave.model import Scenario
from logfile import create_logfile
from logfile import append_logfile
from zoom_smart_view import append_zoom_smartview
from zoom_smart_view import create_zoom_smartview
from bimtester.ifc import IfcStore
from bimtester.lang import switch_locale
this_path = os.path.dirname(os.path.realpath(__file__))
def before_all(context):
userdata = context.config.userdata
if context.config.lang:
switch_locale(userdata.get("localedir"), context.config.lang)
continue_after_failed = userdata.getbool("runner.continue_after_failed_step", True)
Scenario.continue_after_failed_step = continue_after_failed
# TODO: refactor smart view support into a decoupled module
# context.ifc_path = userdata.get("ifc", "")
# context.ifc_basename = os.path.basename(
# os.path.splitext(context.ifc_path)[0]
# )
# context.outpath = os.path.join(this_path, "..")
# context.thelogfile = os.path.join(context.outpath, context.ifc_basename + ".log")
# create_logfile(
# context.thelogfile,
# context.ifc_basename,
# )
# # set up smart view file
# context.smview_file = os.path.join(context.outpath, context.ifc_basename + ".bcsv")
# create_zoom_smartview(
# context.smview_file,
# context.ifc_basename,
# )
def after_step(context, step):
pass
# TODO: refactor smart view support into a decoupled module
#if step.status == "failed":
# # append log file
# append_logfile(context, step)
# # extend smart view
# if hasattr(context, "falseguids"):
# append_zoom_smartview(context.smview_file, step.name, context.falseguids)
@@ -1,30 +0,0 @@
import json
def create_logfile(thelogfile, ifcbasename):
logfile = open(thelogfile, "w")
logfile.write("BIMTester log file\n")
logfile.write("------------------\n\n")
logfile.write("ifc base file name: {}\n".format(ifcbasename))
logfile.close()
def append_logfile(thecontext, step):
# step attributes (also these set by user) scope is the scenario
# https://behave.readthedocs.io/en/latest/thecontext_attributes.html
print("Step '{}' failed".format(step.name))
# log file
logfile = open(thecontext.thelogfile, "a")
logfile.write("\n\nStep '{}' failed\n".format(step.name))
if hasattr(thecontext, "falseelems"):
logfile.write("{}\n".format(
json.dumps(thecontext.falseelems, indent=4)
))
if hasattr(thecontext, "falseprops"):
logfile.write("{}\n".format(
json.dumps(thecontext.falseprops, indent=4)
))
logfile.close()
@@ -1,15 +0,0 @@
use_step_matcher("parse")
from bimtester.features.steps.classification import en
use_step_matcher("parse")
from bimtester.features.steps.element_classes import en
use_step_matcher("parse")
from bimtester.features.steps.geocoding import en
use_step_matcher("parse")
from bimtester.features.steps.geolocation import en
use_step_matcher("parse")
from bimtester.features.steps.geometric_detail import en
use_step_matcher("parse")
from bimtester.features.steps.model_federation import en
use_step_matcher("parse")
from bimtester.features.steps.project_setup import de, en, fr, it, nl
use_step_matcher("parse")
@@ -1,70 +0,0 @@
import json
from behave import step
from bimtester import util
from bimtester.ifc import IfcStore
from bimtester.lang import _
def get_classification(name):
classifications = [c for c in IfcStore.file.by_type("IfcClassification") if c.Name == name]
if len(classifications) != 1:
assert False, f'The classification "{name}" was not found'
return classifications[0]
@step('The classification "{name}" must be used')
def step_impl(context, name):
get_classification(name)
@step('The classification "{name}" is published by "{source}"')
def step_impl(context, name, source):
util.assert_attribute(get_classification(name), "Source", source)
@step('The classification "{name}" is the edition "{edition}" on "{edition_date}"')
def step_impl(context, name, edition, edition_date):
element = get_classification(name)
util.assert_attribute(element, "Edition", edition)
util.assert_attribute(element, "EditionDate", edition_date)
@step('The classification "{name}" has the description "{description}"')
def step_impl(context, name, description):
util.assert_attribute(get_classification(name), "Description", description)
@step('The classification "{name}" is referenced by the website "{location}"')
def step_impl(context, name, location):
util.assert_attribute(get_classification(name), "Location", location)
@step('The classification "{name}" has a hierarchy denoted by the tokens "{tokens}"')
def step_impl(context, name, tokens):
try:
tokens = json.loads(tokens)
except:
assert False, _("Tokens {} are not specified as a JSON list").format(tokens)
util.assert_attribute(get_classification(name), "ReferenceTokens", tokens)
@step('The element "{guid}" is classified as a "{identification}" with name "{reference_name}"')
def step_impl(context, guid, identification, reference_name):
element = util.assert_guid(IfcStore.file, guid)
if not hasattr(element, "HasAssociations") or not element.HasAssociations:
assert False, _("The element {} has no associations.").format(element)
references = [a.RelatingClassification for a in element.HasAssociations if a.is_a("IfcRelAssociatesClassification")]
if not references:
assert False, _("The element {element} has no associated classification references.").format(element)
is_success = False
for reference in references:
try:
util.assert_attribute(reference, "Identification", identification)
util.assert_attribute(reference, "Name", reference_name)
is_success = True
except:
pass
if not is_success:
assert False, _(
"No classification references met the requirement for an identification {} and name {} for the element {}. The references we found were: {}"
).format(identification, reference_name, element, references)
@@ -1,40 +0,0 @@
from behave import step
from bimtester import util
from bimtester.ifc import IfcStore
from bimtester.lang import _
@step('The element "{guid}" is an "{ifc_class}" only')
def step_impl(context, guid, ifc_class):
element = util.assert_guid(IfcStore.file, guid)
util.assert_type(element, ifc_class, is_exact=True)
@step('The element "{guid}" is an "{ifc_class}"')
def step_impl(context, guid, ifc_class):
element = util.assert_guid(IfcStore.file, guid)
util.assert_type(element, ifc_class)
@step('The element "{guid}" is further defined as a "{predefined_type}"')
def step_impl(context, guid, predefined_type):
element = util.assert_guid(IfcStore.file, guid)
if (
hasattr(element, "PredefinedType")
and element.PredefinedType == "USERDEFINED"
and hasattr(element, "ObjectType")
):
util.assert_attribute(element, "ObjectType", predefined_type)
elif hasattr(element, "PredefinedType"):
util.assert_attribute(element, "PredefinedType", predefined_type)
else:
assert False, _("The element {} does not have a PredefinedType or ObjectType attribute").format(element)
@step('The element "{guid}" should not exist because "{reason}"')
def step_impl(context, guid, reason):
try:
element = IfcStore.file.by_id(guid)
except:
return
assert False, _("This element {} should be reevaluated.").format(element)
@@ -1,83 +0,0 @@
from behave import step, use_step_matcher
from bimtester import util
from bimtester.ifc import IfcStore
from bimtester.lang import _
def get_ifc_class_from_spatial_type(spatial_type):
if spatial_type == "site":
return "IfcSite"
elif spatial_type == "building":
return "IfcBuilding"
return "IfcFacility"
def check_geocode_attribute(guid, spatial_type, name, value):
element = util.assert_guid(IfcStore.file, guid)
util.assert_type(element, get_ifc_class_from_spatial_type(spatial_type))
util.assert_attribute(element, name, value)
def check_geocode_address(guid, spatial_type, name, value):
element = util.assert_guid(IfcStore.file, guid)
ifc_class = get_ifc_class_from_spatial_type(spatial_type)
util.assert_type(element, ifc_class)
if ifc_class == "IfcSite":
address_name = "SiteAddress"
elif ifc_class == "IfcBuilding":
address_name = "BuildingAddress"
util.assert_attribute(element, address_name)
util.assert_attribute(getattr(element, address_name), name, value)
use_step_matcher("re")
@step('The (site|building|facility) "(?P<guid>.*)" has a name of "(?P<name>.*)"')
def step_impl(context, spatial_type, guid, name):
check_geocode_attribute(guid, spatial_type, "Name", name)
@step('The (site|building|facility) "(?P<guid>.*)" has a description of "(?P<description>.*)"')
def step_impl(context, spatial_type, guid, description):
check_geocode_attribute(guid, spatial_type, "Description", description)
@step('The site "(?P<guid>.*)" has a land title number of "(?P<land_title_number>.*)"')
def step_impl(context, guid, land_title_number):
check_geocode_attribute(guid, "site", "LandTitleNumber", land_title_number)
@step('The (site|building) "(?P<guid>.*)" has the address "(?P<address_lines>.*)"')
def step_impl(context, spatial_type, guid, address_lines):
check_geocode_address(guid, spatial_type, "AddressLines", address_lines.split("\\n"))
@step('The (site|building) "(?P<guid>.*)" has a postal box of "(?P<postal_box>.*)"')
def step_impl(context, spatial_type, guid, postal_box):
check_geocode_address(guid, spatial_type, "PostalBox", postal_box)
@step('The (site|building) "(?P<guid>.*)" is in the town "(?P<town>.*)"')
def step_impl(context, spatial_type, guid, town):
check_geocode_address(guid, spatial_type, "Town", town)
@step('The (site|building) "(?P<guid>.*)" is in the region "(?P<region>.*)"')
def step_impl(context, spatial_type, guid, region):
check_geocode_address(guid, spatial_type, "Region", region)
@step('The (site|building) "(?P<guid>.*)" has a post code of "(?P<post_code>.*)"')
def step_impl(context, spatial_type, guid, post_code):
check_geocode_address(guid, spatial_type, "PostalCode", post_code)
@step('The (site|building) "(?P<guid>.*)" is in the country "(?P<country>.*)"')
def step_impl(context, spatial_type, guid, country):
check_geocode_address(guid, spatial_type, "Country", country)
@step('The (site|building) "(?P<guid>.*)" has an address description of "(?P<description>.*)"')
def step_impl(context, spatial_type, guid, description):
check_geocode_address(guid, spatial_type, "Description", description)
@@ -1,214 +0,0 @@
import math
import ifcopenshell
import ifcopenshell.util.element
import ifcopenshell.util.geolocation
from behave import step
from bimtester import util
from bimtester.ifc import IfcStore
from bimtester.lang import _
@step(u'There must be at least one "{ifc_class}" element')
def step_impl(context, ifc_class):
assert len(IfcStore.file.by_type(ifc_class)) >= 1, _("An element of {} could not be found").format(ifc_class)
def check_ifc4_geolocation(entity_name, prop_name=None, value=None, should_assert=True):
if entity_name not in IfcStore.bookmarks:
has_entity = False
project = IfcStore.file.by_type("IfcProject")[0]
for context in project.RepresentationContexts:
if entity_name == "IfcMapConversion":
if (
context.is_a("IfcGeometricRepresentationContext")
and context.ContextType == "Model"
and context.HasCoordinateOperation
):
IfcStore.bookmarks[entity_name] = context.HasCoordinateOperation[0]
has_entity = True
elif entity_name == "IfcProjectedCRS":
if (
context.is_a("IfcGeometricRepresentationContext")
and context.ContextType == "Model"
and context.HasCoordinateOperation
and context.HasCoordinateOperation[0].TargetCRS
):
IfcStore.bookmarks[entity_name] = context.HasCoordinateOperation[0].TargetCRS
has_entity = True
if not has_entity:
assert False, _("No model geometric representation contexts refer to an {}").format(entity_name)
if not prop_name:
return
actual_value = getattr(IfcStore.bookmarks[entity_name], prop_name)
if should_assert:
assert actual_value == value, _('We expected a value of "{}" but instead got "{}"').format(value, actual_value)
else:
return actual_value
@step(u"The project must have coordinate reference system data")
def step_impl(context):
if IfcStore.file.schema == "IFC2X3":
for site in IfcStore.file.by_type("IfcSite"):
util.assert_pset(site, "EPset_ProjectedCRS")
return
check_ifc4_geolocation("IfcProjectedCRS")
@step(u'The name of the CRS must be "{coordinate_reference_name}"')
def step_impl(context, coordinate_reference_name):
if IfcStore.file.schema == "IFC2X3":
for site in IfcStore.file.by_type("IfcSite"):
util.assert_pset(site, "EPset_ProjectedCRS", "Name", coordinate_reference_name)
return
check_ifc4_geolocation("IfcProjectedCRS", "Name", coordinate_reference_name)
@step(u'The description of the CRS must be "{value}"')
def step_impl(context, value):
if IfcStore.file.schema == "IFC2X3":
for site in IfcStore.file.by_type("IfcSite"):
util.assert_pset(site, "EPset_ProjectedCRS", "Description", value)
return
check_ifc4_geolocation("IfcProjectedCRS", "Description", value)
@step(u'The geodetic datum must be "{coordinate_reference_name}"')
def step_impl(context, coordinate_reference_name):
if IfcStore.file.schema == "IFC2X3":
for site in IfcStore.file.by_type("IfcSite"):
util.assert_pset(site, "EPset_ProjectedCRS", "GeodeticDatum", coordinate_reference_name)
return
check_ifc4_geolocation("IfcProjectedCRS", "GeodeticDatum", coordinate_reference_name)
@step(u'The vertical datum must be "{coordinate_reference_name}"')
def step_impl(context, coordinate_reference_name):
if IfcStore.file.schema == "IFC2X3":
for site in IfcStore.file.by_type("IfcSite"):
util.assert_pset(site, "EPset_ProjectedCRS", "VerticalDatum", coordinate_reference_name)
return
check_ifc4_geolocation("IfcProjectedCRS", "VerticalDatum", coordinate_reference_name)
@step(u'The map projection must be "{coordinate_reference_name}"')
def step_impl(context, coordinate_reference_name):
if IfcStore.file.schema == "IFC2X3":
for site in IfcStore.file.by_type("IfcSite"):
util.assert_pset(site, "EPset_ProjectedCRS", "MapProjection", coordinate_reference_name)
return
check_ifc4_geolocation("IfcProjectedCRS", "MapProjection", coordinate_reference_name)
@step(u'The map zone must be "{coordinate_reference_name}"')
def step_impl(context, coordinate_reference_name):
if IfcStore.file.schema == "IFC2X3":
for site in IfcStore.file.by_type("IfcSite"):
util.assert_pset(site, "EPset_ProjectedCRS", "MapZone", coordinate_reference_name)
return
check_ifc4_geolocation("IfcProjectedCRS", "MapZone", coordinate_reference_name)
@step(u'The map unit must be "{unit}"')
def step_impl(context, unit):
if IfcStore.file.schema == "IFC2X3":
for site in IfcStore.file.by_type("IfcSite"):
util.assert_pset(site, "EPset_ProjectedCRS", "MapUnit", unit)
return
actual_value = check_ifc4_geolocation("IfcProjectedCRS", "MapUnit", should_assert=False)
if not actual_value:
assert False, _("A unit was not provided in the projected CRS")
if actual_value.is_a("IfcSIUnit"):
prefix = actual_value.Prefix if actual_value.Prefix else ""
actual_value = prefix + actual_value.Name
elif actual_value.is_a("IfcConversionBasedUnit"):
actual_value = actual_value.Name
assert actual_value == unit, _('We expected a value of "{}" but instead got "{}"').format(unit, actual_value)
@step(u"The project must have coordinate transformations to convert from local to global coordinates")
def step_impl(context):
if IfcStore.file.schema == "IFC2X3":
for site in IfcStore.file.by_type("IfcSite"):
util.assert_pset(site, "EPset_MapConversion")
check_ifc4_geolocation("IfcMapConversion")
@step(u'The eastings of the model must be offset by "{number}" to derive its global coordinates')
def step_impl(context, number):
number = util.assert_number(number)
if IfcStore.file.schema == "IFC2X3":
for site in IfcStore.file.by_type("IfcSite"):
util.assert_pset(site, "EPset_MapConversion", "Eastings", number)
return
check_ifc4_geolocation("IfcMapConversion", "Eastings", number)
@step(u'The northings of the model must be offset by "{number}" to derive its global coordinates')
def step_impl(context, number):
number = util.assert_number(number)
if IfcStore.file.schema == "IFC2X3":
for site in IfcStore.file.by_type("IfcSite"):
util.assert_pset(site, "EPset_MapConversion", "Northings", number)
return
check_ifc4_geolocation("IfcMapConversion", "Northings", number)
@step(u'The height of the model must be offset by "{number}" to derive its global coordinates')
def step_impl(context, number):
number = util.assert_number(number)
if IfcStore.file.schema == "IFC2X3":
for site in IfcStore.file.by_type("IfcSite"):
util.assert_pset(site, "EPset_MapConversion", "OrthogonalHeight", number)
return
check_ifc4_geolocation("IfcMapConversion", "OrthogonalHeight", number)
@step(u'The model must be rotated clockwise by "{number}" to derive its global coordinates')
def step_impl(context, number):
number = util.assert_number(number)
if IfcStore.file.schema == "IFC2X3":
return check_ifc2x3_geolocation("EPset_MapConversion", "Height", number)
abscissa = check_ifc4_geolocation("IfcMapConversion", "XAxisAbscissa", should_assert=False)
ordinate = check_ifc4_geolocation("IfcMapConversion", "XAxisOrdinate", should_assert=False)
actual_value = round(ifcopenshell.util.geolocation.xy2angle(abscissa, ordinate), 3)
value = round(number, 3)
assert actual_value == value, _('We expected a value of "{}" but instead got "{}"').format(value, actual_value)
@step(u'The model must be scaled along the horizontal axis by "{number}" to derive its global coordinates')
def step_impl(context, number):
number = util.assert_number(number)
if IfcStore.file.schema == "IFC2X3":
for site in IfcStore.file.by_type("IfcSite"):
util.assert_pset(site, "EPset_MapConversion", "Scale", number)
return
check_ifc4_geolocation("IfcMapConversion", "Scale", number)
@step(u'The site "{guid}" has a longitude of "{number}"')
def step_impl(context, guid, number):
number = util.assert_number(number)
site = util.assert_guid(IfcStore.file, guid)
util.assert_type(site, "IfcSite")
ref = util.assert_attribute(site, "RefLongitude")
number = ifcopenshell.util.geolocation.dd2dms(number, use_ms=(len(ref) == 4))
util.assert_attribute(site, "RefLongitude", number)
@step(u'The site "{guid}" has a latitude of "{number}"')
def step_impl(context, guid, number):
number = util.assert_number(number)
site = util.assert_guid(IfcStore.file, guid)
util.assert_type(site, "IfcSite")
ref = util.assert_attribute(site, "RefLatitude")
number = ifcopenshell.util.geolocation.dd2dms(number, use_ms=(len(ref) == 4))
util.assert_attribute(site, "RefLatitude", number)
@step(u'The site "{guid}" has an elevation of "{number}"')
def step_impl(context, guid, number):
number = util.assert_number(number)
site = util.assert_guid(IfcStore.file, guid)
util.assert_type(site, "IfcSite")
util.assert_attribute(site, "RefElevation", number)
@@ -1,29 +0,0 @@
from behave import step
from bimtester import util
from bimtester.ifc import IfcStore
from bimtester.lang import _
@step('All elements must be under "{number}" polygons')
def step_impl(context, number):
number = int(number)
errors = []
for element in IfcStore.file.by_type("IfcElement"):
if not element.Representation:
continue
total_polygons = 0
tree = IfcStore.file.traverse(element.Representation)
for e in tree:
if e.is_a("IfcFace"):
total_polygons += 1
elif e.is_a("IfcPolygonalFaceSet"):
total_polygons += len(e.Faces)
elif e.is_a("IfcTriangulatedFaceSet"):
total_polygons += len(e.CoordIndex)
if total_polygons > number:
errors.append((total_polygons, element))
if errors:
message = "The following {} elements are over 500 polygons:\n".format(len(errors))
for error in errors:
message += "Polygons: {} - {}\n".format(error[0], error[1])
assert False, message
@@ -1,95 +0,0 @@
import ifcopenshell.util.geolocation
import ifcopenshell.util.placement
from behave import step
from bimtester import util
from bimtester.ifc import IfcStore
from bimtester.lang import _
def get_decimal_points(value):
try:
return len(value.split(".")[1])
except:
return 0
def get_containing_spatial_elements(element):
results = []
if element.is_a("IfcSpatialElement"):
results.append(element)
for rel in element.Decomposes:
if rel.is_a("IfcRelAggregates"):
results.append(get_containing_spatial_elements(rel.RelatingObject))
elif element.is_a("IfcElement"):
for rel in element.ContainedInStructure:
if rel.is_a("ifcRelContainedInSpatialStructure"):
results.append(get_containing_spatial_elements(rel.RelatingStructure))
return results
@step('There is a datum element "{guid}" as an "{ifc_class}"')
def step_impl(context, guid, ifc_class):
element = utils.assert_guid(IfcStore.file, guid)
util.assert_type(element, ifc_class)
@step(
'The element "{guid}" has a global easting, northing, and elevation of "{easting}", "{northing}", and "{elevation}" respectively'
)
def step_impl(context, guid, easting, northing, elevation):
if IfcStore.file.schema == "IFC2X3":
if element.is_a("IfcSite"):
site = element
else:
potential_sites = [s for s in get_containing_spatial_elements(element) if s.is_a("IfcSite")]
if potential_sites:
site = potential_sites[0]
else:
assert False, _("The datum element does not belong to a geolocated site")
map_conversion = assert_pset(site, "EPset_MapConversion")
else:
map_conversion = IfcStore.file.by_type("IfcMapConversion")
if map_conversion:
map_conversion = map_conversion[0].get_info()
else:
assert False, _("No map conversion was found in the file")
element = utils.assert_guid(IfcStore.file, guid)
if not element.ObjectPlacement:
assert False, _("The element does not have an object placement: {}").format(element)
m = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement)
e, n, h = ifcopenshell.util.geolocation.xyz2enh(
m[0][3],
m[1][3],
m[2][3],
float(map_conversion["Eastings"]),
float(map_conversion["Northings"]),
float(map_conversion["OrthogonalHeight"]),
float(map_conversion["XAxisAbscissa"]),
float(map_conversion["XAxisOrdinate"]),
float(map_conversion["Scale"]),
)
element_x = round(e, get_decimal_points(easting))
element_y = round(n, get_decimal_points(northing))
element_z = round(h, get_decimal_points(elevation))
expected_placement = (util.assert_number(easting), util.assert_number(northing), util.assert_number(elevation))
if (element_x, element_y, element_z) != expected_placement:
assert False, _("The element {} is meant to have a location of {} but instead we found {}").format(
element, expected_placement, (element_x, element_y, element_z)
)
@step('The element "{guid}" has a local X, Y, and Z coordinate of "{x}", "{y}", and "{z}" respectively')
def step_impl(context, guid, x, y, z):
element = utils.assert_guid(IfcStore.file, guid)
if not element.ObjectPlacement:
assert False, _("The element does not have an object placement: {}").format(element)
m = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement)
element_x = round(m[0][3], get_decimal_points(x))
element_y = round(m[1][3], get_decimal_points(y))
element_z = round(m[2][3], get_decimal_points(z))
expected_placement = (util.assert_number(x), util.assert_number(y), util.assert_number(z))
if (element_x, element_y, element_z) != expected_placement:
assert False, _("The element {} is meant to have a location of {} but instead we found {}").format(
element, expected_placement, (element_x, element_y, element_z)
)
@@ -1,16 +0,0 @@
from behave import step
@step('Die IFC-Daten müssen das "{schema}" Schema benutzen')
def step_impl(context, schema):
context.execute_steps(f'* IFC data must use the "{schema}" schema')
@step('Die Globale Identifikationskennung (Globally Unique Identifier = GUID) des Projektes ist "{guid}"')
def step_impl(context, guid):
context.execute_steps(f'* The project must have an identifier of "{guid}"')
@step('Der Name, die Abkürzung oder die Kurzkennung des Projektes ist "{value}"')
def step_impl(context, value):
context.execute_steps(f'* The project name, code, or short identifier must be "{value}"')
@@ -1,91 +0,0 @@
from behave import step
from bimtester import util
from bimtester.ifc import IfcStore
from bimtester.lang import _
@step('IFC data must use the "{schema}" schema')
def step_impl(context, schema):
real_schema = IfcStore.file.schema
assert real_schema == schema, _("We expected a schema of {} but instead got {}").format(schema, real_schema)
@step('The IFC file "{file}" is exempt from being provided')
def step_impl(context, file):
pass
@step('No further requirements are specified because "{reason}"')
def step_impl(context, reason):
pass
@step('The project must have an identifier of "{guid}"')
def step_impl(context, guid):
util.assert_attribute(IfcStore.file.by_type("IfcProject")[0], "GlobalId", guid)
@step('The project name, code, or short identifier must be "{value}"')
def step_impl(context, value):
util.assert_attribute(IfcStore.file.by_type("IfcProject")[0], "Name", value)
@step('The project must have a longer form name of "{value}"')
def step_impl(context, value):
util.assert_attribute(IfcStore.file.by_type("IfcProject")[0], "LongName", value)
@step('The project must be described as "{value}"')
def step_impl(context, value):
util.assert_attribute(IfcStore.file.by_type("IfcProject")[0], "Description", value)
@step('The project must be categorised under "{value}"')
def step_impl(context, value):
util.assert_attribute(IfcStore.file.by_type("IfcProject")[0], "ObjectType", value)
@step('The project must contain information about the "{value}" phase')
def step_impl(context, value):
util.assert_attribute(IfcStore.file.by_type("IfcProject")[0], "Phase", value)
@step("The project must contain 3D geometry representing the shape of objects")
def step_impl(context):
assert get_subcontext("Body", "Model", "MODEL_VIEW")
@step("The project must contain 3D geometry representing clearance zones")
def step_impl(context):
assert get_subcontext("Clearance", "Model", "MODEL_VIEW")
@step("The project must contain 3D geometry representing the center of gravity of objects")
def step_impl(context):
assert get_subcontext("CoG", "Model", "MODEL_VIEW")
@step("The project must contain 3D geometry representing the object bounding boxes")
def step_impl(context):
assert get_subcontext("Box", "Model", "MODEL_VIEW")
def get_subcontext(identifier, type, target_view):
project = IfcStore.file.by_type("IfcProject")[0]
for rep_context in project.RepresentationContexts:
for subcontext in rep_context.HasSubContexts:
if (
subcontext.ContextIdentifier == identifier
and subcontext.ContextType == type
and subcontext.TargetView == target_view
):
return True
assert False, "The subcontext with identifier {}, type {}, and target view {} could not be found".format(
identifier, type, target_view
)
@step('the project has a {attribute_name} attribute with a value of "{attribute_value}"')
def step_impl(context, attribute_name, attribute_value):
project = IfcStore.file.by_type("IfcProject")[0]
assert getattr(project, attribute_name) == attribute_value
@@ -1,6 +0,0 @@
from behave import step
@step('Les données IFC doivent utiliser le schéma "{schema}"')
def step_impl(context, schema):
context.execute_steps(f'* IFC data must use the "{schema}" schema')
@@ -1,11 +0,0 @@
from behave import step
@step('I dati IFC devono seguire lo schema "{schema}"')
def step_impl(context, schema):
context.execute_steps(f'* IFC data must use the "{schema}" schema')
@step('Il nome del progetto, codice o identificatore breve deve essere "{value}"')
def step_impl(context, value):
context.execute_steps(f'* "The project name, code, or short identifier must be "{value}"')
@@ -1,11 +0,0 @@
from behave import step
@step('IFC-gegevens moeten het "{schema}" -schema gebruiken')
def step_impl(context, schema):
context.execute_steps(f'* IFC data must use the "{schema}" schema')
@step('De projectnaam, code of korte ID moet "{value}"')
def step_impl(context, value):
context.execute_steps(f'* "The project name, code, or short identifier must be "{value}"')
@@ -1,138 +0,0 @@
import fileinput
def create_zoom_smartview(sm_file, ifcbasename):
smf = open(sm_file, "w")
smf.write('<?xml version="1.0"?>\n')
smf.write("<bimcollabsmartviewfile>\n")
smf.write(" <version>5</version>\n")
smf.write(" <applicationversion>Win - Version: ")
# next line belongs to last, because of line length
smf.write("3.4 (build 3.4.13.559)</applicationversion>\n")
smf.write("</bimcollabsmartviewfile>\n")
smf.write("\n")
smf.write("<SMARTVIEWSETS>\n")
smf.write(" <SMARTVIEWSET>\n")
smf.write(" <TITLE>BIMTester {}</TITLE>\n".format(ifcbasename))
smf.write(" <DESCRIPTION></DESCRIPTION>\n")
smf.write(" <GUID>a2ddfaf7-97f2-4519-aabd-f2d94f6b4d6b</GUID>\n")
smf.write(" <MODIFICATIONDATE>2020-10-30T13:23:30")
# next line belongs to last, because of line length
smf.write("</MODIFICATIONDATE>\n")
smf.write(" <SMARTVIEWS>\n")
smf.write(" </SMARTVIEWS>\n")
smf.write(" </SMARTVIEWSET>\n")
smf.write("</SMARTVIEWSETS>\n")
smf.close()
def append_zoom_smartview(sm_file, step_name, false_elements_guid):
# build the smartview string
smview_string = " <SMARTVIEW>\n"
smview_string += (
" <TITLE>GUID filter, {}</TITLE>\n"
.format(step_name)
)
smview_string += "{}\n".format(each_smartview_string_before)
for guid in false_elements_guid:
smview_string += (
"{}{}{}\n".format(
rule_string_before,
guid,
rule_string_after)
)
smview_string += "{}\n".format(each_smartview_string_after)
# insert smartview string into file
theline = " </SMARTVIEWS>"
newtext = smview_string + theline
for line in fileinput.FileInput(sm_file, inplace=True):
# the print replaces the line in the file
# and add the line afterwards
print(line.replace(theline, newtext), end="")
each_smartview_string_title = """ <SMARTVIEW>
<TITLE>Filter GUID</TITLE>
<DESCRIPTION></DESCRIPTION>"""
each_smartview_string_before = """ <CREATOR>bernd@bimstatik.ch</CREATOR>
<CREATIONDATE>2020-10-30T13:18:45</CREATIONDATE>
<MODIFIER>bernd@bimstatik.ch</MODIFIER>
<MODIFICATIONDATE>2020-10-30T13:23:30</MODIFICATIONDATE>
<GUID>15fda94f-b4bf-43be-8ef4-15d3121137e1</GUID>
<RULES>
<RULE>
<IFCTYPE>Any</IFCTYPE>
<PROPERTY>
<NAME>None</NAME>
<PROPERTYSETNAME>None</PROPERTYSETNAME>
<TYPE>None</TYPE>
<VALUETYPE>None</VALUETYPE>
<UNIT>None</UNIT>
</PROPERTY>
<CONDITION>
<TYPE>Is</TYPE>
<VALUE></VALUE>
</CONDITION>
<ACTION>
<TYPE>AddSetColored</TYPE>
<R>187</R>
<G>187</G>
<B>187</B>
</ACTION>
</RULE>
<RULE>
<IFCTYPE>Any</IFCTYPE>
<PROPERTY>
<NAME>None</NAME>
<PROPERTYSETNAME>None</PROPERTYSETNAME>
<TYPE>None</TYPE>
<VALUETYPE>None</VALUETYPE>
<UNIT>None</UNIT>
</PROPERTY>
<CONDITION>
<TYPE>Is</TYPE>
<VALUE></VALUE>
</CONDITION>
<ACTION>
<TYPE>SetTransparent</TYPE>
</ACTION>
</RULE>"""
each_smartview_string_after = """ </RULES>
<INFORMATIONTAKEOFF>
<PROPERTYSETNAME>None</PROPERTYSETNAME>
<PROPERTYNAME>None</PROPERTYNAME>
<OPERATION>0</OPERATION>
</INFORMATIONTAKEOFF>
</SMARTVIEW>"""
rule_string_before = """ <RULE>
<IFCTYPE>Any</IFCTYPE>
<PROPERTY>
<NAME>GUID</NAME>
<PROPERTYSETNAME>Summary</PROPERTYSETNAME>
<TYPE>Summary</TYPE>
<VALUETYPE>StringValue</VALUETYPE>
<UNIT>None</UNIT>
</PROPERTY>
<CONDITION>
<TYPE>Is</TYPE>
<VALUE>"""
rule_string_after = """</VALUE>
</CONDITION>
<ACTION>
<TYPE>SetColored</TYPE>
<R>255</R>
<G>10</G>
<B>10</B>
</ACTION>
</RULE>"""
-153
View File
@@ -1,153 +0,0 @@
import os
import sys
import bimtester.run
from PySide2 import QtCore
from PySide2 import QtGui
from PySide2 import QtWidgets
def run():
app = QtWidgets.QApplication(sys.argv)
form = GuiWidgetBimTester()
form.show()
sys.exit(app.exec_())
class GuiWidgetBimTester(QtWidgets.QWidget):
def __init__(self, args=[]):
super(GuiWidgetBimTester, self).__init__()
self.args = args
self._setup_ui()
# http://forum.freecadweb.org/viewtopic.php?f=18&t=10732&start=10#p86493
def __del__(self):
return
def _setup_ui(self):
package_path = os.path.dirname(os.path.realpath(__file__))
iconpath = os.path.join(package_path, "resources", "icons", "bimtester.ico")
"""
# as svg
# https://stackoverflow.com/a/35138314
theicon = QtSvg.QSvgWidget(iconpath)
# none works ...
#theicon.setGeometry(20,20,200,200)
#theicon.setSizePolicy(
# QtGui.QSizePolicy.Policy.Maximum,
# QtGui.QSizePolicy.Policy.Maximum
#)
#theicon.sizeHint()
"""
# as pixmap
theicon = QtWidgets.QLabel(self)
iconpixmap = QtGui.QPixmap(iconpath)
iconpixmap = iconpixmap.scaled(100, 100, QtCore.Qt.KeepAspectRatio)
theicon.setPixmap(iconpixmap)
# ifc file
_ifcfile_label = QtWidgets.QLabel("IFC file", self)
self.ifcfile_text = QtWidgets.QLineEdit()
_ifcfile_browse_btn = QtWidgets.QToolButton()
_ifcfile_browse_btn.setText("...")
_ifcfile_browse_btn.clicked.connect(self.select_ifcfile)
# feature files path
# use a layout with a frame and a title, see solver framework tp
# beside button
ffifc_str = "Feature files in a directory 'features' beside the IFC file."
featuredirfromifc_label = QtWidgets.QLabel(ffifc_str, self)
# path browser and line edit
_ffdir_str = "Feature files directory. " "'features' directory has to be in there."
_featurefilesdir_label = QtWidgets.QLabel(_ffdir_str, self)
self.featurefilesdir_text = QtWidgets.QLineEdit()
self.feafilesdir_browse_btn = QtWidgets.QToolButton()
self.feafilesdir_browse_btn.setText("...")
self.feafilesdir_browse_btn.clicked.connect(self.select_featurefilesdir)
# buttons
self.run_button = QtWidgets.QPushButton(QtGui.QIcon.fromTheme("document-new"), "Run")
self.close_button = QtWidgets.QPushButton(QtGui.QIcon.fromTheme("window-close"), "Close")
self.run_button.clicked.connect(self.run_bimtester)
self.close_button.clicked.connect(self.close_widget)
_buttons = QtWidgets.QHBoxLayout()
_buttons.addWidget(self.run_button)
_buttons.addWidget(self.close_button)
# Layout:
layout = QtWidgets.QGridLayout()
layout.addWidget(theicon, 1, 0, alignment=QtCore.Qt.AlignRight)
layout.addWidget(featuredirfromifc_label, 2, 0)
layout.addWidget(_featurefilesdir_label, 3, 0)
layout.addWidget(self.featurefilesdir_text, 4, 0)
layout.addWidget(self.feafilesdir_browse_btn, 4, 1)
layout.addWidget(_ifcfile_label, 5, 0)
layout.addWidget(self.ifcfile_text, 6, 0)
layout.addWidget(_ifcfile_browse_btn, 6, 1)
layout.addLayout(_buttons, 7, 0)
# row stretches by 10 compared to the others, std is 0
# first parameter is the row number
# second is the stretch factor.
layout.setRowStretch(0, 10)
self.setLayout(layout)
def select_ifcfile(self):
ifcfile = QtWidgets.QFileDialog.getOpenFileName(self, dir=self.get_ifcfile())[0]
self.set_ifcfile(ifcfile)
def set_ifcfile(self, a_file):
self.ifcfile_text.setText(a_file)
def get_ifcfile(self):
return self.ifcfile_text.text()
def select_featurefilesdir(self):
thedir = self.featurefilesdir_text.text()
features_path = QtWidgets.QFileDialog.getExistingDirectory(
self,
caption="Choose features directory ...",
dir=thedir,
options=QtWidgets.QFileDialog.HideNameFilterDetails,
)
self.set_featurefilesdir(features_path)
def set_featurefilesdir(self, a_directory):
self.featurefilesdir_text.setText(a_directory)
def get_featurefilesdir(self):
return self.featurefilesdir_text.text()
def run_bimtester(self):
print("Run BIMTester by the GUI")
QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
the_features_path = self.get_featurefilesdir()
print(the_features_path)
# get ifc file
the_ifcfile = self.get_ifcfile()
print(the_ifcfile)
# overwrite the_features_path and ifcfile in args
patched_args = self.args
patched_args["featuresdir"] = the_features_path
patched_args["ifcfile"] = the_ifcfile
bimtester.run.TestRunner("file.ifc").run({})
QtWidgets.QApplication.restoreOverrideCursor()
def close_widget(self):
self.close()
def closeEvent(self, ev):
pw = self.parentWidget()
if pw and pw.inherits("QDockWidget"):
pw.deleteLater()
-4
View File
@@ -1,4 +0,0 @@
class IfcStore:
path = ""
file = None
bookmarks = {}
-15
View File
@@ -1,15 +0,0 @@
import gettext
translation = None
def _(message):
if translation:
return translation(message)
return message
def switch_locale(locale_dir, locale_id="en"):
global translation
newlang = gettext.translation("messages", localedir=locale_dir, languages=[locale_id])
newlang.install()
translation = newlang.gettext
@@ -1,200 +0,0 @@
# German translations for PROJECT.
# Copyright (C) 2020 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
#
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2021-01-17 10:55+0100\n"
"PO-Revision-Date: 2020-12-23 11:20+0100\n"
"Last-Translator: \n"
"Language: de\n"
"Language-Team: de <LL@li.org>\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.6.0\n"
#: reports.py:158
msgid "en"
msgstr "de"
#: reports.py:159
msgid "Success"
msgstr "Bestanden"
#: reports.py:160
msgid "Failure"
msgstr "Durchgefallen"
#: reports.py:161
msgid "Tests passed"
msgstr "Erfolgreiche Tests"
#: reports.py:162
msgid "Duration"
msgstr "Dauer"
#: reports.py:163
msgid "OpenBIM auditing is a feature of"
msgstr "OpenBIM auditing ist eine Funktionalität von"
#: reports.py:164
msgid "and"
msgstr "und"
#: features/steps/attributes_eleclasses_methods.py:26
msgid "All {elemcount} elements in the file are {ifc_class}."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:34
msgid "{falsecount} of {elemcount} element are {ifc_class} elements: {falseelems}"
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:43
#: features/steps/utils.py:158
msgid "Error in falsecount, something went wrong."
msgstr "Fehler in falsecount, es ist etwas falsch gelaufen."
#: features/steps/attributes_eleclasses_methods.py:84
msgid ""
"For all {elemcount} {ifc_class} elements at least one of these class "
"attributes {parameter} has no value."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:85
msgid ""
"For the following {falsecount} out of {elemcount} {ifc_class} elements at"
" least one of these class attributes {parameter} has no value: "
"{falseelems}"
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:86
#: features/steps/attributes_eleclasses_methods.py:112
#: features/steps/attributes_eleclasses_methods.py:139
#: features/steps/attributes_psets_methods.py:33
#: features/steps/geometric_detail_methods.py:56
#: features/steps/geometric_detail_methods.py:134
msgid "There are no {ifc_class} elements in the IFC file."
msgstr "Es sind keine {ifc_class} Bauteile in der IFC-Datei."
#: features/steps/attributes_eleclasses_methods.py:110
msgid "The name of all {elemcount} {elemcount} elements is not set."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:111
msgid ""
"The name of {falsecount} out of {elemcount} {ifc_class} elements is not "
"set: {falseelems}"
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:137
msgid "The description of all {elemcount} {elemcount} elements is not set."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:138
msgid ""
"The description of {falsecount} out of {elemcount} {ifc_class} elements "
"is not set: {falseelems}"
msgstr ""
#: features/steps/attributes_psets_methods.py:31
msgid ""
"All {elemcount} {ifc_class} elements are missing the property {parameter}"
" in the pset."
msgstr ""
#: features/steps/attributes_psets_methods.py:32
msgid ""
"The following {falsecount} of {elemcount} {ifc_class} elements are "
"missing the property {parameter} in the pset: {falseelems}"
msgstr ""
#: features/steps/geometric_detail_methods.py:54
msgid "All {elemcount} {ifc_class} elements are not a {parameter} representation."
msgstr ""
"Alle {elemcount} {ifc_class} Bauteile haben keine geometrische "
"Repräsentation der Klasse {parameter}."
#: features/steps/geometric_detail_methods.py:55
msgid ""
"The following {falsecount} of {elemcount} {ifc_class} elements are not a "
"{parameter} representation: {falseelems}"
msgstr ""
"Die Anzahl Bauteile {falsecount} von allen {elemcount} {ifc_class} "
"Bauteilen haben keine geometrische Repräsentation der Klasse {parameter}:"
" {falseelems}"
#: features/steps/geometric_detail_methods.py:132
msgid "The geometry of all {elemcount} {ifc_class} elements have errors."
msgstr ""
"Die geometrischen Repräsentationen von allen {elemcount} {ifc_class} "
"Bauteilen haben Fehler."
#: features/steps/geometric_detail_methods.py:133
msgid ""
"The geometry of {falsecount} out of all {elemcount} {ifc_class} elements "
"have errors: {falseelems}"
msgstr ""
"Die geometrischen Repräsentationen von {falsecount} von allen {elemcount}"
" {ifc_class} Bauteilen haben Fehler: {falseelems}"
#: features/steps/ifcdata_methods.py:9
msgid "The IFC {} file could not be loaded"
msgstr ""
#: features/steps/ifcdata_methods.py:17
msgid "We expected a schema of {} but instead got {}"
msgstr "Wir haben das Schema {} erwartet, aber die Daten nutzen das Schema {}"
#~ msgid "The geometry of all {} {} elements have errors."
#~ msgstr ""
#~ "Die geometrischen Repräsentationen von allen"
#~ " {} {} Bauteilen haben Fehler."
#~ msgid "The geometry of {} out of all {} {} elements have errors: {}"
#~ msgstr ""
#~ "Die geometrischen Repräsentationen von {} "
#~ "von allen {} {} Bauteilen haben "
#~ "Fehler: {}"
#~ msgid "There are no {} elements in the IFC file."
#~ msgstr "Es sind keine {} Bauteile in der IFC-Datei."
#~ msgid "All {} {} elements are not a IfcFacetedBrep representation."
#~ msgstr ""
#~ "Alle {} {} Bauteile haben keine "
#~ "geometrische Repräsentation der Klasse "
#~ "IfcFacetedBrep."
#~ msgid ""
#~ "The following {} of {} {} elements"
#~ " are not a IfcFacetedBrep representation:"
#~ " {}"
#~ msgstr ""
#~ "Die Anzahl Bauteile {} von allen "
#~ "{} {} Bauteilen haben keine geometrische"
#~ " Repräsentation der Klasse IfcFacetedBrep: "
#~ "{}"
#~ msgid ""
#~ "All {elemcount} {ifc_class} elements are "
#~ "not a IfcFacetedBrep representation."
#~ msgstr ""
#~ "Alle {elemcount} {ifc_class} Bauteile haben"
#~ " keine geometrische Repräsentation der "
#~ "Klasse IfcFacetedBrep."
#~ msgid ""
#~ "The following {falsecount} of {elemcount} "
#~ "{ifc_class} elements are not a "
#~ "IfcFacetedBrep representation: {falseelems}"
#~ msgstr ""
#~ "Die Anzahl Bauteile {falsecount} von "
#~ "allen {elemcount} {ifc_class} Bauteilen haben"
#~ " keine geometrische Repräsentation der "
#~ "Klasse IfcFacetedBrep: {falseelems}"
@@ -1,172 +0,0 @@
# German translations for PROJECT.
# Copyright (C) 2020 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
#
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2021-01-17 10:55+0100\n"
"PO-Revision-Date: 2020-12-18 11:41+0100\n"
"Last-Translator: \n"
"Language: en\n"
"Language-Team: en <LL@li.org>\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.6.0\n"
#: reports.py:158
msgid "en"
msgstr ""
#: reports.py:159
msgid "Success"
msgstr ""
#: reports.py:160
msgid "Failure"
msgstr ""
#: reports.py:161
msgid "Tests passed"
msgstr ""
#: reports.py:162
msgid "Duration"
msgstr ""
#: reports.py:163
msgid "OpenBIM auditing is a feature of"
msgstr ""
#: reports.py:164
msgid "and"
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:26
msgid "All {elemcount} elements in the file are {ifc_class}."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:34
msgid "{falsecount} of {elemcount} element are {ifc_class} elements: {falseelems}"
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:43
#: features/steps/utils.py:158
msgid "Error in falsecount, something went wrong."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:84
msgid ""
"For all {elemcount} {ifc_class} elements at least one of these class "
"attributes {parameter} has no value."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:85
msgid ""
"For the following {falsecount} out of {elemcount} {ifc_class} elements at"
" least one of these class attributes {parameter} has no value: "
"{falseelems}"
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:86
#: features/steps/attributes_eleclasses_methods.py:112
#: features/steps/attributes_eleclasses_methods.py:139
#: features/steps/attributes_psets_methods.py:33
#: features/steps/geometric_detail_methods.py:56
#: features/steps/geometric_detail_methods.py:134
msgid "There are no {ifc_class} elements in the IFC file."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:110
msgid "The name of all {elemcount} {elemcount} elements is not set."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:111
msgid ""
"The name of {falsecount} out of {elemcount} {ifc_class} elements is not "
"set: {falseelems}"
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:137
msgid "The description of all {elemcount} {elemcount} elements is not set."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:138
msgid ""
"The description of {falsecount} out of {elemcount} {ifc_class} elements "
"is not set: {falseelems}"
msgstr ""
#: features/steps/attributes_psets_methods.py:31
msgid ""
"All {elemcount} {ifc_class} elements are missing the property {parameter}"
" in the pset."
msgstr ""
#: features/steps/attributes_psets_methods.py:32
msgid ""
"The following {falsecount} of {elemcount} {ifc_class} elements are "
"missing the property {parameter} in the pset: {falseelems}"
msgstr ""
#: features/steps/geometric_detail_methods.py:54
msgid "All {elemcount} {ifc_class} elements are not a {parameter} representation."
msgstr ""
#: features/steps/geometric_detail_methods.py:55
msgid ""
"The following {falsecount} of {elemcount} {ifc_class} elements are not a "
"{parameter} representation: {falseelems}"
msgstr ""
#: features/steps/geometric_detail_methods.py:132
msgid "The geometry of all {elemcount} {ifc_class} elements have errors."
msgstr ""
#: features/steps/geometric_detail_methods.py:133
msgid ""
"The geometry of {falsecount} out of all {elemcount} {ifc_class} elements "
"have errors: {falseelems}"
msgstr ""
#: features/steps/ifcdata_methods.py:9
msgid "The IFC {} file could not be loaded"
msgstr ""
#: features/steps/ifcdata_methods.py:17
msgid "We expected a schema of {} but instead got {}"
msgstr ""
#~ msgid "The geometry of all {} {} elements have errors."
#~ msgstr ""
#~ msgid "The geometry of {} out of all {} {} elements have errors: {}"
#~ msgstr ""
#~ msgid "There are no {} elements in the IFC file."
#~ msgstr ""
#~ msgid "All {} {} elements are not a IfcFacetedBrep representation."
#~ msgstr ""
#~ msgid ""
#~ "The following {} of {} {} elements"
#~ " are not a IfcFacetedBrep representation:"
#~ " {}"
#~ msgstr ""
#~ msgid ""
#~ "All {elemcount} {ifc_class} elements are "
#~ "not a IfcFacetedBrep representation."
#~ msgstr ""
#~ msgid ""
#~ "The following {falsecount} of {elemcount} "
#~ "{ifc_class} elements are not a "
#~ "IfcFacetedBrep representation: {falseelems}"
#~ msgstr ""
@@ -1,143 +0,0 @@
# French translations for PROJECT.
# Copyright (C) 2020 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
#
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2021-01-17 10:55+0100\n"
"PO-Revision-Date: 2020-12-23 11:21+0100\n"
"Last-Translator: \n"
"Language: fr\n"
"Language-Team: fr <LL@li.org>\n"
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.6.0\n"
#: reports.py:158
msgid "en"
msgstr "fr"
#: reports.py:159
msgid "Success"
msgstr "Succès"
#: reports.py:160
msgid "Failure"
msgstr "Échec"
#: reports.py:161
msgid "Tests passed"
msgstr "Tests réussis"
#: reports.py:162
msgid "Duration"
msgstr "Durée"
#: reports.py:163
msgid "OpenBIM auditing is a feature of"
msgstr "L'audit OpenBIM auditing est une fonctionnalité de"
#: reports.py:164
msgid "and"
msgstr "et"
#: features/steps/attributes_eleclasses_methods.py:26
msgid "All {elemcount} elements in the file are {ifc_class}."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:34
msgid "{falsecount} of {elemcount} element are {ifc_class} elements: {falseelems}"
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:43
#: features/steps/utils.py:158
msgid "Error in falsecount, something went wrong."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:84
msgid ""
"For all {elemcount} {ifc_class} elements at least one of these class "
"attributes {parameter} has no value."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:85
msgid ""
"For the following {falsecount} out of {elemcount} {ifc_class} elements at"
" least one of these class attributes {parameter} has no value: "
"{falseelems}"
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:86
#: features/steps/attributes_eleclasses_methods.py:112
#: features/steps/attributes_eleclasses_methods.py:139
#: features/steps/attributes_psets_methods.py:33
#: features/steps/geometric_detail_methods.py:56
#: features/steps/geometric_detail_methods.py:134
msgid "There are no {ifc_class} elements in the IFC file."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:110
msgid "The name of all {elemcount} {elemcount} elements is not set."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:111
msgid ""
"The name of {falsecount} out of {elemcount} {ifc_class} elements is not "
"set: {falseelems}"
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:137
msgid "The description of all {elemcount} {elemcount} elements is not set."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:138
msgid ""
"The description of {falsecount} out of {elemcount} {ifc_class} elements "
"is not set: {falseelems}"
msgstr ""
#: features/steps/attributes_psets_methods.py:31
msgid ""
"All {elemcount} {ifc_class} elements are missing the property {parameter}"
" in the pset."
msgstr ""
#: features/steps/attributes_psets_methods.py:32
msgid ""
"The following {falsecount} of {elemcount} {ifc_class} elements are "
"missing the property {parameter} in the pset: {falseelems}"
msgstr ""
#: features/steps/geometric_detail_methods.py:54
msgid "All {elemcount} {ifc_class} elements are not a {parameter} representation."
msgstr ""
#: features/steps/geometric_detail_methods.py:55
msgid ""
"The following {falsecount} of {elemcount} {ifc_class} elements are not a "
"{parameter} representation: {falseelems}"
msgstr ""
#: features/steps/geometric_detail_methods.py:132
msgid "The geometry of all {elemcount} {ifc_class} elements have errors."
msgstr ""
#: features/steps/geometric_detail_methods.py:133
msgid ""
"The geometry of {falsecount} out of all {elemcount} {ifc_class} elements "
"have errors: {falseelems}"
msgstr ""
#: features/steps/ifcdata_methods.py:9
msgid "The IFC {} file could not be loaded"
msgstr ""
#: features/steps/ifcdata_methods.py:17
msgid "We expected a schema of {} but instead got {}"
msgstr ""
@@ -1,196 +0,0 @@
# Italian translations for PROJECT.
# Copyright (C) 2020 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
#
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2021-01-17 10:55+0100\n"
"PO-Revision-Date: 2020-12-18 11:41+0100\n"
"Last-Translator: \n"
"Language: it\n"
"Language-Team: it <LL@li.org>\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.6.0\n"
#: reports.py:158
msgid "en"
msgstr "it"
#: reports.py:159
msgid "Success"
msgstr "Successo"
#: reports.py:160
msgid "Failure"
msgstr "Errore"
#: reports.py:161
msgid "Tests passed"
msgstr "Test superati"
#: reports.py:162
msgid "Duration"
msgstr "Durata"
#: reports.py:163
msgid "OpenBIM auditing is a feature of"
msgstr "L'auditing OpenBIM è una caratteristica di"
#: reports.py:164
msgid "and"
msgstr "e"
#: features/steps/attributes_eleclasses_methods.py:26
msgid "All {elemcount} elements in the file are {ifc_class}."
msgstr "Tutti {elemcount} elementi nel file sono classificati {ifc_class}"
#: features/steps/attributes_eleclasses_methods.py:34
msgid "{falsecount} of {elemcount} element are {ifc_class} elements: {falseelems}"
msgstr ""
"{falsecount} di {elemcount} elementi sono elementi {ifc_class}: "
"{falseelems}"
#: features/steps/attributes_eleclasses_methods.py:43
#: features/steps/utils.py:158
msgid "Error in falsecount, something went wrong."
msgstr "Errore in falsecount, qualcosa è andato storto."
#: features/steps/attributes_eleclasses_methods.py:84
msgid ""
"For all {elemcount} {ifc_class} elements at least one of these class "
"attributes {parameter} has no value."
msgstr ""
"Per tutti {elemcount} elementi {ifc_class} almeno uno di questa "
"classedegli attributi {parameter} non contiene alcun valore"
#: features/steps/attributes_eleclasses_methods.py:85
msgid ""
"For the following {falsecount} out of {elemcount} {ifc_class} elements at"
" least one of these class attributes {parameter} has no value: "
"{falseelems}"
msgstr ""
"Per i seguenti {falsecount} di {elemcount} elementi {ifc_class}almeno uno"
" degli attributi {parameter} non contiene alcun valore"
#: features/steps/attributes_eleclasses_methods.py:86
#: features/steps/attributes_eleclasses_methods.py:112
#: features/steps/attributes_eleclasses_methods.py:139
#: features/steps/attributes_psets_methods.py:33
#: features/steps/geometric_detail_methods.py:56
#: features/steps/geometric_detail_methods.py:134
msgid "There are no {ifc_class} elements in the IFC file."
msgstr "Il file IFC non contiene elementi della classe {ifc_class}."
#: features/steps/attributes_eleclasses_methods.py:110
msgid "The name of all {elemcount} {elemcount} elements is not set."
msgstr "Il nome di {elemcount} {elemcount} elementi non è impostato"
#: features/steps/attributes_eleclasses_methods.py:111
msgid ""
"The name of {falsecount} out of {elemcount} {ifc_class} elements is not "
"set: {falseelems}"
msgstr "Il nome di {falsecount} su {elemcount} elementi {ifc_class} non èimpostato"
#: features/steps/attributes_eleclasses_methods.py:137
msgid "The description of all {elemcount} {elemcount} elements is not set."
msgstr "La descrizione di tutti {elemcount} {elemcount} elementi non èimpostato "
#: features/steps/attributes_eleclasses_methods.py:138
msgid ""
"The description of {falsecount} out of {elemcount} {ifc_class} elements "
"is not set: {falseelems}"
msgstr ""
"la descrizione di {falsecount} su {elemcount} elementi {ifc_class} non "
"èimpostato"
#: features/steps/attributes_psets_methods.py:31
msgid ""
"All {elemcount} {ifc_class} elements are missing the property {parameter}"
" in the pset."
msgstr ""
"A {elemcount} gli elementi {ifc_class} manca la proprietà "
"{parameter}nello pset."
#: features/steps/attributes_psets_methods.py:32
msgid ""
"The following {falsecount} of {elemcount} {ifc_class} elements are "
"missing the property {parameter} in the pset: {falseelems}"
msgstr ""
"Ai seguenti {falsecount} di {elemcount} elementi {ifc_class} manca la "
"proprietà{parameter} nello pset: {falseelems}"
#: features/steps/geometric_detail_methods.py:54
msgid "All {elemcount} {ifc_class} elements are not a {parameter} representation."
msgstr "Tutti {elemcount} elementi {ifc_class} non rappresentano {parameter}"
#: features/steps/geometric_detail_methods.py:55
msgid ""
"The following {falsecount} of {elemcount} {ifc_class} elements are not a "
"{parameter} representation: {falseelems}"
msgstr ""
"I seguenti {falsecount} di {elemcount} elementi {ifc_class} non "
"rappresentano{parameter}: {falseelems}"
#: features/steps/geometric_detail_methods.py:132
msgid "The geometry of all {elemcount} {ifc_class} elements have errors."
msgstr "La geometria di tutti {elemcount} elementi {ifc_class} contiene errori"
#: features/steps/geometric_detail_methods.py:133
msgid ""
"The geometry of {falsecount} out of all {elemcount} {ifc_class} elements "
"have errors: {falseelems}"
msgstr ""
"La geometria di {falsecount} su {elemcount} elementi {ifc_class} "
"contieneerrori: {falseelems}"
#: features/steps/ifcdata_methods.py:9
msgid "The IFC {} file could not be loaded"
msgstr ""
#: features/steps/ifcdata_methods.py:17
msgid "We expected a schema of {} but instead got {}"
msgstr "Ci aspettavamo uno schema di {} ma invece abbiamo ottenuto {}"
#~ msgid "The geometry of all {} {} elements have errors."
#~ msgstr "La geometria di tutti gli elementi {} {} contiene errori."
#~ msgid "The geometry of {} out of all {} {} elements have errors: {}"
#~ msgstr "La geometria di {} su {} {} elementi contiene errori."
#~ msgid "There are no {} elements in the IFC file."
#~ msgstr "Non ci sono {} elementi nel file IFC."
#~ msgid "All {} {} elements are not a IfcFacetedBrep representation."
#~ msgstr "Tutti gli elementi {} {} non sono una rappresentazioneIfcFacetedBrep."
#~ msgid ""
#~ "The following {} of {} {} elements"
#~ " are not a IfcFacetedBrep representation:"
#~ " {}"
#~ msgstr ""
#~ "I seguenti {} di {} {} elementi"
#~ " non sono una rappresentazioneIfcFacetedBrep. "
#~ "{}"
#~ msgid ""
#~ "All {elemcount} {ifc_class} elements are "
#~ "not a IfcFacetedBrep representation."
#~ msgstr ""
#~ "Tutti {elemcount} elementi {ifc_class} non"
#~ " sono una rappresentazioneIfcFacetedBrep."
#~ msgid ""
#~ "The following {falsecount} of {elemcount} "
#~ "{ifc_class} elements are not a "
#~ "IfcFacetedBrep representation: {falseelems}"
#~ msgstr ""
#~ "I seguenti {falsecount} su {elemcount} "
#~ "elementi {ifc_class} non sonouna "
#~ "rappresentazione IfcFacetedBrep."
@@ -1,142 +0,0 @@
# Translations template for PROJECT.
# Copyright (C) 2021 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2021.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2021-01-17 10:55+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.6.0\n"
#: reports.py:158
msgid "en"
msgstr ""
#: reports.py:159
msgid "Success"
msgstr ""
#: reports.py:160
msgid "Failure"
msgstr ""
#: reports.py:161
msgid "Tests passed"
msgstr ""
#: reports.py:162
msgid "Duration"
msgstr ""
#: reports.py:163
msgid "OpenBIM auditing is a feature of"
msgstr ""
#: reports.py:164
msgid "and"
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:26
msgid "All {elemcount} elements in the file are {ifc_class}."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:34
msgid "{falsecount} of {elemcount} element are {ifc_class} elements: {falseelems}"
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:43
#: features/steps/utils.py:158
msgid "Error in falsecount, something went wrong."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:84
msgid ""
"For all {elemcount} {ifc_class} elements at least one of these class "
"attributes {parameter} has no value."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:85
msgid ""
"For the following {falsecount} out of {elemcount} {ifc_class} elements at"
" least one of these class attributes {parameter} has no value: "
"{falseelems}"
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:86
#: features/steps/attributes_eleclasses_methods.py:112
#: features/steps/attributes_eleclasses_methods.py:139
#: features/steps/attributes_psets_methods.py:33
#: features/steps/geometric_detail_methods.py:56
#: features/steps/geometric_detail_methods.py:134
msgid "There are no {ifc_class} elements in the IFC file."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:110
msgid "The name of all {elemcount} {elemcount} elements is not set."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:111
msgid ""
"The name of {falsecount} out of {elemcount} {ifc_class} elements is not "
"set: {falseelems}"
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:137
msgid "The description of all {elemcount} {elemcount} elements is not set."
msgstr ""
#: features/steps/attributes_eleclasses_methods.py:138
msgid ""
"The description of {falsecount} out of {elemcount} {ifc_class} elements "
"is not set: {falseelems}"
msgstr ""
#: features/steps/attributes_psets_methods.py:31
msgid ""
"All {elemcount} {ifc_class} elements are missing the property {parameter}"
" in the pset."
msgstr ""
#: features/steps/attributes_psets_methods.py:32
msgid ""
"The following {falsecount} of {elemcount} {ifc_class} elements are "
"missing the property {parameter} in the pset: {falseelems}"
msgstr ""
#: features/steps/geometric_detail_methods.py:54
msgid "All {elemcount} {ifc_class} elements are not a {parameter} representation."
msgstr ""
#: features/steps/geometric_detail_methods.py:55
msgid ""
"The following {falsecount} of {elemcount} {ifc_class} elements are not a "
"{parameter} representation: {falseelems}"
msgstr ""
#: features/steps/geometric_detail_methods.py:132
msgid "The geometry of all {elemcount} {ifc_class} elements have errors."
msgstr ""
#: features/steps/geometric_detail_methods.py:133
msgid ""
"The geometry of {falsecount} out of all {elemcount} {ifc_class} elements "
"have errors: {falseelems}"
msgstr ""
#: features/steps/ifcdata_methods.py:9
msgid "The IFC {} file could not be loaded"
msgstr ""
#: features/steps/ifcdata_methods.py:17
msgid "We expected a schema of {} but instead got {}"
msgstr ""
@@ -1,196 +0,0 @@
# Dutch translations for Bimtester.
# Copyright (C) 2021 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# Marcel Plomp , 2021.
#
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSIE\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRES\n"
"POT-Creation-Date: 2021-01-17 10:55+0100\n"
"PO-Revision-Date: 2020-12-18 11:41+0100\n"
"Last-Translator: \n"
"Language: nl\n"
"Language-Team: nl <LL@li.org>\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.6.0\n"
#: reports.py:158
msgid "en"
msgstr "nl"
#: reports.py:159
msgid "Success"
msgstr "Succes"
#: reports.py:160
msgid "Failure"
msgstr "Fout"
#: reports.py:161
msgid "Tests passed"
msgstr "Tests geslaagd"
#: reports.py:162
msgid "Duration"
msgstr "Tijdsduur"
#: reports.py:163
msgid "OpenBIM auditing is a feature of"
msgstr "OpenBIM-auditing is een kenmerk van"
#: reports.py:164
msgid "and"
msgstr "en"
#: features/steps/attributes_eleclasses_methods.py:26
msgid "All {elemcount} elements in the file are {ifc_class}."
msgstr "Alle {elemcount} de elementen in het bestand zijn {ifc_class}"
#: features/steps/attributes_eleclasses_methods.py:34
msgid "{falsecount} of {elemcount} element are {ifc_class} elements: {falseelems}"
msgstr ""
"{falsecount} van de {elemcount} elementen zijn {ifc_class} elementen: "
"{falseelems}"
#: features/steps/attributes_eleclasses_methods.py:43
#: features/steps/utils.py:158
msgid "Error in falsecount, something went wrong."
msgstr "Fout in de telling, er is iets misgegaan."
#: features/steps/attributes_eleclasses_methods.py:84
msgid ""
"For all {elemcount} {ifc_class} elements at least one of these class "
"attributes {parameter} has no value."
msgstr ""
"Voor alle {elemcount} {ifc_class} elementen heeft ten minste één van deze"
" class attributen {parameter} heeft geen waarde."
#: features/steps/attributes_eleclasses_methods.py:85
msgid ""
"For the following {falsecount} out of {elemcount} {ifc_class} elements at"
" least one of these class attributes {parameter} has no value: "
"{falseelems}"
msgstr ""
"Van de {falsecount} uit {elemcount} {ifc_class} elementen op ten minste "
"een van deze class-attributen {parameter} heeft geen waarde:{falseelems}"
#: features/steps/attributes_eleclasses_methods.py:86
#: features/steps/attributes_eleclasses_methods.py:112
#: features/steps/attributes_eleclasses_methods.py:139
#: features/steps/attributes_psets_methods.py:33
#: features/steps/geometric_detail_methods.py:56
#: features/steps/geometric_detail_methods.py:134
msgid "There are no {ifc_class} elements in the IFC file."
msgstr "Er zijn geen {ifc_class} elementen in het IFC-bestand."
#: features/steps/attributes_eleclasses_methods.py:110
msgid "The name of all {elemcount} {elemcount} elements is not set."
msgstr "De naam van alle {elemcount} {elemcount} elementen is niet ingesteld."
#: features/steps/attributes_eleclasses_methods.py:111
msgid ""
"The name of {falsecount} out of {elemcount} {ifc_class} elements is not "
"set: {falseelems}"
msgstr ""
"De naam van {falsecount} van de {elemcount} {ifc_class} elementen is "
"nietset: {falseelems}"
#: features/steps/attributes_eleclasses_methods.py:137
msgid "The description of all {elemcount} {elemcount} elements is not set."
msgstr ""
"De beschrijving van alle {elemcount} {elemcount} elementen is niet "
"ingesteld."
#: features/steps/attributes_eleclasses_methods.py:138
msgid ""
"The description of {falsecount} out of {elemcount} {ifc_class} elements "
"is not set: {falseelems}"
msgstr ""
"De beschrijving van {falsecount} uit {elemcount} {ifc_class} elementen is"
" niet ingesteld: {falseelems}"
#: features/steps/attributes_psets_methods.py:31
msgid ""
"All {elemcount} {ifc_class} elements are missing the property {parameter}"
" in the pset."
msgstr ""
"Alle {elemcount} {ifc_class} elementen missen de eigenschap {parameter} "
"in de pset."
#: features/steps/attributes_psets_methods.py:32
msgid ""
"The following {falsecount} of {elemcount} {ifc_class} elements are "
"missing the property {parameter} in the pset: {falseelems}"
msgstr ""
"De volgende {falsecount} van {elemcount} {ifc_class} elementen zijn "
"ontbreekt de eigenschap {parameter} in de pset: {falseelems}"
#: features/steps/geometric_detail_methods.py:54
msgid "All {elemcount} {ifc_class} elements are not a {parameter} representation."
msgstr ""
"Alle {elemcount} {ifc_class} elementen zijn geen {parameter} "
"representatie."
#: features/steps/geometric_detail_methods.py:55
msgid ""
"The following {falsecount} of {elemcount} {ifc_class} elements are not a "
"{parameter} representation: {falseelems}"
msgstr ""
"De volgende {falsecount} van {elemcount} {ifc_class} -elementen zijn geen"
" {parameter} representatie: {falseelems}"
#: features/steps/geometric_detail_methods.py:132
msgid "The geometry of all {elemcount} {ifc_class} elements have errors."
msgstr ""
"De geometrie van alle {elemcount} de {ifc_class} elementen bevatten "
"fouten."
#: features/steps/geometric_detail_methods.py:133
msgid ""
"The geometry of {falsecount} out of all {elemcount} {ifc_class} elements "
"have errors: {falseelems}"
msgstr ""
"De geometrie van {falsecount} van alle {elemcount} {ifc_class} elementen "
"hebben fouten: {falseelems}"
#: features/steps/ifcdata_methods.py:9
msgid "The IFC {} file could not be loaded"
msgstr ""
#: features/steps/ifcdata_methods.py:17
msgid "We expected a schema of {} but instead got {}"
msgstr "We verwachtten een schema van {} maar kregen in plaats daarvan {}"
#~ msgid "The geometry of all {} {} elements have errors."
#~ msgstr ""
#~ msgid "The geometry of {} out of all {} {} elements have errors: {}"
#~ msgstr ""
#~ msgid "There are no {} elements in the IFC file."
#~ msgstr ""
#~ msgid "All {} {} elements are not a IfcFacetedBrep representation."
#~ msgstr ""
#~ msgid ""
#~ "The following {} of {} {} elements"
#~ " are not a IfcFacetedBrep representation:"
#~ " {}"
#~ msgstr ""
#~ msgid ""
#~ "All {elemcount} {ifc_class} elements are "
#~ "not a IfcFacetedBrep representation."
#~ msgstr ""
#~ msgid ""
#~ "The following {falsecount} of {elemcount} "
#~ "{ifc_class} elements are not a "
#~ "IfcFacetedBrep representation: {falseelems}"
#~ msgstr ""
-130
View File
@@ -1,130 +0,0 @@
import datetime
import json
import os
import pystache
from bimtester.lang import _
class ReportGenerator:
def __init__(self):
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
self.base_path = sys._MEIPASS
except Exception:
self.base_path = os.path.dirname(os.path.realpath(__file__))
def generate(self, report_json, output_file):
print("# Generating HTML reports.")
report = json.loads(open(report_json).read())
for feature in report:
self.generate_feature_report(feature, output_file)
def generate_feature_report(self, feature, output_file):
file_name = os.path.basename(feature["location"]).split(":")[0]
data = {
"file_name": file_name,
"time": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"name": feature["name"],
"description": feature["description"],
"is_success": feature["status"] == "passed",
"scenarios": [],
}
if "elements" not in feature:
if "status" in feature and feature["status"] == "skipped":
print("Feature was skipped. No html report will be created.")
else:
print("For a unknown reason no html report well be created.")
# happens if the feature file does not consist of any valid Scenario
return
for scenario in feature["elements"]:
scenario_data = self.process_scenario(scenario)
if scenario_data:
data["scenarios"].append(scenario_data)
data["total_passes"] = sum([s["total_passes"] for s in data["scenarios"]])
data["total_steps"] = sum([s["total_steps"] for s in data["scenarios"]])
data["pass_rate"] = round((data["total_passes"] / data["total_steps"]) * 100)
data.update(self.get_template_strings())
with open(output_file, "w", encoding="utf8") as out:
with open(
os.path.join(self.base_path, "resources", "reports", "template.html"), encoding="utf8"
) as template:
out.write(pystache.render(template.read(), data))
def process_scenario(self, scenario):
if len(scenario["steps"]) == 0:
print("Scenario '{}' in feature '{}' has no steps.".format(scenario["name"], feature["name"]))
return
steps = []
total_duration = 0
for step in scenario["steps"]:
step_data = self.process_step(step)
total_duration += step_data["time_raw"]
steps.append(step_data)
total_passes = len([s for s in steps if s["is_success"] is True])
total_steps = len(steps)
pass_rate = round((total_passes / total_steps) * 100)
return {
"name": scenario["name"],
# on behave < 1.2.6 there is no 'status' thus report fails
"is_success": scenario["status"] == "passed",
"time": round(total_duration, 2),
"steps": steps,
"total_passes": total_passes,
"total_steps": total_steps,
"pass_rate": pass_rate,
}
def process_step(self, step):
name = step["name"]
if "match" in step and "arguments" in step["match"]:
for a in step["match"]["arguments"]:
name = name.replace(a["value"], "<b>" + a["value"] + "</b>")
if "result" not in step:
step["result"] = {}
step["result"]["status"] = "skipped"
step["result"]["duration"] = 0
step["result"][
"error_message"
] = "This requirement has been skipped due to a previous failing step."
elif step["result"]["status"] == "undefined":
step["result"] = {}
step["result"]["status"] = "undefined"
step["result"]["duration"] = 0
step["result"]["error_message"] = "This requirement has not yet been specified."
data = {
"name": name,
"time_raw": step["result"]["duration"],
"time": round(step["result"]["duration"], 2),
"is_success": step["result"]["status"] == "passed",
"is_unspecified": step["result"]["status"] == "undefined",
"is_skipped": step["result"]["status"] == "skipped",
"error_message": None
if step["result"]["status"] == "passed"
else step["result"]["error_message"],
}
# TODO: there is probably a better way of doing this
if isinstance(data["error_message"], list):
data["error_message"] = data["error_message"][1]
return data
def get_template_strings(self):
return {
"_lang": _("en"),
"_success": _("Success"),
"_failure": _("Failure"),
"_tests_passed": _("Tests passed"),
"_duration": _("Duration"),
"_auditing": _("OpenBIM auditing is a feature of"),
"_and": _("and"),
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

@@ -1,79 +0,0 @@
<!DOCTYPE html>
<html lang={{_lang}}>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="foobaro">
<title>{{name}}</title>
<link href="https://fonts.googleapis.com/css?family=Comfortaa|Inconsolata|Open+Sans&display=swap" rel="stylesheet">
<style>
body { font-family: 'Arial', sans-serif; padding: 10px 40px; }
span.time { color: #999; font-style: italic; float: right; }
span.step-time { float: right; color: #555; font-size: 0.8em; font-style: italic; }
span.success { background-color: #97cc64; padding: 5px; border-radius: 5px; color: #FFF; font-weight: bold; }
span.failure { background-color: #fb5a3e; padding: 5px; border-radius: 5px; color: #FFF; font-weight: bold; }
p.failure { background-color: #fb5a3e; padding: 5px; border-radius: 5px; color: #fff; }
p.unspecified { background-color: #994f00; padding: 5px; border-radius: 5px; color: #fff; }
p.skipped { background-color: #8b8d8f; padding: 5px; border-radius: 5px; color: #fff; }
p.description { background-color: #eee; border-radius: 5px; padding: 20px; margin-left: auto; margin-right: auto; display: inline-block; font-weight: bold;}
li { padding: 10px; font-family: monospace; }
li.success { background-color: #b6cca1; color: #333; }
li.failure { background-color: #fbb4a8; color: #900; }
li.unspecified { background-color: #ffd37f; color: #a30; }
li.skipped { background-color: #f5f5f5; color: #333; }
li p { margin-bottom: 0px; }
footer { color: #999; font-size: 0.8em; }
header { text-align: center; }
hr { margin: 20px; margin-left: 0px; margin-right: 0px; border: none; border-top: 1px solid #ccc; }
</style>
</head>
<body>
<header>
<h1>{{name}}</h1>
<p><strong>{{time}} {{file_name}}</strong></p>
<hr>
<span class="{{#is_success}}success{{/is_success}}{{^is_success}}failure{{/is_success}}">{{#is_success}}{{_success}}{{/is_success}}{{^is_success}}{{_failure}}{{/is_success}}</span>
{{_tests_passed}}: <strong>{{total_passes}} / {{total_steps}}</strong> ({{pass_rate}}%)
<br />
<p class="description">
{{#description}}
{{.}}<br />
{{/description}}
</p>
<hr>
</header>
{{#scenarios}}
<section>
<h2>{{name}}</h2>
<p>
<span class="{{#is_success}}success{{/is_success}}{{^is_success}}failure{{/is_success}}">{{#is_success}}{{_success}}{{/is_success}}{{^is_success}}{{_failure}}{{/is_success}}</span>
{{_tests_passed}}: <strong>{{total_passes}} / {{total_steps}}</strong> ({{pass_rate}}%)
<span class="time">
{{_duration}}: {{time}}s
</span>
</p>
<ol>
{{#steps}}
<li class="{{#is_success}}success{{/is_success}}{{^is_success}}failure{{/is_success}}{{#is_unspecified}} unspecified{{/is_unspecified}}{{#is_skipped}} skipped{{/is_skipped}}">
{{{name}}}
<span class="step-time">{{time}}s</span>
{{^is_success}}
<p class="failure{{#is_unspecified}} unspecified{{/is_unspecified}}{{#is_skipped}} skipped{{/is_skipped}}">
{{#error_message}}
{{.}}<br />
{{/error_message}}
</p>
{{/is_success}}
</li>
{{/steps}}
</ol>
</section>
{{/scenarios}}
<hr>
<footer>
<p>
{{_auditing}} <a href="https://blenderbim.org/">BlenderBIM</a> {{_and}} <a href="http://ifcopenshell.org/">IfcOpenShell</a>.
</p>
</footer>
</body>
</html>
-62
View File
@@ -1,62 +0,0 @@
import os
import sys
import shutil
import tempfile
import ifcopenshell
try:
import ifcopenshell.express
except:
pass # They are using an old version of IfcOpenShell. Gracefully degrade for now.
import behave.formatter.pretty # Needed for pyinstaller to package it
from bimtester.ifc import IfcStore
from distutils.dir_util import copy_tree
from behave.__main__ import main as behave_main
class TestRunner:
def __init__(self, ifc_path, ifc=None):
IfcStore.path = ifc_path
IfcStore.file = ifc if ifc else ifcopenshell.open(ifc_path)
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
self.base_path = sys._MEIPASS
except Exception:
self.base_path = os.path.dirname(os.path.realpath(__file__))
self.locale_path = os.path.join(self.base_path, "locale")
def run(self, args):
if args["schema_file"]:
schema = ifcopenshell.express.parse(args["schema_file"])
ifcopenshell.register_schema(args["schema_name"])
tmpdir = tempfile.mkdtemp()
features_path = os.path.join(tmpdir, "features")
steps_path = os.path.join(features_path, "steps")
report_json = os.path.join(tmpdir, "report.json")
shutil.copytree(os.path.join(self.base_path, "features"), features_path)
shutil.copy(args["feature"], features_path)
if args["steps"]:
if os.path.isfile(args["steps"]):
shutil.copy(args["steps"], steps_path)
elif os.path.isdir(args["steps"]):
copy_tree(args["steps"], steps_path)
behave_main(self.get_behave_args(args, features_path, report_json))
return report_json
def get_behave_args(self, args, features_path, report_json):
behave_args = [features_path]
behave_args.extend(["--define", "localedir={}".format(self.locale_path)])
if args["advanced_arguments"]:
behave_args.extend(args["advanced_arguments"].split())
if args["ifc"]:
behave_args.extend(["--define", "ifc={}".format(args["ifc"])])
if args["path"]:
behave_args.extend(["--define", "path={}".format(args["path"])])
if args["lang"]:
behave_args.extend(["--lang={}".format(args["lang"])])
if not args["console"]:
# https://github.com/behave/behave/issues/346
behave_args.extend(["--no-capture", "--format", "json.pretty", "--outfile", report_json])
return behave_args
-105
View File
@@ -1,105 +0,0 @@
import ifcopenshell
import ifcopenshell.util.element
from bimtester.lang import _
def assert_guid(ifc, guid):
try:
return ifc.by_guid(guid)
except:
assert False, _("An element with the ID {} could not be found.").format(guid)
def assert_number(number):
try:
return float(number)
except ValueError:
assert False, _("A number should be specified, not {}").format(number)
def assert_type(element, ifc_class, is_exact=False):
if is_exact:
assert element.is_a() == ifc_class, _("The element {} is an {} instead of {}.").format(
element, element.is_a(), ifc_class
)
else:
assert element.is_a(ifc_class), _("The element {} is an {} instead of {}.").format(
element, element.is_a(), ifc_class
)
def assert_attribute(element, name, value=None):
if not hasattr(element, name):
assert False, _("The element {} does not have the attribute {}").format(element, name)
if not value:
if getattr(element, name) is None:
assert False, _("The element {} does not have a value for the attribute {}").format(element, name)
return getattr(element, name)
if value == "NULL":
value = None
actual_value = getattr(element, name)
if isinstance(value, list) and actual_value:
actual_value = list(actual_value)
assert actual_value == value, _('We expected a value of "{}" but instead got "{}" for the element {}').format(
value, actual_value, element
)
def assert_pset(element, pset_name, prop_name=None, value=None):
if value == "NULL":
value = None
psets = ifcopenshell.util.element.get_psets(site)
if pset_name not in psets:
assert False, _("The element {} does not have a property set named {}").format(element, pset_name)
if prop_name is None:
return psets[pset_name]
if prop_name not in psets[pset_name]:
assert False, _('The element {} does not have a property named "{}" in the pset "{}"').format(
element, prop_name, pset_name
)
if value is None:
return psets[pset_name][prop_name]
actual_value = psets[pset_name][prop_name]
assert actual_value == value, _('We expected a value of "{}" but instead got "{}" for the element {}').format(
value, actual_value, element
)
# TODO: what is this?
def assert_elements(
ifc_class,
elemcount,
falsecount,
falseelems,
message_all_falseelems,
message_some_falseelems,
message_no_elems,
parameter=None,
):
if elemcount > 0 and falsecount == 0:
return # Test OK
elif elemcount == 0:
assert False, message_no_elems.format(ifc_class=ifc_class)
elif falsecount == elemcount:
if parameter is None:
assert False, message_all_falseelems.format(elemcount=elemcount, ifc_class=ifc_class)
else:
assert False, message_all_falseelems.format(elemcount=elemcount, ifc_class=ifc_class, parameter=parameter)
elif falsecount > 0 and falsecount < elemcount:
if parameter is None:
assert False, message_some_falseelems.format(
falsecount=falsecount,
elemcount=elemcount,
ifc_class=ifc_class,
falseelems=falseelems,
)
else:
assert False, message_some_falseelems.format(
falsecount=falsecount,
elemcount=elemcount,
ifc_class=ifc_class,
falseelems=falseelems,
parameter=parameter,
)
else:
assert False, _("Error in falsecount, something went wrong.")
-29
View File
@@ -1,29 +0,0 @@
#!/usr/bin/env python3
import os
import argparse
import bimtester.clean
import bimtester.reports
import bimtester.run
parser = argparse.ArgumentParser(description="Runs unit tests for BIM data")
parser.add_argument("-a", "--action", type=str, help="Action to perform, from run/purge", default="run")
parser.add_argument("--advanced-arguments", type=str, help="Specify arguments to Behave", default="")
parser.add_argument("-c", "--console", action="store_true", help="Show results in the console")
parser.add_argument("-f", "--feature", type=str, help="Specify a feature file to test", required=True)
parser.add_argument("-i", "--ifc", type=str, help="Specify an IFC file to test", required=True)
parser.add_argument("-p", "--path", type=str, help="Define a path for use in test steps that use relative paths")
parser.add_argument("-r", "--report", type=str, help="Specify an output file for a HTML report")
parser.add_argument("--steps", type=str, help="Specify a custom step definition Python file or directory")
parser.add_argument("--schema-file", type=str, help="Path to a custom IFC schema, used with --schema-name")
parser.add_argument("--schema-name", type=str, help="The name of a custom IFC schema, used with --schema-file")
parser.add_argument("--lang", type=str, help="Specify a language e.g. en/de/fr/it", default="")
args = vars(parser.parse_args())
if args["action"] == "run":
report_json = bimtester.run.TestRunner(args["ifc"]).run(args)
if args["report"]:
bimtester.reports.ReportGenerator().generate(report_json, args["report"])
elif args["action"] == "purge":
bimtester.clean.TestPurger().purge()
@@ -1,54 +0,0 @@
ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('ViewDefinition [CoordinationView]'),'2;1');
FILE_NAME('col.ifc','2021-01-11T05:16:43',('',''),(''),'IfcOpenShell 0.6.0b0','IfcOpenShell 0.6.0b0','');
FILE_SCHEMA(('IFC2X3'));
ENDSEC;
DATA;
#1=IFCPERSON($,$,'',$,$,$,$,$);
#2=IFCORGANIZATION($,'',$,$,$);
#3=IFCPERSONANDORGANIZATION(#1,#2,$);
#4=IFCAPPLICATION(#2,'0.19 build 23652 (Git)','FreeCAD','118df2cf_ed21_438e_a41');
#5=IFCOWNERHISTORY(#3,#4,$,.ADDED.,1610342203,#3,#4,1610342203);
#6=IFCDIRECTION((1.,0.,0.));
#7=IFCDIRECTION((0.,0.,1.));
#8=IFCCARTESIANPOINT((0.,0.,0.));
#9=IFCAXIS2PLACEMENT3D(#8,#7,#6);
#10=IFCDIRECTION((0.,1.,0.));
#12=IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0);
#13=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.);
#14=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.);
#15=IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.);
#16=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.);
#17=IFCMEASUREWITHUNIT(IFCPLANEANGLEMEASURE(0.017453292519943295),#16);
#18=IFCCONVERSIONBASEDUNIT(#12,.PLANEANGLEUNIT.,'DEGREE',#17);
#19=IFCUNITASSIGNMENT((#13,#14,#15,#18));
#20=IFCDIRECTION((0.,1.));
#21=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#9,#20);
#22=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Model',*,*,*,*,#21,$,.MODEL_VIEW.,$);
#23=IFCPROJECT('2iAYrakL9FABNNwZfj$CbO',#5,'BIMTester Example 1 - IFC2X3',$,$,$,$,(#21),#19);
#24=IFCDIRECTION((1.,0.));
#25=IFCCARTESIANPOINT((0.,0.));
#26=IFCAXIS2PLACEMENT2D(#25,#24);
#27=IFCCIRCLEPROFILEDEF(.AREA.,$,#26,0.2);
#28=IFCCARTESIANPOINT((0.,0.,0.));
#29=IFCAXIS2PLACEMENT3D(#28,#7,#6);
#30=IFCEXTRUDEDAREASOLID(#27,#29,#7,5.);
#31=IFCCOLOURRGB($,1.,0.5,1.);
#32=IFCSURFACESTYLERENDERING(#31,$,$,$,$,$,$,$,.FLAT.);
#33=IFCSURFACESTYLE($,.BOTH.,(#32));
#34=IFCPRESENTATIONSTYLEASSIGNMENT((#33));
#35=IFCSTYLEDITEM(#30,(#34),$);
#36=IFCLOCALPLACEMENT($,#9);
#37=IFCSHAPEREPRESENTATION(#22,'Body','SweptSolid',(#30));
#38=IFCPRODUCTDEFINITIONSHAPE($,$,(#37));
#39=IFCBUILDINGELEMENTPROXY('3JNmm1CUH9H9P6lVsx1y3W',#5,'Structure','',$,#36,#38,$,.ELEMENT.);
#40=IFCSITE('2PJ1ax1HL4SgHFFReEEwE$',#5,'Default Site','',$,$,$,$,.ELEMENT.,$,$,$,$,$);
#41=IFCRELAGGREGATES('1J6GQExT511x6QRu5FmkD2',#5,'ProjectLink','',#23,(#40));
#42=IFCBUILDING('1tIoXRzCXF3vuIMrF6RVcd',#5,'Default Building','',$,$,$,$,.ELEMENT.,$,$,$);
#43=IFCRELAGGREGATES('2GkPanCgnAzQY_0xv8dnHH',#5,'SiteLink','',#40,(#42));
#44=IFCBUILDINGSTOREY('1L8$GCIw116uw35vpyjSsO',#5,'Default Storey','',$,$,$,$,.ELEMENT.,$);
#45=IFCRELAGGREGATES('1lB$$h00nFaPQb2gvlhRX$',#5,'DefaultStoreyLink','',#42,(#44));
#46=IFCRELCONTAINEDINSPATIALSTRUCTURE('3dnpjDLD5DvuyUGcyHqRvU',#5,'UnassignedObjectsLink','',(#39),#44);
ENDSEC;
END-ISO-10303-21;
@@ -1,54 +0,0 @@
ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('ViewDefinition [CoordinationView]'),'2;1');
FILE_NAME('col.ifc','2021-01-11T05:12:19',('',''),(''),'IfcOpenShell 0.6.0b0','IfcOpenShell 0.6.0b0','');
FILE_SCHEMA(('IFC4'));
ENDSEC;
DATA;
#1=IFCPERSON($,$,'',$,$,$,$,$);
#2=IFCORGANIZATION($,'',$,$,$);
#3=IFCPERSONANDORGANIZATION(#1,#2,$);
#4=IFCAPPLICATION(#2,'0.19 build 23652 (Git)','FreeCAD','118df2cf_ed21_438e_a41');
#5=IFCOWNERHISTORY(#3,#4,$,.ADDED.,1610341939,#3,#4,1610341939);
#6=IFCDIRECTION((1.,0.,0.));
#7=IFCDIRECTION((0.,0.,1.));
#8=IFCCARTESIANPOINT((0.,0.,0.));
#9=IFCAXIS2PLACEMENT3D(#8,#7,#6);
#10=IFCDIRECTION((0.,1.,0.));
#12=IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0);
#13=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.);
#14=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.);
#15=IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.);
#16=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.);
#17=IFCMEASUREWITHUNIT(IFCPLANEANGLEMEASURE(0.017453292519943295),#16);
#18=IFCCONVERSIONBASEDUNIT(#12,.PLANEANGLEUNIT.,'DEGREE',#17);
#19=IFCUNITASSIGNMENT((#13,#14,#15,#18));
#20=IFCDIRECTION((0.,1.));
#21=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#9,#20);
#22=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Model',*,*,*,*,#21,$,.MODEL_VIEW.,$);
#23=IFCPROJECT('2iAYrakL9FABNNwZfj$CbO',#5,'BIMTester Example 1 - IFC4',$,$,$,$,(#21),#19);
#24=IFCDIRECTION((1.,0.));
#25=IFCCARTESIANPOINT((0.,0.));
#26=IFCAXIS2PLACEMENT2D(#25,#24);
#27=IFCCIRCLEPROFILEDEF(.AREA.,$,#26,0.2);
#28=IFCCARTESIANPOINT((0.,0.,0.));
#29=IFCAXIS2PLACEMENT3D(#28,#7,#6);
#30=IFCEXTRUDEDAREASOLID(#27,#29,#7,5.);
#31=IFCCOLOURRGB($,1.,0.5,1.);
#32=IFCSURFACESTYLERENDERING(#31,$,$,$,$,$,$,$,.FLAT.);
#33=IFCSURFACESTYLE($,.BOTH.,(#32));
#34=IFCPRESENTATIONSTYLEASSIGNMENT((#33));
#35=IFCSTYLEDITEM(#30,(#34),$);
#36=IFCLOCALPLACEMENT($,#9);
#37=IFCSHAPEREPRESENTATION(#22,'Body','SweptSolid',(#30));
#38=IFCPRODUCTDEFINITIONSHAPE($,$,(#37));
#39=IFCBUILDINGELEMENTPROXY('3JNmm1CUH9H9P6lVsx1y3W',#5,'Structure','',$,#36,#38,$,.COMPLEX.);
#40=IFCSITE('2PJ1ax1HL4SgHFFReEEwE$',#5,'Default Site','',$,$,$,$,.ELEMENT.,$,$,$,$,$);
#41=IFCRELAGGREGATES('1J6GQExT511x6QRu5FmkD2',#5,'ProjectLink','',#23,(#40));
#42=IFCBUILDING('1tIoXRzCXF3vuIMrF6RVcd',#5,'Default Building','',$,$,$,$,.ELEMENT.,$,$,$);
#43=IFCRELAGGREGATES('2GkPanCgnAzQY_0xv8dnHH',#5,'SiteLink','',#40,(#42));
#44=IFCBUILDINGSTOREY('1L8$GCIw116uw35vpyjSsO',#5,'Default Storey','',$,$,$,$,.ELEMENT.,$);
#45=IFCRELAGGREGATES('1lB$$h00nFaPQb2gvlhRX$',#5,'DefaultStoreyLink','',#42,(#44));
#46=IFCRELCONTAINEDINSPATIALSTRUCTURE('3dnpjDLD5DvuyUGcyHqRvU',#5,'UnassignedObjectsLink','',(#39),#44);
ENDSEC;
END-ISO-10303-21;
@@ -1,18 +0,0 @@
# language: de
Funktionalität: Basisdaten
Um BIM-Daten anzusehen
Für alle beteiligten Akteure
Wir brauchen eine IFC-Datei
Szenario: Bereitstellen von IFC-Daten
* Die IFC-Datei wurde durch einen Startparameter zur Verfügung gestellt
* Die IFC-Daten müssen das IFC2X3 Schema benutzen
Szenario: Projektinformationen
* Der Name, die Abkürzung oder die Kurzkennung des Projektes ist "BIMTester Example 1 - IFC2X3"
@@ -1,18 +0,0 @@
# language: en
Feature: Base setup
In order to view the BIM data
As any interested stakeholder
We need an IFC file
Scenario: Receiving a file
* The IFC file has been provided through an argument
* IFC data must use the IFC2X3 schema
Scenario: Project information
* The project name, code, or short identifier must be "BIMTester Example 1 - IFC2X3"
@@ -1,18 +0,0 @@
# language: fr
Fonctionnalité: Base setup
In order to view the BIM data
As any interested stakeholder
We need an IFC file
Scénario: Recevoir e fichier
* The IFC file has been provided through an argument
* Les données IFC doivent utiliser le schéma IFC2X3
Scénario: Project information
* The project name, code, or short identifier must be "BIMTester Example 1 - IFC2X3"
@@ -1,18 +0,0 @@
# language: it
Funzionalità: Dati di base
Per poter consultare dati BIM
a tutti gli attori partecipanti
serve un file IFC
Scenario: Preparare Dati IFC
* Il file IFC è stato fornito attraverso un argumento
* I dati IFC devono seguire lo schema IFC2X3
Scenario: Project information
* Il nome del progetto, codice o identificatore breve deve essere "BIMTester Example 1 - IFC2X3"
@@ -1,18 +0,0 @@
# language: nl
Functionaliteit: Basisgegevens
Om BIM-gegevens te bekijken
Zoals elke geïnteresseerde stakeholder
We hebben een IFC-bestand nodig
Scenario: Bestand ontvangen
* The IFC file has been provided through an argument
* IFC-gegevens moeten het IFC2X3 -schema gebruiken
Scenario: Project informatie
* De projectnaam, code of korte ID moet "BIMTester Example 1 - IFC2X3"
@@ -1,144 +0,0 @@
from behave import step, given, when, then, use_step_matcher
use_step_matcher("parse")
@step("There must be exactly {number} {ifc_class} element")
@step("There must be exactly {number} {ifc_class} elements")
def step_impl(context, number, ifc_class):
num = len(IfcStore.file.by_type(ifc_class))
assert num == int(number), "Could not find {} elements of {}. Found {} element(s).".format(number, ifc_class, num)
@given("a set of specific related elements")
def step_impl(context):
model = getattr(context, "model", None)
if not model:
context.model = TableModel()
for row in context.table:
context.model.add_row(row["RelatedObjects"], row["RelatingGroup"])
@given('a set of specific related elements taken from the file "{path_file}"')
def step_impl(context, path_file):
import csv
import os
model = getattr(context, "model", None)
if not model:
context.model = TableModel()
if context.config.userdata.get("path"):
path_file = os.path.join(context.config.userdata.get("path"), path_file)
if not os.path.exists(path_file):
assert False, "File {} not found".format(path_file)
with open(path_file, "r", encoding="utf-8-sig") as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
context.model.add_row(row["RelatedObjects"], row["RelatingGroup"])
@then("there must be exactly a number of {ifc_class} equals to the number of distinct row value")
def step_impl(context, ifc_class):
try:
context.execute_steps(
"""
then There must be exactly {number} {ifc_class} elements
""".format(
ifc_class=ifc_class, number=context.model.get_count_distinct_values()
)
)
except AssertionError as error:
str_error = str(error)
assert False, str_error[: str_error.find("Traceback")]
assert True
@then(
"there is a relationship {ifc_class} with {left_attribute} and {right_attribute} between the two elements of each row"
)
def step_impl(context, ifc_class, left_attribute, right_attribute):
rows = context.model.rows
elements = IfcStore.file.by_type(ifc_class)
errors = []
for key, value in rows.items():
found = False
for element in elements:
if (
any(x.Name == key for x in getattr(element, left_attribute))
and getattr(element, right_attribute).Name == value
):
found = True
if not found:
errors.append(f"The row ({key}, {value}) does not have the relationship.")
assert not errors, "Errors occured:\n{}".format("\n".join(errors))
use_step_matcher("re")
@step("all IfcGroup must be linked to a type in the list (?P<linked_ifc_classes>.*)")
def step_impl(context, linked_ifc_classes):
groups = IfcStore.file.by_type("IfcGroup")
errors = []
for group in groups:
if not hasattr(group, "IsGroupedBy"):
errors.append(f'The element "{group.Name}" has no "IsGroupedBy" attribute.')
else:
for grouped_by in getattr(group, "IsGroupedBy"):
if not hasattr(grouped_by, "RelatedObjects"):
errors.append(f'The element "{grouped_by.Name}" has no "RelatedObjects" attribute.')
else:
for related_object in getattr(grouped_by, "RelatedObjects"):
found = False
for linked_ifc_class in linked_ifc_classes.split(","):
if related_object.is_a(linked_ifc_class):
found = True
if not found:
errors.append(
f'The element "{related_object.Name}" does not have the right associated type.'
)
assert not errors, "Errors occured:\n{}".format("\n".join(errors))
@then("there is an element of type (?P<ifc_types>.*) with a (?P<attribute_name>.*) attribute for each row key")
def step_impl(context, ifc_types, attribute_name):
check_if_element_exists_by_types_with_attribute_name(ifc_types, attribute_name, context.model.rows.keys())
@then("there is an element of type (?P<ifc_types>.*) with a (?P<attribute_name>.*) attribute for each row value")
def step_impl(context, ifc_types, attribute_name):
values = set(context.model.rows.values())
check_if_element_exists_by_types_with_attribute_name(ifc_types, attribute_name, values)
def check_if_element_exists_by_types_with_attribute_name(ifc_types, attribute_name, attribute_values):
errors = []
elements = []
for ifc_type in ifc_types.split(","):
elements += ifc.by_type(ifc_type.strip())
for attribute_value in attribute_values:
found = False
for element in elements:
if hasattr(element, attribute_name) and getattr(element, attribute_name) == attribute_value:
found = True
if not found:
errors.append(f'An element with {attribute_name} attribute "{attribute_value}" was not found.')
assert not errors, "Errors occured:\n{}".format("\n".join(errors))
class TableModel(object):
"""This class represents a table of data."""
def __init__(self):
self.rows = dict()
def add_row(self, related, relating):
self.rows[related] = relating
def get_count(self):
return len(self.rows)
def get_count_distinct_values(self):
return len(set(self.rows.values()))
@@ -1,52 +0,0 @@
import gettext
from behave import given
from behave import step
from utils import IfcFile
from bimtester.ifc import IfcStore
from bimtester.lang import _
@step("The IFC file must be exported by application full name {fullname}")
def step_impl(context, fullname):
real_fullname = IfcStore.file.by_type("IfcApplication")[0].ApplicationFullName
assert real_fullname == fullname, (
"The IFC file was not exported by application full name {} "
"instead it was exported by application full name {}".format(fullname, real_fullname)
)
@step("The IFC file must be exported by application identifier {identifier}")
def step_impl(context, identifier):
real_identifier = IfcStore.file.by_type("IfcApplication")[0].ApplicationIdentifier
assert (
real_identifier == identifier
), "The IFC file was not exported by application identifier {} " "instead it was exported by identifier {}".format(
identifier, real_identifier
)
@step("The IFC file must be exported by the application version {version}")
def step_impl(context, version):
real_version = IfcStore.file.by_type("IfcApplication")[0].Version
assert (
real_version == version
), "The IFC file was not exported by application version {} " "instead it was exported by version {}".format(
version, real_version
)
@step(
"IFC data header must have a file description of {header_file_description} such as the new Allplan IFC exporter creates it"
)
def step_impl(context, header_file_description):
is_header_file_description = IfcStore.file.wrapped_data.header.file_description.description
assert (
str(is_header_file_description) == header_file_description
), "The file was not exported by the new ifc exporter in Allplan. File description header: {}".format(
is_header_file_description
)
@@ -1,91 +0,0 @@
from behave import step
import attributes_eleclasses_methods as aem
from utils import assert_elements
from utils import IfcFile
@step("There are no {ifc_class} elements")
def step_impl(context, ifc_class):
aem.no_eleclass(context, ifc_class)
@step("There are no {ifc_class} elements because {reason}")
def step_impl(context, ifc_class, reason):
aem.no_eleclass(context, ifc_class)
@step("All {ifc_class} elements class attributes have a value")
def step_impl(context, ifc_class):
aem.eleclass_have_class_attributes_with_a_value(context, ifc_class)
@step("All {ifc_class} elements have a name given")
def step_impl(context, ifc_class):
aem.eleclass_has_name_with_a_value(context, ifc_class)
@step("All {ifc_class} elements have a description given")
def step_impl(context, ifc_class):
aem.eleclass_has_description_with_a_value(context, ifc_class)
@step('all {ifc_class} elements have a name matching the pattern "{pattern}"')
def step_impl(context, ifc_class, pattern):
import re
elements = IfcFile.get().by_type(ifc_class)
for element in elements:
if not re.search(pattern, element.Name):
assert False
@step('there is an {ifc_class} element with a {attribute_name} attribute with a value of "{attribute_value}"')
def step_impl(context, ifc_class, attribute_name, attribute_value):
elements = IfcFile.get().by_type(ifc_class)
for element in elements:
if hasattr(element, attribute_name) and getattr(element, attribute_name) == attribute_value:
return
assert False
use_step_matcher("re")
@step("all (?P<ifc_class>.*) elements have an? (?P<attribute>.*) attribute")
def step_impl(context, ifc_class, attribute):
elements = IfcFile.get().by_type(ifc_class)
for element in elements:
if not getattr(element, attribute):
assert False
@step('all (?P<ifc_class>.*) elements have an? (?P<attribute>.*) matching the pattern "(?P<pattern>.*)"')
def step_impl(context, ifc_class, attribute, pattern):
import re
elements = IfcFile.get().by_type(ifc_class)
for element in elements:
value = getattr(element, attribute)
print(f'Checking value "{value}" for {element}')
assert re.search(pattern, value)
@step('all (?P<ifc_class>.*) elements have an? (?P<attributes>.*) taken from the list in "(?P<list_file>.*)"')
def step_impl(context, ifc_class, attributes, list_file):
import csv
values = []
with open(list_file) as csvfile:
reader = csv.reader(csvfile)
for row in reader:
values.append(row)
elements = IfcFile.get().by_type(ifc_class)
for element in elements:
attribute_values = []
for attribute in attributes.split(","):
if not hasattr(element, attribute):
assert False, f"Failed at element {element.GlobalId}"
attribute_values.append(getattr(element, attribute))
if attribute_values not in values:
assert False, f"Failed at element {element.GlobalId}"
@@ -1,26 +0,0 @@
from behave import step
@step("Es sind keine {ifc_class} Bauteile vorhanden")
def step_impl(context, ifc_class):
context.execute_steps(f"* There are no {ifc_class} elements")
@step("Aus folgendem Grund gibt es keine {ifc_class} Bauteile: {reason}")
def step_impl(context, ifc_class, reason):
context.execute_steps(f"* There are no {ifc_class} elements because {reason}")
@step("Alle {ifc_class} Bauteilklassenattribute haben einen Wert")
def step_impl(context, ifc_class):
context.execute_steps(f"* All {ifc_class} elements class attributes have a value")
@step("Bei allen {ifc_class} Bauteile ist der Name angegeben")
def step_impl(context, ifc_class):
context.execute_steps(f"* All {ifc_class} elements have a name given")
@step("Bei allen {ifc_class} Bauteile ist die Beschreibung angegeben")
def step_impl(context, ifc_class):
context.execute_steps(f"* All {ifc_class} elements have a description given")
@@ -1,140 +0,0 @@
import gettext # noqa
from utils import assert_elements
from utils import IfcFile
def no_eleclass(
context, ifc_class
):
context.falseelems = []
context.falseguids = []
elements = IfcFile.get().by_type(ifc_class)
for elem in elements:
context.falseelems.append(str(elem))
context.falseguids.append(elem.GlobalId)
context.elemcount = len(elements)
context.falsecount = len(context.falseelems)
if context.elemcount == 0 and context.falsecount == 0:
return # Test OK, thus we can not use the assert_elements method
elif context.falsecount == context.elemcount:
assert False, (
_("All {elemcount} elements in the file are {ifc_class}.")
.format(
elemcount=context.elemcount,
ifc_class=ifc_class
)
)
elif context.falsecount > 0 and fcontext.alsecount < context.elemcount:
assert False, (
_("{falsecount} of {elemcount} element are {ifc_class} elements: {falseelems}")
.format(
falsecount=context.falsecount,
elemcount=context.elemcount,
ifc_class=ifc_class,
falseelems=context.falseelems,
)
)
else:
assert False, _("Error in falsecount, something went wrong.")
def eleclass_have_class_attributes_with_a_value(
context, ifc_class
):
from ifcopenshell.ifcopenshell_wrapper import schema_by_name
# schema = schema_by_name("IFC2X3")
schema = schema_by_name(IfcFile.get().schema)
class_attributes = []
for cl_attrib in schema.declaration_by_name(ifc_class).all_attributes():
class_attributes.append(cl_attrib.name())
# print(class_attributes)
context.falseelems = []
context.falseguids = []
context.falseprops = {}
elements = IfcFile.get().by_type(ifc_class)
for elem in elements:
failed_attribs = []
elem_failed = False
for cl_attrib in class_attributes:
attrib_value = getattr(elem, cl_attrib)
if not attrib_value:
elem_failed = True
failed_attribs.append(cl_attrib)
# print(attrib_value)
if elem_failed is True:
context.falseelems.append(str(elem))
context.falseguids.append(elem.GlobalId)
context.falseprops[elem.id()] = failed_attribs
context.elemcount = len(elements)
context.falsecount = len(context.falseelems)
assert_elements(
ifc_class,
context.elemcount,
context.falsecount,
context.falseelems,
message_all_falseelems=_("For all {elemcount} {ifc_class} elements at least one of these class attributes {parameter} has no value."),
message_some_falseelems=_("For the following {falsecount} out of {elemcount} {ifc_class} elements at least one of these class attributes {parameter} has no value: {falseelems}"),
message_no_elems=_("There are no {ifc_class} elements in the IFC file."),
parameter=failed_attribs
)
def eleclass_has_name_with_a_value(context, ifc_class):
context.falseelems = []
context.falseguids = []
elements = IfcFile.get().by_type(ifc_class)
for elem in elements:
# print(elem.Name)
if not elem.Name:
context.falseelems.append(str(elem))
context.falseguids.append(elem.GlobalId)
context.elemcount = len(elements)
context.falsecount = len(context.falseelems)
assert_elements(
ifc_class,
context.elemcount,
context.falsecount,
context.falseelems,
message_all_falseelems=_("The name of all {elemcount} {elemcount} elements is not set."),
message_some_falseelems=_("The name of {falsecount} out of {elemcount} {ifc_class} elements is not set: {falseelems}"),
message_no_elems=_("There are no {ifc_class} elements in the IFC file."),
)
def eleclass_has_description_with_a_value(
context, ifc_class
):
context.falseelems = []
context.falseguids = []
elements = IfcFile.get().by_type(ifc_class)
for elem in elements:
# print(elem.Description)
if not elem.Description:
context.falseelems.append(str(elem))
context.falseguids.append(elem.GlobalId)
context.elemcount = len(elements)
context.falsecount = len(context.falseelems)
assert_elements(
ifc_class,
context.elemcount,
context.falsecount,
context.falseelems,
message_all_falseelems=_("The description of all {elemcount} {elemcount} elements is not set."),
message_some_falseelems=_("The description of {falsecount} out of {elemcount} {ifc_class} elements is not set: {falseelems}"),
message_no_elems=_("There are no {ifc_class} elements in the IFC file."),
)

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