diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..3b83ce65bc --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Dependency and build folders created by the build scripts +/deps*/ +/build*/ +/install*/ +/win/BuildDepsCache*.txt +# IfcExpressParser residue +/src/ifcexpressparser/__pycache__ +/src/ifcexpressparser/express_parser.py +# Python test residue +/test/__pycache__ diff --git a/README.md b/README.md index b64227f291..10d03630a1 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,66 @@ IfcOpenShell ============ -open source (LGPL) software library for working with the IFC file format +Open source (LGPL) software library for working with the IFC ([IFC2x3 TC1] and [IFC4]) file format. [http://ifcopenshell.org](http://ifcopenshell.org) [http://academy.ifcopenshell.org](http://academy.ifcopenshell.org) +Prerequisites +============= +* 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 *optional*, but required for building IfcGeom) - [Official](http://www.opencascade.org/getocc/download/loadocc/) or [community edition](https://github.com/tpaviot/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* +* [ICU](http://site.icu-project.org/) - *optional* For handling code pages and Unicode in the parser -* [OpenCOLLADA](https://github.com/khronosGroup/OpenCOLLADA/) *optional* +* [OpenCOLLADA](https://github.com/khronosGroup/OpenCOLLADA/) - *optional* For IfcConvert to be able to write tessellated Collada (.dae) files -* [SWIG](http://www.swig.org/), [Python](https://www.python.org/) libraries *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 *optional* - For building the 3ds max plug-in +* 3ds Max SDK - *optional* + For building the 3ds Max plug-in Compiling on Windows ==================== -Users are advised to use the Visual Studio .sln file in the win/ folder. -For Windows users a prebuilt Open CASCADE version is available from the -http://opencascade.org website. Download and install this version and -provide the paths to the Open CASCADE header and library files to MS -Visual Studio C++. +Users are advised to build IfcOpenShell using the CMake file provided in +the cmake/ folder. -For building the Autodesk 3ds Max plugin, the 3ds Max SDK needs to be -installed as well as 3ds Max itself. Please provide the include and -library paths to Visual Studio. +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**. Instructions in a nutshell +(**assuming Visual Studio 2015 x64 environment variables set**): -For building the IfcPython wrapper, SWIG needs to be installed. Please -download the latest swigwin version from http://www.swig.org/download.html. -After extracting the .zip file, please add the extracted folder to the PATH -environment variable. Python needs to be installed, please provide the -include and library paths to Visual Studio. + > git clone https://github.com/IfcOpenShell/IfcOpenShell.git + > cd IfcOpenShell\win + > build-deps.cmd + > run-cmake.bat + +You can now open and build the solution file in Visual Studio: + + > ..\build-vs2015-x64\IfcOpenShell.sln + +As the scripts default to using the `RelWithDebInfo` configuration, and a freshly created solution by CMake defaults +to `Debug`, make sure to switch the used build configuration. Build the `INSTALL` project (right-click -> Project +Only) to deploy the headers and binaries into a single location if wanted/needed. + +Alternatively, one can use the utility batch files to build and install the project easily from the command-line: + + > build-ifcopenshell.cmd + > install-ifcopenshell.cmd + +Alternatively, the old Visual Studio solution and project files requiring manual work can +be found from the win/sln folder. Compiling on *nix ================= -Users are advised to build IfcOpenShell using the cmake file provided in +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. @@ -75,7 +92,10 @@ To build IfcOpenShell please take the following steps: $ cmake ../ $ make -If all worked out correctly you can now use IfcOpenShell. For example: +If all worked out correctly you can now use IfcOpenShell. See the examples below. + +Usage examples +============== **Invoking IfcConvert from the command line** @@ -84,8 +104,6 @@ If all worked out correctly you can now use IfcOpenShell. For example: $ ./IfcConvert Munkerud_hus6_BE.ifc $ less Munkerud_hus6_BE.obj -Or: - **Using the IfcOpenShell Python interface** $ wget -O duplex.zip http://projects.buildingsmartalliance.org/files/?artifact_id=4278 @@ -146,3 +164,7 @@ Or: >>> >>> # Writing IFC-SPF files to disk: >>> f.write("out.ifc") + +[win/readme.md]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/win/readme.md "win/readme.md" +[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" \ No newline at end of file diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 429920293e..71963665ca 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -1,17 +1,87 @@ -cmake_minimum_required (VERSION 2.6) +################################################################################ +# # +# This file is part of IfcOpenShell. # +# # +# IfcOpenShell is free software: you can redistribute it and/or modify # +# it under the terms of the Lesser GNU General Public License as published by # +# the Free Software Foundation, either version 3.0 of the License, or # +# (at your option) any later version. # +# # +# IfcOpenShell is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# Lesser GNU General Public License for more details. # +# # +# You should have received a copy of the Lesser GNU General Public License # +# along with this program. If not, see . # +# # +################################################################################ + +cmake_minimum_required (VERSION 2.8.5) + project (IfcOpenShell) +OPTION(UNICODE_SUPPORT "Build IfcOpenShell with Unicode support (requires ICU)." ON) +OPTION(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON) +OPTION(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF) +#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(USE_VLD "Use Visual Leak Detector for debugging memory leaks, MSVC-only." 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) + + +# Create cache entries if absent for environment variables +MACRO(UNIFY_ENVVARS_AND_CACHE VAR) + IF ((NOT DEFINED ${VAR}) AND (NOT "$ENV{${VAR}}" STREQUAL "")) + SET(${VAR} "$ENV{${VAR}}" CACHE STRING "${VAR}" FORCE) + ENDIF() +ENDMACRO() + +UNIFY_ENVVARS_AND_CACHE(OCC_INCLUDE_DIR) +UNIFY_ENVVARS_AND_CACHE(OCC_LIBRARY_DIR) +UNIFY_ENVVARS_AND_CACHE(ICU_INCLUDE_DIR) +UNIFY_ENVVARS_AND_CACHE(ICU_LIBRARY_DIR) +UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_INCLUDE_DIR) +UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_LIBRARY_DIR) +UNIFY_ENVVARS_AND_CACHE(PCRE_LIBRARY_DIR) +UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE) + +# Find Boost +IF(MSVC) + SET(Boost_USE_STATIC_LIBS ON) + SET(Boost_USE_STATIC_RUNTIME ON) + SET(Boost_USE_MULTITHREADED ON) +ENDIF() 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}") -# Find Open CASCADE header files -IF("$ENV{OCC_INCLUDE_DIR}" STREQUAL "") +# Usage: +# SET(SOME_LIRARIES foo bar) +# ADD_DEBUG_VARIANTS(SOME_LIRARIES "${SOME_LIRARIES}" "d") +# "foo bar" -> "optimized foo debug food optimized bar debug bard" +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 debug " 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/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 $ENV{OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files") + SET(OCC_INCLUDE_DIR ${OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files") MESSAGE(STATUS "Looking for opencascade include files in: ${OCC_INCLUDE_DIR}") ENDIF() @@ -22,219 +92,335 @@ ELSE() MESSAGE(FATAL_ERROR "Unable to find header files, aborting") ENDIF() -# Find Open CASCADE library files -IF("$ENV{OCC_LIBRARY_DIR}" STREQUAL "") +SET(OPENCASCADE_LIBRARIES + TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO + 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 opencascade library files in: ${OCC_LIBRARY_DIR}") MESSAGE(STATUS "Use OCC_LIBRARY_DIR to specify another directory") ELSE() - SET(OCC_LIBRARY_DIR $ENV{OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files") + SET(OCC_LIBRARY_DIR ${OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files") MESSAGE(STATUS "Looking for opencascade library files in: ${OCC_LIBRARY_DIR}") ENDIF() -FIND_LIBRARY(libTKernel "TKernel" ${OCC_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64) +FIND_LIBRARY(libTKernel NAMES TKernel TKerneld PATHS ${OCC_LIBRARY_DIR} /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() -IF("$ENV{ICU_INCLUDE_DIR}" STREQUAL "") - MESSAGE(STATUS "No ICU include directory specified") -ElSE() - SET(ICU_INCLUDE_DIR CACHE FILEPATH "ICU header files") +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("${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() + + FIND_LIBRARY(icu NAMES icuuc icuucd PATHS /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR}) + + 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() -IF("$ENV{ICU_LIBRARY_DIR}" STREQUAL "") - MESSAGE(STATUS "No ICU library directory specified") -ElSE() - SET(ICU_LIBRARY_DIR CACHE FILEPATH "ICU library files") +IF(COLLADA_SUPPORT) + # Find OpenCOLLADA + IF("${OPENCOLLADA_INCLUDE_DIR}" STREQUAL "") + MESSAGE(STATUS "No OpenCOLLADA include directory specified") + SET(OPENCOLLADA_INCLUDE_DIR "/usr/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") + 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() + + SET(OPENCOLLADA_INCLUDE_DIRS "${OPENCOLLADA_INCLUDE_DIR}/COLLADABaseUtils" "${OPENCOLLADA_INCLUDE_DIR}/COLLADAStreamWriter") + + FIND_FILE(COLLADASWStreamWriter_h "COLLADASWStreamWriter.h" ${OPENCOLLADA_INCLUDE_DIRS}) + IF(COLLADASWStreamWriter_h) + MESSAGE(STATUS "OpenCOLLADA header files found") + ADD_DEFINITIONS(-DWITH_OPENCOLLADA) + SET(OPENCOLLADA_LIBRARIES + GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader + OpenCOLLADAStreamWriter UTF buffer ftoa pcre + ) + IF(NOT "${PCRE_LIBRARY_DIR}" STREQUAL "") + SET(OPENCOLLADA_LIBRARY_DIR ${OPENCOLLADA_LIBRARY_DIR} ${PCRE_LIBRARY_DIR}) + ENDIF() + IF(MSVC) + ADD_DEBUG_VARIANTS(OPENCOLLADA_LIBRARIES "${OPENCOLLADA_LIBRARIES}" "d") + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find OpenCOLLADA. Disable COLLADA_SUPPORT or fix OpenCOLLADA paths to proceed.") + ENDIF() ENDIF() -FIND_LIBRARY(icu "icuuc" /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR}) + # TODO Are these needed on other platforms still or can these be removed for good? +IF (NOT WIN32) + INCLUDE(CheckIncludeFileCXX) -IF(icu) - MESSAGE(STATUS "ICU libraries found") - ADD_DEFINITIONS(-DHAVE_ICU) -ELSE() - MESSAGE(STATUS "Unable to find ICU library files, continuing") + 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("$ENV{OPENCOLLADA_INCLUDE_DIR}" STREQUAL "") - MESSAGE(STATUS "No OpenCOLLADA include directory specified") - SET(OPENCOLLADA_INCLUDE_DIR "/usr/local/include/opencollada" CACHE FILEPATH "OpenCOLLADA header files") -ElSE() - SET(OPENCOLLADA_INCLUDE_DIR "$ENV{OPENCOLLADA_INCLUDE_DIR}" CACHE FILEPATH "OpenCOLLADA header files") -ENDIF() - -IF("$ENV{OPENCOLLADA_LIBRARY_DIR}" STREQUAL "") - MESSAGE(STATUS "No OpenCOLLADA library directory specified") - SET(OPENCOLLADA_LIBRARY_DIR "/usr/local/lib/opencollada" CACHE FILEPATH "OpenCOLLADA library files") -ElSE() - SET(OPENCOLLADA_LIBRARY_DIR "$ENV{OPENCOLLADA_LIBRARY_DIR}" CACHE FILEPATH "OpenCOLLADA library files") -ENDIF() - -SET(OPENCOLLADA_INCLUDE_DIRS "${OPENCOLLADA_INCLUDE_DIR}/COLLADABaseUtils" "${OPENCOLLADA_INCLUDE_DIR}/COLLADAStreamWriter") - -FIND_FILE(COLLADASWStreamWriter_h "COLLADASWStreamWriter.h" ${OPENCOLLADA_INCLUDE_DIRS}) -IF(COLLADASWStreamWriter_h) - MESSAGE(STATUS "OpenCOLLADA header files found") - ADD_DEFINITIONS(-DWITH_OPENCOLLADA) - SET(OPENCOLLADA_LIBRARIES - GeneratedSaxParser MathMLSolver OpenCOLLADABaseUtils - OpenCOLLADAFramework OpenCOLLADASaxFrameworkLoader - OpenCOLLADAStreamWriter UTF buffer ftoa pcre - ) -ELSE() - MESSAGE(STATUS "OpenCOLLADA header files not found, continuing without COLLADA support") -ENDIF() - -INCLUDE(CheckIncludeFileCXX) - -MACRO(CHECK_ADD_OCE_OCC_DEF INCLUDE) - STRING(REPLACE . _ STR ${INCLUDE}) - STRING(TOUPPER ${STR} STR) - CHECK_INCLUDE_FILE_CXX("${INCLUDE}" FOUND_${STR}) - IF(FOUND_${STR}) - ADD_DEFINITIONS(-DOCE_HAVE_${STR}) - ADD_DEFINITIONS(-DHAVE_${STR}) - ENDIF(FOUND_${STR}) -ENDMACRO(CHECK_ADD_OCE_OCC_DEF) - -CHECK_ADD_OCE_OCC_DEF(limits) -CHECK_ADD_OCE_OCC_DEF(climits) -CHECK_ADD_OCE_OCC_DEF(limits.h) -CHECK_ADD_OCE_OCC_DEF(fstream) -CHECK_ADD_OCE_OCC_DEF(fstream.h) -CHECK_ADD_OCE_OCC_DEF(iomanip) -CHECK_ADD_OCE_OCC_DEF(iomanip.h) -CHECK_ADD_OCE_OCC_DEF(iostream) -CHECK_ADD_OCE_OCC_DEF(iostream.h) - IF(NOT CMAKE_BUILD_TYPE) - SET(CMAKE_BUILD_TYPE "Release") -ENDIF(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) + # C++ + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /GL") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} /Zi") + # Linker + # /OPT:REF enables also /OPT:ICF and disables INCREMENTAL + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF") + # /OPT:NOICF is recommended when /DEBUG is used (http://msdn.microsoft.com/en-us/library/xe4t6fc1.aspx) + set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF") + set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF") + else() + #TODO GCC (& Clang?) optimizations + message(STATUS "ENABLE_BUILD_OPTIMIZATIONS not implemented for GCC/non-MSVC compilers.)") + endif() +endif() IF(MSVC) - ADD_DEFINITIONS(-D_UNICODE) -ElSE(MSVC) - ADD_DEFINITIONS(-fPIC -Wno-non-virtual-dtor) -ENDIF(MSVC) - -INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} /usr/inc /usr/local/inc /usr/local/include/oce ${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS}) - -ADD_LIBRARY(IfcParse STATIC - ../src/ifcparse/Ifc2x3-latebound.cpp - ../src/ifcparse/Ifc2x3.cpp - ../src/ifcparse/Ifc4-latebound.cpp - ../src/ifcparse/Ifc4.cpp - ../src/ifcparse/IfcCharacterDecoder.cpp - ../src/ifcparse/IfcGlobalId.cpp - ../src/ifcparse/IfcHierarchyHelper.cpp - ../src/ifcparse/IfcLateBoundEntity.cpp - ../src/ifcparse/IfcParse.cpp - ../src/ifcparse/IfcSIPrefix.cpp - ../src/ifcparse/IfcSpfHeader.cpp - ../src/ifcparse/IfcUtil.cpp - ../src/ifcparse/IfcWrite.cpp -) - -ADD_LIBRARY(IfcGeom STATIC - ../src/ifcgeom/IfcGeomCurves.cpp - ../src/ifcgeom/IfcGeomFaces.cpp - ../src/ifcgeom/IfcGeomFunctions.cpp - ../src/ifcgeom/IfcGeomHelpers.cpp - ../src/ifcgeom/IfcGeomMaterial.cpp - ../src/ifcgeom/IfcGeomRenderStyles.cpp - ../src/ifcgeom/IfcGeomRepresentation.cpp - ../src/ifcgeom/IfcGeomShapes.cpp - ../src/ifcgeom/IfcGeomWires.cpp - ../src/ifcgeom/IfcRegister.cpp -) - -IF(icu) - TARGET_LINK_LIBRARIES(IfcParse icuuc) + IF(USE_VLD) + ADD_DEFINITIONS(-DUSE_VLD) + ENDIF() + # Enforce Unicode for CRT and Win32 API calls + ADD_DEFINITIONS(-D_UNICODE -DUNICODE) + # Disable warnings about unsafe C functions; we could use the safe C99 & C11 versions if we have no need for supporting old compilers. + ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS) + ADD_DEFINITIONS(-bigobj) # required for building the big ifcXXX.objs, https://msdn.microsoft.com/en-us/library/ms173499.aspx + # Bump up the warning level from the default 3 to 4. + ADD_DEFINITIONS(-W4) + IF(MSVC_VERSION GREATER 1800) # > 2013 + # Disable overeager and false positives causing C4458 ("declaration of 'indentifier' hides class member"), at least for now. + ADD_DEFINITIONS(-wd4458) + ENDIF() + # Link against the static VC runtime + FOREACH(flag CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO) + IF(${flag} MATCHES "/MD") + STRING(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}") + ENDIF() + IF(${flag} MATCHES "/MDd") + STRING(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}") + ENDIF() + ENDFOREACH() +ElSE() + ADD_DEFINITIONS(-fPIC -Wno-non-virtual-dtor) ENDIF() +INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} + ${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} +) +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 + ${IFC_PARSE_DIR}/Ifc${IFC_VERSION}-latebound.cpp + PARENT_SCOPE + ) +endfunction() + +if(COMPILE_SCHEMA) + find_package(PythonInterp) + + IF(NOT PYTHONINTERP_FOUND) + MESSAGE(FATAL_ERROR "A Python interpreter is necessary when COMPILE_SCHEMA is enabled. Disable COMPILE_SCHEMA or fix Python paths to proceed.") + ENDIF() + + set(IFC_RELEASE_NOT_USED "2x3" "4") + + # Install pyparsing if necessary + execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST) + if ("${PYTHON_PACKAGE_LIST}" STREQUAL "") + execute_process(COMMAND pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST) + if ("${PYTHON_PACKAGE_LIST}" STREQUAL "") + message(WARNING "Failed to find pip. Pip is required to automatically install pyparsing") + endif() + endif() + string(FIND "${PYTHON_PACKAGE_LIST}" pyparsing PYPARSING_FOUND) + if ("${PYPARSING_FOUND}" STREQUAL "-1") + message(STATUS "Installing pyparsing") + execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip "install" --user pyparsing RESULT_VARIABLE SUCCESS) + if (NOT "${SUCCESS}" STREQUAL "0") + execute_process(COMMAND pip "install" --user pyparsing RESULT_VARIABLE SUCCESS) + if (NOT "${SUCCESS}" STREQUAL "0") + message(WARNING "Failed to automatically install pyparsing. Please install manually") + endif() + endif() + else() + message(STATUS "Python interpreter with pyparsing found") + endif() + + # Bootstrap the parser + message(STATUS "Compiling schema, this will take a while...") + execute_process(COMMAND ${PYTHON_EXECUTABLE} bootstrap.py express.bnf + WORKING_DIRECTORY ../src/ifcexpressparser + OUTPUT_FILE express_parser.py + RESULT_VARIABLE SUCCESS) + + if (NOT "${SUCCESS}" STREQUAL "0") + MESSAGE(FATAL_ERROR "Failed to bootstrap parser. Make sure pyparsing is installed") + endif() + + # Generate code + execute_process(COMMAND ${PYTHON_EXECUTABLE} ../ifcexpressparser/express_parser.py ../../${COMPILE_SCHEMA} + WORKING_DIRECTORY ../src/ifcparse + OUTPUT_VARIABLE COMPILED_SCHEMA_NAME) + + # Prevent the schema that had just been compiled from being excluded + if("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC2X3") + list(REMOVE_ITEM IFC_RELEASE_NOT_USED "2x3") + add_definitions(-DUSE_IFC2x3) + elseif("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC4") + list(REMOVE_ITEM IFC_RELEASE_NOT_USED "4") + add_definitions(-DUSE_IFC4) + endif() +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 STATIC ${IFCPARSE_FILES}) + +IF(UNICODE_SUPPORT) + TARGET_LINK_LIBRARIES(IfcParse ${ICU_LIBRARIES}) +ENDIF() + +# IfcGeom +file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/*.h) +file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp) + +set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES}) +ADD_LIBRARY(IfcGeom STATIC ${IFCGEOM_FILES}) + TARGET_LINK_LIBRARIES(IfcGeom IfcParse) -LINK_DIRECTORIES (${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} ${OPENCOLLADA_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS}) - -ADD_EXECUTABLE(IfcConvert - ../src/ifcconvert/ColladaSerializer.cpp - ../src/ifcconvert/IfcConvert.cpp - ../src/ifcconvert/OpenCascadeBasedSerializer.cpp - ../src/ifcconvert/WavefrontObjSerializer.cpp - ../src/ifcconvert/XmlSerializer.cpp - ../src/ifcconvert/SvgSerializer.cpp - ../src/ifcconvert/util.cpp +LINK_DIRECTORIES(${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} ${OPENCOLLADA_LIBRARY_DIR} + ${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS} ) +if(NOT WIN32) + LINK_DIRECTORIES(${LINK_DIRECTORIES} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64) +endif() -TARGET_LINK_LIBRARIES (IfcConvert IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES}) +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}) -ADD_EXECUTABLE(IfcGeomServer - ../src/ifcgeomserver/IfcGeomServer.cpp -) +# 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() -TARGET_LINK_LIBRARIES (IfcGeomServer IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset) +TARGET_LINK_LIBRARIES(IfcConvert IfcParse IfcGeom ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${ICU_LIBRARIES}) -# Build python wrapper using separate CMakeLists.txt -ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap) +# IfcGeomServer +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}) -# Build IfcParseExamples using separate CMakeLists.txt -ADD_SUBDIRECTORY(../src/examples examples) +TARGET_LINK_LIBRARIES(IfcGeomServer IfcParse IfcGeom ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBRARIES}) -# ADD_SUBDIRECTORY(../src/qtviewer qtviewer) +IF(BUILD_IFCPYTHON) + ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap) +ENDIF() + +IF(BUILD_EXAMPLES) + ADD_SUBDIRECTORY(../src/examples examples) +ENDIF() # CMake installation targets -SET(include_files_geom - ../src/ifcgeom/IfcGeom.h - ../src/ifcgeom/IfcGeomElement.h - ../src/ifcgeom/IfcGeomIterator.h - ../src/ifcgeom/IfcGeomIteratorSettings.h - ../src/ifcgeom/IfcGeomMaterial.h - ../src/ifcgeom/IfcGeomRenderStyles.h - ../src/ifcgeom/IfcGeomRepresentation.h - ../src/ifcgeom/IfcGeomShapeType.h - ../src/ifcgeom/IfcRegister.h - ../src/ifcgeom/IfcRegisterConvertCurve.h - ../src/ifcgeom/IfcRegisterConvertFace.h - ../src/ifcgeom/IfcRegisterConvertShape.h - ../src/ifcgeom/IfcRegisterConvertShapes.h - ../src/ifcgeom/IfcRegisterConvertWire.h - ../src/ifcgeom/IfcRegisterCreateCache.h - ../src/ifcgeom/IfcRegisterDef.h - ../src/ifcgeom/IfcRegisterGeomHeader.h - ../src/ifcgeom/IfcRegisterPurgeCache.h - ../src/ifcgeom/IfcRegisterShapeType.h - ../src/ifcgeom/IfcRegisterUndef.h - ../src/ifcgeom/IfcRepresentationShapeItem.h -) - -SET(include_files_parse - ../src/ifcparse/Ifc2x3-latebound.h - ../src/ifcparse/Ifc2x3.h - ../src/ifcparse/Ifc2x3enum.h - ../src/ifcparse/Ifc4-latebound.h - ../src/ifcparse/Ifc4.h - ../src/ifcparse/Ifc4enum.h - ../src/ifcparse/IfcCharacterDecoder.h - ../src/ifcparse/IfcEntityDescriptor.h - ../src/ifcparse/IfcException.h - ../src/ifcparse/IfcFile.h - ../src/ifcparse/IfcGlobalId.h - ../src/ifcparse/IfcHierarchyHelper.h - ../src/ifcparse/IfcLateBoundEntity.h - ../src/ifcparse/IfcParse.h - ../src/ifcparse/IfcSIPrefix.h - ../src/ifcparse/IfcSpfHeader.h - ../src/ifcparse/IfcSpfStream.h - ../src/ifcparse/IfcUtil.h - ../src/ifcparse/IfcWritableEntity.h - ../src/ifcparse/IfcWrite.h - ../src/ifcparse/SharedPointer.h -) -INSTALL(FILES ${include_files_geom} DESTINATION include/ifcgeom) -INSTALL(FILES ${include_files_parse} DESTINATION include/ifcparse) -INSTALL(TARGETS IfcConvert DESTINATION bin) +INSTALL(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) diff --git a/nix/build-all.sh b/nix/build-all.sh new file mode 100755 index 0000000000..aa32fc2307 --- /dev/null +++ b/nix/build-all.sh @@ -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 . # +# # +############################################################################### + +############################################################################### +# # +# 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" diff --git a/src/examples/CMakeLists.txt b/src/examples/CMakeLists.txt index e572379ec1..0f0da6a525 100644 --- a/src/examples/CMakeLists.txt +++ b/src/examples/CMakeLists.txt @@ -1,5 +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 . # +# # +################################################################################ + ADD_EXECUTABLE(IfcParseExamples IfcParseExamples.cpp) -TARGET_LINK_LIBRARIES (IfcParseExamples IfcParse) +TARGET_LINK_LIBRARIES(IfcParseExamples IfcParse) ADD_EXECUTABLE(IfcOpenHouse IfcOpenHouse.cpp) -TARGET_LINK_LIBRARIES (IfcOpenHouse IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKOffset) +TARGET_LINK_LIBRARIES(IfcOpenHouse IfcParse IfcGeom ${OPENCASCADE_LIBRARIES}) diff --git a/src/examples/IfcOpenHouse.cpp b/src/examples/IfcOpenHouse.cpp index 5cfb523f63..c7414e76e7 100644 --- a/src/examples/IfcOpenHouse.cpp +++ b/src/examples/IfcOpenHouse.cpp @@ -41,6 +41,10 @@ #include "../ifcparse/IfcHierarchyHelper.h" #include "../ifcgeom/IfcGeom.h" +#if USE_VLD +#include +#endif + // Some convenience typedefs and definitions. typedef std::string S; typedef IfcParse::IfcGlobalId guid; @@ -50,7 +54,7 @@ boost::none_t const null = boost::none; // The creation of Nurbs-surface for the IfcSite mesh, to be implemented lateron void createGroundShape(TopoDS_Shape& shape); -int main(int argc, char** argv) { +int main() { // The IfcHierarchyHelper is a subclass of the regular IfcFile that provides several // convenience functions for working with geometry in IFC files. @@ -195,43 +199,46 @@ int main(int argc, char** argv) { file.addBuildingProduct(north_wall); file.setSurfaceColour(north_wall->Representation(), wall_colour); - IfcSchema::IfcShapeRepresentation* clipped_wall_body_rep = file.addEmptyRepresentation(); - file.addBox(clipped_wall_body_rep, 5000, 360, 6000); - // The east wall geometry is clipped using two IfcHalfSpaceSolids, created from an - // 'axis 3d placement' that specifies the plane against which the geometry is clipped. - file.clipRepresentation(clipped_wall_body_rep, file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false); - file.clipRepresentation(clipped_wall_body_rep, file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false); + // Two identical representations are created for the two remaining walls. Mapped items + // are not used, because it is not allowed by the standard for wall body representations. + // MappedItems are not allowed for Axis representations as per CV-2x3-161 + IfcSchema::IfcProductDefinitionShape* clipped_wall_body_reps[2]; + for (int i = 0; i < 2; ++i) { + IfcSchema::IfcShapeRepresentation* body = file.addEmptyRepresentation(); + file.addBox(body, 5000, 360, 6000); + // The wall geometry is clipped using two IfcHalfSpaceSolids, created from an + // 'axis 3d placement' that specifies the plane against which the geometry is clipped. + file.clipRepresentation(body, file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false); + file.clipRepresentation(body, file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false); + file.setSurfaceColour(body, wall_colour); + + IfcSchema::IfcShapeRepresentation* axis = file.addEmptyRepresentation("Axis", "Curve2D"); + file.addAxis(axis, 5000); + + IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list); + reps->push(body); + reps->push(axis); + clipped_wall_body_reps[i] = new IfcSchema::IfcProductDefinitionShape(null, null, reps); + } // Now create a wall on the east of the building, again starting with just a box shape IfcSchema::IfcWallStandardCase* east_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle(), - S("East wall"), null, null, file.addLocalPlacement(storey_placement, 4820, 2500, 0, 0, 0, 1, 0, 1, 0), file.addMappedItem(clipped_wall_body_rep), null + S("East wall"), null, null, file.addLocalPlacement(storey_placement, 4820, 2500, 0, 0, 0, 1, 0, 1, 0), clipped_wall_body_reps[0], null #ifdef USE_IFC4 , IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD #endif ); file.addBuildingProduct(east_wall); - file.setSurfaceColour(clipped_wall_body_rep, wall_colour); - // The east wall is copied to the west location of the house IfcSchema::IfcWallStandardCase* west_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle(), - S("West wall"), null, null, file.addLocalPlacement(storey_placement, -4820, 2500, 0, 0, 0, 1, 0, -1, 0), file.addMappedItem(clipped_wall_body_rep), null + S("West wall"), null, null, file.addLocalPlacement(storey_placement, -4820, 2500, 0, 0, 0, 1, 0, -1, 0), clipped_wall_body_reps[1], null #ifdef USE_IFC4 , IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD #endif ); file.addBuildingProduct(west_wall); - for (int i = 0; i < 2; ++i) { - // CV-2x3-161: MappedItems are not allowed for Axis representations - IfcSchema::IfcWallStandardCase* wall = i == 0 ? east_wall : west_wall; - IfcSchema::IfcShapeRepresentation* wall_axis_rep = file.addEmptyRepresentation("Axis", "Curve2D"); - file.addAxis(wall_axis_rep, 5000); - IfcSchema::IfcRepresentation::list::ptr reps = wall->Representation()->Representations(); - reps->push(wall_axis_rep); - wall->Representation()->setRepresentations(reps); - } - // The west wall is assigned an opening element we created for the south wall, opening elements are // not shared accross building elements, even if they share the same representation. Hence, the east // wall will not feature this opening. @@ -381,6 +388,10 @@ int main(int argc, char** argv) { file.setSurfaceColour(door->Representation(), 0.9, 0.9, 0.9); file.addEntity(new IfcSchema::IfcRelFillsElement(guid(), file.getSingle(), null, null, door_opening, door)); + IfcSchema::IfcDoorStyle* door_style = new IfcSchema::IfcDoorStyle(guid(), file.getSingle(), S("Door type"), null, null, null, null, null, + IfcSchema::IfcDoorStyleOperationEnum::IfcDoorStyleOperation_SINGLE_SWING_LEFT, IfcSchema::IfcDoorStyleConstructionEnum::IfcDoorStyleConstruction_WOOD, false, false); + file.addRelatedObject(door_style, door); + // Surface styles are assigned to representation items, hence there is no real limitation to // assign different colours within the same representation. However, some viewers have // difficulties rendering products with representation items with different surface styles. diff --git a/src/examples/IfcParseExamples.cpp b/src/examples/IfcParseExamples.cpp index 342a6e8674..7ae158a67f 100644 --- a/src/examples/IfcParseExamples.cpp +++ b/src/examples/IfcParseExamples.cpp @@ -19,6 +19,10 @@ #include "../ifcparse/IfcFile.h" +#if USE_VLD +#include +#endif + using namespace IfcSchema; int main(int argc, char** argv) { diff --git a/src/ifcconvert/ColladaSerializer.cpp b/src/ifcconvert/ColladaSerializer.cpp index 2f9b54fbf1..bf3e65b2ca 100644 --- a/src/ifcconvert/ColladaSerializer.cpp +++ b/src/ifcconvert/ColladaSerializer.cpp @@ -39,8 +39,8 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const COLLADASW::FloatSource source(mSW); source.setId(mesh_id + suffix); source.setArrayId(mesh_id + suffix + COLLADASW::LibraryGeometries::ARRAY_ID_SUFFIX); - source.setAccessorStride(strlen(coords)); - source.setAccessorCount(floats.size() / 3); + source.setAccessorStride((unsigned long)strlen(coords)); + source.setAccessorCount((unsigned long)floats.size() / 3); for (unsigned int i = 0; i < source.getAccessorStride(); ++i) { source.getParameterNameList().push_back(std::string(1, coords[i])); } @@ -73,7 +73,7 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str int previous_material_id = -1; for (std::vector::const_iterator it = faces.begin(); !faces.empty(); it += 3) { const int current_material_id = *(material_it++); - const int num_triangles = std::distance(index_range_start, it) / 3; + const unsigned long num_triangles = (unsigned long)std::distance(index_range_start, it) / 3; if ((previous_material_id != current_material_id && num_triangles > 0) || (it == faces.end())) { COLLADASW::Triangles triangles(mSW); triangles.setMaterial(materials[previous_material_id].name()); @@ -126,9 +126,9 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str for (linelist_t::const_iterator it = linelist.begin(); it != linelist.end(); ++it) { COLLADASW::Lines lines(mSW); lines.setMaterial(materials[it->first].name()); - lines.setCount(it->second.size()); + lines.setCount((unsigned long)it->second.size()); int offset = 0; - lines.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX, "#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, 0)); + lines.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX, "#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++)); lines.prepareToAppendValues(); lines.appendValues(it->second); lines.finish(); diff --git a/src/ifcconvert/ColladaSerializer.h b/src/ifcconvert/ColladaSerializer.h index 63421d5f85..cf3a35e733 100644 --- a/src/ifcconvert/ColladaSerializer.h +++ b/src/ifcconvert/ColladaSerializer.h @@ -22,6 +22,10 @@ #ifndef COLLADASERIALIZER_H #define COLLADASERIALIZER_H +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4201 4512) +#endif #include #include #include @@ -34,6 +38,9 @@ #include #include #include +#ifdef _MSC_VER +#pragma warning(pop) +#endif #include "../ifcgeom/IfcGeomIterator.h" @@ -41,12 +48,15 @@ class ColladaSerializer : public GeometrySerializer { + // TODO The vast amount of implement details of ColladaSerializer could be hidden to the cpp file. private: class ColladaExporter { private: class ColladaGeometries : public COLLADASW::LibraryGeometries { + ColladaGeometries(const ColladaGeometries&); //N/A + ColladaGeometries& operator =(const ColladaGeometries&); //N/A public: explicit ColladaGeometries(COLLADASW::StreamWriter& stream) : COLLADASW::LibraryGeometries(&stream) @@ -58,6 +68,9 @@ private: class ColladaScene : public COLLADASW::LibraryVisualScenes { private: + ColladaScene(const ColladaScene&); //N/A + ColladaScene& operator =(const ColladaScene&); //N/A + const std::string scene_id; bool scene_opened; public: @@ -71,9 +84,13 @@ private: }; class ColladaMaterials : public COLLADASW::LibraryMaterials { + ColladaMaterials(const ColladaMaterials&); //N/A + ColladaMaterials& operator =(const ColladaMaterials&); //N/A private: class ColladaEffects : public COLLADASW::LibraryEffects { + ColladaEffects(const ColladaEffects&); //N/A + ColladaEffects& operator =(const ColladaEffects&); //N/A public: explicit ColladaEffects(COLLADASW::StreamWriter& stream) : COLLADASW::LibraryEffects(&stream) @@ -148,7 +165,7 @@ public: bool ready(); void writeHeader(); void write(const IfcGeom::TriangulationElement* o); - void write(const IfcGeom::BRepElement* o) {} + void write(const IfcGeom::BRepElement* /*o*/) {} void finalize(); bool isTesselated() const { return true; } void setUnitNameAndMagnitude(const std::string& name, float magnitude) { diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index ec307f20f7..359795478b 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -32,6 +32,7 @@ #include #include +#include #include "../ifcparse/Hdf5Settings.h" @@ -44,6 +45,13 @@ #include "../ifcconvert/XmlSerializer.h" #include "../ifcconvert/SvgSerializer.h" +#include +#include + +#if USE_VLD +#include +#endif + static std::string DEFAULT_EXTENSION = "obj"; void printVersion() { @@ -124,11 +132,17 @@ int main(int argc, char** argv) { "This is a potentially time consuming operation, but guarantees a " "consistent orientation of surface normals, even if the faces are not " "properly oriented in the IFC file.") +#if OCC_VERSION_HEX < 0x60900 + // In Open CASCADE version prior to 6.9.0 boolean operations with multiple + // arguments where not introduced yet and a work-around was implemented to + // subtract multiple openings as a single compound. This hack is obsolete + // for newer versions of Open CASCADE. ("merge-boolean-operands", "Specifies whether to merge all IfcOpeningElement operands into a single " "operand before applying the subtraction operation. This may " "introduce a performance improvement at the risk of failing, in " "which case the subtraction is applied one-by-one.") +#endif ("disable-opening-subtractions", "Specifies whether to disable the boolean subtraction of " "IfcOpeningElement Representations from their RelatingElements.") @@ -186,7 +200,9 @@ int main(int argc, char** argv) { const bool use_world_coords = vmap.count("use-world-coords") != 0; const bool convert_back_units = vmap.count("convert-back-units") != 0; const bool sew_shells = vmap.count("sew-shells") != 0; +#if OCC_VERSION_HEX < 0x60900 const bool merge_boolean_operands = vmap.count("merge-boolean-operands") != 0; +#endif const bool disable_opening_subtractions = vmap.count("disable-opening-subtractions") != 0; bool include_entities = vmap.count("include") != 0; const bool include_plan = vmap.count("plan") != 0; @@ -207,11 +223,8 @@ int main(int argc, char** argv) { // Gets the set ifc types to be ignored from the command line. std::set entities; for (std::vector::const_iterator it = entity_vector.begin(); it != entity_vector.end(); ++it) { - std::string lowercase_type = *it; - for (std::string::iterator c = lowercase_type.begin(); c != lowercase_type.end(); ++c) { - *c = tolower(*c); - } - entities.insert(lowercase_type); + const std::string& mixed_case_type = *it; + entities.insert(boost::to_lower_copy(mixed_case_type)); } const std::string input_filename = vmap["input-file"].as(); @@ -227,9 +240,7 @@ int main(int argc, char** argv) { } std::string output_extension = output_filename.substr(output_filename.size()-4); - for (std::string::iterator c = output_extension.begin(); c != output_extension.end(); ++c) { - *c = tolower(*c); - } + boost::to_lower(output_extension); // If no entities are specified these are the defaults to skip from output if (entity_vector.empty()) { @@ -292,7 +303,9 @@ int main(int argc, char** argv) { settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, weld_vertices); settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, sew_shells); settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, convert_back_units); +#if OCC_VERSION_HEX < 0x60900 settings.set(IfcGeom::IteratorSettings::FASTER_BOOLEANS, merge_boolean_operands); +#endif settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, disable_opening_subtractions); settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, include_plan); settings.set(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES, !include_model); diff --git a/src/ifcconvert/IgesSerializer.h b/src/ifcconvert/IgesSerializer.h index 8591af9902..5e11e7b324 100644 --- a/src/ifcconvert/IgesSerializer.h +++ b/src/ifcconvert/IgesSerializer.h @@ -20,7 +20,6 @@ #ifndef IGESSERIALIZER_H #define IGESSERIALIZER_H -#include #include #include @@ -43,9 +42,10 @@ public: void finalize() { writer.Write(out_filename.c_str()); } - void setUnitNameAndMagnitude(const std::string& name, float magnitude) { + void setUnitNameAndMagnitude(const std::string& /*name*/, float magnitude) { const char* symbol = getSymbolForUnitMagnitude(magnitude); if (symbol) { + Interface_Static::SetCVal("xstep.cascade.unit", symbol); Interface_Static::SetCVal("write.iges.unit", symbol); } } diff --git a/src/ifcconvert/OpenCascadeBasedSerializer.cpp b/src/ifcconvert/OpenCascadeBasedSerializer.cpp index 77bc7e7fc9..2dbb642c3d 100644 --- a/src/ifcconvert/OpenCascadeBasedSerializer.cpp +++ b/src/ifcconvert/OpenCascadeBasedSerializer.cpp @@ -40,20 +40,14 @@ void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement* o) { for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) { gp_GTrsf gtrsf = it->Placement(); - const std::vector& matrix = o->transformation().matrix().data(); - - // Convert the matrix back into a transformation object. The tolerance values - // are taken into consideration to reconstruct the form of the transformation. - gp_Trsf o_trsf; - o_trsf.SetValues( - matrix[0], matrix[3], matrix[6], matrix[ 9], - matrix[1], matrix[4], matrix[7], matrix[10], - matrix[2], matrix[5], matrix[8], matrix[11] -#if OCC_VERSION_HEX < 0x60800 - , Precision::Angular(), Precision::Confusion() -#endif - ); + const gp_Trsf& o_trsf = o->transformation().data(); gtrsf.PreMultiply(o_trsf); + + if (o->geometry().settings().convert_back_units()) { + gp_Trsf scale; + scale.SetScaleFactor(1.0 / o->geometry().settings().unit_magnitude()); + gtrsf.PreMultiply(scale); + } const TopoDS_Shape& s = it->Shape(); diff --git a/src/ifcconvert/OpenCascadeBasedSerializer.h b/src/ifcconvert/OpenCascadeBasedSerializer.h index 74a76ca341..6ee69635a4 100644 --- a/src/ifcconvert/OpenCascadeBasedSerializer.h +++ b/src/ifcconvert/OpenCascadeBasedSerializer.h @@ -25,8 +25,10 @@ #include "../ifcconvert/GeometrySerializer.h" class OpenCascadeBasedSerializer : public GeometrySerializer { + OpenCascadeBasedSerializer(const OpenCascadeBasedSerializer&); //N/A + OpenCascadeBasedSerializer& operator =(const OpenCascadeBasedSerializer&); //N/A protected: - const std::string& out_filename; + const std::string out_filename; const char* getSymbolForUnitMagnitude(float mag); public: explicit OpenCascadeBasedSerializer(const std::string& out_filename) @@ -35,10 +37,9 @@ public: {} virtual ~OpenCascadeBasedSerializer() {} void writeHeader() {} - void writeMaterial(const IfcGeom::SurfaceStyle& style) {} bool ready(); virtual void writeShape(const TopoDS_Shape& shape) = 0; - void write(const IfcGeom::TriangulationElement* o) {} + void write(const IfcGeom::TriangulationElement* /*o*/) {} void write(const IfcGeom::BRepElement* o); bool isTesselated() const { return false; } void setFile(IfcParse::IfcFile*) {} diff --git a/src/ifcconvert/StepSerializer.h b/src/ifcconvert/StepSerializer.h index 4667104a38..ff53fa4ae4 100644 --- a/src/ifcconvert/StepSerializer.h +++ b/src/ifcconvert/StepSerializer.h @@ -20,7 +20,6 @@ #ifndef STEPSERIALIZER_H #define STEPSERIALIZER_H -#include #include #include @@ -49,9 +48,10 @@ public: writer.Write(out_filename.c_str()); std::cout.rdbuf(sb); } - void setUnitNameAndMagnitude(const std::string& name, float magnitude) { + void setUnitNameAndMagnitude(const std::string& /*name*/, float magnitude) { const char* symbol = getSymbolForUnitMagnitude(magnitude); if (symbol) { + Interface_Static::SetCVal("xstep.cascade.unit", symbol); Interface_Static::SetCVal("write.step.unit", symbol); } } diff --git a/src/ifcconvert/SvgSerializer.cpp b/src/ifcconvert/SvgSerializer.cpp index 0500699522..9ee477d2ea 100644 --- a/src/ifcconvert/SvgSerializer.cpp +++ b/src/ifcconvert/SvgSerializer.cpp @@ -43,7 +43,7 @@ #include #include #include - +#include #include "../ifcparse/IfcGlobalId.h" #include "SvgSerializer.h" @@ -90,16 +90,10 @@ void SvgSerializer::write(path_object& p, const TopoDS_Wire& wire) { path.add(","); addYCoordinate(path.add(p1.Y())); - if (p1.X() < xmin) xmin = p1.X(); - if (p1.X() > xmax) xmax = p1.X(); - if (p1.Y() < ymin) ymin = p1.Y(); - if (p1.Y() > ymax) ymax = p1.Y(); + growBoundingBox(p1.X(), p1.Y()); } - if (p2.X() < xmin) xmin = p2.X(); - if (p2.X() > xmax) xmax = p2.X(); - if (p2.Y() < ymin) ymin = p2.Y(); - if (p2.Y() > ymax) ymax = p2.Y(); + growBoundingBox(p2.X(), p2.Y()); Handle(Standard_Type) ty = curve->DynamicType(); @@ -184,7 +178,7 @@ void SvgSerializer::write(const IfcGeom::BRepElement* o) { typedef IfcSchema::IfcRelAggregates decomposition_element; #endif - while (true) { + for (;;) { // Iterate over the decomposing element to find the parent IfcBuildingStorey decomposition_element::list::ptr decomposes = obdef->Decomposes(); if (!decomposes->size()) { @@ -218,22 +212,14 @@ void SvgSerializer::write(const IfcGeom::BRepElement* o) { if (!storey) return; - path_object& p = start_path(storey, o->unique_id()); + path_object& p = start_path(storey, nameElement(o)); for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) { gp_GTrsf gtrsf = it->Placement(); - gp_Trsf o_trsf; - const std::vector& matrix = o->transformation().matrix().data(); - o_trsf.SetValues( - matrix[0], matrix[3], matrix[6], matrix[ 9], - matrix[1], matrix[4], matrix[7], matrix[10], - matrix[2], matrix[5], matrix[8], matrix[11] -#if OCC_VERSION_HEX < 0x60800 - , Precision::Angular(), Precision::Confusion() -#endif - ); + const gp_Trsf& o_trsf = o->transformation().data(); gtrsf.PreMultiply(o_trsf); + const TopoDS_Shape& s = it->Shape(); bool trsf_valid = false; @@ -310,7 +296,7 @@ void SvgSerializer::finalize() { const double cx = xmin * sc; const double cy = ymin * sc; - {std::vector< SHARED_PTR >::const_iterator it; + {std::vector< boost::shared_ptr >::const_iterator it; for (it = xcoords.begin(); it != xcoords.end(); ++it) { double& v = (*it)->value(); v = v * sc - cx; @@ -334,9 +320,9 @@ void SvgSerializer::finalize() { svg_file << " \n"; } std::ostringstream oss; - svg_file << " first->GlobalId()).formatted() << "\">\n"; + svg_file << " first) << ">\n"; } - svg_file << " second.first << "\">\n"; + svg_file << " second.first << ">\n"; std::vector::const_iterator jt; for (jt = it->second.second.begin(); jt != it->second.second.end(); ++jt) { svg_file << jt->str(); @@ -353,3 +339,17 @@ void SvgSerializer::finalize() { void SvgSerializer::writeHeader() { svg_file << "\n"; } + +std::string SvgSerializer::nameElement(const IfcGeom::Element* elem) { + std::ostringstream oss; + const std::string type = "product"; + oss << "id=\"" << type << "-" << elem->unique_id() << "\""; + return oss.str(); +} + +std::string SvgSerializer::nameElement(const IfcSchema::IfcProduct* elem) { + std::ostringstream oss; + const std::string type = elem->declaration().is(IfcSchema::Type::IfcBuildingStorey) ? "storey" : "product"; + oss << "id=\"product-" << IfcParse::IfcGlobalId(elem->GlobalId()).formatted() << "\""; + return oss.str(); +} diff --git a/src/ifcconvert/SvgSerializer.h b/src/ifcconvert/SvgSerializer.h index 04dbb34188..46e44f73bb 100644 --- a/src/ifcconvert/SvgSerializer.h +++ b/src/ifcconvert/SvgSerializer.h @@ -35,15 +35,14 @@ class SvgSerializer : public GeometrySerializer { public: typedef std::pair > path_object; protected: - const char* getSymbolForUnitMagnitude(float mag); std::ofstream svg_file; double xmin, ymin, xmax, ymax, width, height; boost::optional section_height; bool rescale; std::multimap paths; - std::vector< SHARED_PTR > xcoords; - std::vector< SHARED_PTR > ycoords; - std::vector< SHARED_PTR > radii; + std::vector< boost::shared_ptr > xcoords; + std::vector< boost::shared_ptr > ycoords; + std::vector< boost::shared_ptr > radii; IfcParse::IfcFile* file; public: explicit SvgSerializer(const std::string& out_filename) @@ -56,23 +55,25 @@ public: , rescale(false) , file(0) {} - virtual void addXCoordinate(const SHARED_PTR& fi) { xcoords.push_back(fi); } - virtual void addYCoordinate(const SHARED_PTR& fi) { ycoords.push_back(fi); } - virtual void addSizeComponent(const SHARED_PTR& fi) { radii.push_back(fi); } + virtual void addXCoordinate(const boost::shared_ptr& fi) { xcoords.push_back(fi); } + virtual void addYCoordinate(const boost::shared_ptr& fi) { ycoords.push_back(fi); } + virtual void addSizeComponent(const boost::shared_ptr& fi) { radii.push_back(fi); } + virtual void growBoundingBox(double x, double y) { if (x < xmin) xmin = x; if (x > xmax) xmax = x; if (y < ymin) ymin = y; if (y > ymax) ymax = y; } virtual ~SvgSerializer() {} virtual void writeHeader(); - virtual void writeMaterial(const IfcGeom::SurfaceStyle& style) {} virtual bool ready(); - virtual void write(const IfcGeom::TriangulationElement* o) {} + virtual void write(const IfcGeom::TriangulationElement* /*o*/) {} virtual void write(const IfcGeom::BRepElement* o); virtual void write(path_object& p, const TopoDS_Wire& wire); virtual path_object& start_path(IfcSchema::IfcBuildingStorey* storey, const std::string& id); virtual bool isTesselated() const { return false; } virtual void finalize(); - virtual void setUnitNameAndMagnitude(const std::string& name, float magnitude) {} + virtual void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {} virtual void setFile(IfcParse::IfcFile* f) { file = f; } virtual void setBoundingRectangle(double width, double height); virtual void setSectionHeight(double h) { section_height = h; } + virtual std::string nameElement(const IfcGeom::Element* elem); + virtual std::string nameElement(const IfcSchema::IfcProduct* elem); }; #endif diff --git a/src/ifcconvert/WavefrontObjSerializer.cpp b/src/ifcconvert/WavefrontObjSerializer.cpp index 19643be430..4bd3f243df 100644 --- a/src/ifcconvert/WavefrontObjSerializer.cpp +++ b/src/ifcconvert/WavefrontObjSerializer.cpp @@ -17,12 +17,13 @@ * * ********************************************************************************/ +#include +#include + #include "../ifcgeom/IfcGeomRenderStyles.h" #include "WavefrontObjSerializer.h" -#include - bool WaveFrontOBJSerializer::ready() { return obj_stream.is_open() && mtl_stream.is_open(); } @@ -70,9 +71,11 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement* obj_stream << "g " << o->unique_id() << "\n"; obj_stream << "s 1" << "\n"; + obj_stream << std::setprecision(std::numeric_limits::digits10); + const IfcGeom::Representation::Triangulation& mesh = o->geometry(); - const int vcount = mesh.verts().size() / 3; + const int vcount = (int)mesh.verts().size() / 3; for ( std::vector::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) { const double x = *(it++); const double y = *(it++); diff --git a/src/ifcconvert/WavefrontObjSerializer.h b/src/ifcconvert/WavefrontObjSerializer.h index 7cb67909d2..1b1ae7d69d 100644 --- a/src/ifcconvert/WavefrontObjSerializer.h +++ b/src/ifcconvert/WavefrontObjSerializer.h @@ -46,10 +46,10 @@ public: void writeHeader(); void writeMaterial(const IfcGeom::Material& style); void write(const IfcGeom::TriangulationElement* o); - void write(const IfcGeom::BRepElement* o) {} + void write(const IfcGeom::BRepElement* /*o*/) {} void finalize() {} bool isTesselated() const { return true; } - void setUnitNameAndMagnitude(const std::string& name, float magnitude) {} + void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {} void setFile(IfcParse::IfcFile*) {} }; diff --git a/src/ifcconvert/XmlSerializer.cpp b/src/ifcconvert/XmlSerializer.cpp index 7ae2c31c13..0f9e7c0489 100644 --- a/src/ifcconvert/XmlSerializer.cpp +++ b/src/ifcconvert/XmlSerializer.cpp @@ -1,3 +1,22 @@ +/******************************************************************************** +* * +* 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 . * +* * +********************************************************************************/ + #include #include @@ -7,6 +26,8 @@ #include "XmlSerializer.h" +#include + using boost::property_tree::ptree; using namespace IfcSchema; @@ -58,7 +79,8 @@ boost::optional format_attribute(const Argument* argument, IfcUtil: unit_name = unit->Name(); } - for (std::string::iterator c = unit_name.begin(); c != unit_name.end(); ++c) *c = tolower(*c); + // TODO add toLower() and toUpper() string helper functions for the project + std::transform(unit_name.begin(), unit_name.end(), unit_name.begin(), ::tolower); value = unit_name; } diff --git a/src/ifcconvert/util.cpp b/src/ifcconvert/util.cpp index 3e6668f53b..cde3645d72 100644 --- a/src/ifcconvert/util.cpp +++ b/src/ifcconvert/util.cpp @@ -24,19 +24,19 @@ using namespace util; -SHARED_PTR string_buffer::add(const std::string& s) { - SHARED_PTR i = SHARED_PTR(new string_item(s)); +boost::shared_ptr string_buffer::add(const std::string& s) { + boost::shared_ptr i = boost::shared_ptr(new string_item(s)); items.push_back(i); return i; } -SHARED_PTR string_buffer::add(const double& d) { - SHARED_PTR i = SHARED_PTR(new float_item(d)); +boost::shared_ptr string_buffer::add(const double& d) { + boost::shared_ptr i = boost::shared_ptr(new float_item(d)); items.push_back(i); return i; } std::string string_buffer::str() const { std::stringstream ss; - for (std::vector< SHARED_PTR >::const_iterator it = items.begin(); it != items.end(); ++it) { + for (std::vector< boost::shared_ptr >::const_iterator it = items.begin(); it != items.end(); ++it) { ss << (**it).str(); } return ss.str(); diff --git a/src/ifcconvert/util.h b/src/ifcconvert/util.h index ee69f9f3b6..3a52c05973 100644 --- a/src/ifcconvert/util.h +++ b/src/ifcconvert/util.h @@ -23,7 +23,7 @@ #include #include -#include "../ifcparse/SharedPointer.h" +#include namespace util { class string_buffer { @@ -51,12 +51,12 @@ namespace util { std::string str() const { std::stringstream ss; ss << d; return ss.str(); } }; private: - std::vector< SHARED_PTR > items; + std::vector< boost::shared_ptr > items; void clear(); - void assign(const std::vector< SHARED_PTR >& other); + void assign(const std::vector< boost::shared_ptr >& other); public: - SHARED_PTR add(const std::string& s); - SHARED_PTR add(const double& d); + boost::shared_ptr add(const std::string& s); + boost::shared_ptr add(const double& d); std::string str() const; }; } diff --git a/src/ifcexpressparser/README.txt b/src/ifcexpressparser/README.txt index d4c4176084..ede43994d3 100644 --- a/src/ifcexpressparser/README.txt +++ b/src/ifcexpressparser/README.txt @@ -4,6 +4,8 @@ the IFC schema and will most likely fail on any other Express schema. The code can be invoked in the following way and results in two header files and a single implementation file named according to the schema name in the -Express file. A python 3 interpreter with the pyparsing library is required. +Express file. A python 3 interpreter with the pyparsing [1] library is required. $ python bootstrap.py express.bnf > express_parser.py && python express_parser.py IFC2X3_TC1.exp + +[1] http://pyparsing.wikispaces.com/Download+and+Installation diff --git a/src/ifcexpressparser/bootstrap.py b/src/ifcexpressparser/bootstrap.py index c9557c769d..badc70a690 100644 --- a/src/ifcexpressparser/bootstrap.py +++ b/src/ifcexpressparser/bootstrap.py @@ -196,4 +196,6 @@ implementation.Implementation(mapping).emit() latebound_header.LateBoundHeader(mapping).emit() latebound_implementation.LateBoundImplementation(mapping).emit() schema_class.SchemaClass(mapping).emit() + +sys.stdout.write(mapping.schema.name) """%('\n '.join(statements))) diff --git a/src/ifcexpressparser/codegen.py b/src/ifcexpressparser/codegen.py new file mode 100644 index 0000000000..6370b3dc87 --- /dev/null +++ b/src/ifcexpressparser/codegen.py @@ -0,0 +1,34 @@ +############################################################################### +# # +# 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 . # +# # +############################################################################### + +class Base(object): + """ + A base class for all code generation classes. Currently only working around + some python 2/3 incompatibilities in terms of unicode file handling. + """ + def emit(self): + import platform + if tuple(map(int, platform.python_version_tuple())) < (2, 8): + from io import open as unicode_open + else: + unicode_open = open + unicode = lambda x, *args, **kwargs: x + f = unicode_open(self.file_name, 'w', encoding='utf-8') + f.write(unicode(repr(self), encoding='utf-8', errors='ignore')) + f.close() diff --git a/src/ifcexpressparser/documentation.py b/src/ifcexpressparser/documentation.py index e83bc132a8..ef8bde5a69 100644 --- a/src/ifcexpressparser/documentation.py +++ b/src/ifcexpressparser/documentation.py @@ -27,11 +27,15 @@ # # ############################################################################### -import re,csv +import re +import os import csv + try: from html.entities import entitydefs except: from htmlentitydefs import entitydefs +make_absolute = lambda fn: os.path.join(os.path.dirname(os.path.realpath(__file__)), fn) + name_to_oid = {} oid_to_desc = {} oid_to_name = {} @@ -39,6 +43,7 @@ oid_to_pid = {} regices = list(zip([re.compile(s,re.M) for s in [r'<[\w\n=" \-/\.;_\t:%#,\?\(\)]+>',r'(\n[\t ]*){2,}',r'^[\t ]+']],['','\n\n',' '])) definition_files = ['DocEntity.csv', 'DocEnumeration.csv', 'DocDefined.csv', 'DocSelect.csv'] +definition_files = map(make_absolute, definition_files) for fn in definition_files: with open(fn) as f: for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'): @@ -46,11 +51,11 @@ for fn in definition_files: oid_to_name[oid] = name oid_to_desc[oid] = desc -with open('DocEntityAttributes.csv') as f: +with open(make_absolute('DocEntityAttributes.csv')) as f: for pid, x, oid in csv.reader(f, delimiter=';', quotechar='"'): oid_to_pid[oid] = pid -with open('DocAttribute.csv') as f: +with open(make_absolute('DocAttribute.csv')) as f: for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'): pid = oid_to_pid[oid] pname = oid_to_name[pid] diff --git a/src/ifcexpressparser/enum_header.py b/src/ifcexpressparser/enum_header.py index 96993ec13f..eb382a3e7a 100644 --- a/src/ifcexpressparser/enum_header.py +++ b/src/ifcexpressparser/enum_header.py @@ -18,8 +18,9 @@ ############################################################################### import templates +import codegen -class EnumHeader: +class EnumHeader(codegen.Base): def __init__(self, mapping): enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()])) @@ -30,9 +31,9 @@ class EnumHeader: } self.schema_name = mapping.schema.name.capitalize() + + self.file_name = '%senum.h'%self.schema_name + + def __repr__(self): return self.str - def emit(self): - f = open('%senum.h'%self.schema_name, 'w', encoding='utf-8') - f.write(str(self)) - f.close() diff --git a/src/ifcexpressparser/header.py b/src/ifcexpressparser/header.py index 51f4a89242..449506bc0f 100644 --- a/src/ifcexpressparser/header.py +++ b/src/ifcexpressparser/header.py @@ -17,10 +17,11 @@ # # ############################################################################### +import codegen import templates import documentation -class Header: +class Header(codegen.Base): def __init__(self, mapping): declarations = [] @@ -123,10 +124,9 @@ class Header: } self.schema_name = mapping.schema.name.capitalize() + + self.file_name = '%s.h'%self.schema_name + + def __repr__(self): return self.str - def emit(self): - f = open('%s.h'%self.schema_name, 'w', encoding='utf-8') - f.write(str(self)) - f.close() - diff --git a/src/ifcexpressparser/implementation.py b/src/ifcexpressparser/implementation.py index f574f3f7f5..d7f73a6e58 100644 --- a/src/ifcexpressparser/implementation.py +++ b/src/ifcexpressparser/implementation.py @@ -17,9 +17,10 @@ # # ############################################################################### +import codegen import templates -class Implementation: +class Implementation(codegen.Base): def __init__(self, mapping): enumeration_functions = [] entity_implementations = [] @@ -235,10 +236,9 @@ class Implementation: } self.schema_name = mapping.schema.name.capitalize() + + self.file_name = '%s.cpp'%self.schema_name + + def __repr__(self): return self.str - def emit(self): - f = open('%s.cpp'%self.schema_name, 'w', encoding='utf-8') - f.write(str(self)) - f.close() - diff --git a/src/ifcexpressparser/latebound_header.py b/src/ifcexpressparser/latebound_header.py index bf2db78f3e..251a288073 100644 --- a/src/ifcexpressparser/latebound_header.py +++ b/src/ifcexpressparser/latebound_header.py @@ -17,9 +17,10 @@ # # ############################################################################### +import codegen import templates -class LateBoundHeader: +class LateBoundHeader(codegen.Base): def __init__(self, mapping): self.str = templates.lb_header % { 'schema_name_upper' : mapping.schema.name.upper(), @@ -27,9 +28,9 @@ class LateBoundHeader: } self.schema_name = mapping.schema.name.capitalize() + + self.file_name = '%s-latebound.h'%self.schema_name + + def __repr__(self): return self.str - def emit(self): - f = open('%s-latebound.h'%self.schema_name, 'w', encoding='utf-8') - f.write(str(self)) - f.close() diff --git a/src/ifcexpressparser/latebound_implementation.py b/src/ifcexpressparser/latebound_implementation.py index fe9e600ecd..1303d000ff 100644 --- a/src/ifcexpressparser/latebound_implementation.py +++ b/src/ifcexpressparser/latebound_implementation.py @@ -17,9 +17,10 @@ # # ############################################################################### +import codegen import templates -class LateBoundImplementation: +class LateBoundImplementation(codegen.Base): def __init__(self, mapping): schema_name = mapping.schema.name.capitalize() @@ -110,10 +111,9 @@ class LateBoundImplementation: } self.schema_name = mapping.schema.name.capitalize() + + self.file_name = '%s-latebound.cpp'%self.schema_name + + def __repr__(self): return self.str - def emit(self): - f = open('%s-latebound.cpp'%self.schema_name, 'w', encoding='utf-8') - f.write(str(self)) - f.close() - diff --git a/src/ifcexpressparser/mapping.py b/src/ifcexpressparser/mapping.py index 76633f3746..5b9721e191 100644 --- a/src/ifcexpressparser/mapping.py +++ b/src/ifcexpressparser/mapping.py @@ -17,6 +17,8 @@ # # ############################################################################### +from __future__ import print_function + import sys import nodes import templates @@ -33,11 +35,11 @@ class Mapping: 'binary' : 'boost::dynamic_bitset<>' } - supported_argument_types = { + supported_argument_types = set([ 'INT', 'BOOL', 'DOUBLE', 'STRING', 'BINARY', 'ENUMERATION', 'ENTITY_INSTANCE', 'AGGREGATE_OF_INT', 'AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_STRING', 'AGGREGATE_OF_BINARY', 'AGGREGATE_OF_ENTITY_INSTANCE', 'AGGREGATE_OF_AGGREGATE_OF_INT', 'AGGREGATE_OF_AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE', - } + ]) def __init__(self, schema): self.schema = schema @@ -52,11 +54,11 @@ class Mapping: def simple_type_parent(self, type): parent = self.schema.types[type].type.type if isinstance(parent, nodes.AggregationType): parent = None - return None if parent in self.express_to_cpp_typemapping else parent + return None if str(parent) in self.express_to_cpp_typemapping else parent def make_type_string(self, type): - if isinstance(type, str): - return self.express_to_cpp_typemapping.get(type, type) + if isinstance(type, (str, nodes.BinaryType)): + return self.express_to_cpp_typemapping.get(str(type), type) else: is_list = self.schema.is_entity(type.type) is_nested_list = isinstance(type.type, nodes.AggregationType) @@ -83,12 +85,8 @@ class Mapping: def make_argument_type(self, attr): def _make_argument_type(type): - if type in self.express_to_cpp_typemapping: - return self.express_to_cpp_typemapping.get(type, type).split('::')[-1].upper() - elif self.schema.is_entity(type) or isinstance(type, nodes.SelectType): + if self.schema.is_entity(type) or isinstance(type, nodes.SelectType): return "ENTITY_INSTANCE" - elif self.schema.is_type(type): - return _make_argument_type(self.schema.types[type].type.type) elif isinstance(type, nodes.BinaryType): return "BINARY" elif isinstance(type, nodes.EnumerationType): @@ -97,17 +95,21 @@ class Mapping: ty = _make_argument_type(type.type) if ty == "UNKNOWN": return "UNKNOWN" return "AGGREGATE_OF_" + ty + elif str(type) in self.express_to_cpp_typemapping: + return self.express_to_cpp_typemapping.get(str(type), type).split('::')[-1].upper() + elif self.schema.is_type(type): + return _make_argument_type(self.schema.types[type].type.type) else: raise ValueError("Unable to map type %r for attribute %r" % (type, attr)) ty = _make_argument_type(attr.type if hasattr(attr, 'type') else attr) if ty not in self.supported_argument_types: - print("Attribute %r mapped as 'unknown'" % (type, attr), file=sys.stderr) + print("Attribute %r mapped as 'unknown'" % (attr), file=sys.stderr) ty = 'UNKNOWN' return "IfcUtil::Argument_%s" % ty def get_type_dep(self, type): if isinstance(type, str): - return self.express_to_cpp_typemapping.get(type, type) + return self.express_to_cpp_typemapping.get(str(type), type) else: return self.get_type_dep(type.type) @@ -124,7 +126,7 @@ class Mapping: ty = self.get_parameter_type(attr_type.type if is_nested_list else attr_type, False, allow_entities, False) if self.schema.is_select(attr_type.type): type_str = templates.untyped_list - elif self.schema.is_simpletype(ty) or ty in self.express_to_cpp_typemapping.values(): + elif self.schema.is_simpletype(ty) or str(ty) in self.express_to_cpp_typemapping.values(): tmpl = templates.nested_array_type if is_nested_list else templates.array_type type_str = tmpl % { 'instance_type' : ty, diff --git a/src/ifcexpressparser/schema.py b/src/ifcexpressparser/schema.py index 73ff5596fe..18335f3cdf 100644 --- a/src/ifcexpressparser/schema.py +++ b/src/ifcexpressparser/schema.py @@ -18,29 +18,34 @@ ############################################################################### import nodes +import platform import collections +if tuple(map(int, platform.python_version_tuple())) < (2, 7): + import ordereddict + collections.OrderedDict = ordereddict.OrderedDict + class Schema: def is_enumeration(self, v): - return v in self.enumerations + return str(v) in self.enumerations def is_select(self, v): - return v in self.selects + return str(v) in self.selects def is_simpletype(self, v): - return v in self.simpletypes + return str(v) in self.simpletypes def is_type(self, v): - return v in self.types + return str(v) in self.types def is_entity(self, v): - return v in self.entities + return str(v) in self.entities def __init__(self, parsetree): self.name = parsetree[1] - sort = lambda d: collections.OrderedDict(sorted(d.items())) + sort = lambda d: collections.OrderedDict(sorted(d)) - self.types = sort({t.name:t for t in parsetree if isinstance(t, nodes.TypeDeclaration)}) - self.entities = sort({t.name:t for t in parsetree if isinstance(t, nodes.EntityDeclaration)}) + self.types = sort([(t.name,t) for t in parsetree if isinstance(t, nodes.TypeDeclaration)]) + self.entities = sort([(t.name,t) for t in parsetree if isinstance(t, nodes.EntityDeclaration)]) - of_type = lambda *types: sort({a: b.type.type for a,b in self.types.items() if any(isinstance(b.type.type, ty) for ty in types)}) + of_type = lambda *types: sort([(a, b.type.type) for a,b in self.types.items() if any(isinstance(b.type.type, ty) for ty in types)]) self.enumerations = of_type(nodes.EnumerationType) self.selects = of_type(nodes.SelectType) - self.simpletypes = of_type(str, nodes.AggregationType) + self.simpletypes = of_type(str, nodes.AggregationType, nodes.BinaryType) diff --git a/src/ifcexpressparser/templates.py b/src/ifcexpressparser/templates.py index c067d9fa2d..ee47f8650d 100644 --- a/src/ifcexpressparser/templates.py +++ b/src/ifcexpressparser/templates.py @@ -23,7 +23,6 @@ header = """ #include #include -#include #include @@ -34,6 +33,11 @@ header = """ const IfcParse::schema_definition& get_schema(); +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + #define IfcSchema %(schema_name)s namespace %(schema_name)s { @@ -50,6 +54,10 @@ void InitStringMap(); IfcUtil::IfcBaseClass* SchemaEntity(IfcAbstractEntity* e = 0); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + #endif """ @@ -111,6 +119,8 @@ implementation= """ #include "../ifcparse/IfcWrite.h" #include "../ifcparse/IfcWritableEntity.h" +#include + using namespace %(schema_name)s; using namespace IfcParse; using namespace IfcWrite; @@ -268,49 +278,49 @@ std::pair Type::GetEnumerationIndex(Enum t, const std::string& } std::pair Type::GetInverseAttribute(Enum t, const std::string& a) { - if (inverse_map.empty()) ::InitInverseMap(); - inverse_map_t::const_iterator it; - inverse_map_t::mapped_type::const_iterator jt; - while (true) { + if (inverse_map.empty()) ::InitInverseMap(); + inverse_map_t::const_iterator it; + inverse_map_t::mapped_type::const_iterator jt; + for(;;) { it = inverse_map.find(t); if (it != inverse_map.end()) { - jt = it->second.find(a); - if (jt != it->second.end()) { - return jt->second; - } - } + jt = it->second.find(a); + if (jt != it->second.end()) { + return jt->second; + } + } if ((t = Parent(t)) == -1) break; } throw IfcException("Attribute not found"); } std::set Type::GetInverseAttributeNames(Enum t) { - if (inverse_map.empty()) ::InitInverseMap(); - inverse_map_t::const_iterator it; - inverse_map_t::mapped_type::const_iterator jt; + if (inverse_map.empty()) ::InitInverseMap(); + inverse_map_t::const_iterator it; + inverse_map_t::mapped_type::const_iterator jt; - std::set return_value; + std::set return_value; - while (true) { + for (;;) { it = inverse_map.find(t); if (it != inverse_map.end()) { - for (jt = it->second.begin(); jt != it->second.end(); ++jt) { - return_value.insert(jt->first); - } - } + for (jt = it->second.begin(); jt != it->second.end(); ++jt) { + return_value.insert(jt->first); + } + } if ((t = Parent(t)) == -1) break; } - - return return_value; + + return return_value; } void Type::PopulateDerivedFields(IfcWrite::IfcWritableEntity* e) { std::map >::const_iterator i = derived_map.find(e->type()); - if (i != derived_map.end()) { - for (std::set::const_iterator it = i->second.begin(); it != i->second.end(); ++it) { - e->setArgumentDerived(*it); - } - } + if (i != derived_map.end()) { + for (std::set::const_iterator it = i->second.begin(); it != i->second.end(); ++it) { + e->setArgumentDerived(*it); + } + } } """ diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index 88539d7b43..bcb08f9f5c 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -109,6 +109,7 @@ public: bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes); bool convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes); IfcSchema::IfcSurfaceStyleShading* get_surface_style(IfcSchema::IfcRepresentationItem* item); + const IfcSchema::IfcRepresentationItem* find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item); bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid); bool is_compound(const TopoDS_Shape& shape); bool is_convex(const TopoDS_Wire& wire); @@ -121,9 +122,12 @@ public: double face_area(const TopoDS_Face& f); void apply_tolerance(TopoDS_Shape& s, double t); void setValue(GeomValue var, double value); - double getValue(GeomValue var); + double getValue(GeomValue var) const; bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape); - void remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.); + void remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.); + void remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.); + bool wire_to_sequence_of_point(const TopoDS_Wire&, TColgp_SequenceOfPnt&); + void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed); std::pair initializeUnits(IfcSchema::IfcUnitAssignment*); @@ -135,6 +139,10 @@ public: const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem* representation_item); template std::pair get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) { + // For certain representation items, most notably boolean operands, + // a style definition might reside on one of its operands. + representation_item = find_item_carrying_style(representation_item); + IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem(); for (IfcSchema::IfcStyledItem::list::it jt = styled_items->begin(); jt != styled_items->end(); ++jt) { #ifdef USE_IFC4 diff --git a/src/ifcgeom/IfcGeomCurves.cpp b/src/ifcgeom/IfcGeomCurves.cpp index 2b0b1905cb..23eb1168d5 100644 --- a/src/ifcgeom/IfcGeomCurves.cpp +++ b/src/ifcgeom/IfcGeomCurves.cpp @@ -149,8 +149,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineCurveWithKnots* l, Hand const std::vector knots = l->Knots(); TColgp_Array1OfPnt Poles(0, cps->size() - 1); - TColStd_Array1OfReal Knots(0, knots.size() - 1); - TColStd_Array1OfInteger Mults(0, mults.size() - 1); + TColStd_Array1OfReal Knots(0, (int)knots.size() - 1); + TColStd_Array1OfInteger Mults(0, (int)mults.size() - 1); Standard_Integer Degree = l->Degree(); Standard_Boolean Periodic = l->ClosedCurve(); diff --git a/src/ifcgeom/IfcGeomFaces.cpp b/src/ifcgeom/IfcGeomFaces.cpp index 9ae4d974f7..296c4ddc50 100644 --- a/src/ifcgeom/IfcGeomFaces.cpp +++ b/src/ifcgeom/IfcGeomFaces.cpp @@ -88,6 +88,8 @@ #include #include +#include + #ifdef USE_IFC4 #include #include @@ -101,7 +103,6 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) { IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds(); Handle(Geom_Surface) face_surface; - bool reversed_face_surface = false; const bool is_face_surface = l->declaration().is(IfcSchema::Type::IfcFaceSurface); if (is_face_surface) { @@ -164,7 +165,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) { if (is_interior == !process_interior) continue; TopoDS_Wire wire; - if (!convert_wire(loop, wire)) break; + if (!convert_wire(loop, wire)) { + Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop); + delete mf; + return false; + } /* The approach below does not result in a significant speed-up @@ -233,9 +238,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) { // If the wires are reversed the face needs to be reversed as well in order // to maintain the counter-clock-wise ordering of the bounding wire's vertices. bool all_reversed = true; - TopoDS_Iterator it(outer_face_bound, false); - for (; it.More(); it.Next()) { - const TopoDS_Wire& w = TopoDS::Wire(it.Value()); + TopoDS_Iterator jt(outer_face_bound, false); + for (; jt.More(); jt.Next()) { + const TopoDS_Wire& w = TopoDS::Wire(jt.Value()); if ((w.Orientation() != TopAbs_REVERSED) == same_sense) { all_reversed = false; } @@ -252,13 +257,16 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) { // Reinitialize the builder to the outer face // bound in order to add holes more robustly. delete mf; + // TODO: What about the face_surface? mf = new BRepBuilderAPI_MakeFace(outer_face_bound); } else { face = outer_face_bound; success = true; } } else { - break; + Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary", bound); + delete mf; + return false; } } else { @@ -849,7 +857,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeProfileDef* l, TopoDS builder.MakeCompound(compound); IfcSchema::IfcProfileDef::list::ptr profiles = l->Profiles(); - bool first = true; + //bool first = true; for (IfcSchema::IfcProfileDef::list::it it = profiles->begin(); it != profiles->end(); ++it) { TopoDS_Face f; if (convert_face(*it, f)) { @@ -883,20 +891,32 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcDerivedProfileDef* l, TopoDS_S } } +bool IfcGeom::Kernel::convert(const IfcSchema::IfcPlane* l, TopoDS_Shape& face) { + gp_Pln pln; + convert(l, pln); + Handle_Geom_Surface surf = new Geom_Plane(pln); +#if OCC_VERSION_HEX < 0x60502 + face = BRepBuilderAPI_MakeFace(surf); +#else + face = BRepBuilderAPI_MakeFace(surf, getValue(GV_PRECISION)); +#endif + return true; +} + #ifdef USE_IFC4 bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineSurfaceWithKnots* l, TopoDS_Shape& face) { - SHARED_PTR< IfcTemplatedEntityListList > cps = l->ControlPointsList(); + boost::shared_ptr< IfcTemplatedEntityListList > cps = l->ControlPointsList(); std::vector uknots = l->UKnots(); std::vector vknots = l->VKnots(); std::vector umults = l->UMultiplicities(); std::vector vmults = l->VMultiplicities(); - TColgp_Array2OfPnt Poles (0, cps->size() - 1, 0, (*cps->begin()).size() - 1); - TColStd_Array1OfReal UKnots(0, uknots.size() - 1); - TColStd_Array1OfReal VKnots(0, vknots.size() - 1); - TColStd_Array1OfInteger UMults(0, umults.size() - 1); - TColStd_Array1OfInteger VMults(0, vmults.size() - 1); + TColgp_Array2OfPnt Poles (0, (int)cps->size() - 1, 0, (int)(*cps->begin()).size() - 1); + TColStd_Array1OfReal UKnots(0, (int)uknots.size() - 1); + TColStd_Array1OfReal VKnots(0, (int)vknots.size() - 1); + TColStd_Array1OfInteger UMults(0, (int)umults.size() - 1); + TColStd_Array1OfInteger VMults(0, (int)vmults.size() - 1); Standard_Integer UDegree = l->UDegree(); Standard_Integer VDegree = l->VDegree(); @@ -928,17 +948,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineSurfaceWithKnots* l, To } Handle_Geom_Surface surf = new Geom_BSplineSurface(Poles, UKnots, VKnots, UMults, VMults, UDegree, VDegree); +#if OCC_VERSION_HEX < 0x60502 + face = BRepBuilderAPI_MakeFace(surf); +#else face = BRepBuilderAPI_MakeFace(surf, getValue(GV_PRECISION)); +#endif return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcPlane* l, TopoDS_Shape& face) { - gp_Pln pln; - convert(l, pln); - Handle_Geom_Surface surf = new Geom_Plane(pln); - face = BRepBuilderAPI_MakeFace(surf, getValue(GV_PRECISION)); - return true; -} - #endif \ No newline at end of file diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index 842f26444a..78c1b2fcdf 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -63,6 +63,9 @@ #include #include #include +#include + +#include #include #include @@ -95,14 +98,23 @@ #include #include -#include #include #include #include +#include + #include "../ifcparse/IfcSIPrefix.h" #include "../ifcgeom/IfcGeom.h" +#if OCC_VERSION_HEX < 0x60900 +#ifdef _MSC_VER +#pragma message("warning: You are linking against Open CASCADE version " OCC_VERSION_COMPLETE ". Version 6.9.0 introduces various improvements with relation to boolean operations. You are advised to upgrade.") +#else +#warning "You are linking against linking against an older version of Open CASCADE. Version 6.9.0 introduces various improvements with relation to boolean operations. You are advised to upgrade." +#endif +#endif + bool IfcGeom::Kernel::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape) { BRepOffsetAPI_Sewing builder; builder.SetTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE)); @@ -160,10 +172,15 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons IfcSchema::IfcRelVoidsElement* v = *it; IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement(); if ( fes->declaration().is(IfcSchema::Type::IfcOpeningElement) ) { + if (!fes->hasRepresentation()) continue; // Convert the IfcRepresentation of the IfcOpeningElement gp_Trsf opening_trsf; - IfcGeom::Kernel::convert(fes->ObjectPlacement(),opening_trsf); + if (fes->hasObjectPlacement()) { + try { + convert(fes->ObjectPlacement(),opening_trsf); + } catch (...) {} + } // Move the opening into the coordinate system of the IfcProduct opening_trsf.PreMultiply(entity_trsf.Inverted()); @@ -208,12 +225,11 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons ? BRepBuilderAPI_GTransform(opening_shape_unlocated,opening_shape_gtrsf,true).Shape() : opening_shape_unlocated.Moved(opening_shape_gtrsf.Trsf()); - double opening_volume, original_shape_volume; + double opening_volume; if ( Logger::Verbosity() >= Logger::LOG_WARNING ) { opening_volume = shape_volume(opening_shape); if ( opening_volume <= ALMOST_ZERO ) Logger::Message(Logger::LOG_WARNING, "Empty opening for:", entity); - original_shape_volume = shape_volume(entity_shape); } if (entity_shape.ShapeType() == TopAbs_COMPSOLID) { @@ -228,16 +244,30 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons TopExp_Explorer exp(entity_shape, TopAbs_SOLID); for (; exp.More(); exp.Next()) { + +#if OCC_VERSION_HEX < 0x60900 BRepAlgoAPI_Cut brep_cut(exp.Current(), opening_shape); +#else + BRepAlgoAPI_Cut brep_cut; + TopTools_ListOfShape s1s; + s1s.Append(exp.Current()); + TopTools_ListOfShape s2s; + s2s.Append(opening_shape); + brep_cut.SetFuzzyValue(getValue(GV_PRECISION)); + brep_cut.SetArguments(s1s); + brep_cut.SetTools(s2s); + brep_cut.Build(); +#endif + bool added = false; if ( brep_cut.IsDone() ) { TopoDS_Shape brep_cut_result = brep_cut; BRepCheck_Analyzer analyser(brep_cut_result); bool is_valid = analyser.IsValid() != 0; if (is_valid) { - TopExp_Explorer exp(brep_cut_result, TopAbs_SOLID); - for (; exp.More(); exp.Next()) { - builder.Add(compound, exp.Current()); + TopExp_Explorer exp2(brep_cut_result, TopAbs_SOLID); + for (; exp2.More(); exp2.Next()) { + builder.Add(compound, exp2.Current()); added = true; } } @@ -253,7 +283,19 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons entity_shape = compound; } else { +#if OCC_VERSION_HEX < 0x60900 BRepAlgoAPI_Cut brep_cut(entity_shape,opening_shape); +#else + BRepAlgoAPI_Cut brep_cut; + TopTools_ListOfShape s1s; + s1s.Append(entity_shape); + TopTools_ListOfShape s2s; + s2s.Append(opening_shape); + brep_cut.SetFuzzyValue(getValue(GV_PRECISION)); + brep_cut.SetArguments(s1s); + brep_cut.SetTools(s2s); + brep_cut.Build(); +#endif if ( brep_cut.IsDone() ) { TopoDS_Shape brep_cut_result = brep_cut; @@ -272,7 +314,7 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons entity_shape = brep_cut_result; if ( Logger::Verbosity() >= Logger::LOG_WARNING ) { const double volume_after_subtraction = shape_volume(entity_shape); - + double original_shape_volume = shape_volume(entity_shape); if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) ) Logger::Message(Logger::LOG_WARNING, "Subtraction yields unchanged volume:", entity); } @@ -291,6 +333,7 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons return true; } +#if OCC_VERSION_HEX < 0x60900 bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcGeom::IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::IfcRepresentationShapeItems& cut_shapes) { @@ -303,10 +346,15 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, IfcSchema::IfcRelVoidsElement* v = *it; IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement(); if ( fes->declaration().is(IfcSchema::Type::IfcOpeningElement) ) { + if (!fes->hasRepresentation()) continue; // Convert the IfcRepresentation of the IfcOpeningElement gp_Trsf opening_trsf; - IfcGeom::Kernel::convert(fes->ObjectPlacement(),opening_trsf); + if (fes->hasObjectPlacement()) { + try { + convert(fes->ObjectPlacement(),opening_trsf); + } catch (...) {} + } // Move the opening into the coordinate system of the IfcProduct opening_trsf.PreMultiply(entity_trsf.Inverted()); @@ -346,6 +394,7 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, } BRepAlgoAPI_Cut brep_cut(entity_shape,opening_compound); + bool is_valid = false; if ( brep_cut.IsDone() ) { TopoDS_Shape brep_cut_result = brep_cut; @@ -367,6 +416,93 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, } return true; } +#else +bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, + const IfcGeom::IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::IfcRepresentationShapeItems& cut_shapes) { + + TopTools_ListOfShape opening_shapelist; + + for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) { + IfcSchema::IfcRelVoidsElement* v = *it; + IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement(); + if ( fes->is(IfcSchema::Type::IfcOpeningElement) ) { + if (!fes->hasRepresentation()) continue; + + // Convert the IfcRepresentation of the IfcOpeningElement + gp_Trsf opening_trsf; + if (fes->hasObjectPlacement()) { + try { + convert(fes->ObjectPlacement(),opening_trsf); + } catch (...) {} + } + + // Move the opening into the coordinate system of the IfcProduct + opening_trsf.PreMultiply(entity_trsf.Inverted()); + + IfcSchema::IfcProductRepresentation* prodrep = fes->Representation(); + IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations(); + + IfcGeom::IfcRepresentationShapeItems opening_shapes; + + for ( IfcSchema::IfcRepresentation::list::it it2 = reps->begin(); it2 != reps->end(); ++ it2 ) { + convert_shapes(*it2,opening_shapes); + } + + for ( unsigned int i = 0; i < opening_shapes.size(); ++ i ) { + gp_GTrsf gtrsf = opening_shapes[i].Placement(); + gtrsf.PreMultiply(opening_trsf); + const TopoDS_Shape& opening_shape = gtrsf.Form() == gp_Other + ? BRepBuilderAPI_GTransform(opening_shapes[i].Shape(),gtrsf,true).Shape() + : (opening_shapes[i].Shape()).Moved(gtrsf.Trsf()); + opening_shapelist.Append(opening_shape); + } + + } + } + + // Iterate over the shapes of the IfcProduct + for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { + TopoDS_Shape entity_shape_solid; + const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(it3->Shape(),entity_shape_solid); + const gp_GTrsf& entity_shape_gtrsf = it3->Placement(); + TopoDS_Shape entity_shape; + if ( entity_shape_gtrsf.Form() == gp_Other ) { + Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to:",entity->entity); + entity_shape = BRepBuilderAPI_GTransform(entity_shape_unlocated,entity_shape_gtrsf,true).Shape(); + } else { + entity_shape = entity_shape_unlocated.Moved(entity_shape_gtrsf.Trsf()); + } + + BRepAlgoAPI_Cut brep_cut; + TopTools_ListOfShape s1s; + s1s.Append(entity_shape); + brep_cut.SetFuzzyValue(getValue(GV_PRECISION)); + brep_cut.SetArguments(s1s); + brep_cut.SetTools(opening_shapelist); + brep_cut.Build(); + + bool is_valid = false; + if ( brep_cut.IsDone() ) { + TopoDS_Shape brep_cut_result = brep_cut; + + BRepCheck_Analyzer analyser(brep_cut_result); + is_valid = analyser.IsValid() != 0; + if ( is_valid ) { + cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(brep_cut_result, &it3->Style())); + } + } + if ( !is_valid ) { + // Apparently processing the boolean operation failed or resulted in an invalid result + // in which case the original shape without the subtractions is returned instead + // we try convert the openings in the original way, one by one. + Logger::Message(Logger::LOG_WARNING, "Subtracting combined openings compound failed:", entity->entity); + return false; + } + + } + return true; +} +#endif bool IfcGeom::Kernel::convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face) { BRepBuilderAPI_MakeFace mf(wire, false); @@ -554,7 +690,7 @@ void IfcGeom::Kernel::setValue(GeomValue var, double value) { } } -double IfcGeom::Kernel::getValue(GeomValue var) { +double IfcGeom::Kernel::getValue(GeomValue var) const { switch (var) { case GV_DEFLECTION_TOLERANCE: return deflection_tolerance; @@ -615,11 +751,11 @@ IfcSchema::IfcProductDefinitionShape* IfcGeom::tesselate(TopoDS_Shape& shape, do IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, face.Orientation() != TopAbs_REVERSED); IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list); bounds->push(bound); - IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds); + IfcSchema::IfcFace* face2 = new IfcSchema::IfcFace(bounds); es->push(loop); es->push(bound); - es->push(face); - faces->push(face); + es->push(face2); + faces->push(face2); } } } @@ -703,7 +839,6 @@ bool IfcGeom::Kernel::fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& sha // Now loop over all the vertices that are part of the wire(s) to be filled for (int i = 1; i <= num_verts; ++i) { first = current = TopoDS::Vertex(vertex_to_edges.FindKey(i)); - const bool isSame = first.IsSame(current); // We keep track of the vertices we already used if (visited.find(vertex_to_edges.FindIndex(current)) != visited.end()) { continue; @@ -711,7 +846,7 @@ bool IfcGeom::Kernel::fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& sha // Given these vertices, try to find closed loops and create new // wires out of them. BRepBuilderAPI_MakeWire w; - while (true) { + for (;;) { visited.insert(vertex_to_edges.FindIndex(current)); // Find the edge that the current vertex is part of and points // away from the previous vertex (null for the first vertex). @@ -776,8 +911,14 @@ bool IfcGeom::Kernel::flatten_shape_list(const IfcGeom::IfcRepresentationShapeIt _trsf = trsf.Trsf(); trsf_valid = true; } catch (...) {} - const TopoDS_Shape moved_shape = trsf_valid ? merged.Moved(_trsf) : - BRepBuilderAPI_GTransform(merged,trsf,true).Shape(); + + const TopoDS_Shape moved_shape = trsf.Form() == gp_Identity + ? merged + : ( + trsf_valid + ? merged.Moved(_trsf) + : BRepBuilderAPI_GTransform(merged,trsf,true).Shape() + ); if (shapes.size() == 1) { result = moved_shape; @@ -809,6 +950,10 @@ bool IfcGeom::Kernel::flatten_shape_list(const IfcGeom::IfcRepresentationShapeIt } } + if (!fuse) { + result = compound; + } + const bool success = !result.IsNull(); if (success) { const double precision = getValue(GV_PRECISION); @@ -818,11 +963,11 @@ bool IfcGeom::Kernel::flatten_shape_list(const IfcGeom::IfcRepresentationShapeIt return success; } -void IfcGeom::Kernel::remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) { +void IfcGeom::Kernel::remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) { if (tol <= 0.) tol = getValue(GV_POINT_EQUALITY_TOLERANCE); tol *= tol; - while (true) { + for (;;) { bool removed = false; int n = polygon.Length() - (closed ? 0 : 1); for (int i = 1; i <= n; ++i) { @@ -842,6 +987,69 @@ void IfcGeom::Kernel::remove_redundant_points_from_loop(TColgp_SequenceOfPnt& po } } +void IfcGeom::Kernel::remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) { + if (tol <= 0.) tol = getValue(GV_POINT_EQUALITY_TOLERANCE); + const int start = closed ? 1 : 2; + const int end = polygon.Length() - (closed ? 0 : 1); + std::vector to_remove(polygon.Length(), false); + for (int i = start; i <= end; ++i) { + const gp_Pnt& a = polygon.Value(((i - 2 + polygon.Length()) % polygon.Length()) + 1); + const gp_Pnt& b = polygon.Value(i); + const gp_Pnt& c = polygon.Value((i % polygon.Length()) + 1); + const gp_Vec d1 = c.XYZ() - a.XYZ(); + const gp_Vec d2 = b.XYZ() - a.XYZ(); + const double dt = d2.Dot(d1) / d1.Dot(d1); + const gp_Vec d3 = d1.Scaled(dt); + const gp_Pnt b2 = a.XYZ() + d3.XYZ(); + if (b.Distance(b2) < tol) { + to_remove[i-1] = true; + } + } + for (int i = (int) to_remove.size() - 1; i >= 0; --i) { + if (to_remove[i]) { + polygon.Remove(i+1); + } + } +} + +bool IfcGeom::Kernel::wire_to_sequence_of_point(const TopoDS_Wire& w, TColgp_SequenceOfPnt& p) { + TopExp_Explorer exp(w, TopAbs_EDGE); + for (; exp.More(); exp.Next()) { + double a, b; + Handle_Geom_Curve crv = BRep_Tool::Curve(TopoDS::Edge(exp.Current()), a, b); + if (crv->DynamicType() != STANDARD_TYPE(Geom_Line)) { + return false; + } + } + + exp.ReInit(); + + int i = 0; + for (; exp.More(); exp.Next(), ++i) { + TopoDS_Vertex v1, v2; + TopExp::Vertices(TopoDS::Edge(exp.Current()), v1, v2, true); + if (exp.More()) { + if (i == 0) { + p.Append(BRep_Tool::Pnt(v1)); + } + p.Append(BRep_Tool::Pnt(v2)); + } + } + + return true; +} + +void IfcGeom::Kernel::sequence_of_point_to_wire(const TColgp_SequenceOfPnt& p, TopoDS_Wire& w, bool close) { + BRepBuilderAPI_MakePolygon builder; + for (int i = 1; i <= p.Length(); ++i) { + builder.Add(p.Value(i)); + } + if (close) { + builder.Close(); + } + w = builder.Wire(); +} + template IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_representation_and_product(const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product) { IfcGeom::Representation::BRep* shape; @@ -898,7 +1106,12 @@ IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_representation_and_pro if ( !settings.disable_opening_subtractions() && openings && openings->size() ) { IfcGeom::IfcRepresentationShapeItems opened_shapes; try { - if ( settings.faster_booleans() ) { +#if OCC_VERSION_HEX < 0x60900 + const bool faster_booleans = settings.faster_booleans(); +#else + const bool faster_booleans = true; +#endif + if (faster_booleans) { bool succes = convert_openings_fast(product,openings,shapes,trsf,opened_shapes); if ( ! succes ) { opened_shapes.clear(); @@ -1065,4 +1278,26 @@ std::pair IfcGeom::Kernel::initializeUnits(IfcSchema::IfcUn } return std::pair(unit_name, unit_magnitude); -} \ No newline at end of file +} + +const IfcSchema::IfcRepresentationItem* IfcGeom::Kernel::find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item) { + if (item->StyledByItem()->size()) { + return item; + } + + while (item->declaration().is(IfcSchema::Type::IfcBooleanClippingResult)) { + // All instantiations of IfcBooleanOperand (type of FirstOperand) are subtypes of + // IfcGeometricRepresentationItem + item = (IfcSchema::IfcGeometricRepresentationItem*) ((IfcSchema::IfcBooleanClippingResult*) item)->FirstOperand(); + if (item->StyledByItem()->size()) { + return item; + } + } + + // TODO: Ideally this would be done for other entities (such as IfcCsgSolid) as well. + // But neither are these very prevalent, nor does the current IfcOpenShell style + // mechanism enable to conveniently style subshapes, which would be necessary for + // distinctly styled union operands. + + return item; +} diff --git a/src/ifcgeom/IfcGeomHelpers.cpp b/src/ifcgeom/IfcGeomHelpers.cpp index 932896a95b..075ebebfd2 100644 --- a/src/ifcgeom/IfcGeomHelpers.cpp +++ b/src/ifcgeom/IfcGeomHelpers.cpp @@ -287,7 +287,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& t return false; } IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l; - while (1) { + for (;;) { gp_Trsf trsf2; IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement(); if ( relplacement->declaration().is(IfcSchema::Type::IfcAxis2Placement3D) ) { diff --git a/src/ifcgeom/IfcGeomIterator.h b/src/ifcgeom/IfcGeomIterator.h index 475fb50509..9913b1e876 100644 --- a/src/ifcgeom/IfcGeomIterator.h +++ b/src/ifcgeom/IfcGeomIterator.h @@ -64,6 +64,8 @@ #include #include +#include + #include #include #include @@ -125,10 +127,7 @@ namespace IfcGeom { void populate_set(const std::set& include_or_ignore) { entities_to_include_or_exclude.clear(); for (std::set::const_iterator it = include_or_ignore.begin(); it != include_or_ignore.end(); ++it) { - std::string uppercase_type = *it; - for (std::string::iterator c = uppercase_type.begin(); c != uppercase_type.end(); ++c) { - *c = toupper(*c); - } + const std::string uppercase_type = boost::to_upper_copy(*it); IfcSchema::Type::Enum ty; try { ty = IfcSchema::Type::FromString(uppercase_type); @@ -181,15 +180,15 @@ namespace IfcGeom { // by the parent's context inverse attributes. continue; } - if (context->hasContextType()) { - std::string context_type_lc = context->ContextType(); - for (std::string::iterator c = context_type_lc.begin(); c != context_type_lc.end(); ++c) { - *c = tolower(*c); + try { + if (context->hasContextType()) { + std::string context_type = context->ContextType(); + boost::to_lower(context_type); + if (context_types.find(context_type) != context_types.end()) { + filtered_contexts->push(context); + } } - if (context_types.find(context_type_lc) != context_types.end()) { - filtered_contexts->push(context); - } - } + } catch (const IfcParse::IfcException&) {} } // In case no contexts are identified based on their ContextType, all contexts are @@ -207,10 +206,12 @@ namespace IfcGeom { IfcSchema::IfcGeometricRepresentationContext* context = *it; representations->push(context->RepresentationsInContext()); - if (context->hasPrecision() && context->Precision() < lowest_precision_encountered) { - lowest_precision_encountered = context->Precision(); - any_precision_encountered = true; - } + try { + if (context->hasPrecision() && context->Precision() < lowest_precision_encountered) { + lowest_precision_encountered = context->Precision(); + any_precision_encountered = true; + } + } catch (const IfcParse::IfcException&) {} IfcSchema::IfcGeometricRepresentationSubContext::list::ptr sub_contexts = context->HasSubContexts(); for (jt = sub_contexts->begin(); jt != sub_contexts->end(); ++jt) { representations->push((*jt)->RepresentationsInContext()); @@ -288,7 +289,7 @@ namespace IfcGeom { } BRepElement

* create_shape_model_for_next_entity() { - while ( true ) { + for (;;) { IfcSchema::IfcRepresentation* representation; // Have we reached the end of our list of representations? @@ -321,16 +322,16 @@ namespace IfcGeom { // Filter the products based on the set of entities being included or excluded for // processing. The set is iterated over te able to filter on subtypes. - for ( IfcSchema::IfcProduct::list::it it = unfiltered_products->begin(); it != unfiltered_products->end(); ++it ) { + for ( IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin(); jt != unfiltered_products->end(); ++jt ) { bool found = false; - for (std::set::const_iterator jt = entities_to_include_or_exclude.begin(); jt != entities_to_include_or_exclude.end(); ++jt) { - if ((*it)->declaration().is(*jt)) { + for (std::set::const_iterator kt = entities_to_include_or_exclude.begin(); kt != entities_to_include_or_exclude.end(); ++kt) { + if ((*jt)->declaration().is(*kt)) { found = true; break; } } if (found == include_entities_in_processing) { - ifcproducts->push(*it); + ifcproducts->push(*jt); } } diff --git a/src/ifcgeom/IfcGeomRenderStyles.cpp b/src/ifcgeom/IfcGeomRenderStyles.cpp index b88899cd6c..b931ffdce3 100644 --- a/src/ifcgeom/IfcGeomRenderStyles.cpp +++ b/src/ifcgeom/IfcGeomRenderStyles.cpp @@ -21,7 +21,7 @@ #include "IfcGeom.h" -bool process_colour(IfcSchema::IfcColourRgb* colour, std::tr1::array& rgb) { +bool process_colour(IfcSchema::IfcColourRgb* colour, double* rgb) { if (colour != 0) { rgb[0] = colour->Red(); rgb[1] = colour->Green(); @@ -30,7 +30,7 @@ bool process_colour(IfcSchema::IfcColourRgb* colour, std::tr1::array& return colour != 0; } -bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, std::tr1::array& rgb) { +bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, double* rgb) { if (factor != 0) { const double f = *factor; rgb[0] = rgb[1] = rgb[2] = f; @@ -38,7 +38,7 @@ bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, std::tr1::arra return factor != 0; } -bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, std::tr1::array& rgb) { +bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, double* rgb) { if (colour_or_factor == 0) { return false; } else if (colour_or_factor->declaration().is(IfcSchema::Type::IfcColourRgb)) { @@ -66,7 +66,7 @@ const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepr } else { surface_style = SurfaceStyle(surface_style_id); } - std::tr1::array rgb; + double rgb[3]; if (process_colour(shading_styles.second->SurfaceColour(), rgb)) { surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2])); } diff --git a/src/ifcgeom/IfcGeomRenderStyles.h b/src/ifcgeom/IfcGeomRenderStyles.h index cd8d771246..d84b85d737 100644 --- a/src/ifcgeom/IfcGeomRenderStyles.h +++ b/src/ifcgeom/IfcGeomRenderStyles.h @@ -20,16 +20,6 @@ #ifndef IFCGEOMRENDERSTYLES_H #define IFCGEOMRENDERSTYLES_H -#ifdef __GNUC__ -#include -#else -#if _MSC_VER < 1600 -#include -#else -#include -#endif -#endif - #ifdef USE_IFC4 #include "../ifcparse/Ifc4.h" #else @@ -41,7 +31,7 @@ namespace IfcGeom { public: class ColorComponent { private: - std::tr1::array data; + double data[3]; public: ColorComponent(double r, double g, double b) { data[0] = r; data[1] = g; data[2] = b; diff --git a/src/ifcgeom/IfcGeomRepresentation.h b/src/ifcgeom/IfcGeomRepresentation.h index 4448a07b86..4561e71c91 100644 --- a/src/ifcgeom/IfcGeomRepresentation.h +++ b/src/ifcgeom/IfcGeomRepresentation.h @@ -41,6 +41,8 @@ namespace IfcGeom { namespace Representation { class Representation { + Representation(const Representation&); //N/A + Representation& operator =(const Representation&); //N/A protected: const ElementSettings _settings; public: @@ -116,33 +118,33 @@ namespace IfcGeom { : Representation(shape_model.settings()) , _id(shape_model.getId()) { - for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it = shape_model.begin(); it != shape_model.end(); ++ it ) { + for ( IfcGeom::IfcRepresentationShapeItems::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++ iit ) { int surface_style_id = -1; - if (it->hasStyle()) { - Material adapter(&it->Style()); + if (iit->hasStyle()) { + Material adapter(&iit->Style()); std::vector::const_iterator jt = std::find(_materials.begin(), _materials.end(), adapter); if (jt == _materials.end()) { - surface_style_id = _materials.size(); + surface_style_id = (int)_materials.size(); _materials.push_back(adapter); } else { - surface_style_id = jt - _materials.begin(); + surface_style_id = (int)(jt - _materials.begin()); } } if (settings().apply_default_materials() && surface_style_id == -1) { Material material(IfcGeom::get_default_style(settings().element_type())); - std::vector::const_iterator it = std::find(_materials.begin(), _materials.end(), material); - if (it == _materials.end()) { - surface_style_id = _materials.size(); + std::vector::const_iterator mit = std::find(_materials.begin(), _materials.end(), material); + if (mit == _materials.end()) { + surface_style_id = (int)_materials.size(); _materials.push_back(material); } else { - surface_style_id = it - _materials.begin(); + surface_style_id = (int)(mit - _materials.begin()); } } - const TopoDS_Shape& s = it->Shape(); - const gp_GTrsf& trsf = it->Placement(); + const TopoDS_Shape& s = iit->Shape(); + const gp_GTrsf& trsf = iit->Placement(); // Triangulate the shape try { @@ -231,11 +233,11 @@ namespace IfcGeom { addEdge(dict[n2], dict[n3], edgecount, edges_temp); addEdge(dict[n3], dict[n1], edgecount, edges_temp); } - for ( std::vector >::const_iterator it = edges_temp.begin(); it != edges_temp.end(); ++it ) { - if (edgecount[*it] == 1) { + for ( std::vector >::const_iterator jt = edges_temp.begin(); jt != edges_temp.end(); ++jt ) { + if (edgecount[*jt] == 1) { // non manifold edge, face boundary - _edges.push_back(it->first); - _edges.push_back(it->second); + _edges.push_back(jt->first); + _edges.push_back(jt->second); } } } @@ -245,11 +247,11 @@ namespace IfcGeom { // Edges are only emitted if there are no faces. A mixed representation of faces // and loose edges is discouraged by the standard. An alternative would be to use // TopExp::MapShapesAndAncestors() to find edges that do not belong to any face. - for (TopExp_Explorer exp(s, TopAbs_EDGE); exp.More(); exp.Next()) { - BRepAdaptor_Curve crv(TopoDS::Edge(exp.Current())); + for (TopExp_Explorer texp(s, TopAbs_EDGE); texp.More(); texp.Next()) { + BRepAdaptor_Curve crv(TopoDS::Edge(texp.Current())); GCPnts_QuasiUniformDeflection tessellater(crv, settings().deflection_tolerance()); int n = tessellater.NbPoints(); - int start = _verts.size() / 3; + int start = (int)_verts.size() / 3; for (int i = 1; i <= n; ++i) { gp_XYZ p = tessellater.Value(i).XYZ(); trsf.Transforms(p); diff --git a/src/ifcgeom/IfcGeomShapes.cpp b/src/ifcgeom/IfcGeomShapes.cpp index 15e5f30f0f..ade88c0adc 100644 --- a/src/ifcgeom/IfcGeomShapes.cpp +++ b/src/ifcgeom/IfcGeomShapes.cpp @@ -65,6 +65,8 @@ #include #include #include +#include + #include #include @@ -99,10 +101,15 @@ #include "../ifcgeom/IfcGeom.h" bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_Shape& shape) { + const double height = l->Depth() * getValue(GV_LENGTH_UNIT); + if (height < getValue(GV_PRECISION)) { + Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l); + return false; + } + TopoDS_Shape face; if ( !convert_face(l->SweptArea(),face) ) return false; - const double height = l->Depth() * getValue(GV_LENGTH_UNIT); gp_Trsf trsf; IfcGeom::Kernel::convert(l->Position(),trsf); @@ -244,10 +251,20 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, TopoDS_Shap bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l, TopoDS_Shape& shape) { TopoDS_Shape halfspace; if ( ! IfcGeom::Kernel::convert((IfcSchema::IfcHalfSpaceSolid*)l,halfspace) ) return false; + TopoDS_Wire wire; - if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false; + if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false; + gp_Trsf trsf; - convert(l->Position(),trsf); + if ( ! convert(l->Position(),trsf) ) return false; + + TColgp_SequenceOfPnt points; + if (wire_to_sequence_of_point(wire, points)) { + remove_duplicate_points_from_loop(points, wire.Closed()); // Note: wire always closed, as per if statement above + remove_collinear_points_from_loop(points, wire.Closed()); + sequence_of_point_to_wire(points, wire, wire.Closed()); + } + TopoDS_Shape prism = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,200)); gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-100.0)); prism.Move(trsf*down); @@ -272,6 +289,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, Ifc } bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) { + TopoDS_Shape s1, s2; IfcRepresentationShapeItems items1, items2; TopoDS_Wire boundary_wire; @@ -325,10 +343,36 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator(); + /* + // TK: A little debugging trick to output both operands for visual inspection + + BRep_Builder builder; + TopoDS_Compound compound; + builder.MakeCompound(compound); + builder.Add(compound, s1); + builder.Add(compound, s2); + shape = compound; + return true; + */ + if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { bool valid_cut = false; - BRepAlgoAPI_Cut brep_cut(s1,s2); + +#if OCC_VERSION_HEX < 0x60900 + BRepAlgoAPI_Cut brep_cut(s1, s2); +#else + BRepAlgoAPI_Cut brep_cut; + TopTools_ListOfShape s1s; + s1s.Append(s1); + TopTools_ListOfShape s2s; + s2s.Append(s2); + brep_cut.SetFuzzyValue(getValue(GV_PRECISION)); + brep_cut.SetArguments(s1s); + brep_cut.SetTools(s2s); + brep_cut.Build(); +#endif + if ( brep_cut.IsDone() ) { TopoDS_Shape result = brep_cut; @@ -399,7 +443,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Shape& shape) { IfcSchema::IfcFace::list::ptr faces = l->CfsFaces(); bool facesAdded = false; - const unsigned int num_faces = faces->size(); + const unsigned int num_faces = (unsigned)faces->size(); bool valid_shell = false; if ( num_faces < getValue(GV_MAX_FACES_TO_SEW) ) { BRepOffsetAPI_Sewing builder; @@ -492,11 +536,22 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentati trsf = trsf_2d; } gtrsf.Multiply(trsf); + + const IfcGeom::SurfaceStyle* mapped_item_style = get_style(l); + const unsigned int previous_size = (const unsigned int) shapes.size(); - bool b = convert_shapes(map->MappedRepresentation(),shapes); + bool b = convert_shapes(map->MappedRepresentation(), shapes); + for ( unsigned int i = previous_size; i < shapes.size(); ++ i ) { shapes[i].append(gtrsf); + + // Apply styles assigned to the mapped item only if on + // a more granular level no styles have been applied + if (!shapes[i].hasStyle()) { + shapes[i].setStyle(mapped_item_style); + } } + return b; } @@ -627,9 +682,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_S BRepBuilderAPI_MakeFace mf (outer); mf.Add(outer); - IfcSchema::IfcCurve::list::ptr inner = l->InnerBoundaries(); + IfcSchema::IfcCurve::list::ptr boundaries = l->InnerBoundaries(); - for (IfcSchema::IfcCurve::list::it it = inner->begin(); it != inner->end(); ++it) { + for (IfcSchema::IfcCurve::list::it it = boundaries->begin(); it != boundaries->end(); ++it) { TopoDS_Wire inner; convert_wire(*it, inner); @@ -762,8 +817,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shap // Subtraction of pipes with small radii is unstable. hasInnerRadius = false; } else { - Handle(Geom_Circle) circle = new Geom_Circle(directrix, r2); - section2 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle)); + Handle(Geom_Circle) circle2 = new Geom_Circle(directrix, r2); + section2 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle2)); } } @@ -817,7 +872,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCylindricalSurface* l, TopoDS_ gp_Trsf trsf; IfcGeom::Kernel::convert(l->Position(),trsf); +#if OCC_VERSION_HEX < 0x60502 + face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius())).Face().Moved(trsf); +#else face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius()), getValue(GV_PRECISION)).Face().Moved(trsf); +#endif return true; } @@ -882,7 +941,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, TopoDS if (faces.empty()) return false; - const unsigned int num_faces = indices.size(); + const unsigned int num_faces = (unsigned)indices.size(); bool valid_shell = false; if (faces.size() < getValue(GV_MAX_FACES_TO_SEW)) { diff --git a/src/ifcgeom/IfcGeomWires.cpp b/src/ifcgeom/IfcGeomWires.cpp index eb7b086c00..4fc056f640 100644 --- a/src/ifcgeom/IfcGeomWires.cpp +++ b/src/ifcgeom/IfcGeomWires.cpp @@ -168,6 +168,25 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire //last_vertex = w.Vertex(); if ( w.Error() != BRepBuilderAPI_WireDone ) { Logger::Message(Logger::LOG_ERROR, "Failed to join curve segments:", l); + + TopoDS_Vertex v1, v2, last; + last = w.Vertex(); + + if (!last.IsNull()) { + std::stringstream ss; + gp_Pnt p = BRep_Tool::Pnt(last); + ss << std::setprecision(4) << "Last vertex at (" << p.X() << " " << p.Y() << " " << p.Z() << ")"; + Logger::Message(Logger::LOG_NOTICE, ss.str()); + } + + TopExp::Vertices(wire2, v1, v2); + if (!v1.IsNull()) { + std::stringstream ss; + gp_Pnt p = BRep_Tool::Pnt(v1); + ss << std::setprecision(4) << "Segment starts at (" << p.X() << " " << p.Y() << " " << p.Z() << ") for:"; + Logger::Message(Logger::LOG_NOTICE, ss.str(), *it); + } + return false; } } @@ -184,8 +203,6 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& bool trim_cartesian = l->MasterRepresentation() == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN; IfcEntityList::ptr trims1 = l->Trim1(); IfcEntityList::ptr trims2 = l->Trim2(); - bool trimmed1 = false; - bool trimmed2 = false; unsigned sense_agreement = l->SenseAgreement() ? 0 : 1; double flts[2]; gp_Pnt pnts[2]; @@ -257,7 +274,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& flts[1] -= M_PI / 2.; } } - if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],(double)(M_PI*2.0)),0.0f) ) { + if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],M_PI*2.),0.) ) { w.Add(BRepBuilderAPI_MakeEdge(curve)); } else { BRepBuilderAPI_MakeEdge e (curve,flts[0],flts[1]); @@ -286,7 +303,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& resu } // Remove points that are too close to one another - remove_redundant_points_from_loop(polygon, false); + remove_duplicate_points_from_loop(polygon, false); BRepBuilderAPI_MakePolygon w; for (int i = 1; i <= polygon.Length(); ++i) { @@ -316,7 +333,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& resu } // Remove points that are too close to one another - remove_redundant_points_from_loop(polygon, true); + remove_duplicate_points_from_loop(polygon, true); int count = polygon.Length(); if (original_count - count != 0) { @@ -411,9 +428,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeLoop* l, TopoDS_Wire& resu TopoDS_Wire w; if (convert_wire(*it, w)) { if (!(*it)->Orientation()) w.Reverse(); - TopoDS_Iterator it(w, false); - for (; it.More(); it.Next()) { - const TopoDS_Edge& e = TopoDS::Edge(it.Value()); + TopoDS_Iterator topoit(w, false); + for (; topoit.More(); topoit.Next()) { + const TopoDS_Edge& e = TopoDS::Edge(topoit.Value()); mw.Add(e); } // mw.Add(w); diff --git a/src/ifcgeom/IfcRegister.cpp b/src/ifcgeom/IfcRegister.cpp index 5a639f96dc..942d7df5c6 100644 --- a/src/ifcgeom/IfcRegister.cpp +++ b/src/ifcgeom/IfcRegister.cpp @@ -24,6 +24,15 @@ using namespace IfcSchema; using namespace IfcUtil; bool IfcGeom::Kernel::convert_shapes(const IfcBaseClass* l, IfcRepresentationShapeItems& r) { + if (shape_type(l) != ST_SHAPELIST) { + TopoDS_Shape shp; + if (convert_shape(l, shp)) { + r.push_back(IfcGeom::IfcRepresentationShapeItem(shp, get_style(l->as()))); + return true; + } + return false; + } + #include "IfcRegisterConvertShapes.h" Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l); return false; diff --git a/src/ifcgeom/IfcRegister.h b/src/ifcgeom/IfcRegister.h index dc231b2b40..305c0c9f5e 100644 --- a/src/ifcgeom/IfcRegister.h +++ b/src/ifcgeom/IfcRegister.h @@ -53,9 +53,9 @@ SHAPE(IfcCylindricalSurface); SHAPE(IfcAdvancedBrep); // FIXME: Surfaces should have a shape type of their own SHAPE(IfcBSplineSurfaceWithKnots); -SHAPE(IfcPlane); SHAPE(IfcTriangulatedFaceSet); #endif +SHAPE(IfcPlane); SHAPE(IfcExtrudedAreaSolid); SHAPE(IfcRevolvedAreaSolid); SHAPE(IfcConnectedFaceSet); diff --git a/src/ifcgeom/IfcRepresentationShapeItem.h b/src/ifcgeom/IfcRepresentationShapeItem.h index 88ac340214..1d2c3fa8b5 100644 --- a/src/ifcgeom/IfcRepresentationShapeItem.h +++ b/src/ifcgeom/IfcRepresentationShapeItem.h @@ -46,6 +46,7 @@ namespace IfcGeom { const gp_GTrsf& Placement() const { return placement; } bool hasStyle() const { return style != 0; } const SurfaceStyle& Style() const { return *style; } + void setStyle(const SurfaceStyle* style) { this->style = style; } }; typedef std::vector IfcRepresentationShapeItems; } diff --git a/src/ifcgeomserver/IfcGeomServer.cpp b/src/ifcgeomserver/IfcGeomServer.cpp index 22eaca9844..975c3c471e 100644 --- a/src/ifcgeomserver/IfcGeomServer.cpp +++ b/src/ifcgeomserver/IfcGeomServer.cpp @@ -37,6 +37,10 @@ #include "../ifcgeom/IfcGeomIterator.h" +#if USE_VLD +#include +#endif + using namespace boost; template @@ -69,7 +73,7 @@ void swrite(std::ostream& s, T t) { template <> void swrite(std::ostream& s, std::string t) { - int32_t len = t.size(); + int32_t len = (int32_t)t.size(); swrite(s, len); s.write(t.c_str(), len); while (len++ % 4) s.put(0); @@ -156,16 +160,16 @@ public: class Get : public Command { protected: - void read_content(std::istream& s) {} - void write_content(std::ostream& s) {} + void read_content(std::istream& /*s*/) {} + void write_content(std::ostream& /*s*/) {} public: Get() : Command(GET) {}; }; class GetLog : public Command { protected: - void read_content(std::istream& s) {} - void write_content(std::ostream& s) {} + void read_content(std::istream& /*s*/) {} + void write_content(std::ostream& /*s*/) {} public: GetLog() : Command(GET_LOG) {}; }; @@ -189,7 +193,7 @@ private: const IfcGeom::TriangulationElement* geom; bool append_line_data; protected: - void read_content(std::istream& s) {} + void read_content(std::istream& /*s*/) {} void write_content(std::ostream& s) { swrite(s, geom->id()); swrite(s, geom->guid()); @@ -238,9 +242,9 @@ protected: } { std::vector diffuse_color_array; for (std::vector::const_iterator it = geom->geometry().materials().begin(); it != geom->geometry().materials().end(); ++it) { - const IfcGeom::Material& m = *it; - if (m.hasDiffuse()) { - const double* color = m.diffuse(); + const IfcGeom::Material& mat = *it; + if (mat.hasDiffuse()) { + const double* color = mat.diffuse(); diffuse_color_array.push_back(static_cast(color[0])); diffuse_color_array.push_back(static_cast(color[1])); diffuse_color_array.push_back(static_cast(color[2])); @@ -249,8 +253,8 @@ protected: diffuse_color_array.push_back(0.f); diffuse_color_array.push_back(0.f); } - if (m.hasTransparency()) { - diffuse_color_array.push_back(static_cast(1. - m.transparency())); + if (mat.hasTransparency()) { + diffuse_color_array.push_back(static_cast(1. - mat.transparency())); } else { diffuse_color_array.push_back(1.f); } @@ -268,25 +272,21 @@ public: class Next : public Command { protected: - void read_content(std::istream& s) {} - void write_content(std::ostream& s) {} + void read_content(std::istream& /*s*/) {} + void write_content(std::ostream& /*s*/) {} public: Next() : Command(NEXT) {}; }; class Bye : public Command { protected: - void read_content(std::istream& s) {} - void write_content(std::ostream& s) {} + void read_content(std::istream& /*s*/) {} + void write_content(std::ostream& /*s*/) {} public: Bye() : Command(BYE) {}; }; -int main (int argc, char** argv) { - if (sizeof(float) != 4 || sizeof(int32_t) != 4) { - return 1; - } - +int main () { // Redirect stdout to this stream, so that involuntary // writes to stdout do not interfere with our protocol. std::ostringstream oss; @@ -308,7 +308,7 @@ int main (int argc, char** argv) { Hello().write(std::cout); int exit_code = 0; - while (1) { + for (;;) { const int32_t msg_type = sread(std::cin); switch (msg_type) { case IFC_MODEL: { @@ -323,7 +323,7 @@ int main (int argc, char** argv) { settings.convert_back_units() = true; settings.include_curves() = true; - iterator = new IfcGeom::Iterator(settings, data, len); + iterator = new IfcGeom::Iterator(settings, data, (int)len); has_more = iterator->initialize(); More(has_more).write(std::cout); diff --git a/src/ifcopenshell-python/ifcopenshell/__init__.py b/src/ifcopenshell-python/ifcopenshell/__init__.py index 4d9f8b4d34..eb14ece33a 100644 --- a/src/ifcopenshell-python/ifcopenshell/__init__.py +++ b/src/ifcopenshell-python/ifcopenshell/__init__.py @@ -82,6 +82,9 @@ class entity_instance(object): attr_type = self.attribute_type(idx).title().replace(' ', '') attr_type = attr_type.replace('Binary', 'String') attr_type = attr_type.replace('Enumeration', 'String') + try: + if isinstance(value, unicode): value = value.encode("utf-8") + except: pass getattr(self.wrapped_data, "setArgumentAs%s" % attr_type)(idx, entity_instance.unwrap_value(value)) return value def __len__(self): return len(self.wrapped_data) @@ -141,3 +144,6 @@ def create_entity(type,*args,**kwargs): for idx, arg in attrs: e[idx] = arg return e + +version = ifcopenshell_wrapper.version() +schema_identifier = ifcopenshell_wrapper.schema_identifier() diff --git a/src/ifcopenshell-python/ifcopenshell/geom/__init__.py b/src/ifcopenshell-python/ifcopenshell/geom/__init__.py index 8550f4013d..f4d05f86dc 100644 --- a/src/ifcopenshell-python/ifcopenshell/geom/__init__.py +++ b/src/ifcopenshell-python/ifcopenshell/geom/__init__.py @@ -31,7 +31,7 @@ def has_occ(): has_occ = has_occ() wrap_shape_creation = lambda settings, shape: shape if has_occ: - import occ_utils as utils + from . import occ_utils as utils wrap_shape_creation = lambda settings, shape: utils.create_shape_from_serialization(shape) if getattr(settings, 'use_python_opencascade', False) else shape diff --git a/src/ifcopenshell-python/ifcopenshell/geom/occ_utils.py b/src/ifcopenshell-python/ifcopenshell/geom/occ_utils.py index be5c93e8b3..004151ec1e 100644 --- a/src/ifcopenshell-python/ifcopenshell/geom/occ_utils.py +++ b/src/ifcopenshell-python/ifcopenshell/geom/occ_utils.py @@ -1,3 +1,22 @@ +############################################################################### +# # +# 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 . # +# # +############################################################################### + import random from collections import namedtuple @@ -52,8 +71,14 @@ def get_bounding_box_center(bbox): def create_shape_from_serialization(brep_object): brep_data, occ_shape = None, None - try: brep_data = brep_object.geometry.brep_data - except: pass + is_product_shape = True + try: + brep_data = brep_object.geometry.brep_data + except: + try: + brep_data = brep_object.brep_data + is_product_shape = False + except: pass if not brep_data: return tuple(brep_object, None) try: @@ -62,5 +87,8 @@ def create_shape_from_serialization(brep_object): occ_shape = ss.Shape(ss.NbShapes()) except: pass - return tuple(brep_object, occ_shape) + if is_product_shape: + return tuple(brep_object, occ_shape) + else: + return occ_shape diff --git a/src/ifcparse/Ifc2x3-latebound.cpp b/src/ifcparse/Ifc2x3-latebound.cpp index 289b4279c4..fcc21020e0 100644 --- a/src/ifcparse/Ifc2x3-latebound.cpp +++ b/src/ifcparse/Ifc2x3-latebound.cpp @@ -4247,48 +4247,48 @@ std::pair Type::GetEnumerationIndex(Enum t, const std::string& } std::pair Type::GetInverseAttribute(Enum t, const std::string& a) { - if (inverse_map.empty()) ::InitInverseMap(); - inverse_map_t::const_iterator it; - inverse_map_t::mapped_type::const_iterator jt; - while (true) { + if (inverse_map.empty()) ::InitInverseMap(); + inverse_map_t::const_iterator it; + inverse_map_t::mapped_type::const_iterator jt; + for(;;) { it = inverse_map.find(t); if (it != inverse_map.end()) { - jt = it->second.find(a); - if (jt != it->second.end()) { - return jt->second; - } - } + jt = it->second.find(a); + if (jt != it->second.end()) { + return jt->second; + } + } if ((t = Parent(t)) == -1) break; } throw IfcException("Attribute not found"); } std::set Type::GetInverseAttributeNames(Enum t) { - if (inverse_map.empty()) ::InitInverseMap(); - inverse_map_t::const_iterator it; - inverse_map_t::mapped_type::const_iterator jt; + if (inverse_map.empty()) ::InitInverseMap(); + inverse_map_t::const_iterator it; + inverse_map_t::mapped_type::const_iterator jt; - std::set return_value; + std::set return_value; - while (true) { + for (;;) { it = inverse_map.find(t); if (it != inverse_map.end()) { - for (jt = it->second.begin(); jt != it->second.end(); ++jt) { - return_value.insert(jt->first); - } - } + for (jt = it->second.begin(); jt != it->second.end(); ++jt) { + return_value.insert(jt->first); + } + } if ((t = Parent(t)) == -1) break; } - - return return_value; + + return return_value; } void Type::PopulateDerivedFields(IfcWrite::IfcWritableEntity* e) { std::map >::const_iterator i = derived_map.find(e->type()); - if (i != derived_map.end()) { - for (std::set::const_iterator it = i->second.begin(); it != i->second.end(); ++it) { - e->setArgumentDerived(*it); - } - } + if (i != derived_map.end()) { + for (std::set::const_iterator it = i->second.begin(); it != i->second.end(); ++it) { + e->setArgumentDerived(*it); + } + } } #endif diff --git a/src/ifcparse/Ifc2x3.cpp b/src/ifcparse/Ifc2x3.cpp index bc9cdb79b4..dfd535c7ba 100644 --- a/src/ifcparse/Ifc2x3.cpp +++ b/src/ifcparse/Ifc2x3.cpp @@ -32,6 +32,8 @@ #include "../ifcparse/IfcWrite.h" #include "../ifcparse/IfcWritableEntity.h" +#include + using namespace Ifc2x3; using namespace IfcParse; using namespace IfcWrite; diff --git a/src/ifcparse/Ifc2x3.h b/src/ifcparse/Ifc2x3.h index 39286420c9..fb919dca1a 100644 --- a/src/ifcparse/Ifc2x3.h +++ b/src/ifcparse/Ifc2x3.h @@ -29,7 +29,6 @@ #include #include -#include #include @@ -40,6 +39,11 @@ const IfcParse::schema_definition& get_schema(); +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + #define IfcSchema Ifc2x3 namespace Ifc2x3 { @@ -37317,4 +37321,8 @@ void InitStringMap(); IfcUtil::IfcBaseClass* SchemaEntity(IfcAbstractEntity* e = 0); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + #endif diff --git a/src/ifcparse/Ifc4-latebound.cpp b/src/ifcparse/Ifc4-latebound.cpp index 4cb4bb0364..e136fba57c 100644 --- a/src/ifcparse/Ifc4-latebound.cpp +++ b/src/ifcparse/Ifc4-latebound.cpp @@ -4941,48 +4941,48 @@ std::pair Type::GetEnumerationIndex(Enum t, const std::string& } std::pair Type::GetInverseAttribute(Enum t, const std::string& a) { - if (inverse_map.empty()) ::InitInverseMap(); - inverse_map_t::const_iterator it; - inverse_map_t::mapped_type::const_iterator jt; - while (true) { + if (inverse_map.empty()) ::InitInverseMap(); + inverse_map_t::const_iterator it; + inverse_map_t::mapped_type::const_iterator jt; + for(;;) { it = inverse_map.find(t); if (it != inverse_map.end()) { - jt = it->second.find(a); - if (jt != it->second.end()) { - return jt->second; - } - } + jt = it->second.find(a); + if (jt != it->second.end()) { + return jt->second; + } + } if ((t = Parent(t)) == -1) break; } throw IfcException("Attribute not found"); } std::set Type::GetInverseAttributeNames(Enum t) { - if (inverse_map.empty()) ::InitInverseMap(); - inverse_map_t::const_iterator it; - inverse_map_t::mapped_type::const_iterator jt; + if (inverse_map.empty()) ::InitInverseMap(); + inverse_map_t::const_iterator it; + inverse_map_t::mapped_type::const_iterator jt; - std::set return_value; + std::set return_value; - while (true) { + for (;;) { it = inverse_map.find(t); if (it != inverse_map.end()) { - for (jt = it->second.begin(); jt != it->second.end(); ++jt) { - return_value.insert(jt->first); - } - } + for (jt = it->second.begin(); jt != it->second.end(); ++jt) { + return_value.insert(jt->first); + } + } if ((t = Parent(t)) == -1) break; } - - return return_value; + + return return_value; } void Type::PopulateDerivedFields(IfcWrite::IfcWritableEntity* e) { std::map >::const_iterator i = derived_map.find(e->type()); - if (i != derived_map.end()) { - for (std::set::const_iterator it = i->second.begin(); it != i->second.end(); ++it) { - e->setArgumentDerived(*it); - } - } + if (i != derived_map.end()) { + for (std::set::const_iterator it = i->second.begin(); it != i->second.end(); ++it) { + e->setArgumentDerived(*it); + } + } } #endif diff --git a/src/ifcparse/Ifc4.cpp b/src/ifcparse/Ifc4.cpp index dd3a4b39b1..a262cf7ce4 100644 --- a/src/ifcparse/Ifc4.cpp +++ b/src/ifcparse/Ifc4.cpp @@ -32,6 +32,8 @@ #include "../ifcparse/IfcWrite.h" #include "../ifcparse/IfcWritableEntity.h" +#include + using namespace Ifc4; using namespace IfcParse; using namespace IfcWrite; diff --git a/src/ifcparse/Ifc4.h b/src/ifcparse/Ifc4.h index 347fd153f3..97063ebf92 100644 --- a/src/ifcparse/Ifc4.h +++ b/src/ifcparse/Ifc4.h @@ -29,7 +29,6 @@ #include #include -#include #include @@ -40,6 +39,11 @@ const IfcParse::schema_definition& get_schema(); +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + #define IfcSchema Ifc4 namespace Ifc4 { @@ -50176,4 +50180,8 @@ void InitStringMap(); IfcUtil::IfcBaseClass* SchemaEntity(IfcAbstractEntity* e = 0); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + #endif diff --git a/src/ifcparse/IfcCharacterDecoder.cpp b/src/ifcparse/IfcCharacterDecoder.cpp index c33a6f9b0c..f45c941528 100644 --- a/src/ifcparse/IfcCharacterDecoder.cpp +++ b/src/ifcparse/IfcCharacterDecoder.cpp @@ -47,6 +47,7 @@ #define ENDEXTENDED_0 (1 << 20) #define FOURTH_SOLIDUS (1 << 21) #define IGNORED_DIRECTIVE (1 << 22) +#define ENCOUNTERED_HEX (1 << 23) // FIXME: These probably need to be less forgiving in terms of wrongly defined sequences #define EXPECTS_ALPHABET(S) (S & FIRST_SOLIDUS) @@ -64,7 +65,7 @@ #define IS_VALID_ALPHABET_DEFINITION(C) (C >= 0x40 && C <= 0x4A) #define IS_HEXADECIMAL(C) ((C >= 0x30 && C <= 0x39 ) || (C >= 0x41 && C <= 0x46 )) #define HEX_TO_INT(C) ((C >= 0x30 && C <= 0x39 ) ? C - 0x30 : (C+10) - 0x41) -#define CLEAR_HEX(C) (C &= ~(HEX(1)&HEX(2)&HEX(3)&HEX(4)&HEX(5)&HEX(6)&HEX(7)&HEX(8))) +#define CLEAR_HEX(C) (C &= ~(HEX(1)|HEX(2)|HEX(3)|HEX(4)|HEX(5)|HEX(6)|HEX(7)|HEX(8))) using namespace IfcParse; using namespace IfcWrite; @@ -117,6 +118,7 @@ IfcCharacterDecoder::~IfcCharacterDecoder() { destination = 0; converter = 0; compatibility_converter = 0; + ucnv_flushCache(); #endif } IfcCharacterDecoder::operator std::string() { @@ -130,12 +132,12 @@ IfcCharacterDecoder::operator std::string() { #ifdef HAVE_ICU unsigned int old_hex = 0; // for compatibility_mode #endif - while ( current_char = file->Peek() ) { + while ( (current_char = file->Peek()) != 0 ) { if ( EXPECTS_CHARACTER(parse_state) ) { #ifdef HAVE_ICU if ( previous_codepage != codepage ) { if ( converter ) ucnv_close(converter); - char encoder[11] = {'i','s','o','-','8','8','5','9','-',codepage + 0x30}; + char encoder[11] = {'i','s','o','-','8','8','5','9','-', (char)codepage + 0x30}; converter = ucnv_open(encoder, &status); } const char characters[2] = { current_char + 0x80 }; @@ -155,7 +157,10 @@ IfcCharacterDecoder::operator std::string() { if ( parse_state & ALPHABET_DEFINITION || parse_state & IGNORED_DIRECTIVE || parse_state & ENDEXTENDED_0 ) parse_state = hex = hex_count = 0; - else if ( parse_state & HEX(3) ) parse_state += THIRD_SOLIDUS; + else if ( parse_state & ENCOUNTERED_HEX ) { + parse_state += THIRD_SOLIDUS; + parse_state -= ENCOUNTERED_HEX; + } else parse_state += SECOND_SOLIDUS; } else if ( current_char == 'X' && EXPECTS_ENDEXTENDED_X(parse_state) ) { parse_state += ENDEXTENDED_X; @@ -188,7 +193,7 @@ IfcCharacterDecoder::operator std::string() { if (old_hex == 0) { old_hex = hex; } else { - char characters[3] = { old_hex, hex }; + char characters[3] = { (char)old_hex, (char)hex }; const char* char_array = &characters[0]; UChar32 ch = ucnv_getNextUChar(compatibility_converter,&char_array,char_array+2,&status); addChar(s,ch); @@ -202,7 +207,10 @@ IfcCharacterDecoder::operator std::string() { } #endif if ( hex_count == 2 ) parse_state = 0; - else CLEAR_HEX(parse_state); + else { + CLEAR_HEX(parse_state); + parse_state |= ENCOUNTERED_HEX; + } hex = hex_count = 0; } } else if ( parse_state && !( @@ -227,7 +235,7 @@ void IfcCharacterDecoder::dryRun() { unsigned int parse_state = 0; char current_char; unsigned int hex_count = 0; - while ( current_char = file->Peek() ) { + while ((current_char = file->Peek()) != 0) { if ( EXPECTS_CHARACTER(parse_state) ) { parse_state = 0; } else if ( current_char == '\'' && ! parse_state ) { @@ -238,7 +246,10 @@ void IfcCharacterDecoder::dryRun() { if ( parse_state & ALPHABET_DEFINITION || parse_state & IGNORED_DIRECTIVE || parse_state & ENDEXTENDED_0 ) parse_state = hex_count = 0; - else if ( parse_state & HEX(3) ) parse_state += THIRD_SOLIDUS; + else if ( parse_state & ENCOUNTERED_HEX ) { + parse_state += THIRD_SOLIDUS; + parse_state -= ENCOUNTERED_HEX; + } else parse_state += SECOND_SOLIDUS; } else if ( current_char == 'X' && EXPECTS_ENDEXTENDED_X(parse_state) ) { parse_state += ENDEXTENDED_X; @@ -264,7 +275,10 @@ void IfcCharacterDecoder::dryRun() { (hex_count == 4 && !(parse_state & EXTENDED4)) || (hex_count == 8) ) { if ( hex_count == 2 ) parse_state = 0; - else CLEAR_HEX(parse_state); + else { + CLEAR_HEX(parse_state); + parse_state |= ENCOUNTERED_HEX; + } hex_count = 0; } } else if ( parse_state && !( @@ -288,7 +302,7 @@ UErrorCode IfcCharacterDecoder::status = U_ZERO_ERROR; #endif #ifdef HAVE_ICU -IfcCharacterDecoder::ConversionMode IfcCharacterDecoder::mode = IfcCharacterDecoder::JSON; +IfcCharacterDecoder::ConversionMode IfcCharacterDecoder::mode = IfcCharacterDecoder::UTF8; // Many BIM software (eg. Revit, ArchiCAD, ...) has wrong behavior bool IfcCharacterDecoder::compatibility_mode = false; @@ -340,8 +354,8 @@ IfcCharacterEncoder::operator std::string() { oss << "\\X" << num_bytes_str << "\\"; } if ( within_spf_range ) { - oss.put(ch); - if ( ch == '\\' || ch == '\'' ) oss.put(ch); + oss.put((char)ch); + if ( ch == '\\' || ch == '\'' ) oss.put((char)ch); } else { oss << std::hex << std::setw(num_bytes*2) << std::uppercase << std::setfill('0') << (int) ch; } @@ -352,8 +366,15 @@ IfcCharacterEncoder::operator std::string() { #else for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) { char ch = *i; - if ( ch == '\\' || ch == '\'' ) oss.put(ch); - oss.put(ch); + const bool within_spf_range = ch >= 0x20 && ch <= 0x7e; + if (within_spf_range) { + if ( ch == '\\' || ch == '\'' ) { + oss.put(ch); + } + oss.put(ch); + } else { + oss.put('_'); + } } #endif oss.put('\''); diff --git a/src/ifcparse/IfcEntityDescriptor.h b/src/ifcparse/IfcEntityDescriptor.h index 588a90337e..12aa562c70 100644 --- a/src/ifcparse/IfcEntityDescriptor.h +++ b/src/ifcparse/IfcEntityDescriptor.h @@ -26,7 +26,8 @@ #include #include -#include "../ifcparse/SharedPointer.h" +#include + #include "../ifcparse/IfcUtil.h" #include "../ifcparse/IfcException.h" @@ -48,7 +49,7 @@ namespace IfcUtil { std::pair getIndex(const std::string& value) const { std::vector::const_iterator it = std::find(values.begin(), values.end(), value); if (it != values.end()) { - return std::make_pair(it->c_str(), std::distance(it, values.begin())); + return std::make_pair(it->c_str(), (int)std::distance(it, values.begin())); } else { throw IfcParse::IfcException("Invalid enumeration value"); } @@ -91,7 +92,7 @@ namespace IfcUtil { arguments.push_back(IfcArgumentDescriptor(name, optional, argument_type, data_type)); } unsigned getArgumentCount() const { - return (parent ? parent->getArgumentCount() : 0) + arguments.size(); + return (parent ? parent->getArgumentCount() : 0) + (unsigned)arguments.size(); } const std::string& getArgumentName(unsigned i) const { const unsigned a = argument_start(); diff --git a/src/ifcparse/IfcGlobalId.cpp b/src/ifcparse/IfcGlobalId.cpp index 85cdc1ad1c..e70189071f 100644 --- a/src/ifcparse/IfcGlobalId.cpp +++ b/src/ifcparse/IfcGlobalId.cpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "../ifcparse/IfcGlobalId.h" #include "../ifcparse/IfcException.h" @@ -38,7 +40,7 @@ std::string base64(unsigned v, int l) { r.push_back(chars[v%64]); v /= 64; } - while ( r.size() != l ) r.push_back('0'); + while ( (int)r.size() != l ) r.push_back('0'); std::reverse(r.begin(),r.end()); return r; } @@ -52,7 +54,7 @@ unsigned from_base64(const std::string& s) { r *= 64; const char* c = strchr(chars,*i); if ( !c ) throw IfcParse::IfcException("Failed to decode GlobalId"); - r += (c-chars); + r += (unsigned)(c-chars); } return r; } @@ -70,7 +72,7 @@ std::string compress(unsigned char* v) { // Expands the base64 representation into a UUID byte array void expand(const std::string& s, std::vector& v) { - v.push_back(from_base64(s.substr(0,2))); + v.push_back((unsigned char)from_base64(s.substr(0,2))); for( unsigned i = 0; i < 5; ++i ) { unsigned d = from_base64(s.substr(2+4*i,4)); for ( unsigned j = 0; j < 3; ++ j ) { @@ -87,7 +89,11 @@ IfcParse::IfcGlobalId::IfcGlobalId() { std::vector v(uuid_data.size()); std::copy(uuid_data.begin(), uuid_data.end(), v.begin()); string_data = compress(&v[0]); +#if BOOST_VERSION < 104400 + formatted_string = boost::lexical_cast(uuid_data); +#else formatted_string = boost::uuids::to_string(uuid_data); +#endif #ifndef NDEBUG std::vector test_vector; @@ -106,7 +112,11 @@ IfcParse::IfcGlobalId::IfcGlobalId(const std::string& s) std::vector v; expand(string_data, v); std::copy(v.begin(), v.end(), uuid_data.begin()); +#if BOOST_VERSION < 104400 + formatted_string = boost::lexical_cast(uuid_data); +#else formatted_string = boost::uuids::to_string(uuid_data); +#endif #ifndef NDEBUG const std::string test_string = compress(&uuid_data.data[0]); diff --git a/src/ifcparse/IfcHierarchyHelper.cpp b/src/ifcparse/IfcHierarchyHelper.cpp index d29e5d716f..a11c69480a 100644 --- a/src/ifcparse/IfcHierarchyHelper.cpp +++ b/src/ifcparse/IfcHierarchyHelper.cpp @@ -290,7 +290,7 @@ void IfcHierarchyHelper::addBox(IfcSchema::IfcShapeRepresentation* rep, double w IfcSchema::IfcAxis2Placement2D* place, IfcSchema::IfcAxis2Placement3D* place2, IfcSchema::IfcDirection* dir, IfcSchema::IfcRepresentationContext* context) { - if (false) { + if (false) { // TODO What's this? IfcSchema::IfcRectangleProfileDef* profile = new IfcSchema::IfcRectangleProfileDef( IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, boost::none, place ? place : addPlacement2d(), w, d); IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(profile, @@ -303,10 +303,10 @@ void IfcHierarchyHelper::addBox(IfcSchema::IfcShapeRepresentation* rep, double w rep->setItems(items); } else { std::vector > points; - points.push_back(std::pair(-w/2, -d/2)); - points.push_back(std::pair(w/2, -d/2)); - points.push_back(std::pair(w/2, d/2)); - points.push_back(std::pair(-w/2, d/2)); + points.push_back(std::make_pair(-w/2, -d/2)); + points.push_back(std::make_pair(w/2, -d/2)); + points.push_back(std::make_pair(w/2, d/2)); + points.push_back(std::make_pair(-w/2, d/2)); // The call to addExtrudedPolyline() closes the polyline addExtrudedPolyline(rep, points, h, place, place2, dir, context); } diff --git a/src/ifcparse/IfcHierarchyHelper.h b/src/ifcparse/IfcHierarchyHelper.h index b8ad5d7a21..7a1393632b 100644 --- a/src/ifcparse/IfcHierarchyHelper.h +++ b/src/ifcparse/IfcHierarchyHelper.h @@ -78,8 +78,8 @@ public: double xx=1.0, double xy=0.0, double xz=0.0); template - void addRelatedObject(IfcSchema::IfcObjectDefinition* related_object, - IfcSchema::IfcObjectDefinition* relating_object, IfcSchema::IfcOwnerHistory* owner_hist = 0) + void addRelatedObject(IfcSchema::IfcObjectDefinition* relating_object, + IfcSchema::IfcObjectDefinition* related_object, IfcSchema::IfcOwnerHistory* owner_hist = 0) { typename T::list::ptr li = entitiesByType(); bool found = false; @@ -100,9 +100,9 @@ public: if (! owner_hist) { owner_hist = addOwnerHistory(); } - IfcSchema::IfcObjectDefinition::list::ptr relating_objects (new IfcTemplatedEntityList()); - relating_objects->push(relating_object); - T* t = new T(IfcParse::IfcGlobalId(), owner_hist, boost::none, boost::none, related_object, relating_objects); + IfcSchema::IfcObjectDefinition::list::ptr related_objects (new IfcTemplatedEntityList()); + related_objects->push(related_object); + T* t = new T(IfcParse::IfcGlobalId(), owner_hist, boost::none, boost::none, relating_object, related_objects); addEntity(t); } } @@ -174,14 +174,14 @@ private: }; template <> -inline void IfcHierarchyHelper::addRelatedObject (IfcSchema::IfcObjectDefinition* related_object, - IfcSchema::IfcObjectDefinition* relating_object, IfcSchema::IfcOwnerHistory* owner_hist) +inline void IfcHierarchyHelper::addRelatedObject (IfcSchema::IfcObjectDefinition* relating_structure, + IfcSchema::IfcObjectDefinition* related_object, IfcSchema::IfcOwnerHistory* owner_hist) { IfcSchema::IfcRelContainedInSpatialStructure::list::ptr li = entitiesByType(); bool found = false; for (IfcSchema::IfcRelContainedInSpatialStructure::list::it i = li->begin(); i != li->end(); ++i) { IfcSchema::IfcRelContainedInSpatialStructure* rel = *i; - if (rel->RelatingStructure() == relating_object) { + if (rel->RelatingStructure() == relating_structure) { IfcSchema::IfcProduct::list::ptr products = rel->RelatedElements(); products->push((IfcSchema::IfcProduct*)related_object); rel->setRelatedElements(products); @@ -196,10 +196,42 @@ inline void IfcHierarchyHelper::addRelatedObject ()); - relating_objects->push((IfcSchema::IfcProduct*)relating_object); + IfcSchema::IfcProduct::list::ptr related_objects (new IfcTemplatedEntityList()); + related_objects->push((IfcSchema::IfcProduct*)related_object); IfcSchema::IfcRelContainedInSpatialStructure* t = new IfcSchema::IfcRelContainedInSpatialStructure(IfcParse::IfcGlobalId(), owner_hist, - boost::none, boost::none, relating_objects, (IfcSchema::IfcSpatialStructureElement*)related_object); + boost::none, boost::none, related_objects, (IfcSchema::IfcSpatialStructureElement*)relating_structure); + + addEntity(t); + } +} + +template <> +inline void IfcHierarchyHelper::addRelatedObject (IfcSchema::IfcObjectDefinition* relating_type, + IfcSchema::IfcObjectDefinition* related_object, IfcSchema::IfcOwnerHistory* owner_hist) +{ + IfcSchema::IfcRelDefinesByType::list::ptr li = entitiesByType(); + bool found = false; + for (IfcSchema::IfcRelDefinesByType::list::it i = li->begin(); i != li->end(); ++i) { + IfcSchema::IfcRelDefinesByType* rel = *i; + if (rel->RelatingType() == relating_type) { + IfcSchema::IfcObject::list::ptr objects = rel->RelatedObjects(); + objects->push((IfcSchema::IfcObject*)related_object); + rel->setRelatedObjects(objects); + found = true; + break; + } + } + if (! found) { + if (! owner_hist) { + owner_hist = getSingle(); + } + if (! owner_hist) { + owner_hist = addOwnerHistory(); + } + IfcSchema::IfcObject::list::ptr related_objects (new IfcTemplatedEntityList()); + related_objects->push((IfcSchema::IfcObject*)related_object); + IfcSchema::IfcRelDefinesByType* t = new IfcSchema::IfcRelDefinesByType(IfcParse::IfcGlobalId(), owner_hist, + boost::none, boost::none, related_objects, (IfcSchema::IfcTypeObject*)relating_type); addEntity(t); } diff --git a/src/ifcparse/IfcLateBoundEntity.cpp b/src/ifcparse/IfcLateBoundEntity.cpp index 43d0281498..f18dc74403 100644 --- a/src/ifcparse/IfcLateBoundEntity.cpp +++ b/src/ifcparse/IfcLateBoundEntity.cpp @@ -19,6 +19,8 @@ #include +#include + #include "../ifcparse/IfcWritableEntity.h" #include "../ifcparse/IfcUtil.h" @@ -44,14 +46,14 @@ IfcWrite::IfcWritableEntity* IfcParse::IfcLateBoundEntity::writable_entity() { return e; } IfcParse::IfcLateBoundEntity::IfcLateBoundEntity(const std::string& s) { - std::string S = s; - for (std::string::iterator i = S.begin(); i != S.end(); ++i ) *i = toupper(*i); - _type = IfcSchema::Type::FromString(S); + _type = IfcSchema::Type::FromString(boost::to_upper_copy(s)); data_ = new IfcWrite::IfcWritableEntity(_type); + for (unsigned i = 0; i < getArgumentCount(); ++i) { // Side effect of this is that a NULL attribute is created. data_->getArgument(i); } + IfcSchema::Type::PopulateDerivedFields(writable_entity()); } IfcParse::IfcLateBoundEntity::IfcLateBoundEntity(IfcAbstractEntity* e) { @@ -83,9 +85,7 @@ std::string IfcParse::IfcLateBoundEntity::is_a() const { return IfcSchema::Type::ToString(_type); } bool IfcParse::IfcLateBoundEntity::is_a(const std::string& s) const { - std::string S = s; - for (std::string::iterator i = S.begin(); i != S.end(); ++i ) *i = toupper(*i); - return is(IfcSchema::Type::FromString(S)); + return is(IfcSchema::Type::FromString(boost::to_upper_copy(s))); } IfcSchema::Type::Enum IfcParse::IfcLateBoundEntity::type() const { return _type; @@ -94,35 +94,35 @@ unsigned int IfcParse::IfcLateBoundEntity::getArgumentCount() const { return IfcSchema::Type::GetAttributeCount(_type); } IfcUtil::ArgumentType IfcParse::IfcLateBoundEntity::getArgumentType(unsigned int i) const { - return IfcSchema::Type::GetAttributeDerived(_type, i) + return IfcSchema::Type::GetAttributeDerived(_type, (unsigned char)i) ? IfcUtil::Argument_DERIVED - : IfcSchema::Type::GetAttributeType(_type,i); + : IfcSchema::Type::GetAttributeType(_type, (unsigned char)i); } IfcSchema::Type::Enum IfcParse::IfcLateBoundEntity::getArgumentEntity(unsigned int i) const { - return IfcSchema::Type::GetAttributeEntity(_type, i); + return IfcSchema::Type::GetAttributeEntity(_type, (unsigned char)i); } Argument* IfcParse::IfcLateBoundEntity::getArgument(unsigned int i) const { return data_->getArgument(i); } const char* IfcParse::IfcLateBoundEntity::getArgumentName(unsigned int i) const { - return IfcSchema::Type::GetAttributeName(_type,i).c_str(); + return IfcSchema::Type::GetAttributeName(_type, (unsigned char)i).c_str(); } bool IfcParse::IfcLateBoundEntity::getArgumentOptionality(unsigned int i) const { - return IfcSchema::Type::GetAttributeOptional(_type, i); + return IfcSchema::Type::GetAttributeOptional(_type, (unsigned char)i); } void IfcParse::IfcLateBoundEntity::invalid_argument(unsigned int i, const std::string& t) { - const std::string arg_name = IfcSchema::Type::GetAttributeName(_type,i); + const std::string arg_name = IfcSchema::Type::GetAttributeName(_type, (unsigned char)i); throw IfcException(t + " is not a valid type for '" + arg_name + "'"); } void IfcParse::IfcLateBoundEntity::setArgumentAsNull(unsigned int i) { - bool is_optional = IfcSchema::Type::GetAttributeOptional(_type, i); + bool is_optional = IfcSchema::Type::GetAttributeOptional(_type, (unsigned char)i); if (is_optional) { writable_entity()->setArgument(i); } else invalid_argument(i,"NULL"); } void IfcParse::IfcLateBoundEntity::setArgumentAsInt(unsigned int i, int v) { - IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); + IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type, (unsigned char)i); if (arg_type == Argument_INT) { writable_entity()->setArgument(i,v); } else if ( (arg_type == Argument_BOOL) && ( (v == 0) || (v == 1) ) ) { @@ -130,23 +130,23 @@ void IfcParse::IfcLateBoundEntity::setArgumentAsInt(unsigned int i, int v) { } else invalid_argument(i,"INTEGER"); } void IfcParse::IfcLateBoundEntity::setArgumentAsBool(unsigned int i, bool v) { - IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); + IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type, (unsigned char)i); if (arg_type == Argument_BOOL) { writable_entity()->setArgument(i,v); } else invalid_argument(i,"BOOLEAN"); } void IfcParse::IfcLateBoundEntity::setArgumentAsDouble(unsigned int i, double v) { - IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); + IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type, (unsigned char)i); if (arg_type == Argument_DOUBLE) { writable_entity()->setArgument(i,v); } else invalid_argument(i,"REAL"); } void IfcParse::IfcLateBoundEntity::setArgumentAsString(unsigned int i, const std::string& a) { - IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); + IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type, (unsigned char)i); if (arg_type == Argument_STRING) { writable_entity()->setArgument(i,a); } else if (arg_type == Argument_ENUMERATION) { - std::pair enum_data = IfcSchema::Type::GetEnumerationIndex(IfcSchema::Type::GetAttributeEntity(_type, i), a); + std::pair enum_data = IfcSchema::Type::GetEnumerationIndex(IfcSchema::Type::GetAttributeEntity(_type, (unsigned char)i), a); writable_entity()->setArgument(i, enum_data.second, enum_data.first); } else if (arg_type == Argument_BINARY) { if (valid_binary_string(a)) { @@ -158,19 +158,19 @@ void IfcParse::IfcLateBoundEntity::setArgumentAsString(unsigned int i, const std } else invalid_argument(i,"STRING"); } void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfInt(unsigned int i, const std::vector& v) { - IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); + IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type, (unsigned char)i); if (arg_type == Argument_AGGREGATE_OF_INT) { writable_entity()->setArgument(i,v); } else invalid_argument(i,"AGGREGATE OF INT"); } void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfDouble(unsigned int i, const std::vector& v) { - IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); + IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type, (unsigned char)i); if (arg_type == Argument_AGGREGATE_OF_DOUBLE) { writable_entity()->setArgument(i,v); } else invalid_argument(i,"AGGREGATE OF DOUBLE"); } void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfString(unsigned int i, const std::vector& v) { - IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); + IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type, (unsigned char)i); if (arg_type == Argument_AGGREGATE_OF_STRING) { writable_entity()->setArgument(i,v); } else if (arg_type == Argument_AGGREGATE_OF_BINARY) { @@ -187,31 +187,31 @@ void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfString(unsigned int i } else invalid_argument(i,"AGGREGATE OF STRING"); } void IfcParse::IfcLateBoundEntity::setArgumentAsEntityInstance(unsigned int i, IfcParse::IfcLateBoundEntity* v) { - IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); + IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type, (unsigned char)i); if (arg_type == Argument_ENTITY_INSTANCE) { writable_entity()->setArgument(i,v); } else invalid_argument(i,"ENTITY INSTANCE"); } void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfEntityInstance(unsigned int i, IfcEntityList::ptr v) { - IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); + IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type, (unsigned char)i); if (arg_type == Argument_AGGREGATE_OF_ENTITY_INSTANCE) { writable_entity()->setArgument(i,v); } else invalid_argument(i,"AGGREGATE OF ENTITY INSTANCE"); } void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfAggregateOfInt(unsigned int i, const std::vector< std::vector >& v) { - IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); + IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type, (unsigned char)i); if (arg_type == Argument_AGGREGATE_OF_AGGREGATE_OF_INT) { writable_entity()->setArgument(i,v); } else invalid_argument(i,"AGGREGATE OF AGGREGATE OF INT"); } void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfAggregateOfDouble(unsigned int i, const std::vector< std::vector >& v) { - IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); + IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type, (unsigned char)i); if (arg_type == Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE) { writable_entity()->setArgument(i,v); } else invalid_argument(i,"AGGREGATE OF AGGREGATE OF DOUBLE"); } void IfcParse::IfcLateBoundEntity::setArgumentAsAggregateOfAggregateOfEntityInstance(unsigned int i, IfcEntityListList::ptr v) { - IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type,i); + IfcUtil::ArgumentType arg_type = IfcSchema::Type::GetAttributeType(_type, (unsigned char)i); if (arg_type == Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE) { writable_entity()->setArgument(i,v); } else invalid_argument(i,"AGGREGATE OF AGGREGATE OF ENTITY INSTANCE"); @@ -237,7 +237,7 @@ bool IfcParse::IfcLateBoundEntity::is_valid() { const Argument& arg = *getArgument(i); is_null = arg.isNull(); } catch(IfcException) {} - if (!IfcSchema::Type::GetAttributeOptional(_type,i) && is_null) { + if (!IfcSchema::Type::GetAttributeOptional(_type, (unsigned char)i) && is_null) { if (!valid) { oss << ", "; } diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index ebbb7e6bdb..9573a0707c 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -28,6 +28,8 @@ #include #endif +#include + #include "../ifcparse/IfcCharacterDecoder.h" #include "../ifcparse/IfcParse.h" #include "../ifcparse/IfcException.h" @@ -127,6 +129,11 @@ IfcSpfStream::IfcSpfStream(void* data, int l) { len = l; } +IfcSpfStream::~IfcSpfStream() +{ + Close(); +} + void IfcSpfStream::Close() { #ifdef BUF_SIZE if ( paging ) fclose(stream); @@ -143,6 +150,8 @@ void IfcSpfStream::ReadBuffer(bool inc) { offset += len; fseek(stream, offset, SEEK_SET); } +#else + (void)inc; #endif eof = feof(stream) != 0; if ( eof ) return; @@ -308,7 +317,7 @@ Token IfcSpfLexer::Next() { while ( ! stream->eof ) { // Read character and increment pointer if not starting a new token - char c = stream->Peek(); + c = stream->Peek(); if ( len && (c == '(' || c == ')' || c == '=' || c == ',' || c == ';' || c == '/') ) break; stream->Inc(); len ++; @@ -363,7 +372,7 @@ bool TokenFunc::startsWith(const Token& t, char c) { } bool TokenFunc::isOperator(const Token& t, char op) { - return (!t.first) && (!op || op == t.second); + return (!t.first) && (!op || (unsigned)op == t.second); } bool TokenFunc::isIdentifier(const Token& t) { @@ -394,8 +403,8 @@ bool TokenFunc::isInt(const Token& t) { const std::string str = asString(t); const char* start = str.c_str(); char* end; - long result = strtol(start,&end,10); - return ((end - start) == str.length()); + /*long result =*/ strtol(start,&end,10); + return ((end - start) == (ptrdiff_t)str.length()); } bool TokenFunc::isBool(const Token& t) { @@ -412,11 +421,11 @@ bool TokenFunc::isFloat(const Token& t) { const char* start = str.c_str(); char* end; #ifdef _MSC_VER - double result = _strtod_l(start,&end,locale); + /*double result =*/ _strtod_l(start,&end,locale); #else double result = strtod_l(start,&end,locale); #endif - return ((end - start) == str.length()); + return ((end - start) == (ptrdiff_t)str.length()); } int TokenFunc::asInt(const Token& t) { @@ -467,7 +476,7 @@ boost::dynamic_bitset<> TokenFunc::asBinary(const Token& t) { } ++it; - unsigned i = (str.size()-1) * 4 - n; + unsigned i = ((unsigned)str.size()-1) * 4 - n; boost::dynamic_bitset<> bitset(i); for(; it != str.end(); ++it) { @@ -508,8 +517,7 @@ EntityArgument::EntityArgument(const Token& t) { // Aditionally, stores the ids (i.e. #[\d]+) in a vector // void ArgumentList::read(IfcSpfLexer* t, std::vector& ids) { - IfcParse::IfcFile* file = t->file; - + //IfcParse::IfcFile* file = t->file; Token next = t->Next(); while( next.second || next.first ) { if ( TokenFunc::isOperator(next,',') ) { @@ -517,9 +525,9 @@ void ArgumentList::read(IfcSpfLexer* t, std::vector& ids) { } else if ( TokenFunc::isOperator(next,')') ) { break; } else if ( TokenFunc::isOperator(next,'(') ) { - ArgumentList* list = new ArgumentList(); - list->read(t, ids); - push(list); + ArgumentList* alist = new ArgumentList(); + alist->read(t, ids); + push(alist); } else { if ( TokenFunc::isIdentifier(next) ) { ids.push_back(TokenFunc::asInt(next)); @@ -640,7 +648,7 @@ ArgumentList::operator IfcEntityListList::ptr() const { for ( it = list.begin(); it != list.end(); ++ it ) { const Argument* arg = *it; const ArgumentList* arg_list; - if ((arg_list = dynamic_cast(arg))) { + if ((arg_list = dynamic_cast(arg)) != 0) { IfcEntityList::ptr e = *arg_list; l->push(e); } @@ -732,7 +740,7 @@ TokenArgument::operator std::vector< std::vector >() const { throw IfcExcep TokenArgument::operator std::vector< std::vector >() const { throw IfcException("Argument is not a list of list of floats"); } TokenArgument::operator IfcEntityListList::ptr() const { throw IfcException("Argument is not a list of list of entity instances"); } unsigned int TokenArgument::size() const { return 1; } -Argument* TokenArgument::operator [] (unsigned int i) const { throw IfcException("Argument is not a list of attributes"); } +Argument* TokenArgument::operator [] (unsigned int /*i*/) const { throw IfcException("Argument is not a list of attributes"); } std::string TokenArgument::toString(bool upper) const { if ( upper && TokenFunc::isString(token) ) { return IfcWrite::IfcCharacterEncoder(TokenFunc::asString(token)); @@ -764,7 +772,7 @@ EntityArgument::operator std::vector< std::vector >() const { throw IfcExce EntityArgument::operator std::vector< std::vector >() const { throw IfcException("Argument is not a list of list of floats"); } EntityArgument::operator IfcEntityListList::ptr() const { throw IfcException("Argument is not a list of list of entity instances"); } unsigned int EntityArgument::size() const { return 1; } -Argument* EntityArgument::operator [] (unsigned int i) const { throw IfcException("Argument is not a list of arguments"); } +Argument* EntityArgument::operator [] (unsigned int /*i*/) const { throw IfcException("Argument is not a list of arguments"); } std::string EntityArgument::toString(bool upper) const { return entity->data().toString(upper); } @@ -862,7 +870,7 @@ std::string Entity::toString(bool upper) const { std::string dt = datatype(); if (upper) { - for (std::string::iterator p = dt.begin(); p != dt.end(); ++p ) *p = toupper(*p); + boost::to_upper(dt); } if (!IfcSchema::Type::IsSimple(type()) || _id != 0) { @@ -1065,9 +1073,9 @@ void IfcFile::addEntities(IfcEntityList::ptr es) { IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* instance) { // If this instance has been inserted before, return // a reference to the copy that was created from it. - entity_entity_map_t::iterator it = entity_file_map.find(instance); - if (it != entity_file_map.end()) { - return it->second; + entity_entity_map_t::iterator mit = entity_file_map.find(instance); + if (mit != entity_file_map.end()) { + return mit->second; } // Obtain all forward references by a depth-first @@ -1281,11 +1289,12 @@ void IfcFile::removeEntity(IfcUtil::IfcBaseClass* instance) { // moment, inversely related instances affected by the removal of the // instance being deleted are not deleted themselves. if (references) { - for (IfcEntityList::it it = references->begin(); it != references->end(); ++it) { - IfcUtil::IfcBaseEntity* related_instance = (IfcUtil::IfcBaseEntity*) *it; + for (IfcEntityList::it iit = references->begin(); iit != references->end(); ++iit) { + IfcUtil::IfcBaseEntity* related_instance = (IfcUtil::IfcBaseEntity*) *iit; for (unsigned i = 0; i < related_instance->data().getArgumentCount(); ++i) { Argument* attr = related_instance->data().getArgument(i); + if (attr->isNull()) continue; IfcUtil::ArgumentType attr_type = attr->type(); @@ -1368,9 +1377,7 @@ IfcEntityList::ptr IfcFile::entitiesByType(IfcSchema::Type::Enum t) { } IfcEntityList::ptr IfcFile::entitiesByType(const std::string& t) { - std::string ty = t; - for (std::string::iterator p = ty.begin(); p != ty.end(); ++p ) *p = toupper(*p); - return entitiesByType(IfcSchema::Type::FromString(ty)); + return entitiesByType(IfcSchema::Type::FromString(boost::to_upper_copy(t))); } IfcEntityList::ptr IfcFile::entitiesByReference(int t) { @@ -1507,21 +1514,21 @@ std::pair IfcFile::getUnit(IfcSchema::IfcUnitE if (named_unit->UnitType() != type) { continue; } - IfcSchema::IfcSIUnit* unit = 0; + IfcSchema::IfcSIUnit* siunit = 0; if (named_unit->declaration().is(IfcSchema::Type::IfcConversionBasedUnit)) { IfcSchema::IfcConversionBasedUnit* u = (IfcSchema::IfcConversionBasedUnit*)named_unit; IfcSchema::IfcMeasureWithUnit* mu = u->ConversionFactor(); return_value.second *= static_cast(*mu->ValueComponent()->data().getArgument(0)); return_value.first = named_unit; if (mu->UnitComponent()->declaration().is(IfcSchema::Type::IfcSIUnit)) { - unit = (IfcSchema::IfcSIUnit*) mu->UnitComponent(); + siunit = (IfcSchema::IfcSIUnit*) mu->UnitComponent(); } } else if (named_unit->declaration().is(IfcSchema::Type::IfcSIUnit)) { - return_value.first = unit = (IfcSchema::IfcSIUnit*) named_unit; + return_value.first = siunit = (IfcSchema::IfcSIUnit*) named_unit; } - if (unit) { - if (unit->hasPrefix()) { - return_value.second *= IfcSIPrefixToValue(unit->Prefix()); + if (siunit) { + if (siunit->hasPrefix()) { + return_value.second *= IfcSIPrefixToValue(siunit->Prefix()); } } } diff --git a/src/ifcparse/IfcParse.h b/src/ifcparse/IfcParse.h index 7769b60e6b..aa95772509 100644 --- a/src/ifcparse/IfcParse.h +++ b/src/ifcparse/IfcParse.h @@ -37,9 +37,9 @@ #include #include +#include #include -#include "../ifcparse/SharedPointer.h" #include "../ifcparse/IfcCharacterDecoder.h" #include "../ifcparse/IfcUtil.h" @@ -248,7 +248,7 @@ namespace IfcParse { unsigned int offset; Entity(unsigned int i, IfcFile* t); Entity(unsigned int i, IfcFile* t, unsigned int o); - ~Entity(); + virtual ~Entity(); IfcEntityList::ptr getInverse(IfcSchema::Type::Enum type, int attribute_index); void Load(std::vector& ids, bool seek=false) const; void Unload(); diff --git a/src/ifcparse/IfcSpfHeader.h b/src/ifcparse/IfcSpfHeader.h index fe118bdbc6..2f9e421579 100644 --- a/src/ifcparse/IfcSpfHeader.h +++ b/src/ifcparse/IfcSpfHeader.h @@ -29,6 +29,9 @@ class HeaderEntity : public IfcAbstractEntity { private: ArgumentList* _list; const char * const _datatype; + + HeaderEntity(const HeaderEntity&); //N/A + HeaderEntity& operator =(const HeaderEntity&); //N/A protected: HeaderEntity(const char * const datatype, IfcSpfLexer* lexer) : _datatype(datatype), _list(0) @@ -40,7 +43,7 @@ protected: } } - ~HeaderEntity() { + virtual ~HeaderEntity() { delete _list; } @@ -65,7 +68,7 @@ public: return (*_list)[i]; } - IfcEntityList::ptr getInverse(IfcSchema::Type::Enum type, int attribute_index) { + IfcEntityList::ptr getInverse(IfcSchema::Type::Enum /*type*/, int /*attribute_index*/) { return IfcEntityList::ptr(new IfcEntityList); } @@ -81,7 +84,7 @@ public: return (IfcSchema::Type::Enum) -1; } - bool is(IfcSchema::Type::Enum v) const { + bool is(IfcSchema::Type::Enum /*v*/) const { return false; } @@ -167,7 +170,14 @@ public: _file_name = new FileName(); _file_schema = new FileSchema(); } - + + ~IfcSpfHeader() + { + delete _file_schema; + delete _file_name; + delete _file_description; + } + IfcSpfLexer* lexer() { return _lexer; } void lexer(IfcSpfLexer* l) { _lexer = l; } diff --git a/src/ifcparse/IfcSpfStream.h b/src/ifcparse/IfcSpfStream.h index 9f5799f2a2..a3d947606c 100644 --- a/src/ifcparse/IfcSpfStream.h +++ b/src/ifcparse/IfcSpfStream.h @@ -64,6 +64,7 @@ namespace IfcParse { IfcSpfStream(const std::string& fn); IfcSpfStream(std::istream& f, int len); IfcSpfStream(void* data, int len); + ~IfcSpfStream(); /// Returns the character at the cursor char Peek(); /// Returns the character at specified offset diff --git a/src/ifcparse/IfcUtil.h b/src/ifcparse/IfcUtil.h index 89535c4828..8e96766f42 100644 --- a/src/ifcparse/IfcUtil.h +++ b/src/ifcparse/IfcUtil.h @@ -26,10 +26,10 @@ #include #include +#include #include #include "../ifcparse/IfcSchema.h" -#include "../ifcparse/SharedPointer.h" #ifdef USE_IFC4 #include "../ifcparse/Ifc4enum.h" @@ -155,7 +155,7 @@ class IfcTemplatedEntityList; class IfcEntityList { std::vector ls; public: - typedef SHARED_PTR ptr; + typedef boost::shared_ptr ptr; typedef std::vector::const_iterator it; void push(IfcUtil::IfcBaseClass* l); void push(const ptr& l); @@ -179,7 +179,7 @@ template class IfcTemplatedEntityList { std::vector ls; public: - typedef SHARED_PTR< IfcTemplatedEntityList > ptr; + typedef boost::shared_ptr< IfcTemplatedEntityList > ptr; typedef typename std::vector::const_iterator it; void push(T* t) { if (t) { ls.push_back(t); } } void push(ptr t) { if (t) { for ( typename T::list::it it = t->begin(); it != t->end(); ++it ) push(*it); } } @@ -213,7 +213,7 @@ class IfcTemplatedEntityListList; class IfcEntityListList { std::vector< std::vector > ls; public: - typedef SHARED_PTR< IfcEntityListList > ptr; + typedef boost::shared_ptr< IfcEntityListList > ptr; typedef std::vector< std::vector >::const_iterator outer_it; typedef std::vector::const_iterator inner_it; void push(const std::vector& l) { @@ -230,11 +230,11 @@ public: } outer_it begin() const { return ls.begin(); } outer_it end() const { return ls.end(); } - int size() const { return ls.size(); } + int size() const { return (int)ls.size(); } int totalSize() const { int accum = 0; for (outer_it it = begin(); it != end(); ++it) { - accum += it->size(); + accum += (int)it->size(); } return accum; } @@ -267,13 +267,13 @@ template class IfcTemplatedEntityListList { std::vector< std::vector > ls; public: - typedef typename SHARED_PTR< IfcTemplatedEntityListList > ptr; + typedef typename boost::shared_ptr< IfcTemplatedEntityListList > ptr; typedef typename std::vector< std::vector >::const_iterator outer_it; typedef typename std::vector::const_iterator inner_it; void push(const std::vector& t) {ls.push_back(t);} outer_it begin() { return ls.begin(); } outer_it end() { return ls.end(); } - int size() const { return ls.size(); } + int size() const { return (int)ls.size(); } int totalSize() const { int accum = 0; for (outer_it it = begin(); it != end(); ++it) { diff --git a/src/ifcparse/IfcWrite.cpp b/src/ifcparse/IfcWrite.cpp index 010a3fea7e..b8132a3b60 100644 --- a/src/ifcparse/IfcWrite.cpp +++ b/src/ifcparse/IfcWrite.cpp @@ -19,6 +19,9 @@ #include #include +#include + +#include #include "../ifcparse/IfcParse.h" #include "../ifcparse/IfcWrite.h" @@ -82,7 +85,7 @@ Argument* IfcWritableEntity::getArgument (unsigned int i) { } return args[i]; } -unsigned int IfcWritableEntity::getArgumentCount() const {return args.size(); } +unsigned int IfcWritableEntity::getArgumentCount() const { return (unsigned)args.size(); } IfcSchema::Type::Enum IfcWritableEntity::type() const { return _type; } bool IfcWritableEntity::is(IfcSchema::Type::Enum v) const { return _type == v; } std::string IfcWritableEntity::toString(bool upper) const { @@ -91,7 +94,7 @@ std::string IfcWritableEntity::toString(bool upper) const { std::string dt = datatype(); if (upper) { - for (std::string::iterator p = dt.begin(); p != dt.end(); ++p ) *p = toupper(*p); + boost::to_upper(dt); } if (_id && !IfcSchema::Type::IsSimple(type())) { @@ -102,7 +105,6 @@ std::string IfcWritableEntity::toString(bool upper) const { ss << dt << "("; for (std::map::const_iterator it = args.begin(); it != args.end(); ++ it) { if ( it != args.begin() ) ss << ","; - const Argument* a = it->second; ss << it->second->toString(upper); } ss << ")"; @@ -139,7 +141,6 @@ void IfcWritableEntity::setArgument(int i) { } void IfcWritableEntity::setArgument(int i, Argument* a) { - IfcWrite::IfcWriteArgument* wa = new IfcWrite::IfcWriteArgument(this); IfcUtil::ArgumentType attr_type = a->type(); switch(attr_type) { case IfcUtil::Argument_NULL: @@ -181,7 +182,7 @@ void IfcWritableEntity::setArgument(int i, Argument* a) { this->setArgument(i, attr_value); } break; case IfcUtil::Argument_ENUMERATION: { - IfcSchema::Type::Enum ty = IfcSchema::Type::GetAttributeEntity(_type, i); + IfcSchema::Type::Enum ty = IfcSchema::Type::GetAttributeEntity(_type, (unsigned char)i); std::string enum_literal = a->toString(); // Remove leading and trailing '.' enum_literal = enum_literal.substr(1, enum_literal.size() - 2); @@ -290,27 +291,30 @@ void IfcWritableEntity::setArgument(int i,const std::vector< boost::dynamic_bits class SizeVisitor : public boost::static_visitor { public: - int operator()(const boost::none_t& i) const { return -1; } - int operator()(const IfcWriteArgument::Derived& i) const { return -1; } - int operator()(const int& i) const { return -1; } - int operator()(const bool& i) const { return -1; } - int operator()(const double& i) const { return -1; } - int operator()(const std::string& i) const { return -1; } - int operator()(const boost::dynamic_bitset<>& i) const { return -1; } - int operator()(const std::vector& i) const { return i.size(); } - int operator()(const std::vector& i) const { return i.size(); } - int operator()(const std::vector< std::vector >& i) const { return i.size(); } - int operator()(const std::vector< std::vector >& i) const { return i.size(); } - int operator()(const std::vector& i) const { return i.size(); } - int operator()(const std::vector< boost::dynamic_bitset<> >& i) const { return i.size(); } - int operator()(const IfcWriteArgument::EnumerationReference& i) const { return -1; } - int operator()(const IfcUtil::IfcBaseClass* const& i) const { return -1; } + int operator()(const boost::none_t& /*i*/) const { return -1; } + int operator()(const IfcWriteArgument::Derived& /*i*/) const { return -1; } + int operator()(const int& /*i*/) const { return -1; } + int operator()(const bool& /*i*/) const { return -1; } + int operator()(const double& /*i*/) const { return -1; } + int operator()(const std::string& /*i*/) const { return -1; } + int operator()(const boost::dynamic_bitset<>& /*i*/) const { return -1; } + int operator()(const std::vector& i) const { return (int)i.size(); } + int operator()(const std::vector& i) const { return (int)i.size(); } + int operator()(const std::vector< std::vector >& i) const { return (int)i.size(); } + int operator()(const std::vector< std::vector >& i) const { return (int)i.size(); } + int operator()(const std::vector& i) const { return (int)i.size(); } + int operator()(const std::vector< boost::dynamic_bitset<> >& i) const { return (int)i.size(); } + int operator()(const IfcWriteArgument::EnumerationReference& /*i*/) const { return -1; } + int operator()(const IfcUtil::IfcBaseClass* const& /*i*/) const { return -1; } int operator()(const IfcEntityList::ptr& i) const { return i->size(); } int operator()(const IfcEntityListList::ptr& i) const { return i->size(); } }; class StringBuilderVisitor : public boost::static_visitor { private: + StringBuilderVisitor(const StringBuilderVisitor&); //N/A + StringBuilderVisitor& operator =(const StringBuilderVisitor&); //N/A + std::ostringstream& data; template void serialize(const std::vector& i) { data << "("; @@ -326,7 +330,7 @@ private: std::string format_double(const double& d) { std::ostringstream oss; oss.imbue(std::locale::classic()); - oss << std::setprecision(15) << d; + oss << std::setprecision(std::numeric_limits::digits10) << d; const std::string str = oss.str(); oss.str(""); std::string::size_type e = str.find('e'); @@ -350,7 +354,7 @@ private: oss.imbue(std::locale::classic()); oss.put('"'); oss << std::hex << std::setw(1); - unsigned c = b.size(); + unsigned c = (unsigned)b.size(); unsigned n = (4 - (c % 4)) & 3; oss << n; for (unsigned i = 0; i < c + n;) { @@ -369,8 +373,8 @@ private: public: StringBuilderVisitor(std::ostringstream& stream, bool upper = false) : data(stream), upper(upper) {} - void operator()(const boost::none_t& i) { data << "$"; } - void operator()(const IfcWriteArgument::Derived& i) { data << "*"; } + void operator()(const boost::none_t& /*i*/) { data << "$"; } + void operator()(const IfcWriteArgument::Derived& /*i*/) { data << "*"; } void operator()(const int& i) { data << i; } void operator()(const bool& i) { data << (i ? ".T." : ".F."); } void operator()(const double& i) { data << format_double(i); } @@ -500,7 +504,7 @@ IfcWriteArgument::operator std::vector< std::vector >() const { return as >() const { return as > >(); } IfcWriteArgument::operator IfcEntityListList::ptr() const { throw; } bool IfcWriteArgument::isNull() const { return type() == IfcUtil::Argument_NULL; } -Argument* IfcWriteArgument::operator [] (unsigned int i) const { throw IfcParse::IfcException("Invalid cast"); } +Argument* IfcWriteArgument::operator [] (unsigned int /*i*/) const { throw IfcParse::IfcException("Invalid cast"); } std::string IfcWriteArgument::toString(bool upper) const { std::ostringstream str; str.imbue(std::locale::classic()); diff --git a/src/ifcparse/SharedPointer.h b/src/ifcparse/SharedPointer.h deleted file mode 100644 index 3d261aa8c8..0000000000 --- a/src/ifcparse/SharedPointer.h +++ /dev/null @@ -1,41 +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 . * - * * - ********************************************************************************/ - -/******************************************************************************** - * * - * This file defines the shared pointer implementation to use, shared pointers * - * are used extensively in IfcOpenShell * - * * - ********************************************************************************/ - -#ifdef __GNUC__ -#include -#define SHARED_PTR std::tr1::shared_ptr -#else -#if _MSC_VER >= 1600 -// MSVC 2008 does not have shared_ptr by default, but it comes -// in a feature pack. Therefore for IDEs prior to MSVC 2010 the -// shared_ptr that ships with boost is used. -#include -#define SHARED_PTR std::tr1::shared_ptr -#else -#include -#define SHARED_PTR boost::shared_ptr -#endif -#endif \ No newline at end of file diff --git a/src/ifcwrap/CMakeLists.txt b/src/ifcwrap/CMakeLists.txt index ba87b658c9..ba2b6a0c59 100644 --- a/src/ifcwrap/CMakeLists.txt +++ b/src/ifcwrap/CMakeLists.txt @@ -1,37 +1,82 @@ +################################################################################ +# # +# 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 . # +# # +################################################################################ + FIND_PACKAGE(SWIG) +IF(NOT SWIG_FOUND) + MESSAGE(FATAL_ERROR "BUILD_IFCPYTHON enabled, but unable to find SWIG. Disable BUILD_IFCPYTHON or fix SWIG paths to proceed.") +ENDIF() -IF(SWIG_FOUND) +INCLUDE(${SWIG_USE_FILE}) -INCLUDE(${SWIG_USE_FILE}) +IF(NOT "$ENV{PYTHON_INCLUDE_DIR}" STREQUAL "") + SET(PYTHON_INCLUDE_DIR $ENV{PYTHON_INCLUDE_DIR} CACHE FILEPATH "Python header files") + MESSAGE(STATUS "Looking for Python header files in: ${PYTHON_INCLUDE_DIR}") +ENDIF() +IF(NOT "$ENV{PYTHON_LIBRARY}" STREQUAL "") + SET(PYTHON_LIBRARY $ENV{PYTHON_LIBRARY} CACHE FILEPATH "Python library file") + MESSAGE(STATUS "Looking for Python library file in: ${PYTHON_LIBRARY}") +ENDIF() FIND_PACKAGE(PythonLibs) - -IF(PYTHONLIBS_FOUND) +IF(NOT PYTHONLIBS_FOUND) + MESSAGE(FATAL_ERROR "BUILD_IFCPYTHON enabled, but unable to find Python. Disable BUILD_IFCPYTHON or fix Python paths to proceed.") +ENDIF() INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH}) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) SET(CMAKE_SWIG_FLAGS "") +# NOTE Workaround for most likely missing debug Python libraries on Windows (requires Python built from the source). +# Python 3.5 intaller and onwards will have an option to install the debug libraries too. +IF (WIN32 AND NOT PYTHON_DEBUG_LIBRARIES) + MESSAGE(STATUS "PYTHON_DEBUG_LIBRARIES not found, defining SWIG_PYTHON_INTERPRETER_NO_DEBUG workaround for IfcWrap.") + ADD_DEFINITIONS(-DSWIG_PYTHON_INTERPRETER_NO_DEBUG) +ENDIF() SET_SOURCE_FILES_PROPERTIES(IfcPython.i PROPERTIES CPLUSPLUS ON) SWIG_ADD_MODULE(ifcopenshell_wrapper python IfcPython.i) -SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${PYTHON_LIBRARIES} IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKOffset) +SWIG_LINK_LIBRARIES(ifcopenshell_wrapper IfcParse IfcGeom ${PYTHON_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${ICU_LIBRARIES}) -# To install IfcPython let's get the site-packages dir from python -EXECUTE_PROCESS(COMMAND python -c "import sys; from distutils.sysconfig import get_python_lib; sys.stdout.write(get_python_lib())" - OUTPUT_VARIABLE python_package_dir) +# Try to find the Python interpreter to get the site-packages +# directory in which the wrapper can be installed. +FIND_PACKAGE(PythonInterp) +IF(PYTHONINTERP_FOUND) + EXECUTE_PROCESS( + COMMAND ${PYTHON_EXECUTABLE} -c "import sys; from distutils.sysconfig import get_python_lib; sys.stdout.write(get_python_lib())" + OUTPUT_VARIABLE python_package_dir + ) -INSTALL(FILES - "${CMAKE_BINARY_DIR}/ifcwrap/ifcopenshell_wrapper.py" - "${CMAKE_CURRENT_SOURCE_DIR}/../ifcopenshell-python/ifcopenshell/__init__.py" - "${CMAKE_CURRENT_SOURCE_DIR}/../ifcopenshell-python/ifcopenshell/guid.py" - DESTINATION "${python_package_dir}/ifcopenshell") -INSTALL(FILES - "${CMAKE_CURRENT_SOURCE_DIR}/../ifcopenshell-python/ifcopenshell/geom/__init__.py" - DESTINATION "${python_package_dir}/ifcopenshell/geom") -INSTALL(TARGETS _ifcopenshell_wrapper DESTINATION "${python_package_dir}/ifcopenshell") - -ENDIF(PYTHONLIBS_FOUND) - -ENDIF(SWIG_FOUND) \ No newline at end of file + IF("${python_package_dir}" STREQUAL "") + MESSAGE(WARNING "Unable to locate Python site-package directory, unable to install the Python wrapper") + ELSE() + INSTALL(FILES + "${CMAKE_BINARY_DIR}/ifcwrap/ifcopenshell_wrapper.py" + "${CMAKE_CURRENT_SOURCE_DIR}/../ifcopenshell-python/ifcopenshell/__init__.py" + "${CMAKE_CURRENT_SOURCE_DIR}/../ifcopenshell-python/ifcopenshell/guid.py" + DESTINATION "${python_package_dir}/ifcopenshell") + INSTALL(FILES + "${CMAKE_CURRENT_SOURCE_DIR}/../ifcopenshell-python/ifcopenshell/geom/__init__.py" + "${CMAKE_CURRENT_SOURCE_DIR}/../ifcopenshell-python/ifcopenshell/geom/occ_utils.py" + DESTINATION "${python_package_dir}/ifcopenshell/geom") + INSTALL(TARGETS _ifcopenshell_wrapper DESTINATION "${python_package_dir}/ifcopenshell") + ENDIF() +ELSE() + MESSAGE(WARNING "No Python interpreter found, unable to install the Python wrapper") +ENDIF() diff --git a/src/ifcwrap/IfcGeomWrapper.i b/src/ifcwrap/IfcGeomWrapper.i index 3b669d069b..84a435b69e 100644 --- a/src/ifcwrap/IfcGeomWrapper.i +++ b/src/ifcwrap/IfcGeomWrapper.i @@ -72,17 +72,35 @@ } } +// A visitor +%{ +struct ShapeRTTI : public boost::static_visitor +{ + PyObject* operator()(IfcGeom::Element* elem) const { + IfcGeom::SerializedElement* serialized_elem = dynamic_cast*>(elem); + IfcGeom::TriangulationElement* triangulation_elem = dynamic_cast*>(elem); + if (triangulation_elem) { + return SWIG_NewPointerObj(SWIG_as_voidptr(triangulation_elem), SWIGTYPE_p_IfcGeom__TriangulationElementT_double_t, SWIG_POINTER_OWN); + } else if (serialized_elem) { + return SWIG_NewPointerObj(SWIG_as_voidptr(serialized_elem), SWIGTYPE_p_IfcGeom__SerializedElementT_double_t, SWIG_POINTER_OWN); + } + } + PyObject* operator()(IfcGeom::Representation::Representation* representation) const { + IfcGeom::Representation::Serialization* serialized_representation = dynamic_cast(representation); + IfcGeom::Representation::Triangulation* triangulated_representation = dynamic_cast*>(representation); + if (serialized_representation) { + return SWIG_NewPointerObj(SWIG_as_voidptr(serialized_representation), SWIGTYPE_p_IfcGeom__Representation__Serialization, SWIG_POINTER_OWN); + } else if (triangulated_representation) { + return SWIG_NewPointerObj(SWIG_as_voidptr(triangulated_representation), SWIGTYPE_p_IfcGeom__Representation__TriangulationT_double_t, SWIG_POINTER_OWN); + } + } +}; +%} + // Note that these elements ARE to be owned by SWIG/Python %typemap(out) boost::variant*, IfcGeom::Representation::Representation*> { // See which type is set and return appropriate - IfcGeom::Element* elem = boost::get*>($1); - IfcGeom::SerializedElement* serialized_elem = dynamic_cast*>(elem); - IfcGeom::TriangulationElement* triangulation_elem = dynamic_cast*>(elem); - if (triangulation_elem) { - $result = SWIG_NewPointerObj(SWIG_as_voidptr(triangulation_elem), SWIGTYPE_p_IfcGeom__TriangulationElementT_double_t, SWIG_POINTER_OWN); - } else if (serialized_elem) { - $result = SWIG_NewPointerObj(SWIG_as_voidptr(serialized_elem), SWIGTYPE_p_IfcGeom__SerializedElementT_double_t, SWIG_POINTER_OWN); - } + $result = boost::apply_visitor(ShapeRTTI(), $1); } // This does not seem to work: @@ -93,47 +111,6 @@ %ignore IfcGeom::Iterator::Iterator(const IfcGeom::IteratorSettings&, void*, int); %ignore IfcGeom::Iterator::Iterator(const IfcGeom::IteratorSettings&, std::istream&, int); -// Ignore the std::vector accessors and replace them to pairs that will -// be expanded to Python tuples by means of typemaps. This in order to -// minimize passing STL objects across dynamic library boundaries. -%ignore IfcGeom::Representation::Triangulation::verts; -%ignore IfcGeom::Representation::Triangulation::faces; -%ignore IfcGeom::Representation::Triangulation::edges; -%ignore IfcGeom::Representation::Triangulation::normals; -%ignore IfcGeom::Representation::Triangulation::material_ids; -%ignore IfcGeom::Representation::Triangulation::materials; -%extend IfcGeom::Representation::Triangulation { - std::pair get_faces() { - return std::make_pair(&$self->faces()[0], $self->faces().size()); - } - std::pair get_edges() { - return std::make_pair(&$self->edges()[0], $self->edges().size()); - } - std::pair get_material_ids() { - return std::make_pair(&$self->material_ids()[0], $self->material_ids().size()); - } - std::pair get_materials() { - return std::make_pair(&$self->materials()[0], $self->materials().size()); - } -} -%extend IfcGeom::Representation::Triangulation { - std::pair get_verts() { - return std::make_pair(&$self->verts()[0], $self->verts().size()); - } - std::pair get_normals() { - return std::make_pair(&$self->normals()[0], $self->normals().size()); - } -} -%extend IfcGeom::Representation::Triangulation { - std::pair get_verts() { - return std::make_pair(&$self->verts()[0], $self->verts().size()); - } - std::pair get_normals() { - return std::make_pair(&$self->normals()[0], $self->normals().size()); - } -} - - %extend IfcGeom::IteratorSettings { %pythoncode %{ attrs = ("convert_back_units", "deflection_tolerance", "disable_opening_subtractions", "disable_triangulation", "faster_booleans", "sew_shells", "use_brep_data", "use_world_coords", "weld_vertices") @@ -159,10 +136,10 @@ if _newclass: # Hide the getters with read-only property implementations id = property(id) - faces = property(get_faces) - edges = property(get_edges) - material_ids = property(get_material_ids) - materials = property(get_materials) + faces = property(faces) + edges = property(edges) + material_ids = property(material_ids) + materials = property(materials) %} }; @@ -172,16 +149,16 @@ %pythoncode %{ if _newclass: # Hide the getters with read-only property implementations - verts = property(get_verts) - normals = property(get_normals) + verts = property(verts) + normals = property(normals) %} }; %extend IfcGeom::Representation::Triangulation { %pythoncode %{ if _newclass: # Hide the getters with read-only property implementations - verts = property(get_verts) - normals = property(get_normals) + verts = property(verts) + normals = property(normals) %} }; @@ -259,25 +236,25 @@ %inline %{ boost::variant*, IfcGeom::Representation::Representation*> create_shape(IfcGeom::IteratorSettings& settings, IfcParse::IfcLateBoundEntity* instance, IfcParse::IfcLateBoundEntity* representation = 0) { + IfcParse::IfcFile* file = instance->entity->file; + IfcSchema::IfcProject::list::ptr projects = file->entitiesByType(); + if (projects->size() != 1) { + throw IfcParse::IfcException("Not a single IfcProject instance"); + } + IfcSchema::IfcProject* project = *projects->begin(); + + IfcGeom::Kernel kernel; + kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.sew_shells() ? 1000 : -1); + kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.include_curves() ? (settings.exclude_solids_and_surfaces() ? -1. : 0.) : +1.)); + std::pair length_unit = kernel.initializeUnits(project->UnitsInContext()); + if (instance->is(IfcSchema::Type::IfcProduct)) { if (representation) { if (!representation->is(IfcSchema::Type::IfcRepresentation)) { throw IfcParse::IfcException("Supplied representation not of type IfcRepresentation"); } } - - IfcParse::IfcFile* file = instance->entity->file; - - IfcSchema::IfcProject::list::ptr projects = file->entitiesByType(); - if (projects->size() != 1) { - throw IfcParse::IfcException("Not a single IfcProject instance"); - } - IfcSchema::IfcProject* project = *projects->begin(); - - IfcGeom::Kernel kernel; - kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.sew_shells() ? 1000 : -1); - kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.include_curves() ? (settings.exclude_solids_and_surfaces() ? -1. : 0.) : +1.)); - + IfcSchema::IfcProduct* product = (IfcSchema::IfcProduct*) instance; if (!representation && !product->hasRepresentation()) { @@ -359,7 +336,6 @@ if (context->hasPrecision()) { precision = context->Precision(); } - std::pair length_unit = kernel.initializeUnits(project->UnitsInContext()); precision *= length_unit.second; // Some arbitrary factor that has proven to work better for the models in the set of test files. @@ -383,7 +359,28 @@ throw IfcParse::IfcException("No element to return based on provided settings"); } } else { - throw IfcParse::IfcException("Only obtaining representations for IfcProduct instances is currently supported"); + if (!representation) { + if (instance->is(IfcSchema::Type::IfcRepresentationItem) || instance->is(IfcSchema::Type::IfcRepresentation)) { + IfcGeom::IfcRepresentationShapeItems shapes; + if (kernel.convert_shapes(instance, shapes)) { + IfcGeom::ElementSettings element_settings(settings, kernel.getValue(IfcGeom::Kernel::GV_LENGTH_UNIT), IfcSchema::Type::ToString(instance->type())); + IfcGeom::Representation::BRep brep(element_settings, instance->entity->id(), shapes); + try { + if (settings.use_brep_data()) { + return new IfcGeom::Representation::Serialization(brep); + } else if (!settings.disable_triangulation()) { + return new IfcGeom::Representation::Triangulation(brep); + } + } catch (...) { + throw IfcParse::IfcException("Error during shape serialization"); + } + } else { + throw IfcParse::IfcException("Geometrical element not understood"); + } + } + } else { + throw IfcParse::IfcException("Invalid additional representation specified"); + } } } %} diff --git a/src/ifcwrap/IfcParseWrapper.i b/src/ifcwrap/IfcParseWrapper.i index a4ebb234bc..23955f190f 100644 --- a/src/ifcwrap/IfcParseWrapper.i +++ b/src/ifcwrap/IfcParseWrapper.i @@ -200,4 +200,12 @@ namespace IfcUtil { f->Init(s); return f; } + + const char* const schema_identifier() { + return IfcSchema::Identifier; + } + + const char* const version() { + return IFCOPENSHELL_VERSION; + } %} \ No newline at end of file diff --git a/src/ifcwrap/IfcPython.i b/src/ifcwrap/IfcPython.i index 4fb584a088..ef42830a14 100644 --- a/src/ifcwrap/IfcPython.i +++ b/src/ifcwrap/IfcPython.i @@ -17,6 +17,36 @@ * * ********************************************************************************/ +%begin %{ +#if defined(_DEBUG) && defined(SWIG_PYTHON_INTERPRETER_NO_DEBUG) +/* https://github.com/swig/swig/issues/325 */ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable : 4127 4244 4702 4510 4512 4610) +# if _MSC_VER > 1800 +# pragma warning(disable : 4456 4459) +# endif +#endif +// TODO add '# pragma warning(pop)' to the very end of the file +%} + %include "std_string.i" %include "exception.i" diff --git a/src/ifcwrap/utils/type_conversion.i b/src/ifcwrap/utils/type_conversion.i index 604be11ced..9ea0644457 100644 --- a/src/ifcwrap/utils/type_conversion.i +++ b/src/ifcwrap/utils/type_conversion.i @@ -110,9 +110,11 @@ PyObject* pythonize(const unsigned int& t) { return PyInt_FromLong(t); } PyObject* pythonize(const bool& t) { return PyBool_FromLong(t); } PyObject* pythonize(const double& t) { return PyFloat_FromDouble(t); } - PyObject* pythonize(const std::string& t) { return PyString_FromString(t.c_str()); } + PyObject* pythonize(const std::string& t) { return PyUnicode_FromString(t.c_str()); } PyObject* pythonize(const IfcUtil::IfcBaseClass* t) { return SWIG_NewPointerObj(SWIG_as_voidptr(t), SWIGTYPE_p_IfcParse__IfcLateBoundEntity, 0); } - + // NB: This cannot be temporary as a Python object is constructed from a pointer to the address of this object + PyObject* pythonize(const IfcGeom::Material& t) { return SWIG_NewPointerObj(SWIG_as_voidptr(&t), SWIGTYPE_p_IfcGeom__Material, 0); } + PyObject* pythonize(const boost::dynamic_bitset<>& t) { std::string bitstring; boost::to_string(t, bitstring); @@ -130,9 +132,9 @@ template PyObject* pythonize_vector(const std::vector& v) { - const unsigned size = v.size(); + const size_t size = v.size(); PyObject* pyobj = PyTuple_New(size); - for (unsigned int i = 0; i < size; ++i) { + for (size_t i = 0; i < size; ++i) { PyTuple_SetItem(pyobj, i, pythonize(v[i])); } return pyobj; @@ -140,9 +142,9 @@ template PyObject* pythonize_vector2(const std::vector< std::vector >& v) { - const unsigned size = v.size(); + const size_t size = v.size(); PyObject* pyobj = PyTuple_New(size); - for (unsigned int i = 0; i < size; ++i) { + for (size_t i = 0; i < size; ++i) { PyTuple_SetItem(pyobj, i, pythonize_vector(v[i])); } return pyobj; diff --git a/src/ifcwrap/utils/typemaps_out.i b/src/ifcwrap/utils/typemaps_out.i index 5680a07ab5..69cccc8081 100644 --- a/src/ifcwrap/utils/typemaps_out.i +++ b/src/ifcwrap/utils/typemaps_out.i @@ -105,3 +105,4 @@ CREATE_VECTOR_TYPEMAP_OUT(int) CREATE_VECTOR_TYPEMAP_OUT(unsigned int) CREATE_VECTOR_TYPEMAP_OUT(double) CREATE_VECTOR_TYPEMAP_OUT(std::string) +CREATE_VECTOR_TYPEMAP_OUT(IfcGeom::Material) diff --git a/src/qtviewer/CMakeLists.txt b/src/qtviewer/CMakeLists.txt index f6442fcfa8..81f97eba20 100644 --- a/src/qtviewer/CMakeLists.txt +++ b/src/qtviewer/CMakeLists.txt @@ -1,9 +1,21 @@ - -OPTION( QT_USE_QTVIEWER "IfcOpenShell QT GUI Viewer, QT environment required" OFF ) - - -IF (QT_USE_QTVIEWER) - +################################################################################ +# # +# 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 . # +# # +################################################################################ # Find QT header files SET(QT_MIN_VERSION "4.5.0") @@ -40,7 +52,4 @@ QT_WRAP_CPP(QTviewer QTviewer_SRCS ${QTviewer_MOC_SRCS}) ADD_EXECUTABLE( QTviewer ${QTviewer_SRCS} ${QTviewer_MOC_SRCS}) #http://www.qtcentre.org/wiki/index.php?title=Compiling_Qt4_apps_with_CMake -TARGET_LINK_libRARIES (QTviewer IfcParse IfcGeom ${QT_LIBRARIES} TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet) - - -ENDIF (QT_USE_QTVIEWER) +TARGET_LINK_libRARIES (QTviewer IfcParse IfcGeom ${QT_LIBRARIES} ${OPENCASCADE_LIBRARIES}) diff --git a/test/input/mapped_item_style.ifc b/test/input/mapped_item_style.ifc new file mode 100644 index 0000000000..61c905545c --- /dev/null +++ b/test/input/mapped_item_style.ifc @@ -0,0 +1,183 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION (('ViewDefinition [CoordinationView_V2.0]'), '2;1'); +FILE_NAME ('GreenPipe', '2015-11-18T12:57:39', ('- -'), ('-'), 'BSProLib (15th of March 2014)', 'MagiCAD HPV 2014.4', ' '); +FILE_SCHEMA (('IFC2X3')); +ENDSEC; +DATA; +#1 = IFCOWNERHISTORY(#2, #3, $, .ADDED., $, $, $, 1447851459); +#2 = IFCPERSONANDORGANIZATION(#4, #5, $); +#3 = IFCAPPLICATION(#6, 'Not Defined', 'Not Defined', 'Not Defined'); +#4 = IFCPERSON($, $, $, $, $, $, $, $); +#5 = IFCORGANIZATION($, 'simplebim', $, $, $); +#6 = IFCORGANIZATION($, 'Datacubist', $, $, $); +#7 = IFCBUILDING('026Lkbgdr7wf6pe_Hm4pbI', #8, $, $, '', #139, $, $, .ELEMENT., $, $, $); +#8 = IFCOWNERHISTORY(#9, #12, $, .NOCHANGE., $, $, $, 1422863967); +#9 = IFCPERSONANDORGANIZATION(#10, #11, $); +#10 = IFCPERSON($, '-', '-', $, $, $, $, $); +#11 = IFCORGANIZATION($, '-', $, $, $); +#12 = IFCAPPLICATION(#11, '2012.11', 'MagiCAD HPV 2012.11', 'MagiCAD HPV'); +#13 = IFCBUILDINGSTOREY('0AhpSxd0P1QRiBUgahlB62', #8, '3. etasje', $, '', #141, $, $, .ELEMENT., 55900.); +#14 = IFCFLOWSEGMENT('0k6g4TkpX8LvcVQUYZl7mx', #15, $, $, '', #144, #17, $); +#15 = IFCOWNERHISTORY(#9, #16, $, .NOCHANGE., $, $, $, 1429106599); +#16 = IFCAPPLICATION(#11, '2014.4', 'MagiCAD HPV 2014.4', 'MagiCAD HPV'); +#17 = IFCPRODUCTDEFINITIONSHAPE($, $, (#18)); +#18 = IFCSHAPEREPRESENTATION(#19, 'Body', 'MappedRepresentation', (#27)); +#19 = IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body', 'Model', *, *, *, *, #20, $, .MODEL_VIEW., $); +#20 = IFCGEOMETRICREPRESENTATIONCONTEXT($, 'Model', 3, 1.E-5, #21, $); +#21 = IFCAXIS2PLACEMENT3D(#22, #23, #24); +#22 = IFCCARTESIANPOINT((0., 0., 0.)); +#23 = IFCDIRECTION((0., 0., 1.)); +#24 = IFCDIRECTION((1., 0., 0.)); +#25 = IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body', 'Model', *, *, *, *, #20, $, .MODEL_VIEW., $); +#26 = IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body', 'Model', *, *, *, *, #20, $, .MODEL_VIEW., $); +#27 = IFCMAPPEDITEM(#28, #113); +#28 = IFCREPRESENTATIONMAP(#29, #30); +#29 = IFCAXIS2PLACEMENT3D(#22, #23, #24); +#30 = IFCSHAPEREPRESENTATION(#19, 'Body', 'SurfaceModel', (#31)); +#31 = IFCSHELLBASEDSURFACEMODEL((#32)); +#32 = IFCOPENSHELL((#33, #40, #45, #50, #55, #60, #65, #70, #75, #80, #85, #90, #95, #100, #105, #110)); +#33 = IFCFACE((#34)); +#34 = IFCFACEOUTERBOUND(#35, .T.); +#35 = IFCPOLYLOOP((#36, #37, #38, #39)); +#36 = IFCCARTESIANPOINT((-725., 383.1113, -115.00318)); +#37 = IFCCARTESIANPOINT((-725., 397.9585, 40.36126)); +#38 = IFCCARTESIANPOINT((725., 397.9585, 40.36126)); +#39 = IFCCARTESIANPOINT((725., 383.1113, -115.00318)); +#40 = IFCFACE((#41)); +#41 = IFCFACEOUTERBOUND(#42, .T.); +#42 = IFCPOLYLOOP((#37, #43, #44, #38)); +#43 = IFCCARTESIANPOINT((-725., 352.22013, 189.58107)); +#44 = IFCCARTESIANPOINT((725., 352.22013, 189.58107)); +#45 = IFCFACE((#46)); +#46 = IFCFACEOUTERBOUND(#47, .T.); +#47 = IFCPOLYLOOP((#43, #48, #49, #44)); +#48 = IFCCARTESIANPOINT((-725., 252.85943, 309.93888)); +#49 = IFCCARTESIANPOINT((725., 252.85943, 309.93888)); +#50 = IFCFACE((#51)); +#51 = IFCFACEOUTERBOUND(#52, .T.); +#52 = IFCPOLYLOOP((#48, #53, #54, #49)); +#53 = IFCCARTESIANPOINT((-725., 115.00318, 383.1113)); +#54 = IFCCARTESIANPOINT((725., 115.00318, 383.1113)); +#55 = IFCFACE((#56)); +#56 = IFCFACEOUTERBOUND(#57, .T.); +#57 = IFCPOLYLOOP((#53, #58, #59, #54)); +#58 = IFCCARTESIANPOINT((-725., -40.36126, 397.9585)); +#59 = IFCCARTESIANPOINT((725., -40.36126, 397.9585)); +#60 = IFCFACE((#61)); +#61 = IFCFACEOUTERBOUND(#62, .T.); +#62 = IFCPOLYLOOP((#58, #63, #64, #59)); +#63 = IFCCARTESIANPOINT((-725., -189.58107, 352.22013)); +#64 = IFCCARTESIANPOINT((725., -189.58107, 352.22013)); +#65 = IFCFACE((#66)); +#66 = IFCFACEOUTERBOUND(#67, .T.); +#67 = IFCPOLYLOOP((#63, #68, #69, #64)); +#68 = IFCCARTESIANPOINT((-725., -309.93888, 252.85943)); +#69 = IFCCARTESIANPOINT((725., -309.93888, 252.85943)); +#70 = IFCFACE((#71)); +#71 = IFCFACEOUTERBOUND(#72, .T.); +#72 = IFCPOLYLOOP((#68, #73, #74, #69)); +#73 = IFCCARTESIANPOINT((-725., -383.1113, 115.00318)); +#74 = IFCCARTESIANPOINT((725., -383.1113, 115.00318)); +#75 = IFCFACE((#76)); +#76 = IFCFACEOUTERBOUND(#77, .T.); +#77 = IFCPOLYLOOP((#73, #78, #79, #74)); +#78 = IFCCARTESIANPOINT((-725., -397.9585, -40.36126)); +#79 = IFCCARTESIANPOINT((725., -397.9585, -40.36126)); +#80 = IFCFACE((#81)); +#81 = IFCFACEOUTERBOUND(#82, .T.); +#82 = IFCPOLYLOOP((#78, #83, #84, #79)); +#83 = IFCCARTESIANPOINT((-725., -352.22013, -189.58107)); +#84 = IFCCARTESIANPOINT((725., -352.22013, -189.58107)); +#85 = IFCFACE((#86)); +#86 = IFCFACEOUTERBOUND(#87, .T.); +#87 = IFCPOLYLOOP((#83, #88, #89, #84)); +#88 = IFCCARTESIANPOINT((-725., -252.85943, -309.93888)); +#89 = IFCCARTESIANPOINT((725., -252.85943, -309.93888)); +#90 = IFCFACE((#91)); +#91 = IFCFACEOUTERBOUND(#92, .T.); +#92 = IFCPOLYLOOP((#88, #93, #94, #89)); +#93 = IFCCARTESIANPOINT((-725., -115.00318, -383.1113)); +#94 = IFCCARTESIANPOINT((725., -115.00318, -383.1113)); +#95 = IFCFACE((#96)); +#96 = IFCFACEOUTERBOUND(#97, .T.); +#97 = IFCPOLYLOOP((#93, #98, #99, #94)); +#98 = IFCCARTESIANPOINT((-725., 40.36126, -397.9585)); +#99 = IFCCARTESIANPOINT((725., 40.36126, -397.9585)); +#100 = IFCFACE((#101)); +#101 = IFCFACEOUTERBOUND(#102, .T.); +#102 = IFCPOLYLOOP((#98, #103, #104, #99)); +#103 = IFCCARTESIANPOINT((-725., 189.58107, -352.22013)); +#104 = IFCCARTESIANPOINT((725., 189.58107, -352.22013)); +#105 = IFCFACE((#106)); +#106 = IFCFACEOUTERBOUND(#107, .T.); +#107 = IFCPOLYLOOP((#103, #108, #109, #104)); +#108 = IFCCARTESIANPOINT((-725., 309.93888, -252.85943)); +#109 = IFCCARTESIANPOINT((725., 309.93888, -252.85943)); +#110 = IFCFACE((#111)); +#111 = IFCFACEOUTERBOUND(#112, .T.); +#112 = IFCPOLYLOOP((#108, #36, #39, #109)); +#113 = IFCCARTESIANTRANSFORMATIONOPERATOR3DNONUNIFORM($, $, #22, 2.689655, $, 1., 1.); +#114 = IFCPROJECT('0EHdefYCr4XA02OBEnhWph', #8, $, $, '', $, $, (#20), #148); +#115 = IFCSITE('0yjrC3GhPFGhTAhGjFoXgU', #8, $, $, '', #137, $, $, .ELEMENT., $, $, $, $, $); +#116 = IFCDUCTSEGMENTTYPE('33ZUtxFLT3oflCfdbTV7YR', #15, 'Sirk. kanal, Forsinket st\X\E5l', '2-SIRK', $, (#119), $, $, $, .RIGIDSEGMENT.); +#117 = IFCCLASSIFICATIONREFERENCE($, 'VB2.121212', 'Not defined', #118); +#118 = IFCCLASSIFICATION('NS', '', $, 'NS3420'); +#119 = IFCPROPERTYSET('0KogclmVD8u9NLoxd55q2Z', #1, 'Pset_DuctSegmentTypeCommon', $, (#120, #121)); +#120 = IFCPROPERTYSINGLEVALUE('Length', $, IFCPOSITIVELENGTHMEASURE(3900.), $); +#121 = IFCPROPERTYLISTVALUE('NominalDiameterOrWidth', $, (IFCPOSITIVELENGTHMEASURE(800.)), $); +#122 = IFCRELDEFINESBYTYPE('2QWHtAK4v0NuXpTn$cwRcO', #1, $, $, (#14), #116); +#123 = IFCRELASSIGNSTOGROUP('2NMUbNdzv2NPmHrl0xeehB', #1, $, $, (#14), $, #124); +#124 = IFCSYSTEM('2qqMrTwlLERAeiT2j5aCl8', #125, '3601 Tilluft', '3601-1', $); +#125 = IFCOWNERHISTORY($, $, $, .NOCHANGE., $, $, $, 1429103705); +#126 = IFCRELSERVICESBUILDINGS('2k0QCS0pjDDPvlG2POE5oE', #1, $, $, #124, (#7)); +#127 = IFCPRESENTATIONLAYERASSIGNMENT('362--V-3601-T-36', $, (#18), $); +#128 = IFCCOLOURRGB($, 0., 1., 0.); +#129 = IFCSURFACESTYLERENDERING(#128, 0., $, $, $, $, $, $, .NOTDEFINED.); +#130 = IFCSURFACESTYLE($, .BOTH., (#129)); +#131 = IFCPRESENTATIONSTYLEASSIGNMENT((#130)); +#132 = IFCSTYLEDITEM(#27, (#131), $); +#133 = IFCRELCONTAINEDINSPATIALSTRUCTURE('0WOibVXVXFLQabcILOoRAW', #1, $, $, (#14), #13); +#134 = IFCRELAGGREGATES('1PBxJnWMLBlP8BcL_PXo71', #1, $, $, #7, (#13)); +#135 = IFCRELAGGREGATES('3$h1BhDfnDQfWZXBRDMGbj', #1, $, $, #115, (#7)); +#136 = IFCRELAGGREGATES('1UmwNW7crDGeh$LdqIdCWH', #1, $, $, #114, (#115)); +#137 = IFCLOCALPLACEMENT($, #138); +#138 = IFCAXIS2PLACEMENT3D(#22, #23, #24); +#139 = IFCLOCALPLACEMENT(#137, #140); +#140 = IFCAXIS2PLACEMENT3D(#22, #23, #24); +#141 = IFCLOCALPLACEMENT(#139, #142); +#142 = IFCAXIS2PLACEMENT3D(#143, #23, #24); +#143 = IFCCARTESIANPOINT((0., 0., 55900.)); +#144 = IFCLOCALPLACEMENT(#141, #145); +#145 = IFCAXIS2PLACEMENT3D(#146, #147, #23); +#146 = IFCCARTESIANPOINT((0, 0, 0)); +#147 = IFCDIRECTION((9.57778850166525E-1, 2.87505955023003E-1, 0.)); +#148 = IFCUNITASSIGNMENT((#149, #150, #151, #152, #153, #154, #155, #156, #157, #158, #159, #160, #164, #167, #172)); +#149 = IFCSIUNIT(*, .PLANEANGLEUNIT., $, .RADIAN.); +#150 = IFCSIUNIT(*, .AREAUNIT., $, .SQUARE_METRE.); +#151 = IFCSIUNIT(*, .LENGTHUNIT., .MILLI., .METRE.); +#152 = IFCSIUNIT(*, .MASSUNIT., $, .GRAM.); +#153 = IFCSIUNIT(*, .POWERUNIT., $, .WATT.); +#154 = IFCSIUNIT(*, .PRESSUREUNIT., .KILO., .PASCAL.); +#155 = IFCSIUNIT(*, .FORCEUNIT., .KILO., .NEWTON.); +#156 = IFCSIUNIT(*, .ELECTRICCURRENTUNIT., $, .AMPERE.); +#157 = IFCSIUNIT(*, .THERMODYNAMICTEMPERATUREUNIT., $, .DEGREE_CELSIUS.); +#158 = IFCSIUNIT(*, .TIMEUNIT., $, .SECOND.); +#159 = IFCSIUNIT(*, .VOLUMEUNIT., $, .CUBIC_METRE.); +#160 = IFCDERIVEDUNIT((#161, #162), .LINEARVELOCITYUNIT., $); +#161 = IFCDERIVEDUNITELEMENT(#163, 1); +#162 = IFCDERIVEDUNITELEMENT(#158, -1); +#163 = IFCSIUNIT(*, .LENGTHUNIT., $, .METRE.); +#164 = IFCDERIVEDUNIT((#165, #166), .VOLUMETRICFLOWRATEUNIT., $); +#165 = IFCDERIVEDUNITELEMENT(#159, 1); +#166 = IFCDERIVEDUNITELEMENT(#158, -1); +#167 = IFCDERIVEDUNIT((#168, #169, #170), .THERMALTRANSMITTANCEUNIT., $); +#168 = IFCDERIVEDUNITELEMENT(#153, 1); +#169 = IFCDERIVEDUNITELEMENT(#171, -1); +#170 = IFCDERIVEDUNITELEMENT(#150, -1); +#171 = IFCSIUNIT(*, .THERMODYNAMICTEMPERATUREUNIT., $, .KELVIN.); +#172 = IFCDERIVEDUNIT((#173), .SOUNDPRESSUREUNIT., $); +#173 = IFCDERIVEDUNITELEMENT(#174, 1); +#174 = IFCSIUNIT(*, .PRESSUREUNIT., $, .PASCAL.); +ENDSEC; +END-ISO-10303-21; diff --git a/win/build-all.cmd b/win/build-all.cmd new file mode 100644 index 0000000000..4f29f0edd3 --- /dev/null +++ b/win/build-all.cmd @@ -0,0 +1,44 @@ +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: :: +:: 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 . :: +:: :: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +:: The first argument is assumed to be a CMake generator and it is passed for build-deps, run-cmake, build-ifcopenshell, +:: and install-ifcopenshell. The second argument is assumed to be a build configuration type and it is passed for build-deps, +:: build-ifcopenshell and install-ifcopenshell. The rest of the arguments are passed for run-cmake. +:: Usage example for doing an optimized vs2015-x64 build with debug information and using IFC 4: +:: > build-all.cmd vs2015-x64 RelWithDebInfo -DUSE_IFC4=1 -DENABLE_BUILD_OPTIMIZATIONS=1 + +@echo off + +setlocal EnableDelayedExpansion + +call vs-cfg.cmd %1 +if not %ERRORLEVEL%==0 GOTO :Error +:: Use "yes" trick to break the pause in build-deps.cmd +echo y | call .\build-deps %1 %2 +if not %ERRORLEVEL%==0 goto :EOF +:: Same trick as in run-cmake.bat +set ARGUMENTS=%* +if not (%1)==() call set ARGUMENTS=%%ARGUMENTS:%1=%% +if not (%2)==() call set ARGUMENTS=%%ARGUMENTS:%2=%% +call .\run-cmake %1 %ARGUMENTS% +if not %ERRORLEVEL%==0 goto :EOF +call .\build-ifcopenshell %1 %2 +ECHO %ERRORLEVEL% +if not %ERRORLEVEL%==0 goto :EOF +call .\install-ifcopenshell %1 %2 diff --git a/win/build-deps.cmd b/win/build-deps.cmd new file mode 100644 index 0000000000..d7d8b44b35 --- /dev/null +++ b/win/build-deps.cmd @@ -0,0 +1,437 @@ +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: :: +:: 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 . :: +:: :: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +:: This batch file expects CMake generator as %1 and build configuration type as %2. If not provided, +:: a deduced generator will be used for %1 and BUILD_CFG_DEFAULT for %2 (both set in vs-cfg.cmd) +:: Optionally a build type (Build/Rebuild/Clean) can be passed as %3. + +@echo off +echo. + +set PROJECT_NAME=IfcOpenShell +call utils\cecho.cmd 15 0 "This script fetches and builds all %PROJECT_NAME% dependencies" +echo. + +:: Enable the delayed environment variable expansion needed in vs-cfg.cmd. +setlocal EnableDelayedExpansion + +:: Make sure vcvarsall.bat is called and dev env set is up. +IF "%VSINSTALLDIR%"=="" ( + call utils\cecho.cmd 0 12 "Visual Studio environment variables not set- cannot proceed." + GOTO :ErrorAndPrintUsage +) + +:: Check for cl.exe - at least the "Typical" Visual Studio 2015 installation does not include the C++ toolset by default, +:: http://blogs.msdn.com/b/vcblog/archive/2015/07/24/setup-changes-in-visual-studio-2015-affecting-c-developers.aspx +where cl.exe 2>&1>NUL +if not %ERRORLEVEL%==0 ( + call utils\cecho.cmd 0 12 "%~nx0: cl.exe not in PATH. Make sure to select the C++ toolset when installing Visual Studio- cannot proceed." + GOTO :ErrorAndPrintUsage +) + +:: Set up variables depending on the used Visual Studio version +call vs-cfg.cmd %1 +IF NOT %ERRORLEVEL%==0 GOTO :Error +call build-type-cfg.cmd %2 +IF NOT %ERRORLEVEL%==0 GOTO :Error + +set BUILD_TYPE=%3 +IF "%BUILD_TYPE%"=="" set BUILD_TYPE=Build + +IF NOT "!BUILD_TYPE!"=="Build" IF NOT "!BUILD_TYPE!"=="Rebuild" IF NOT "!BUILD_TYPE!"=="Clean" ( + call utils\cecho.cmd 0 12 "Invalid build type passed: !BUILD_TYPE!. Cannot proceed, aborting!" + GOTO :Error +) + +:: Make sure deps and install folders exists. +IF NOT EXIST %DEPS_DIR%. mkdir %DEPS_DIR% +IF NOT EXIST %INSTALL_DIR%. mkdir %INSTALL_DIR% + +:: If we use VS2008, framework path (for MSBuild) may not be correctly set. Manually attempt to add in that case +IF %VS_VER%==2008 set PATH=C:\Windows\Microsoft.NET\Framework\v3.5;%PATH% + +:: User-configurable build options +IF NOT DEFINED IFCOS_INSTALL_PYTHON set IFCOS_INSTALL_PYTHON=TRUE +IF NOT DEFINED IFCOS_USE_PYTHON2 set IFCOS_USE_PYTHON2=FALSE +IF NOT DEFINED IFCOS_NUM_BUILD_PROCS set IFCOS_NUM_BUILD_PROCS=%NUMBER_OF_PROCESSORS% + +:: For subroutines +set MSBUILD_CMD=MSBuild.exe /nologo /m:%IFCOS_NUM_BUILD_PROCS% /t:%BUILD_TYPE% +REM /clp:ErrorsOnly;WarningsOnly +:: Note BUILD_TYPE not passed, Clean e.g. wouldn't delete the installed files. +set INSTALL_CMD=MSBuild.exe /nologo /m:%IFCOS_NUM_BUILD_PROCS% + +echo. + +:: Check that required tools are in PATH +FOR %%i IN (powershell git cmake) DO ( + where.exe %%i 1> NUL 2> NUL || call cecho.cmd 0 12 "Required tool `'%%i`' not installed or not added to PATH" && goto :ErrorAndPrintUsage +) + +:: Print build configuration information + +call cecho.cmd 0 10 "Script configuration:" +call cecho.cmd 0 13 "* CMake Generator`t= '`"%GENERATOR%`'`t +echo - Passed to CMake -G option. +call cecho.cmd 0 13 "* Target Architecture`t= %TARGET_ARCH%" +echo - Whether were doing 32-bit (x86) or 64-bit (x64) build. +call cecho.cmd 0 13 "* Dependency Directory`t= %DEPS_DIR%" +echo - The directory where %PROJECT_NAME% dependencies are fetched and built. +call cecho.cmd 0 13 "* Installation Directory = %INSTALL_DIR%" +echo - The directory where %PROJECT_NAME% dependencies are installed. +call cecho.cmd 0 13 "* Build Config Type`t= %BUILD_CFG%" +echo - The used build configuration type for the dependencies. +echo Defaults to RelWithDebInfo if not specified. +IF %BUILD_CFG%==MinSizeRel call cecho.cmd 0 14 " WARNING: MinSizeRel build can suffer from a significant performance loss." +call cecho.cmd 0 13 "* Build Type`t`t= %BUILD_TYPE%" +echo - The used build type for the dependencies (Build, Rebuild, Clean). +echo Defaults to Build if not specified. Rebuild/Clean also uninstalls Python (if it was installed by this script). +call cecho.cmd 0 13 "* IFCOS_INSTALL_PYTHON`t= %IFCOS_INSTALL_PYTHON%" +echo - Download and install Python. +echo Set to something other than TRUE if you wish to use an already installed version of Python. +call cecho.cmd 0 13 "* IFCOS_USE_PYTHON2`t= %IFCOS_USE_PYTHON2%" +echo - Use Python 2 instead of 3. +echo Set to TRUE if you wish to use Python 2 instead of 3. Has no effect if IFCOS_INSTALL_PYTHON is not TRUE. +call cecho.cmd 0 13 "* IFCOS_NUM_BUILD_PROCS`t= %IFCOS_NUM_BUILD_PROCS%" +echo - How many MSBuild.exe processes may be run in parallel. +echo Defaults to NUMBER_OF_PROCESSORS. Used also by other IfcOpenShell build scripts. +echo. + +call :PrintUsage + +call cecho.cmd 0 14 "Warning: You will need roughly 8 GB of disk space to proceed `(VS 2015 x64 RelWithDebInfo`)." +echo. + +call cecho.cmd black cyan "If you are not ready with the above, press Ctrl-C to abort!" + +pause +echo. +set START_TIME=%TIME% +echo Build started at %START_TIME%. +set BUILD_STARTED=TRUE +echo. + +cd %DEPS_DIR% + +:: Note all of the depedencies have approriate label so that user can easily skip something if wanted +:: by modifying this file and using goto. +:Boost +set BOOST_VERSION=1.59.0 +:: DEPENDENCY_NAME is used for logging and DEPENDENCY_DIR for saving from some redundant typing +set DEPENDENCY_NAME=Boost %BOOST_VERSION% +set DEPENDENCY_DIR="%DEPS_DIR%\boost" +:: Version string with underscores instead of dots. +set BOOST_VER=%BOOST_VERSION:.=_% +set BOOST_ROOT=%DEPS_DIR%\boost +REM set BOOST_INCLUDEDIR=%DEPS_DIR%\boost +set BOOST_LIBRARYDIR=%DEPS_DIR%\boost\stage\%VS_PLATFORM%\lib +:: NOTE Also zip download exists, if encountering problems with 7z for some reason. +set ZIP_EXT=7z +set BOOST_ZIP=boost_%BOOST_VER%.%ZIP_EXT% + +call :DownloadFile http://downloads.sourceforge.net/project/boost/boost/%BOOST_VERSION%/%BOOST_ZIP% "%DEPS_DIR%" %BOOST_ZIP% + +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :ExtractArchive %BOOST_ZIP% "%DEPS_DIR%" "%DEPS_DIR%\boost" +IF NOT %ERRORLEVEL%==0 GOTO :Error + +:: Build Boost build script +IF EXIST "%DEPS_DIR%\boost_%BOOST_VER%". ( + cd "%DEPS_DIR%" + ren boost_%BOOST_VER% boost + IF NOT EXIST "%DEPS_DIR%\boost\boost.css" GOTO :Error + cd "%DEPS_DIR%\boost" + call cecho.cmd 0 13 "Building Boost build script." + call bootstrap vc%VC_VER% + IF NOT %ERRORLEVEL%==0 GOTO :Error +) + +set BOOST_LIBS=--with-system --with-regex --with-thread --with-program_options --with-date_time +:: NOTE Boost is fast to build with limited set of libraries so build it always. +cd "%DEPS_DIR%\boost" +call cecho.cmd 0 13 "Building %DEPENDENCY_NAME% %BOOST_LIBS% Please be patient, this will take a while." +IF EXIST "%DEPS_DIR%\boost\bin.v2\project-cache.jam" del "%DEPS_DIR%\boost\bin.v2\project-cache.jam" +call .\b2 toolset=msvc-%VC_VER%.0 runtime-link=static address-model=%ARCH_BITS% -j%IFCOS_NUM_BUILD_PROCS% ^ + variant=%DEBUG_OR_RELEASE_LOWERCASE% %BOOST_LIBS% stage --stagedir=stage/vs%VS_VER%-%VS_PLATFORM% +IF NOT %ERRORLEVEL%==0 GOTO :Error + +:ICU +set DEPENDENCY_NAME=ICU +set DEPENDENCY_DIR=N/A +set ICU_ZIP=icu-55.1-vs%VS_VER%.7z +cd "%DEPS_DIR%" +call :DownloadFile http://www.npcglib.org/~stathis/downloads/%ICU_ZIP% "%DEPS_DIR%" %ICU_ZIP% +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :ExtractArchive %ICU_ZIP% "%DEPS_DIR%" "%INSTALL_DIR%\icu" +IF NOT %ERRORLEVEL%==0 GOTO :Error +:: Rename lib and bin directories to predictable form +IF EXIST "%DEPS_DIR%\icu-55.1-vs%VS_VER%". ( + pushd "%DEPS_DIR%\icu-55.1-vs%VS_VER%" + IF EXIST bin. ren bin bin%ARCH_BITS%" + IF EXIST lib. ren lib lib%ARCH_BITS%" + popd +) + +IF EXIST "%DEPS_DIR%\icu-55.1-vs%VS_VER%\". ( + robocopy "%DEPS_DIR%\icu-55.1-vs%VS_VER%\include" "%INSTALL_DIR%\icu\include" /E /IS /njh /njs + IF NOT EXIST "%INSTALL_DIR%\icu\lib". mkdir "%INSTALL_DIR%\icu\lib" + copy /y "%DEPS_DIR%\icu-55.1-vs%VS_VER%\lib%ARCH_BITS%\sicutest%POSTFIX_D%.lib" "%INSTALL_DIR%\icu\lib\icutest%POSTFIX_D%.lib" + copy /y "%DEPS_DIR%\icu-55.1-vs%VS_VER%\lib%ARCH_BITS%\sicutu%POSTFIX_D%.lib" "%INSTALL_DIR%\icu\lib\icutu%POSTFIX_D%.lib" + copy /y "%DEPS_DIR%\icu-55.1-vs%VS_VER%\lib%ARCH_BITS%\sicuuc%POSTFIX_D%.lib" "%INSTALL_DIR%\icu\lib\icuuc%POSTFIX_D%.lib" + copy /y "%DEPS_DIR%\icu-55.1-vs%VS_VER%\lib%ARCH_BITS%\sicudt%POSTFIX_D%.lib" "%INSTALL_DIR%\icu\lib\icudt%POSTFIX_D%.lib" + copy /y "%DEPS_DIR%\icu-55.1-vs%VS_VER%\lib%ARCH_BITS%\sicuin%POSTFIX_D%.lib" "%INSTALL_DIR%\icu\lib\icuin%POSTFIX_D%.lib" + copy /y "%DEPS_DIR%\icu-55.1-vs%VS_VER%\lib%ARCH_BITS%\sicuio%POSTFIX_D%.lib" "%INSTALL_DIR%\icu\lib\icuio%POSTFIX_D%.lib" + copy /y "%DEPS_DIR%\icu-55.1-vs%VS_VER%\lib%ARCH_BITS%\sicule%POSTFIX_D%.lib" "%INSTALL_DIR%\icu\lib\icule%POSTFIX_D%.lib" + copy /y "%DEPS_DIR%\icu-55.1-vs%VS_VER%\lib%ARCH_BITS%\siculx%POSTFIX_D%.lib" "%INSTALL_DIR%\icu\lib\iculx%POSTFIX_D%.lib" +) + +:OpenCOLLADA +:: Note OpenCOLLADA has only Release and Debug builds. +set DEPENDENCY_NAME=OpenCOLLADA +set DEPENDENCY_DIR=%DEPS_DIR%\OpenCOLLADA +call :GitCloneOrPullRepository https://github.com/KhronosGroup/OpenCOLLADA.git "%DEPENDENCY_DIR%" +IF NOT %ERRORLEVEL%==0 GOTO :Error +cd "%DEPENDENCY_DIR%" +:: Debug build of OpenCOLLADAValidator fails (https://github.com/KhronosGroup/OpenCOLLADA/issues/377) so +:: so disable it from the build altogether as we have no use for it +findstr #add_subdirectory(COLLADAValidator) CMakeLists.txt>NUL +IF NOT %ERRORLEVEL%==0 git apply --reject --whitespace=fix "%~dp0patches\OpenCOLLADA_CMakeLists.txt.patch" +:: NOTE OpenCOLLADA has been observed to have problems with switching between debug and release builds so +:: uncomment to following line in order to delete the CMakeCache.txt always if experiencing problems. +REM IF EXIST "%DEPENDENCY_DIR%\%BUILD_DIR%\CMakeCache.txt". del "%DEPENDENCY_DIR%\%BUILD_DIR%\CMakeCache.txt" +:: NOTE Enforce that the embedded LibXml2 and PCRE are used as there might be problems with arbitrary versions of the libraries. +call :RunCMake -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%\OpenCOLLADA" -DUSE_STATIC_MSVC_RUNTIME=1 -DCMAKE_DEBUG_POSTFIX=d ^ + -DLIBXML2_LIBRARIES="" -DLIBXML2_INCLUDE_DIR="" -DPCRE_INCLUDE_DIR="" -DPCRE_LIBRARIES="" +IF NOT %ERRORLEVEL%==0 GOTO :Error +REM IF NOT EXIST "%DEPS_DIR%\OpenCOLLADA\%BUILD_DIR%\lib\%DEBUG_OR_RELEASE%\OpenCOLLADASaxFrameworkLoader.lib". +call :BuildSolution "%DEPENDENCY_DIR%\%BUILD_DIR%\OPENCOLLADA.sln" %DEBUG_OR_RELEASE% +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :InstallCMakeProject "%DEPENDENCY_DIR%\%BUILD_DIR%" %DEBUG_OR_RELEASE% +IF NOT %ERRORLEVEL%==0 GOTO :Error + +:OCE +set DEPENDENCY_NAME=Open CASCADE Community Edition +set DEPENDENCY_DIR=%DEPS_DIR%\oce +call :GitCloneOrPullRepository https://github.com/tpaviot/oce.git "%DEPENDENCY_DIR%" +IF NOT %ERRORLEVEL%==0 GOTO :Error +:: Use the oce-win-bundle for OCE's dependencies +call :GitCloneOrPullRepository https://github.com/QbProg/oce-win-bundle.git "%DEPENDENCY_DIR%\oce-win-bundle" +IF NOT %ERRORLEVEL%==0 GOTO :Error + +cd "%DEPENDENCY_DIR%" +set OCE_BUNDLE_ROOT_PATH="%INSTALL_DIR%\oce-win-bundle" +:: NOTE Specify OCE_NO_LIBRARY_VERSION as rc.exe can fail due to long filenames and huge command-line parameter +:: input (more than 32,000 characters). Could maybe try using subst for the build dir to overcome this. +call :RunCMake -DOCE_BUILD_SHARED_LIB=0 -DOCE_INSTALL_PREFIX="%INSTALL_DIR%\oce" -DOCE_TESTING=0 ^ + -DOCE_NO_LIBRARY_VERSION=1 -DOCE_USE_STATIC_MSVC_RUNTIME=1 +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :BuildSolution "%DEPENDENCY_DIR%\%BUILD_DIR%\OCE.sln" %BUILD_CFG% +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :InstallCMakeProject "%DEPENDENCY_DIR%\%BUILD_DIR%" %BUILD_CFG% +IF NOT %ERRORLEVEL%==0 GOTO :Error + +:Python +:: TODO Update to 3.5 when it's released as it will have an option to install debug libraries. +:: NOTE If updating the default Python version, change PY_VER_MAJOR_MINOR accordingly in run-cmake.bat +set PYTHON_VERSION=3.4.3 +IF "%IFCOS_USE_PYTHON2%"=="TRUE" set PYTHON_VERSION=2.7.10 +set PY_VER_MAJOR_MINOR=%PYTHON_VERSION:~0,3% +set PY_VER_MAJOR_MINOR=%PY_VER_MAJOR_MINOR:.=% +set PYTHONHOME=%INSTALL_DIR%\Python%PY_VER_MAJOR_MINOR% + +set DEPENDENCY_NAME=Python %PYTHON_VERSION% +set DEPENDENCY_DIR=N/A +set PYTHON_AMD64_POSTFIX=.amd64 +:: NOTE/TODO Beginning from 3.5.0: set PYTHON_AMD64_POSTFIX=-amd64 +IF NOT %TARGET_ARCH%==x64 set PYTHON_AMD64_POSTFIX= +set PYTHON_INSTALLER=python-%PYTHON_VERSION%%PYTHON_AMD64_POSTFIX%.msi +:: NOTE/TODO 3.5.0 doesn't use MSI any longer, but exe: set PYTHON_INSTALLER=python-%PYTHON_VERSION%%PYTHON_AMD64_POSTFIX%.exe +IF "%IFCOS_INSTALL_PYTHON%"=="TRUE" ( + REM Store Python versions to BuildDepsCache.txt for run-cmake.bat + echo PY_VER_MAJOR_MINOR=%PY_VER_MAJOR_MINOR%>"%~dp0\BuildDepsCache-%TARGET_ARCH%.txt" + echo PYTHONHOME=%PYTHONHOME%>>"%~dp0\BuildDepsCache-%TARGET_ARCH%.txt" + + cd "%DEPS_DIR%" + call :DownloadFile https://www.python.org/ftp/python/%PYTHON_VERSION%/%PYTHON_INSTALLER% "%DEPS_DIR%" %PYTHON_INSTALLER% + IF NOT %ERRORLEVEL%==0 GOTO :Error + REM Uninstall if build Rebuild/Clean used + IF NOT %BUILD_TYPE%==Build ( + call cecho.cmd 0 13 "Uninstalling %DEPENDENCY_NAME%. Please be patient, this will take a while." + msiexec /x %PYTHON_INSTALLER% /qn + ) + + IF NOT EXIST "%PYTHONHOME%". ( + call cecho.cmd 0 13 "Installing %DEPENDENCY_NAME%. Please be patient, this will take a while." + msiexec /qn /i %PYTHON_INSTALLER% TARGETDIR="%PYTHONHOME%" + ) ELSE ( + call cecho.cmd 0 13 "%DEPENDENCY_NAME% already installed. Skipping." + ) +) ELSE ( + call cecho.cmd 0 13 "IFCOS_INSTALL_PYTHON not true, skipping installation of Python." +) + +:SWIG +set SWIG_VERSION=3.0.7 +set DEPENDENCY_NAME=SWIG %SWIG_VERSION% +set DEPENDENCY_DIR=N/A +set SWIG_ZIP=swigwin-%SWIG_VERSION%.zip +cd "%DEPS_DIR%" +call :DownloadFile http://sourceforge.net/projects/swig/files/swigwin/swigwin-%SWIG_VERSION%/%SWIG_ZIP% "%DEPS_DIR%" %SWIG_ZIP% +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :ExtractArchive %SWIG_ZIP% "%DEPS_DIR%" "%DEPS_DIR%\swigwin" +IF NOT %ERRORLEVEL%==0 GOTO :Error +IF EXIST "%DEPS_DIR%\swigwin-%SWIG_VERSION%". ( + pushd %DEPS% + ren swigwin-%SWIG_VERSION% swigwin + popd +) +IF EXIST "%DEPS_DIR%\swigwin\". robocopy "%DEPS_DIR%\swigwin" "%INSTALL_DIR%\swigwin" /E /IS /MOVE /njh /njs + +:Successful +echo. +call %~dp0\utils\cecho.cmd 0 10 "%PROJECT_NAME% dependencies built." +set IFCOS_SCRIPT_RET=0 +goto :Finish + +:ErrorAndPrintUsage +echo. +call :PrintUsage +:Error +echo. +call %~dp0\utils\cecho.cmd 0 12 "An error occurred! Aborting!" +set IFCOS_SCRIPT_RET=1 +goto :Finish + +:Finish +:: Print end time and elapsed time, http://stackoverflow.com/a/9935540 +if not defined BUILD_STARTED goto :BuildTimeSkipped +set END_TIME=%TIME% +for /F "tokens=1-4 delims=:.," %%a in ("%START_TIME%") do ( + set /A "start=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100" +) +for /F "tokens=1-4 delims=:.," %%a in ("%END_TIME%") do ( + set /A "end=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100" +) +set /A elapsed=end-start +set /A hh=elapsed/(60*60*100), rest=elapsed%%(60*60*100), mm=rest/(60*100), rest%%=60*100, ss=rest/100, cc=rest%%100 +if %mm% lss 10 set mm=0%mm% +if %ss% lss 10 set ss=0%ss% +if %cc% lss 10 set cc=0%cc% +echo. +echo Build ended at %END_TIME%. Time elapsed %hh%:%mm%:%ss%.%cc%. +:BuildTimeSkipped +set PATH=%ORIGINAL_PATH% +cd %~dp0 +exit /b %IFCOS_SCRIPT_RET% + +::::::::::::::::::::::::::::::::::::: Subroutines ::::::::::::::::::::::::::::::::::::: + +:: DownloadFile - Downloads a file using wget +:: Params: %1 url, %2 destinationDir, %3 filename +:DownloadFile +pushd %2 +IF NOT EXIST "%3". ( + call cecho.cmd 0 13 "Downloading %DEPENDENCY_NAME% into %2." + powershell -Command "$webClient = new-object System.Net.WebClient; $webClient.DownloadFile('%1', '%3')" + REM Old wget version in case someone has problem with PowerShell: wget --no-check-certificate %1 +) ELSE ( + call cecho.cmd 0 13 "%DEPENDENCY_NAME% already downloaded. Skipping." +) +set RET=%ERRORLEVEL% +popd +exit /b %RET% + +:: ExtractArchive - Extracts an archive file using 7-zip +:: Params: %1 filename, %2 destinationDir, %3 dirAfterExtraction +:ExtractArchive +IF NOT EXIST "%3". ( + call cecho.cmd 0 13 "Extracting %DEPENDENCY_NAME% into %2." + 7za x %1 -y -o%2 +) ELSE ( + call cecho.cmd 0 13 "%DEPENDENCY_NAME% already extracted into %3. Skipping." +) +exit /b %ERRORLEVEL% + +:: GitCloneOrPullRepository - Clones or pulls (if repository already cloned) a Git repository +:: Params: %1 gitUrl, %2 destDir +:: F.ex. call :GitCloneRepository https://github.com/KhronosGroup/OpenCOLLADA.git "%DEPS_DIR%\OpenCOLLADA\" +:GitCloneOrPullRepository +IF NOT EXIST %2. ( + call cecho.cmd 0 13 "Cloning %DEPENDENCY_NAME% into %2." + pushd "%DEPS_DIR%" + call git clone %1 %2 + set RET=%ERRORLEVEL% +) ELSE ( + call cecho.cmd 0 13 "%DEPENDENCY_NAME% already cloned. Pulling latest changes." + pushd %2 + call git pull + set RET=0 +) +popd +exit /b %RET% + +:: RunCMake - Runs CMake for a CMake-based project +:: Params: %* cmakeOptions +:: NOTE cd to root CMakeLists.txt folder before calling this if the CMakeLists.txt is not in the repo root. +:RunCMake +call cecho.cmd 0 13 "Running CMake for %DEPENDENCY_NAME%." +IF NOT EXIST %BUILD_DIR%. mkdir %BUILD_DIR% +IF NOT %ERRORLEVEL%==0 GOTO :Error +pushd %BUILD_DIR% +:: TODO make deleting cache a parameter for this subroutine? We probably want to delete the +:: cache always e.g. when we've had new changes in the repository. +IF %BUILD_TYPE%==Rebuild IF EXIST CMakeCache.txt. del CMakeCache.txt +cmake .. -G %GENERATOR% %* +set RET=%ERRORLEVEL% +popd +exit /b %RET% + +:: BuildSolution - Builds/Rebuilds/Cleans a solution using MSBuild +:: Params: %1 solutioName, %2 configuration +:BuildSolution +call cecho.cmd 0 13 "%BUILD_TYPE%ing %2 %DEPENDENCY_NAME%. Please be patient, this will take a while." +%MSBUILD_CMD% %1 /p:configuration=%2;platform=%VS_PLATFORM% +exit /b %ERRORLEVEL% + +:: InstallCMakeProject - Builds the INSTALL project of CMake-based project +:: Params: %1 buildDir, %2 == configuration +:: NOTE the actual install dir is set during cmake run. +:InstallCMakeProject +pushd %1 +call cecho.cmd 0 13 "Installing %2 %DEPENDENCY_NAME%. Please be patient, this will take a while." +%INSTALL_CMD% INSTALL.%VCPROJ_FILE_EXT% /p:configuration=%2;platform=%VS_PLATFORM% +set RET=%ERRORLEVEL% +popd +exit /b %RET% + +:: PrintUsage - Prints usage information +:PrintUsage +call %~dp0\utils\cecho.cmd 0 10 "Requirements for a successful execution:" +echo 1. Install PowerShell (preinstalled in Windows ^>= 7) and make sure 'powershell' is accessible from PATH. +echo - https://support.microsoft.com/en-us/kb/968929 +echo 2. Install Git and make sure 'git' is accessible from PATH. +echo - http://code.google.com/p/tortoisegit/ +echo 3. Install CMake and make sure 'cmake' is accessible from PATH. +echo - http://www.cmake.org/ +echo 4. Visual Studio 2008 or newer (2013 or newer recommended) with C++ toolset. +echo - https://www.visualstudio.com/ +echo 5. Run this batch script with Visual Studio environment variables set. +echo - https://msdn.microsoft.com/en-us/library/ms229859(v=vs.110).aspx +echo. +REM TODO 3ds Max SDK instructions? diff --git a/win/build-ifcopenshell.cmd b/win/build-ifcopenshell.cmd new file mode 100644 index 0000000000..632b768dfd --- /dev/null +++ b/win/build-ifcopenshell.cmd @@ -0,0 +1,56 @@ +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: :: +:: 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 . :: +:: :: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +:: This batch file expects CMake generator as %1 and build configuration type as %2. If not provided, +:: a deduced generator will be used for %1 and BUILD_CFG_DEFAULT for %2 (both set in vs-cfg.cmd) +:: Possible extra parameters are passed for the MSBuild call. + +@echo off +set PROJECT_NAME=IfcOpenShell +echo. + +:: Enable the delayed environment variable expansion needed in VSConfig.cmd. +setlocal EnableDelayedExpansion +call vs-cfg.cmd %1 +IF NOT %ERRORLEVEL%==0 GOTO :Error +call build-type-cfg.cmd %2 +IF NOT %ERRORLEVEL%==0 GOTO :Error + +echo. +IF "%IFCOS_NUM_BUILD_PROCS%"=="" set IFCOS_NUM_BUILD_PROCS=%NUMBER_OF_PROCESSORS% +call cecho.cmd 0 13 "* IFCOS_NUM_BUILD_PROCS`t= %IFCOS_NUM_BUILD_PROCS%" +echo. + +call cecho.cmd 0 13 "Building %VS_PLATFORM% %BUILD_CFG% %PROJECT_NAME%" +MSBuild ..\%BUILD_DIR%\%PROJECT_NAME%.sln /nologo /m:%IFCOS_NUM_BUILD_PROCS% /p:Platform=%VS_PLATFORM% ^ + /p:Configuration=%BUILD_CFG% %3 %4 %5 %6 %7 %8 %9 +IF NOT %ERRORLEVEL%==0 GOTO :Error + +echo. +call cecho.cmd 0 10 "%VS_PLATFORM% %BUILD_CFG% %PROJECT_NAME% build finished." +set IFCOS_SCRIPT_RET=0 +goto :End + +:Error +echo. +call %~dp0\utils\cecho.cmd 0 12 "%VS_PLATFORM% %BUILD_CFG% %PROJECT_NAME% build failed!" +set IFCOS_SCRIPT_RET=1 + +:End +exit /b %IFCOS_SCRIPT_RET% diff --git a/win/build-type-cfg.cmd b/win/build-type-cfg.cmd new file mode 100644 index 0000000000..acb75d64ad --- /dev/null +++ b/win/build-type-cfg.cmd @@ -0,0 +1,60 @@ +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: :: +:: 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 . :: +:: :: +::::::::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::: + +:: This script initializes various CMake build configuration type related variables. +:: This batch file expects CMake build configuration type as %1. + +@echo off + +:: Set up variables depending on the used build configuration type. +set BUILD_CFG=%1 + +:: The default build types provided by CMake +set BUILD_CFG_MINSIZEREL=MinSizeRel +set BUILD_CFG_RELEASE=Release +set BUILD_CFG_RELWITHDEBINFO=RelWithDebInfo +set BUILD_CFG_DEBUG=Debug +set BUILD_CFG_DEFAULT=%BUILD_CFG_RELWITHDEBINFO% + +IF "!BUILD_CFG!"=="" ( + set BUILD_CFG=%BUILD_CFG_DEFAULT% + call utils\cecho.cmd 0 14 "%~nx0: Warning: BUILD_CFG not specified - using the default %BUILD_CFG_DEFAULT%" +) +IF NOT !BUILD_CFG!==%BUILD_CFG_MINSIZEREL% IF NOT !BUILD_CFG!==%BUILD_CFG_RELEASE% ( +IF NOT !BUILD_CFG!==%BUILD_CFG_RELWITHDEBINFO% IF NOT !BUILD_CFG!==%BUILD_CFG_DEBUG% ( + call utils\cecho.cmd 0 12 "%~nx0: Invalid or unsupported CMake build configuration type passed: !BUILD_CFG!. Cannot proceed." + exit /b 1 +)) + +:: DEBUG_OR_RELEASE and DEBUG_OR_RELEASE_LOWERCASE are "Debug" and "debug" for Debug build and "Release" and +:: "release" for all of the Release variants. +:: POSTFIX_D, POSTFIX_UNDERSCORE_D and POSTFIX_UNDERSCORE_DEBUG are helpers for performing file copies and +:: checking for existence of files. In release build these variables are empty. +set DEBUG_OR_RELEASE=Release +set DEBUG_OR_RELEASE_LOWERCASE=release +set POSTFIX_D= +set POSTFIX_UNDERSCORE_D= +set POSTFIX_UNDERSCORE_DEBUG= +IF %BUILD_CFG%==Debug ( + set DEBUG_OR_RELEASE=Debug + set DEBUG_OR_RELEASE_LOWERCASE=debug + set POSTFIX_D=d + set POSTFIX_UNDERSCORE_D=_d + set POSTFIX_UNDERSCORE_DEBUG=_debug +) diff --git a/win/install-ifcopenshell.cmd b/win/install-ifcopenshell.cmd new file mode 100644 index 0000000000..571461dd2b --- /dev/null +++ b/win/install-ifcopenshell.cmd @@ -0,0 +1,56 @@ +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: :: +:: 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 . :: +:: :: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +:: This batch file expects CMake generator as %1 and build configuration type as %2. If not provided, +:: a deduced generator will be used for %1 and BUILD_CFG_DEFAULT for %2 (both set in vs-cfg.cmd) +:: Possible extra parameters are passed for the MSBuild call. + +@echo off +set PROJECT_NAME=IfcOpenShell +echo. + +:: Enable the delayed environment variable expansion needed in VSConfig.cmd. +setlocal EnableDelayedExpansion +call vs-cfg.cmd %1 +IF NOT %ERRORLEVEL%==0 GOTO :Error +call build-type-cfg.cmd %2 +IF NOT %ERRORLEVEL%==0 GOTO :Error + +echo. +IF "%IFCOS_NUM_BUILD_PROCS%"=="" set IFCOS_NUM_BUILD_PROCS=%NUMBER_OF_PROCESSORS% +call cecho.cmd 0 13 "* IFCOS_NUM_BUILD_PROCS`t= %IFCOS_NUM_BUILD_PROCS%" +echo. + +call cecho.cmd 0 13 "Installing %VS_PLATFORM% %BUILD_CFG% %PROJECT_NAME%" +MSBuild ..\%BUILD_DIR%\INSTALL.%VCPROJ_FILE_EXT% /nologo /m:%IFCOS_NUM_BUILD_PROCS% /p:Platform=%VS_PLATFORM% ^ + /p:Configuration=%BUILD_CFG% %3 %4 %5 %6 %7 %8 %9 +IF NOT %ERRORLEVEL%==0 GOTO :Error + +echo. +call cecho.cmd 0 10 "%VS_PLATFORM% %BUILD_CFG% %PROJECT_NAME% installation finished." +set IFCOS_SCRIPT_RET=0 +goto :End + +:Error +echo. +call %~dp0\utils\cecho.cmd 0 12 "%VS_PLATFORM% %BUILD_CFG% %PROJECT_NAME% installation failed!" +set IFCOS_SCRIPT_RET=1 + +:End +exit /b %IFCOS_SCRIPT_RET% diff --git a/win/patches/OpenCOLLADA_CMakeLists.txt.patch b/win/patches/OpenCOLLADA_CMakeLists.txt.patch new file mode 100644 index 0000000000..bdb33edbf4 --- /dev/null +++ b/win/patches/OpenCOLLADA_CMakeLists.txt.patch @@ -0,0 +1,13 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 9e28557..7549c16 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -271,7 +271,7 @@ add_subdirectory(COLLADASaxFrameworkLoader) + add_subdirectory(COLLADAStreamWriter) + + # building COLLADAValidator app +-add_subdirectory(COLLADAValidator) ++#add_subdirectory(COLLADAValidator) + + + # Library export diff --git a/win/readme.md b/win/readme.md new file mode 100644 index 0000000000..dd85e652e0 --- /dev/null +++ b/win/readme.md @@ -0,0 +1,87 @@ +Windows Build Tools and Scripts +=============================== +This folder contains build tools and script for automatic building and deployment of IfcOpenShell (IFCOS) +and its dependencies. + +As a general guideline, `.cmd` files are non-standalone batch files that need to be run from command +prompt or from another batch file, and/or while the Visual Studio environment variables set, and `.bat` files are +standalone batch files that can be run also e.g. from the File Explorer. + +Usage Instructions +------------------ +Execute `build-deps.cmd` to fetch, build and install the dependencies. The batch file will print +the requirements for a successful execution. The script allows a few user-configurable build options +which are listed in the usage instructions. Either edit the script file or set these values before +running the script. + +`build-deps.cmd` expects a CMake generator as `%1` and a build configuration type (`RelWithDebInfo/Release/MinSizeRel/Debug`, +defaults to `RelWithDebInfo`) as `%2`. If the generator is not provided, the generator is deduced from the Visual Studio +environment variables. User-friendly VS generator shorthands are supported, e.g. `vs2013-x86` or `vs2015-x64`, and these are +converted to the appropriate CMake ones by the scripts. A build type (`Build/Rebuild/Clean`, defaults to `Build`) can be +provided as `%3`. See `vs-cfg.cmd` if you wish to change the defaults. The batch file will create `deps\` and +`deps-vs--installed\` directories to the project root. Debug and release builds of the depedencies +can co-exist by simply running `build-deps.cmd Debug` and `build-deps.cmd `. + +After the dependencies are build, execute `run-cmake.bat`. The batch file expects always a CMake generator as `%1` +(if not provided, the same default value as above is used), and the rest of possible parameters are passed as is. +If passing build options for the script, the generator must be always passed as the first option: +``` +> run-cmake.bat vs2015-x64 -DUSE_IFC4=1 -DBUILD_IFCPYTHON=0 +``` + +**If you wish to use any library from a custom location, modify the paths in `run-cmake.bat` accordingly**. The batch +script will create a folder of form `build-vs-\` which will contain the solution and project +files for Visual Studio. + +Note that building IfcOpenShell as 64-bit is recommended as many of real life IFC files has been observed to take +easily more than 2 GBs of RAM while converting. + +After this, one can build the project using the `IfcOpenShell.sln` file in the build folder. Build the `INSTALL` project +if wanted. Convenience batch files `build-ifcopenshell.cmd` and `install-ifcopenshell.cmd` can also be used. The batch files +expect `%1` and `%2` in same fashion as above and possible extra parameters are passed for the `MSBuild` call. The project will +be installed to `installed-vs-\` folder in the project's root folder and the required IfcOpenShell-Python +parts are deployed to the `\Lib\site-packages\` folder. + +**Note:** All of the dependencies are build as static libraries against the static run-time allowing the developer +to effortlessly deploy standalone IFCOS binaries. + +Using an already existing Python installation +--------------------------------------------- + +Let's say you have already installed 64-bit Python 3.5.1 to `C:\Python3`. +Before building the dependencies, disable the script from installing Python: +``` +> set IFCOS_INSTALL_PYTHON=FALSE +> buid-deps.cmd +``` + +After bulding the dependencies, create BuildDepsCache file to `IfcOpenShell\win` which tells the used Python version and intallation directory: +``` +> echo PY_VER_MAJOR_MINOR=35> BuildDepsCache-x64.txt +> echo PYTHONHOME=C:\Python3>> BuildDepsCache-x64.txt +``` + +After this you should be able to run `run-cmake.bat` normally. If using 32-bit Python, the name of the file must be `BuildDepsCache-x86.txt`. + +Directory Structure +------------------ +``` +.. ++---build-vs- - Created by run-cmake.bat, for a certain VS version and target architecture ++---deps - Created by build-deps.cmd, common for all VS versions and target architectures ++---deps-installed-vs- - Created by build-deps.cmd, for a certain VS version and target architecture ++---installed-vs- - Created by building the IFCOS's INSTALL project +\---win +| build-all.cmd - Runs all of the build scripts for IFCOS and it dependencies in a row without pauses +| build-deps.cmd - Fetches and builds all needed dependencies for IFCOS +| BuildDepsCache-.txt - Cache file created by build-deps.cmd +| build-ifcopenshell.cmd - Builds IFCOS +| build-type-cfg.cmd - Utility file used by the build scripts +| install-ifcopenshell.cmd - Builds IFCOS's INSTALL project +| readme.md - This file +| run-cmake.bat - Sets environment variables for the dependencies and runs CMake for IFCOS +| set-python-to-path.bat - Utility for setting PYTHONHOME (read from BuildDepsCache-.txt) to PATH +| vs-cfg.cmd - Utility file used by the build scripts ++---sln - Contains the old Visual Studio solution and project files +\---utils - Contains various utilities for the build scripts +``` diff --git a/win/run-cmake.bat b/win/run-cmake.bat new file mode 100644 index 0000000000..1c2865d723 --- /dev/null +++ b/win/run-cmake.bat @@ -0,0 +1,107 @@ +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: :: +:: 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 . :: +:: :: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +@echo off +echo. + +set PROJECT_NAME=IfcOpenShell + +setlocal EnableDelayedExpansion + +call vs-cfg.cmd %1 +IF NOT %ERRORLEVEL%==0 GOTO :Error +:: As CMake options are typically of format -DSOMETHING:BOOL=ON or -DSOMETHING=1, i.e. they contain an equal sign, +:: they will mess up the batch file argument parsing if the arguments are passed on by splitting them %2 %3 %4 %5 +:: %6 %7 %8 %9. Work around that, http://scripts.dragon-it.co.uk/scripts.nsf/docs/batch-search-replace-substitute +if not (%1)==() ( + set ARGUMENTS=%* + call set ARGUMENTS=%%ARGUMENTS:%1=%% +) + +:: Read Python related variables from BuildDepsCache.txt +for /f "delims== tokens=1,2" %%G in (BuildDepsCache-%TARGET_ARCH%.txt) do set %%G=%%H + +pushd .. +set CMAKE_INSTALL_PREFIX=%CD%\installed-vs%VS_VER%-%TARGET_ARCH% +popd + +IF NOT EXIST ..\%BUILD_DIR%. mkdir ..\%BUILD_DIR% +pushd ..\%BUILD_DIR% + +set BOOST_ROOT=%DEPS_DIR%\boost +set BOOST_LIBRARYDIR=%DEPS_DIR%\boost\stage\vs%VS_VER%-%VS_PLATFORM%\lib +set ICU_INCLUDE_DIR=%INSTALL_DIR%\icu\include +set ICU_LIBRARY_DIR=%INSTALL_DIR%\icu\lib +set OCC_INCLUDE_DIR=%INSTALL_DIR%\oce\include\oce +set OCC_LIBRARY_DIR=%INSTALL_DIR%\oce\Win%ARCH_BITS%\lib +set OPENCOLLADA_INCLUDE_DIR=%INSTALL_DIR%\OpenCOLLADA\include\opencollada +set OPENCOLLADA_LIBRARY_DIR=%INSTALL_DIR%\OpenCOLLADA\lib\opencollada +if not defined PY_VER_MAJOR_MINOR set PY_VER_MAJOR_MINOR=34 +if not defined PYTHONHOME set PYTHONHOME=%INSTALL_DIR%\Python%PY_VER_MAJOR_MINOR% +set PYTHON_INCLUDE_DIR=%PYTHONHOME%\include +set PYTHON_LIBRARY=%PYTHONHOME%\libs\python%PY_VER_MAJOR_MINOR%.lib +set PYTHON_EXECUTABLE=%PYTHONHOME%\python.exe +set SWIG_DIR=%INSTALL_DIR%\swigwin +set PATH=%PATH%;%SWIG_DIR%;%PYTHONHOME% +:: TODO 3ds Max SDK? + +echo. +call cecho.cmd 0 10 "Script configuration:" +echo Generator = %GENERATOR% +echo Arguments = %ARGUMENTS% +echo. +call cecho.cmd 0 10 "Dependency Environment Variables for %PROJECT_NAME%:" +echo BOOST_ROOT = %BOOST_ROOT% +echo BOOST_LIBRARYDIR = %BOOST_LIBRARYDIR% +echo ICU_INCLUDE_DIR = %ICU_INCLUDE_DIR% +echo ICU_LIBRARY_DIR = %ICU_LIBRARY_DIR% +echo OCC_INCLUDE_DIR = %OCC_INCLUDE_DIR% +echo OCC_LIBRARY_DIR = %OCC_LIBRARY_DIR% +echo OPENCOLLADA_INCLUDE_DIR = %OPENCOLLADA_INCLUDE_DIR% +echo OPENCOLLADA_LIBRARY_DIR = %OPENCOLLADA_LIBRARY_DIR% +echo PYTHONHOME = %PYTHONHOME% +echo PYTHON_INCLUDE_DIR = %PYTHON_INCLUDE_DIR% +echo PYTHON_LIBRARY = %PYTHON_LIBRARY% +echo PYTHON_EXECUTABLE = %PYTHON_EXECUTABLE% +echo SWIG_DIR = %SWIG_DIR% +echo. +echo CMAKE_INSTALL_PREFIX = %CMAKE_INSTALL_PREFIX% +echo. + +set CMAKELISTS_DIR=..\cmake +:: For now clear CMakeCache.txt always in order to assure that when changing build options everything goes smoothly. +IF EXIST CMakeCache.txt. del /Q CMakeCache.txt +call cecho.cmd 0 13 "Running CMake for %PROJECT_NAME%." +cmake.exe %CMAKELISTS_DIR% -G %GENERATOR% -DCMAKE_INSTALL_PREFIX="%CMAKE_INSTALL_PREFIX%" %ARGUMENTS% +IF NOT %ERRORLEVEL%==0 GOTO :Error + +echo. + +set IFCOS_SCRIPT_RET=0 +goto :Finish + +:Error +echo. +call %~dp0\utils\cecho.cmd 0 12 "An error occurred! Aborting!" +set IFCOS_SCRIPT_RET=1 +goto :Finish + +:Finish +popd +exit /b %IFCOS_SCRIPT_RET% diff --git a/win/set-python-to-path.bat b/win/set-python-to-path.bat new file mode 100644 index 0000000000..b9f225be7a --- /dev/null +++ b/win/set-python-to-path.bat @@ -0,0 +1,36 @@ +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: :: +:: 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 . :: +:: :: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +:: Pass x86 or x64 as %1, if not specified x64 assumed. + +@echo off +set TARGET_ARCH=%1 +if "%TARGET_ARCH%"=="" set TARGET_ARCH=x64 +if not exist BuildDepsCache-%TARGET_ARCH%.txt. ( + echo BuildDepsCache-%TARGET_ARCH%.txt does not exist + goto :EOF +) +for /f "delims== tokens=1,2" %%G in (BuildDepsCache-%TARGET_ARCH%.txt) do set %%G=%%H +if not defined PYTHONHOME ( + echo PYTHONHOME PYTHONHOME not defined + goto :EOF +) + +echo %PYTHONHOME% set to PATH +set PATH=%PYTHONHOME%;%PATH% diff --git a/win/IfcConvert.vcproj b/win/sln/IfcConvert.vcproj similarity index 78% rename from win/IfcConvert.vcproj rename to win/sln/IfcConvert.vcproj index b7e27a2ca2..edc1b07ac1 100644 --- a/win/IfcConvert.vcproj +++ b/win/sln/IfcConvert.vcproj @@ -17,8 +17,8 @@ @@ -88,8 +88,8 @@ @@ -202,43 +202,43 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > diff --git a/win/IfcGeom.vcproj b/win/sln/IfcGeom.vcproj similarity index 69% rename from win/IfcGeom.vcproj rename to win/sln/IfcGeom.vcproj index 561649b717..4d13716f3d 100644 --- a/win/IfcGeom.vcproj +++ b/win/sln/IfcGeom.vcproj @@ -151,43 +151,43 @@ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > @@ -197,87 +197,87 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > diff --git a/win/IfcMax.vcproj b/win/sln/IfcMax.vcproj similarity index 90% rename from win/IfcMax.vcproj rename to win/sln/IfcMax.vcproj index e8e107280f..8778979fb9 100644 --- a/win/IfcMax.vcproj +++ b/win/sln/IfcMax.vcproj @@ -17,8 +17,8 @@ @@ -91,8 +91,8 @@ @@ -186,16 +186,16 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > diff --git a/win/IfcOpenHouse.vcproj b/win/sln/IfcOpenHouse.vcproj similarity index 93% rename from win/IfcOpenHouse.vcproj rename to win/sln/IfcOpenHouse.vcproj index dd884cc213..4f0ce2b955 100644 --- a/win/IfcOpenHouse.vcproj +++ b/win/sln/IfcOpenHouse.vcproj @@ -17,8 +17,8 @@ @@ -88,8 +88,8 @@ diff --git a/win/IfcOpenShell.sln b/win/sln/IfcOpenShell.sln similarity index 100% rename from win/IfcOpenShell.sln rename to win/sln/IfcOpenShell.sln diff --git a/win/IfcParse.vcproj b/win/sln/IfcParse.vcproj similarity index 69% rename from win/IfcParse.vcproj rename to win/sln/IfcParse.vcproj index 0723f5743a..e36d27bd4c 100644 --- a/win/IfcParse.vcproj +++ b/win/sln/IfcParse.vcproj @@ -17,8 +17,8 @@ @@ -240,87 +240,83 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > - - diff --git a/win/IfcParseExamples.vcproj b/win/sln/IfcParseExamples.vcproj similarity index 93% rename from win/IfcParseExamples.vcproj rename to win/sln/IfcParseExamples.vcproj index c53313c791..94027eb617 100644 --- a/win/IfcParseExamples.vcproj +++ b/win/sln/IfcParseExamples.vcproj @@ -18,8 +18,8 @@ @@ -90,8 +90,8 @@ diff --git a/win/IfcWrap.vcproj b/win/sln/IfcWrap.vcproj similarity index 94% rename from win/IfcWrap.vcproj rename to win/sln/IfcWrap.vcproj index 99a3820186..51ffcc7320 100644 --- a/win/IfcWrap.vcproj +++ b/win/sln/IfcWrap.vcproj @@ -14,12 +14,12 @@ - - + <..\.. Name="Debug|Win32" OutputDirectory="..\build\debug" IntermediateDirectory="..\temp\wrap\debug" - ConfigurationType="2" + ..\..Type="2" CharacterSet="2" BuildLogFile="$(IntDir)\BuildLog.htm" > @@ -87,12 +87,12 @@ - - + <..\.. Name="Release|Win32" OutputDirectory="..\build\release" IntermediateDirectory="..\temp\wrap\release" - ConfigurationType="2" + ..\..Type="2" CharacterSet="2" WholeProgramOptimization="1" > @@ -160,8 +160,8 @@ - - + + @@ -184,7 +184,7 @@ - - - + - + . :: +:: :: +::::::::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::: + +:: This script initializes various Visual Studio related environment variables needed for building. +:: the dependencies. This batch file expects a CMake generator as %1. If %1 is not provided, it is +:: deduced from the VisualStudioVersion environment variable and from the location of cl.exe. +:: User-friendly VS generators are allowed (e.g. "vs2013-x86") and converted to the appropriate CMake ones. + +:: NOTE This batch file expects the generator string to be CMake 3.0.0 and newer format, i.e. +:: "Visual Studio 10 2010" instead of "Visual Studio 10". However, one can use this batch file +:: also with CMake 2 as the generator will be converted into the older format if necessary. + +:: NOTE: The delayed environment variable expansion needs to be enabled before calling this. + +@echo off + +set GENERATOR=%1 + +:: Supported Visual Studio versions: +set GENERATORS[0]="Visual Studio 9 2008 Win64" +set GENERATORS[1]="Visual Studio 9 2008" +set GENERATORS[2]="Visual Studio 10 2010 Win64" +set GENERATORS[3]="Visual Studio 10 2010" +set GENERATORS[4]="Visual Studio 11 2012 Win64" +set GENERATORS[5]="Visual Studio 11 2012" +set GENERATORS[6]="Visual Studio 12 2013 Win64" +set GENERATORS[7]="Visual Studio 12 2013" +set GENERATORS[8]="Visual Studio 14 2015 Win64" +set GENERATORS[9]="Visual Studio 14 2015" +set LAST_GENERATOR_IDX=9 + +set STEP=2 +:: Is generator shorthand used? +set GEN_SHORTHAND=!GENERATOR:vs=! +if not "!GEN_SHORTHAND!"=="" if !GEN_SHORTHAND!==!GENERATOR! goto :GeneratorShorthandCheckDone +set START=%LAST_GENERATOR_IDX% +:: "echo if" trick from http://stackoverflow.com/a/8758579 +echo(!GEN_SHORTHAND! | findstr /c:"-x86" >nul && ( set START=1 ) +echo(!GEN_SHORTHAND! | findstr /c:"-x64" >nul && ( set START=0 ) +set VS_VER=!GEN_SHORTHAND:-x86=! +set VS_VER=!VS_VER:-x64=! +echo(!GENERATOR! | findstr /c:"vs20" >nul && ( + for /l %%i in (!START!,!STEP!,%LAST_GENERATOR_IDX%) do ( + echo(!GENERATORS[%%i]! | findstr /c:"!VS_VER!" >nul && ( + set GENERATOR=!GENERATORS[%%i]! + goto :GeneratorShorthandCheckDone + ) + ) +) +:GeneratorShorthandCheckDone + +:: Deduce desired architecture from the location of cl.exe +where cl.exe | findstr /c:"amd64" >nul +set START=%ERRORLEVEL% + +IF "!GENERATOR!"=="" IF NOT "%VisualStudioVersion%"=="" ( + set VC_VER=%VisualStudioVersion:.0=% + FOR /l %%i in (%START%,%STEP%,%LAST_GENERATOR_IDX%) DO ( + REM NOTE add space before VC_VER so that e.g. "12" doesn't match with "2012" + echo(!GENERATORS[%%i]! | findstr /c:" !VC_VER!" >nul && ( + set GENERATOR=!GENERATORS[%%i]! + call utils\cecho.cmd black cyan "Generator not passed, but VisualStudioVersion=%VisualStudioVersion% environment variable detected:" + call utils\cecho.cmd black cyan "using '`"!GENERATOR!`'" as the generator." + GOTO :GeneratorValid + ) + ) +) +:: Check that the used CMake version supports the chosen generator +set GENERATOR_CHECK=%GENERATOR: Win64=% +cmake --help | findstr /c:%GENERATOR_CHECK% >nul +if not %ERRORLEVEL%==0 ( +call utils\cecho.cmd 0 12 "%~nx0: The used CMake version does not support '`"!GENERATOR!`'"- cannot proceed." +exit /b 1 +) + +FOR /l %%i in (0,1,%LAST_GENERATOR_IDX%) DO ( + IF !GENERATOR!==!GENERATORS[%%i]! GOTO :GeneratorValid +) +call utils\cecho.cmd 0 12 "%~nx0: Invalid or unsupported CMake generator string passed: '`"!GENERATOR!`'"- cannot proceed." +echo Supported CMake generator strings: +FOR /l %%i in (0,1,%LAST_GENERATOR_IDX%) DO ( + echo !GENERATORS[%%i]! +) +exit /b 1 + +:GeneratorValid +:: Figure out the build configuration from the CMake generator string. +:: Are we building 32-bit or 64-bit version. +set ARCH_BITS=32 +set TARGET_ARCH=x86 +:: Visual Studio platform name, Win32 (i.e. x86) or x64. +set VS_PLATFORM=Win32 + +:: Find out VS version, VC versions and are we doing 64-bit or not. +:: VS_VER and VC_VER are convenience variables used f.ex. for filenames. +set GENERATOR_NO_DOUBLEQUOTES=%GENERATOR:"=% +set GENERATOR_SPLIT=%GENERATOR_NO_DOUBLEQUOTES: =,% +FOR %%i IN (%GENERATOR_SPLIT%) DO ( + call :StrLength LEN %%i + IF !LEN!==1 set VC_VER=%%i + IF !LEN!==2 set VC_VER=%%i + IF !LEN!==4 set VS_VER=%%i + REM Are going to perform a 64-bit build? + IF %%i==Win64 ( + set ARCH_BITS=64 + set TARGET_ARCH=x64 + set VS_PLATFORM=x64 + ) +) + +:: Check CMake version and convert possible new format (>= 3.0) generator names to the old versions if using older CMake for VS <= 2013, +:: see http://www.cmake.org/cmake/help/v3.0/release/3.0.0.html#other-changes +FOR /f "delims=" %%i in ('where cmake') DO set CMAKE_PATH=%%i +IF NOT "%CMAKE_PATH%"=="" ( + FOR /f "delims=" %%i in ('cmake --version ^| findstr /C:"cmake version 3"') DO GOTO :CMake3AndNewer +) +:: CMake older than 3.0.0: convert new format generators to the old format (simple brute force for simplicity) +set GENERATOR=%GENERATOR: 2013=% +set GENERATOR=%GENERATOR: 2012=% +set GENERATOR=%GENERATOR: 2010=% +:CMake3AndNewer + +:: VS project file extension is different on older VS versions +set VCPROJ_FILE_EXT=vcxproj +IF %VS_VER%==2008 set VCPROJ_FILE_EXT=vcproj + +:: Add utils to PATH +set ORIGINAL_PATH=%PATH% +set PATH=%PATH%;%~dp0utils + +:: Fetch and build the dependencies to a dedicated directory depending on the used VS version and target architecture. +:: NOTE For IfcOpenShell we can build all of our deps both x86 and x64 using different VS versions in the same directories +:: so no need for -%VS_VER%-%TARGET_ARCH% postfix. +:: set DEPS_DIR=%CD%\deps-%VS_VER%-%TARGET_ARCH% +pushd .. +set DEPS_DIR=%CD%\deps +set INSTALL_DIR=%CD%\deps-vs%VS_VER%-%TARGET_ARCH%-installed +REM set INSTALL_DIR=%CD%\deps-vs%VS_VER%-%TARGET_ARCH%-%DEBUG_OR_RELEASE_LOWERCASE%-installed +:: BUILD_DIR is a relative build directory used for CMake-based projects +set BUILD_DIR=build-vs%VS_VER%-%TARGET_ARCH% +popd + +GOTO :EOF +:: http://geekswithblogs.net/SoftwareDoneRight/archive/2010/01/30/useful-dos-batch-functions-substring-and-length.aspx +:StrLength +set #=%2% +set length=0 +:stringLengthLoop +if defined # (set #=%#:~1%&set /A length += 1&goto stringLengthLoop) +::echo the string is %length% characters long! +set "%~1=%length%" +GOTO :EOF \ No newline at end of file