mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-06 16:01:36 +00:00
Compare commits
195 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 62386c663a | |||
| a10e852a35 | |||
| 7f5d733ed8 | |||
| cdfbde8f18 | |||
| 0d7f6af681 | |||
| d76c599477 | |||
| c09de2c568 | |||
| 3f7290cdc6 | |||
| 7bd4699f65 | |||
| e137036bbb | |||
| b1a0e2a62b | |||
| a97577d272 | |||
| 53bcb333da | |||
| 49fb919fbc | |||
| 5dbbd917d1 | |||
| 10d11031e5 | |||
| c8def0474e | |||
| f6aa7c8930 | |||
| 92f7d26835 | |||
| 5ccc7213a0 | |||
| fd9c57b77d | |||
| b08e52bd9b | |||
| 0cb2c81227 | |||
| bbf271a10e | |||
| d45d843173 | |||
| 4fa283fb3c | |||
| 4400a6ea4f | |||
| 9cb321e73d | |||
| e566af84c2 | |||
| 310013dfe4 | |||
| de3633e742 | |||
| a24ad023a5 | |||
| adc0e92528 | |||
| 46ba5661d6 | |||
| 33bcf786fd | |||
| 8e6a6ec56d | |||
| b862f633db | |||
| f9e839817d | |||
| a0c01ff756 | |||
| 5b066c9f95 | |||
| 3afb9169b1 | |||
| 24b552a822 | |||
| 884064f213 | |||
| 4d39dbca2a | |||
| 30479ca0a6 | |||
| a7a1ad129e | |||
| bea627d01e | |||
| 059a1cb14b | |||
| 8c5349feaa | |||
| fa0a33f3c0 | |||
| 5a7c7ed048 | |||
| 16d6420352 | |||
| d804575974 | |||
| ad24b6be0f | |||
| 0072e1f247 | |||
| 116b80cf91 | |||
| 208f6d4d74 | |||
| a0dfdc78ef | |||
| cf2dd2aa8d | |||
| 6737b54457 | |||
| 9ae55ab303 | |||
| 8baf6197d5 | |||
| 42f23a786f | |||
| 8b539d2b93 | |||
| b732759388 | |||
| 02244400ab | |||
| 85a36738d2 | |||
| 164e67a50b | |||
| de83633891 | |||
| 9f2a617ad7 | |||
| 26bd03e407 | |||
| 248c73c2ab | |||
| 8d9acfa677 | |||
| 7b7f9b4852 | |||
| 7189219aa4 | |||
| f03a228280 | |||
| 91e5b337d3 | |||
| 009f50abe1 | |||
| c9267d7ace | |||
| 4a340027bf | |||
| 612f8f36db | |||
| c1887f3f1f | |||
| 71ad7dd4bc | |||
| ed9676ed38 | |||
| a6195290f5 | |||
| 583c334802 | |||
| f8f4db72ec | |||
| dd206a2a52 | |||
| 12967790ba | |||
| d0b71a2e57 | |||
| 4061f93560 | |||
| 71d7bbd6ba | |||
| 62ca6f6a7d | |||
| 8090bb4c00 | |||
| cf6bd5a629 | |||
| cf9605f108 | |||
| 507d4778fa | |||
| 95e6c14f39 | |||
| 2bbe80fd28 | |||
| 0ffa633a6d | |||
| 30e88210b2 | |||
| 98ce04ed64 | |||
| d2aef0fcbd | |||
| 38cbdbc0f4 | |||
| 83689a1cec | |||
| 81cb7f379e | |||
| 7d16b725a3 | |||
| 54331062c3 | |||
| 4419331710 | |||
| 81a33309f3 | |||
| d02918070d | |||
| ac7099ab39 | |||
| b5e79b2558 | |||
| b1df91ffd9 | |||
| 287fb9f0ed | |||
| 06c10dc4da | |||
| 3972727f9d | |||
| 3e918180d2 | |||
| 0fbadc2985 | |||
| 8f89498a32 | |||
| 7bcd0d0a8d | |||
| 0596827b9d | |||
| 619b4fbed5 | |||
| deea0f6558 | |||
| 15e4e1952f | |||
| e922212357 | |||
| 0d36693780 | |||
| cb7ed51fc6 | |||
| a3df0556aa | |||
| 3f94d4af37 | |||
| 7f96b3a523 | |||
| 27d8e86024 | |||
| 66048610e2 | |||
| 31d4de228a | |||
| 29021d8b06 | |||
| 1fb76a9749 | |||
| b299c27473 | |||
| 64e385c361 | |||
| 27b5fd0fc5 | |||
| 4f5ecee81e | |||
| ca19d447cc | |||
| 484cea968e | |||
| 033a2e7482 | |||
| 1d3732aa62 | |||
| 584b2e5584 | |||
| 1bcc369c7a | |||
| 64bc8e9d4f | |||
| b9828b029c | |||
| 749071601e | |||
| bbe0b74f83 | |||
| efb8bce25a | |||
| c59ae03cb3 | |||
| 7145b1ae85 | |||
| 596c4f8b77 | |||
| 302e7b2db8 | |||
| bece7053a0 | |||
| 82cd4056b7 | |||
| 6297ff74f1 | |||
| c9633273a6 | |||
| 2cb53a860d | |||
| db85bebc1a | |||
| 57fae25de8 | |||
| 451ccd4e21 | |||
| b893f5a3f0 | |||
| 64eb707996 | |||
| c0732f5197 | |||
| e47d128b18 | |||
| 9d4463b73a | |||
| d9d5f17725 | |||
| f4274e4b46 | |||
| b463dfe88a | |||
| 44634eb42d | |||
| 1755752ab7 | |||
| 7051104bc7 | |||
| 2894b0cb92 | |||
| 42b512960b | |||
| 96e9c8ecc1 | |||
| bae84b6753 | |||
| e1702fc0cf | |||
| 6aff3d0f3d | |||
| 6b47e9ca1d | |||
| 1525cf6bfc | |||
| 5724e1ac34 | |||
| f2a45b7057 | |||
| 233aaeaca2 | |||
| 9c21e05184 | |||
| 0821dd4702 | |||
| cac9c91c56 | |||
| a4264f3143 | |||
| 4d12bf7e8d | |||
| 3958204c1c | |||
| d17f714dc5 | |||
| 4fa7f293d6 | |||
| 7e3f96e410 | |||
| 8018c9cc44 |
@@ -12,3 +12,5 @@ __pycache__
|
||||
.vscode
|
||||
# PyCharm files
|
||||
.idea
|
||||
# OSX files
|
||||
.DS_Store
|
||||
|
||||
+5
-3
@@ -1,7 +1,9 @@
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
os: linux
|
||||
dist: xenial
|
||||
dist: bionic
|
||||
sudo: required
|
||||
|
||||
before_install:
|
||||
@@ -36,7 +38,7 @@ script:
|
||||
-DPYTHON_INCLUDE_DIR=/usr/include/python2.7 \
|
||||
-DPYTHON_EXECUTABLE=/usr/bin/python2.7 \
|
||||
-DLIBXML2_INCLUDE_DIR=/usr/include/libxml2 \
|
||||
-DLIBXML2_LIBRARIES="/usr/lib/x86_64-linux-gnu/libxml2.a;/lib/x86_64-linux-gnu/libz.so.1;/lib/x86_64-linux-gnu/liblzma.so.5;/usr/lib/x86_64-linux-gnu/libicuuc.so.55;/usr/lib/x86_64-linux-gnu/libicudata.so.55" \
|
||||
-DLIBXML2_LIBRARIES="/usr/lib/x86_64-linux-gnu/libxml2.a;/lib/x86_64-linux-gnu/libz.so.1;/lib/x86_64-linux-gnu/liblzma.so.5;/usr/lib/x86_64-linux-gnu/libicuuc.so;/usr/lib/x86_64-linux-gnu/libicudata.so" \
|
||||
-DGLTF_SUPPORT=On \
|
||||
-DJSON_INCLUDE_DIR=/usr/include/json \
|
||||
..
|
||||
|
||||
+139
-34
@@ -42,6 +42,9 @@ OPTION(BUILD_GEOMSERVER "Build IfcGeomServer executable." ON)
|
||||
OPTION(BUILD_CONVERT "Build IfcConvert executable." ON)
|
||||
OPTION(USE_VLD "Use Visual Leak Detector for debugging memory leaks, MSVC-only." OFF)
|
||||
OPTION(USE_MMAP "Adds a command line options to parse IFC files from memory mapped files using Boost.Iostreams" OFF)
|
||||
OPTION(USE_VOXELS "Use voxelized geometries as a fallback mechanism to calculate quantities in IfcGeomServer" OFF)
|
||||
OPTION(USE_CGAL "Use CGAL as an alternative geometry kernel implementation" OFF)
|
||||
OPTION(USE_STATIC_MSVC_RUNTIME "Link to the static runtime on MSVC." ON)
|
||||
OPTION(BUILD_SHARED_LIBS "Build IfcParse and IfcGeom as shared libs (SO/DLL)." OFF)
|
||||
if (${HAS_MAX})
|
||||
OPTION(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." ON)
|
||||
@@ -111,6 +114,14 @@ UNIFY_ENVVARS_AND_CACHE(LIBXML2_INCLUDE_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(LIBXML2_LIBRARIES)
|
||||
UNIFY_ENVVARS_AND_CACHE(PCRE_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE)
|
||||
UNIFY_ENVVARS_AND_CACHE(CGAL_INCLUDE_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(CGAL_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(GMP_INCLUDE_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(GMP_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(MPFR_INCLUDE_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(MPFR_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(VOXEL_INCLUDE_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(VOXEL_LIBRARY_DIR)
|
||||
|
||||
if (GLTF_SUPPORT AND BUILD_CONVERT)
|
||||
UNIFY_ENVVARS_AND_CACHE(JSON_INCLUDE_DIR)
|
||||
@@ -140,8 +151,10 @@ ENDMACRO()
|
||||
# runtime, when doing running conda-build we pick what conda prepared for us.
|
||||
IF(WIN32 AND ("$ENV{CONDA_BUILD}" STREQUAL ""))
|
||||
SET(Boost_USE_STATIC_LIBS ON)
|
||||
SET(Boost_USE_STATIC_RUNTIME ON)
|
||||
SET(Boost_USE_MULTITHREADED ON)
|
||||
if (USE_STATIC_MSVC_RUNTIME)
|
||||
SET(Boost_USE_STATIC_RUNTIME ON)
|
||||
endif()
|
||||
ELSE()
|
||||
# Disable Boost's autolinking as the libraries to be linked to are supplied
|
||||
# already by CMake, and it's going to conflict if there are multiple, as is
|
||||
@@ -154,20 +167,29 @@ ELSE()
|
||||
ENDIF()
|
||||
|
||||
set(BOOST_COMPONENTS system program_options regex thread date_time)
|
||||
if(USE_MMAP)
|
||||
if(USE_MMAP OR USE_VOXELS)
|
||||
if(MSVC)
|
||||
# filesystem is necessary for the utf-16 wpath
|
||||
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} iostreams filesystem)
|
||||
else()
|
||||
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} iostreams)
|
||||
endif()
|
||||
add_definitions(-DUSE_MMAP)
|
||||
if(USE_MMAP)
|
||||
add_definitions(-DUSE_MMAP)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (IFCXML_SUPPORT)
|
||||
add_definitions(-DWITH_IFCXML)
|
||||
endif()
|
||||
|
||||
if (USE_VOXELS)
|
||||
FIND_LIBRARY(libvoxel NAMES voxel libvoxel PATHS ${VOXEL_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
FIND_LIBRARY(libvoxec NAMES voxec libvoxec PATHS ${VOXEL_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
set(VOXEL_LIBRARIES ${libvoxel} ${libvoxec})
|
||||
ADD_DEFINITIONS("-DUSE_VOXELS")
|
||||
endif()
|
||||
|
||||
FIND_PACKAGE(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
||||
MESSAGE(STATUS "Boost include files found in ${Boost_INCLUDE_DIRS}")
|
||||
MESSAGE(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}")
|
||||
@@ -255,6 +277,61 @@ foreach(lib ${OPENCASCADE_LIBRARY_NAMES})
|
||||
list(APPEND OPENCASCADE_LIBRARIES "${lib_path}")
|
||||
endforeach()
|
||||
|
||||
list(APPEND GEOMETRY_KERNELS opencascade)
|
||||
|
||||
if (USE_CGAL)
|
||||
add_definitions(-DIFOPSH_USE_CGAL)
|
||||
list(APPEND GEOMETRY_KERNELS cgal)
|
||||
SET(CGAL_LIBRARY_NAMES libCGAL_Core libCGAL_ImageIO libCGAL)
|
||||
# Find CGAL
|
||||
IF("${CGAL_INCLUDE_DIR}" STREQUAL "")
|
||||
SET(CGAL_INCLUDE_DIR "/usr/include/" CACHE FILEPATH "CGAL header files")
|
||||
MESSAGE(STATUS "Looking for CGAL include files in: ${CGAL_INCLUDE_DIR}")
|
||||
MESSAGE(STATUS "Use CGAL_INCLUDE_DIR to specify another directory")
|
||||
ELSE()
|
||||
SET(CGAL_INCLUDE_DIR ${CGAL_INCLUDE_DIR} CACHE FILEPATH "CGAL header files")
|
||||
MESSAGE(STATUS "Looking for CGAL include files in: ${CGAL_INCLUDE_DIR}")
|
||||
ENDIF()
|
||||
IF("${CGAL_LIBRARY_DIR}" STREQUAL "")
|
||||
SET(CGAL_LIBRARY_DIR "/usr/lib/" CACHE FILEPATH "CGAL library files")
|
||||
MESSAGE(STATUS "Looking for CGAL library files in: ${CGAL_LIBRARY_DIR}")
|
||||
MESSAGE(STATUS "Use CGAL_LIBRARY_DIR to specify another directory")
|
||||
ELSE()
|
||||
SET(CGAL_LIBRARY_DIR ${CGAL_LIBRARY_DIR} CACHE FILEPATH "CGAL library files")
|
||||
MESSAGE(STATUS "Looking for CGAL library files in: ${CGAL_LIBRARY_DIR}")
|
||||
ENDIF()
|
||||
FIND_LIBRARY(libCGAL NAMES CGAL PATHS ${CGAL_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
IF(libCGAL)
|
||||
MESSAGE(STATUS "CGAL library files found")
|
||||
foreach(lib ${CGAL_LIBRARY_NAMES})
|
||||
string(REPLACE libCGAL "${lib}" lib_path "${libCGAL}")
|
||||
list(APPEND CGAL_LIBRARIES "${lib_path}")
|
||||
endforeach()
|
||||
ELSE()
|
||||
FILE(GLOB CGAL_LIBRARIES ${CGAL_LIBRARY_DIR}/*CGAL*.lib)
|
||||
message(STATUS CGAL_LIBRARIES ${CGAL_LIBRARIES})
|
||||
LIST(LENGTH CGAL_LIBRARY_NAMES num_cgal_library_names)
|
||||
LIST(LENGTH CGAL_LIBRARIES num_cgal_libraries)
|
||||
message(STATUS ${num_cgal_library_names} ${num_cgal_libraries})
|
||||
LINK_DIRECTORIES("${CGAL_LIBRARY_DIR}")
|
||||
if(NOT "${num_cgal_library_names}" STREQUAL "${num_cgal_libraries}")
|
||||
MESSAGE(FATAL_ERROR "Unable to find CGAL library files, aborting")
|
||||
endif()
|
||||
MESSAGE(STATUS "CGAL library files found")
|
||||
ENDIF()
|
||||
|
||||
FIND_LIBRARY(libGMP NAMES gmp mpir PATHS ${GMP_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
FIND_LIBRARY(libMPFR NAMES mpfr PATHS ${MPFR_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
IF(NOT libGMP)
|
||||
MESSAGE(FATAL_ERROR "Unable to find GMP library files, aborting")
|
||||
ENDIF()
|
||||
IF(NOT libMPFR)
|
||||
MESSAGE(FATAL_ERROR "Unable to find MPFR library files, aborting")
|
||||
ENDIF()
|
||||
list(APPEND CGAL_LIBRARIES "${libMPFR}")
|
||||
list(APPEND CGAL_LIBRARIES "${libGMP}")
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
add_definitions(-DHAVE_NO_DLL)
|
||||
add_debug_variants(OPENCASCADE_LIBRARIES "${OPENCASCADE_LIBRARIES}" d)
|
||||
@@ -274,7 +351,7 @@ endif()
|
||||
if(OCCT_STATIC)
|
||||
find_package(Threads)
|
||||
# OPENCASCADE_LIBRARIES repeated three times below in order to fix cyclic dependencies - use --start-group ... --end-group instead?
|
||||
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
set(OPENCASCADE_LIBRARIES -Wl,--start-group ${OPENCASCADE_LIBRARIES} -Wl,--end-group ${CMAKE_THREAD_LIBS_INIT})
|
||||
if (NOT APPLE AND NOT WIN32)
|
||||
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} "rt")
|
||||
endif()
|
||||
@@ -412,22 +489,25 @@ IF(MSVC)
|
||||
ENDIF()
|
||||
# Enforce standards-conformance on VS > 2015, older Boost versions fail to compile with this
|
||||
if (MSVC_VERSION GREATER 1900 AND (Boost_MAJOR_VERSION GREATER 1 OR Boost_MINOR_VERSION GREATER 66))
|
||||
add_definitions(-permissive-)
|
||||
# @todo currently fails
|
||||
# add_definitions(-permissive-)
|
||||
endif()
|
||||
|
||||
if(USE_STATIC_MSVC_RUNTIME)
|
||||
# Link against the static VC runtime
|
||||
IF("$ENV{CONDA_BUILD}" STREQUAL "")
|
||||
FOREACH(flag CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL
|
||||
CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
|
||||
IF(${flag} MATCHES "/MD")
|
||||
STRING(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}")
|
||||
ENDIF()
|
||||
IF(${flag} MATCHES "/MDd")
|
||||
STRING(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}")
|
||||
ENDIF()
|
||||
ENDFOREACH()
|
||||
ENDIF()
|
||||
endif()
|
||||
# Link against the static VC runtime
|
||||
# TODO Make this configurable
|
||||
IF("$ENV{CONDA_BUILD}" STREQUAL "")
|
||||
FOREACH(flag CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL
|
||||
CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
|
||||
IF(${flag} MATCHES "/MD")
|
||||
STRING(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}")
|
||||
ENDIF()
|
||||
IF(${flag} MATCHES "/MDd")
|
||||
STRING(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}")
|
||||
ENDIF()
|
||||
ENDFOREACH()
|
||||
ENDIF()
|
||||
ElSE()
|
||||
add_definitions(-Wall -Wextra)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
@@ -447,6 +527,7 @@ endif()
|
||||
|
||||
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS}
|
||||
${Boost_INCLUDE_DIRS} ${LIBXML2_INCLUDE_DIR} ${JSON_INCLUDE_DIR}
|
||||
${CGAL_INCLUDE_DIR} ${GMP_INCLUDE_DIR} ${MPFR_INCLUDE_DIR} ${VOXEL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
function(files_for_ifc_version IFC_VERSION RESULT_NAME)
|
||||
@@ -549,20 +630,44 @@ TARGET_LINK_LIBRARIES(IfcParse ${Boost_LIBRARIES} ${BCRYPT_LIBRARIES} ${LIBXML2_
|
||||
|
||||
if (BUILD_IFCGEOM)
|
||||
|
||||
# IfcGeom
|
||||
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/*.h)
|
||||
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp)
|
||||
foreach(kernel ${GEOMETRY_KERNELS})
|
||||
string(TOUPPER ${kernel} KERNEL_UPPER)
|
||||
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/schema_agnostic/${kernel}/*.h)
|
||||
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/schema_agnostic/${kernel}/*.cpp)
|
||||
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES})
|
||||
|
||||
foreach(s ${SCHEMA_VERSIONS})
|
||||
add_library(IfcGeom_ifc${s} STATIC ${IFCGEOM_FILES})
|
||||
set_target_properties(IfcGeom_ifc${s} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${s}")
|
||||
TARGET_LINK_LIBRARIES(IfcGeom_ifc${s} IfcParse ${OPENCASCADE_LIBRARIES})
|
||||
add_library(IfcGeom_${kernel} STATIC ${IFCGEOM_FILES})
|
||||
set_target_properties(IfcGeom_${kernel} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS")
|
||||
target_link_libraries(IfcGeom_${kernel} IfcParse ${${KERNEL_UPPER}_LIBRARIES})
|
||||
list(APPEND IfcGeom_libraries IfcGeom_${kernel})
|
||||
endforeach()
|
||||
|
||||
# IfcGeom (schema agnostic)
|
||||
file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom_schema_agnostic/*.h)
|
||||
file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom_schema_agnostic/*.cpp)
|
||||
foreach(schema ${SCHEMA_VERSIONS})
|
||||
|
||||
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/kernel_agnostic/*.h)
|
||||
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/kernel_agnostic/*.cpp)
|
||||
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES})
|
||||
|
||||
add_library(IfcGeom_ifc${schema} STATIC ${IFCGEOM_FILES})
|
||||
set_target_properties(IfcGeom_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema}")
|
||||
target_link_libraries(IfcGeom_ifc${schema} IfcParse)
|
||||
list(APPEND IfcGeom_libraries IfcGeom_ifc${schema})
|
||||
|
||||
foreach(kernel ${GEOMETRY_KERNELS})
|
||||
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/kernels/${kernel}/*.h)
|
||||
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/kernels/${kernel}/*.cpp)
|
||||
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES})
|
||||
|
||||
add_library(IfcGeom_${kernel}_ifc${schema} STATIC ${IFCGEOM_FILES})
|
||||
set_target_properties(IfcGeom_${kernel}_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema}")
|
||||
target_link_libraries(IfcGeom_${kernel}_ifc${schema} IfcGeom_${kernel} IfcGeom_ifc${schema})
|
||||
list(APPEND IfcGeom_libraries IfcGeom_${kernel}_ifc${schema})
|
||||
endforeach()
|
||||
|
||||
endforeach()
|
||||
|
||||
file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom/schema_agnostic/*.h)
|
||||
file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom/schema_agnostic/*.cpp)
|
||||
set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES})
|
||||
|
||||
add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES})
|
||||
@@ -572,7 +677,7 @@ if (UNIX)
|
||||
find_package(Threads)
|
||||
endif()
|
||||
|
||||
TARGET_LINK_LIBRARIES(IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
TARGET_LINK_LIBRARIES(IfcGeom ${IfcGeom_libraries} ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
endif(BUILD_IFCGEOM)
|
||||
|
||||
@@ -604,7 +709,7 @@ set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES})
|
||||
ADD_EXECUTABLE(IfcConvert ${IFCCONVERT_FILES})
|
||||
set_target_properties(IfcConvert PROPERTIES COMPILE_FLAGS "${CONVERT_PRECISION}")
|
||||
|
||||
TARGET_LINK_LIBRARIES(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES})
|
||||
TARGET_LINK_LIBRARIES(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES})
|
||||
|
||||
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
|
||||
# Only set RPATHs when building shared libraries (i.e. IfcParse and
|
||||
@@ -628,7 +733,7 @@ file(GLOB CPP_FILES ../src/ifcgeomserver/*.cpp)
|
||||
file(GLOB H_FILES ../src/ifcgeomserver/*.h)
|
||||
set(SOURCE_FILES ${CPP_FILES} ${H_FILES})
|
||||
ADD_EXECUTABLE(IfcGeomServer ${SOURCE_FILES})
|
||||
TARGET_LINK_LIBRARIES(IfcGeomServer ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES})
|
||||
TARGET_LINK_LIBRARIES(IfcGeomServer ${IFCOPENSHELL_LIBRARIES} ${Boost_LIBRARIES} ${VOXEL_LIBRARIES})
|
||||
|
||||
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
|
||||
SET_INSTALL_RPATHS(IfcGeomServer "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS}")
|
||||
@@ -671,10 +776,10 @@ INSTALL(FILES ${IFCGEOM_H_FILES}
|
||||
)
|
||||
|
||||
INSTALL(FILES ${SCHEMA_AGNOSTIC_H_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/ifcgeom_schema_agnostic
|
||||
DESTINATION ${INCLUDEDIR}/ifcgeom/schema_agnostic
|
||||
)
|
||||
|
||||
INSTALL(TARGETS ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom
|
||||
INSTALL(TARGETS IfcGeom ${IfcGeom_libraries}
|
||||
ARCHIVE DESTINATION ${LIBDIR}
|
||||
LIBRARY DESTINATION ${LIBDIR}
|
||||
RUNTIME DESTINATION ${BINDIR}
|
||||
|
||||
+58
-12
@@ -84,7 +84,7 @@ OCE_VERSION="0.18"
|
||||
# OCCT_VERSION="7.2.0"
|
||||
# OCCT_HASH="88af392"
|
||||
OCCT_VERSION="7.3.0p3"
|
||||
BOOST_VERSION="1.59.0"
|
||||
BOOST_VERSION="1.69.0"
|
||||
#PCRE_VERSION="8.39"
|
||||
PCRE_VERSION="8.41"
|
||||
#LIBXML2_VERSION="2.9.3"
|
||||
@@ -95,8 +95,9 @@ SWIG_VERSION="3.0.12"
|
||||
#SWIG_VERSION="4.0.0"
|
||||
#OPENCOLLADA_VERSION="v1.6.63"
|
||||
OPENCOLLADA_VERSION="v1.6.68"
|
||||
|
||||
|
||||
GMP_VERSION="6.1.2"
|
||||
MPFR_VERSION="3.1.5"
|
||||
CGAL_VERSION="4.13"
|
||||
|
||||
# binaries
|
||||
cp="cp"
|
||||
@@ -216,17 +217,19 @@ cecho(""" - How many compiler processes may be run in parallel.
|
||||
|
||||
dependency_tree = {
|
||||
'IfcParse': ('boost', 'libxml2'),
|
||||
'IfcGeom': ('IfcParse', 'occ'),
|
||||
'IfcGeom': ('IfcParse', 'occ', 'cgal', 'voxel'),
|
||||
'IfcConvert': ('IfcGeom', 'OpenCOLLADA', 'json'),
|
||||
'OpenCOLLADA': ('libxml2', 'pcre'),
|
||||
'IfcGeomServer': ('IfcGeom',),
|
||||
'IfcGeomServer': ('IfcGeom', ),
|
||||
'IfcOpenShell-Python': ('python', 'swig', 'IfcGeom'),
|
||||
'voxel': ('occ',),
|
||||
'swig': ('pcre',),
|
||||
'boost': (),
|
||||
'libxml2': (),
|
||||
'python': (),
|
||||
'swig': (),
|
||||
'occ': (),
|
||||
'cgal': (),
|
||||
'pcre': (),
|
||||
'json': ()
|
||||
}
|
||||
@@ -257,7 +260,7 @@ print("Building:", *sorted(targets, key=lambda t: len(list(v(t)))))
|
||||
|
||||
# Check that required tools are in PATH
|
||||
|
||||
for cmd in [git, bunzip2, tar, cc, cplusplus, autoconf, automake, yacc, make, "patch"]:
|
||||
for cmd in [git, bunzip2, tar, cc, cplusplus, autoconf, automake, yacc, make, "patch", "m4"]:
|
||||
if which(cmd) is None:
|
||||
raise ValueError("Required tool '%s' not installed or not added to PATH" % (cmd,))
|
||||
|
||||
@@ -310,10 +313,14 @@ BOOST_LOCATION="http://downloads.sourceforge.net/project/boost/boost/%s/boost_%s
|
||||
|
||||
def run_autoconf(arg1, configure_args, cwd):
|
||||
configure_path = os.path.realpath(os.path.join(cwd, "..", "configure"))
|
||||
install_dir = os.path.realpath("%s/install/%s" % (DEPS_DIR, arg1))
|
||||
if not os.path.exists(install_dir):
|
||||
# Some (MPFR) need to have prefix dir manually created
|
||||
os.makedirs(install_dir)
|
||||
if not os.path.exists(configure_path):
|
||||
run([bash, "./autogen.sh"], cwd=os.path.realpath(os.path.join(cwd, ".."))) # only run autogen.sh in the directory it is located and use cwd to achieve that in order to not mess up things
|
||||
# Using `sh` over `bash` fixes issues with building swig
|
||||
run(["/bin/sh", "../configure"]+configure_args+["--prefix=%s" % (os.path.realpath("%s/install/%s" % (DEPS_DIR, arg1)),)], cwd=cwd)
|
||||
run(["/bin/sh", "../configure"]+configure_args+["--prefix=%s" % install_dir], cwd=cwd)
|
||||
|
||||
def run_cmake(arg1, cmake_args, cmake_dir=None, cwd=None):
|
||||
if cmake_dir is None:
|
||||
@@ -547,6 +554,8 @@ if USE_OCCT and "occ" in targets:
|
||||
patch="./patches/occt/enable-exception-handling.patch",
|
||||
revision="V" + OCCT_VERSION.replace('.', '_')
|
||||
)
|
||||
occ_include_dir = "{DEPS_DIR}/install/occt-{OCCT_VERSION}/include/opencascade".format(**locals())
|
||||
occ_library_dir = "{DEPS_DIR}/install/occt-{OCCT_VERSION}/lib".format(**locals())
|
||||
elif "occ" in targets:
|
||||
build_dependency(
|
||||
name="oce-{OCE_VERSION}".format(**locals()),
|
||||
@@ -563,6 +572,9 @@ elif "occ" in targets:
|
||||
download_url="https://github.com/tpaviot/oce/archive/",
|
||||
download_name="OCE-{OCE_VERSION}.tar.gz".format(**locals())
|
||||
)
|
||||
occ_include_dir = "{DEPS_DIR}/install/oce-{OCE_VERSION}/include/oce".format(**locals())
|
||||
occ_library_dir = "{DEPS_DIR}/install/oce-{OCE_VERSION}/lib"
|
||||
|
||||
|
||||
if "libxml2" in targets:
|
||||
build_dependency(
|
||||
@@ -656,6 +668,34 @@ if "boost" in targets:
|
||||
download_name="boost_{BOOST_VERSION_UNDERSCORE}.tar.bz2".format(**locals())
|
||||
)
|
||||
|
||||
if "cgal" in targets:
|
||||
build_dependency(name="gmp-%s" % (GMP_VERSION,), mode="autoconf", build_tool_args=["--disable-shared", "--with-pic"], download_url="https://ftp.gnu.org/gnu/gmp/", download_name="gmp-%s.tar.bz2" % (GMP_VERSION,))
|
||||
build_dependency(name="mpfr-%s" % (MPFR_VERSION,), mode="autoconf", build_tool_args=["--disable-shared", "--with-gmp=%s/install/gmp-%s" % (DEPS_DIR, GMP_VERSION)], download_url="http://www.mpfr.org/mpfr-%s/" % (MPFR_VERSION,), download_name="mpfr-%s.tar.bz2" % (MPFR_VERSION,))
|
||||
|
||||
OLD_BUILD_CFG = BUILD_CFG
|
||||
if BUILD_CFG != "Debug":
|
||||
# CGAL only supports Debug and Release for CMAKE_BUILD_TYPE
|
||||
BUILD_CFG = "Release"
|
||||
build_dependency(name="cgal-{CGAL_VERSION}".format(**locals()), mode="cmake", build_tool_args=["-DGMP_LIBRARIES=%s/install/gmp-%s/lib/libgmp.a" % (DEPS_DIR, GMP_VERSION), "-DGMP_INCLUDE_DIR=%s/install/gmp-%s/include" % (DEPS_DIR, GMP_VERSION), "-DMPFR_LIBRARIES=%s/install/mpfr-%s/lib/libmpfr.a" % (DEPS_DIR, MPFR_VERSION), "-DMPFR_INCLUDE_DIR=%s/install/mpfr-%s/include" % (DEPS_DIR, MPFR_VERSION), "-DBoost_INCLUDE_DIR=%s/install/boost-%s" % (DEPS_DIR, BOOST_VERSION), "-DCMAKE_INSTALL_PREFIX=%s/install/cgal-%s/" % (DEPS_DIR, CGAL_VERSION), "-DBUILD_SHARED_LIBS=Off"], download_url="https://github.com/CGAL/cgal.git", download_name="cgal", download_tool=download_tool_git, revision="releases/CGAL-{CGAL_VERSION}".format(**locals()))
|
||||
BUILD_CFG = OLD_BUILD_CFG
|
||||
|
||||
if "voxel" in targets:
|
||||
build_dependency(
|
||||
"voxel",
|
||||
"cmake",
|
||||
build_tool_args=[
|
||||
"-DIFC_SUPPORT=Off",
|
||||
"-DOCC_INCLUDE_DIR=" +occ_include_dir,
|
||||
"-DOCC_LIBRARY_DIR=" +occ_library_dir,
|
||||
"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/voxel".format(**locals()),
|
||||
"-DBOOST_ROOT=" "{DEPS_DIR}/install/boost-{BOOST_VERSION}".format(**locals())
|
||||
],
|
||||
download_url="https://github.com/opensourceBIM/voxel.git",
|
||||
download_name="voxel",
|
||||
download_tool=download_tool_git,
|
||||
revision="master"
|
||||
)
|
||||
|
||||
cecho("Building IfcOpenShell:", GREEN)
|
||||
|
||||
IFCOS_DIR=os.path.join(DEPS_DIR, "build", "ifcopenshell")
|
||||
@@ -685,21 +725,27 @@ cmake_args=[
|
||||
"-DJSON_INCLUDE_DIR=" "{DEPS_DIR}/install/json".format(**locals())
|
||||
]
|
||||
|
||||
if "occ" in targets and USE_OCCT:
|
||||
occ_include_dir = "{DEPS_DIR}/install/occt-{OCCT_VERSION}/include/opencascade".format(**locals())
|
||||
occ_library_dir = "{DEPS_DIR}/install/occt-{OCCT_VERSION}/lib".format(**locals())
|
||||
if "occ" in targets:
|
||||
cmake_args.extend([
|
||||
"-DOCC_INCLUDE_DIR=" +occ_include_dir,
|
||||
"-DOCC_LIBRARY_DIR=" +occ_library_dir
|
||||
])
|
||||
elif "occ" in targets:
|
||||
occ_include_dir = "{DEPS_DIR}/install/oce-{OCE_VERSION}/include/oce".format(**locals())
|
||||
occ_library_dir = "{DEPS_DIR}/install/oce-{OCE_VERSION}/lib"
|
||||
cmake_args.extend([
|
||||
"-DOCC_INCLUDE_DIR=" +occ_include_dir,
|
||||
"-DOCC_LIBRARY_DIR=" +occ_library_dir
|
||||
])
|
||||
|
||||
if "cgal" in targets:
|
||||
cmake_args.extend([
|
||||
"-DCGAL_INCLUDE_DIR=" "{DEPS_DIR}/install/cgal-{CGAL_VERSION}/include".format(**locals()),
|
||||
"-DCGAL_LIBRARY_DIR=" "{DEPS_DIR}/install/cgal-{CGAL_VERSION}/lib".format(**locals()),
|
||||
"-DGMP_INCLUDE_DIR=" "{DEPS_DIR}/install/gmp-{GMP_VERSION}/include".format(**locals()),
|
||||
"-DGMP_LIBRARY_DIR=" "{DEPS_DIR}/install/gmp-{GMP_VERSION}/lib".format(**locals()),
|
||||
"-DMPFR_INCLUDE_DIR=" "{DEPS_DIR}/install/mpfr-{MPFR_VERSION}/include".format(**locals()),
|
||||
"-DMPFR_LIBRARY_DIR=" "{DEPS_DIR}/install/mpfr-{MPFR_VERSION}/lib".format(**locals())
|
||||
])
|
||||
|
||||
if "OpenCOLLADA" in targets:
|
||||
cmake_args.extend([
|
||||
"-DOPENCOLLADA_INCLUDE_DIR=" "{DEPS_DIR}/install/OpenCOLLADA/include/opencollada".format(**locals()),
|
||||
|
||||
@@ -38,18 +38,13 @@
|
||||
|
||||
#include <Standard_Version.hxx>
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include "../ifcparse/Ifc4.h"
|
||||
#define IfcSchema Ifc4
|
||||
#else
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#define IfcSchema Ifc2x3
|
||||
#endif
|
||||
|
||||
#include "../ifcparse/macros.h"
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/Serialization.h"
|
||||
|
||||
#include "../ifcgeom/schema_agnostic/Serialization.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
|
||||
@@ -33,18 +33,15 @@
|
||||
#include <BRepGProp.hxx>
|
||||
#include <GProp_GProps.hxx>
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include "../ifcparse/Ifc4.h"
|
||||
#define IfcSchema Ifc4
|
||||
#else
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#define IfcSchema Ifc2x3
|
||||
#endif
|
||||
#include <Precision.hxx>
|
||||
|
||||
#define IfcSchema Ifc2x3
|
||||
#include "../ifcparse/macros.h"
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../ifcparse/IfcHierarchyHelper.h"
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom_schema_agnostic/Serialization.h"
|
||||
|
||||
#include "../ifcgeom/schema_agnostic/Serialization.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
|
||||
@@ -34,9 +34,9 @@
|
||||
#include "../serializers/XmlSerializer.h"
|
||||
#include "../serializers/SvgSerializer.h"
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomFilter.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
|
||||
#include "../ifcgeom/schema_agnostic/IfcGeomFilter.h"
|
||||
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom/schema_agnostic/IfcGeomRenderStyles.h"
|
||||
|
||||
#include "../ifcparse/utils.h"
|
||||
|
||||
@@ -194,6 +194,7 @@ int main(int argc, char** argv) {
|
||||
exclusion_traverse_filter exclude_traverse_filter;
|
||||
path_t filter_filename;
|
||||
path_t default_material_filename;
|
||||
std::string geometry_kernel;
|
||||
std::string log_format;
|
||||
|
||||
po::options_description generic_options("Command line options");
|
||||
@@ -214,7 +215,7 @@ int main(int argc, char** argv) {
|
||||
#endif
|
||||
("input-file", new po::typed_value<path_t, char_t>(0), "input IFC file")
|
||||
("output-file", new po::typed_value<path_t, char_t>(0), "output geometry file");
|
||||
|
||||
|
||||
po::options_description ifc_options("IFC options");
|
||||
ifc_options.add_options()
|
||||
("calculate-quantities", "Calculate or fix the physical quantity definitions "
|
||||
@@ -224,6 +225,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
po::options_description geom_options("Geometry options");
|
||||
geom_options.add_options()
|
||||
("kernel", po::value<std::string>(&geometry_kernel)->default_value("opencascade"),
|
||||
"Geometry kernel to use (opencascade or cgal).")
|
||||
("threads,j", po::value<int>(&num_threads)->default_value(1),
|
||||
"Number of parallel processing threads for geometry interpretation.")
|
||||
("plan",
|
||||
@@ -746,7 +749,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
Logger::SetOutput(quiet ? nullptr : &cout_, &log_stream);
|
||||
|
||||
IfcGeom::Iterator<real_t> context_iterator(settings, ifc_file, filter_funcs, num_threads);
|
||||
IfcGeom::Iterator<real_t> context_iterator(settings, ifc_file, filter_funcs, geometry_kernel, num_threads);
|
||||
if (!context_iterator.initialize()) {
|
||||
/// @todo It would be nice to know and print separate error prints for a case where we found no entities
|
||||
/// and for a case we found no entities that satisfy our filtering criteria.
|
||||
@@ -810,7 +813,7 @@ int main(int argc, char** argv) {
|
||||
// The functions IfcGeom::Iterator::get() and IfcGeom::Iterator::next()
|
||||
// wrap an iterator of all geometrical products in the Ifc file.
|
||||
// IfcGeom::Iterator::get() returns an IfcGeom::TriangulationElement or
|
||||
// -BRepElement pointer, based on current settings. (see IfcGeomIterator.h
|
||||
// -NativeElement pointer, based on current settings. (see IfcGeomIterator.h
|
||||
// for definition) IfcGeom::Iterator::next() is used to poll whether more
|
||||
// geometrical entities are available. None of these functions throw
|
||||
// exceptions, neither for parsing errors or geometrical errors. Upon
|
||||
@@ -828,7 +831,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
else
|
||||
{
|
||||
serializer->write(static_cast<const IfcGeom::BRepElement<real_t>*>(geom_object));
|
||||
serializer->write(static_cast<const IfcGeom::NativeElement<real_t>*>(geom_object));
|
||||
}
|
||||
|
||||
if (!no_progress) {
|
||||
@@ -1264,7 +1267,7 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std
|
||||
if (num_created) {
|
||||
has_more = context_iterator.next();
|
||||
}
|
||||
IfcGeom::BRepElement<double>* geom_object = nullptr;
|
||||
IfcGeom::NativeElement<double>* geom_object = nullptr;
|
||||
if (has_more) {
|
||||
geom_object = context_iterator.get_native();
|
||||
}
|
||||
@@ -1317,7 +1320,7 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std
|
||||
auto quantity_count = latebound_access::create(f, "IfcQuantityCount");
|
||||
latebound_access::set(quantity_count, "Name", std::string("Surface Genus"));
|
||||
latebound_access::set(quantity_count, "Description", '#' + boost::lexical_cast<std::string>(part.ItemId()));
|
||||
latebound_access::set(quantity_count, "CountValue", IfcGeom::Kernel::surface_genus(part.Shape()));
|
||||
latebound_access::set(quantity_count, "CountValue", part.Shape()->surface_genus());
|
||||
|
||||
quantities_2->push(quantity_count);
|
||||
}
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "IfcGeom.h"
|
||||
|
||||
namespace {
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourRgb* colour, double* rgb) {
|
||||
if (colour != 0) {
|
||||
rgb[0] = colour->Red();
|
||||
rgb[1] = colour->Green();
|
||||
rgb[2] = colour->Blue();
|
||||
}
|
||||
return colour != 0;
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, double* rgb) {
|
||||
if (factor != 0) {
|
||||
const double f = *factor;
|
||||
rgb[0] = rgb[1] = rgb[2] = f;
|
||||
}
|
||||
return factor != 0;
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, double* rgb) {
|
||||
if (colour_or_factor == 0) {
|
||||
return false;
|
||||
} else if (colour_or_factor->declaration().is(IfcSchema::IfcColourRgb::Class())) {
|
||||
return process_colour(static_cast<IfcSchema::IfcColourRgb*>(colour_or_factor), rgb);
|
||||
} else if (colour_or_factor->declaration().is(IfcSchema::IfcNormalisedRatioMeasure::Class())) {
|
||||
return process_colour(static_cast<IfcSchema::IfcNormalisedRatioMeasure*>(colour_or_factor), rgb);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::internalize_surface_style(const std::pair<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*>& shading_styles) {
|
||||
if (shading_styles.second == 0) {
|
||||
return 0;
|
||||
}
|
||||
int surface_style_id = shading_styles.first->data().id();
|
||||
std::map<int,SurfaceStyle>::const_iterator it = style_cache.find(surface_style_id);
|
||||
if (it != style_cache.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
SurfaceStyle surface_style;
|
||||
|
||||
IfcSchema::IfcSurfaceStyle* style = shading_styles.first->as<IfcSchema::IfcSurfaceStyle>();
|
||||
IfcSchema::IfcSurfaceStyleShading* shading = shading_styles.second->as<IfcSchema::IfcSurfaceStyleShading>();
|
||||
|
||||
if (style->hasName()) {
|
||||
surface_style = SurfaceStyle(surface_style_id, style->Name());
|
||||
} else {
|
||||
surface_style = SurfaceStyle(surface_style_id);
|
||||
}
|
||||
double rgb[3];
|
||||
if (process_colour(shading->SurfaceColour(), rgb)) {
|
||||
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
|
||||
}
|
||||
if (shading_styles.second->declaration().is(IfcSchema::IfcSurfaceStyleRendering::Class())) {
|
||||
IfcSchema::IfcSurfaceStyleRendering* rendering_style = static_cast<IfcSchema::IfcSurfaceStyleRendering*>(shading_styles.second);
|
||||
if (rendering_style->hasDiffuseColour() && process_colour(rendering_style->DiffuseColour(), rgb)) {
|
||||
SurfaceStyle::ColorComponent diffuse = surface_style.Diffuse().get_value_or(SurfaceStyle::ColorComponent(1,1,1));
|
||||
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(diffuse.R() * rgb[0], diffuse.G() * rgb[1], diffuse.B() * rgb[2]));
|
||||
}
|
||||
if (rendering_style->hasDiffuseTransmissionColour()) {
|
||||
// Not supported
|
||||
}
|
||||
if (rendering_style->hasReflectionColour()) {
|
||||
// Not supported
|
||||
}
|
||||
if (rendering_style->hasSpecularColour() && process_colour(rendering_style->SpecularColour(), rgb)) {
|
||||
surface_style.Specular().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
|
||||
}
|
||||
if (rendering_style->hasSpecularHighlight()) {
|
||||
IfcSchema::IfcSpecularHighlightSelect* highlight = rendering_style->SpecularHighlight();
|
||||
if (highlight->declaration().is(IfcSchema::IfcSpecularRoughness::Class())) {
|
||||
double roughness = *((IfcSchema::IfcSpecularRoughness*)highlight);
|
||||
if (roughness >= 1e-9) {
|
||||
surface_style.Specularity().reset(1.0 / roughness);
|
||||
}
|
||||
} else if (highlight->declaration().is(IfcSchema::IfcSpecularExponent::Class())) {
|
||||
surface_style.Specularity().reset(*((IfcSchema::IfcSpecularExponent*)highlight));
|
||||
}
|
||||
}
|
||||
if (rendering_style->hasTransmissionColour()) {
|
||||
// Not supported
|
||||
}
|
||||
if (rendering_style->hasTransparency()) {
|
||||
const double d = rendering_style->Transparency();
|
||||
surface_style.Transparency().reset(d);
|
||||
}
|
||||
}
|
||||
return &(style_cache[surface_style_id] = surface_style);
|
||||
}
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepresentationItem* item) {
|
||||
return internalize_surface_style(get_surface_style<IfcSchema::IfcSurfaceStyleShading>(item));
|
||||
}
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcMaterial* material) {
|
||||
IfcSchema::IfcMaterialDefinitionRepresentation::list::ptr defs = material->HasRepresentation();
|
||||
for (IfcSchema::IfcMaterialDefinitionRepresentation::list::it jt = defs->begin(); jt != defs->end(); ++jt) {
|
||||
IfcSchema::IfcRepresentation::list::ptr reps = (*jt)->Representations();
|
||||
IfcSchema::IfcStyledItem::list::ptr styles(new IfcSchema::IfcStyledItem::list);
|
||||
for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) {
|
||||
styles->push((**it).Items()->as<IfcSchema::IfcStyledItem>());
|
||||
}
|
||||
for (IfcSchema::IfcStyledItem::list::it it = styles->begin(); it != styles->end(); ++it) {
|
||||
const std::pair<IfcSchema::IfcSurfaceStyle*, IfcSchema::IfcSurfaceStyleShading*> ss = get_surface_style<IfcSchema::IfcSurfaceStyleShading>(*it);
|
||||
if (ss.second) {
|
||||
return internalize_surface_style(ss);
|
||||
}
|
||||
}
|
||||
}
|
||||
IfcGeom::SurfaceStyle material_style = IfcGeom::SurfaceStyle(material->data().id(), material->Name());
|
||||
return &(style_cache[material->data().id()] = material_style);
|
||||
}
|
||||
@@ -1,415 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMREPRESENTATION_H
|
||||
#define IFCGEOMREPRESENTATION_H
|
||||
|
||||
#include <BRepMesh_IncrementalMesh.hxx>
|
||||
#include <BRepGProp_Face.hxx>
|
||||
|
||||
#include <Poly_Triangulation.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColgp_Array1OfPnt2d.hxx>
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <GCPnts_QuasiUniformDeflection.hxx>
|
||||
#include <Geom_SphericalSurface.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h"
|
||||
#include "../ifcgeom/IfcRepresentationShapeItem.h"
|
||||
|
||||
#include <TopoDS_Compound.hxx>
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
namespace Representation {
|
||||
|
||||
class IFC_GEOM_API Representation {
|
||||
Representation(const Representation&); //N/A
|
||||
Representation& operator =(const Representation&); //N/A
|
||||
protected:
|
||||
const ElementSettings settings_;
|
||||
public:
|
||||
explicit Representation(const ElementSettings& settings)
|
||||
: settings_(settings)
|
||||
{}
|
||||
const ElementSettings& settings() const { return settings_; }
|
||||
virtual ~Representation() {}
|
||||
};
|
||||
|
||||
class IFC_GEOM_API BRep : public Representation {
|
||||
private:
|
||||
std::string id_;
|
||||
const IfcGeom::IfcRepresentationShapeItems shapes_;
|
||||
BRep(const BRep& other);
|
||||
BRep& operator=(const BRep& other);
|
||||
public:
|
||||
BRep(const ElementSettings& settings, const std::string& id, const IfcGeom::IfcRepresentationShapeItems& shapes)
|
||||
: Representation(settings)
|
||||
, id_(id)
|
||||
, shapes_(shapes)
|
||||
{}
|
||||
virtual ~BRep() {}
|
||||
IfcGeom::IfcRepresentationShapeItems::const_iterator begin() const { return shapes_.begin(); }
|
||||
IfcGeom::IfcRepresentationShapeItems::const_iterator end() const { return shapes_.end(); }
|
||||
const IfcGeom::IfcRepresentationShapeItems& shapes() const { return shapes_; }
|
||||
const std::string& id() const { return id_; }
|
||||
TopoDS_Compound as_compound(bool force_meters = false) const;
|
||||
|
||||
bool calculate_volume(double&) const;
|
||||
bool calculate_surface_area(double&) const;
|
||||
bool calculate_projected_surface_area(const gp_Ax3& ax, double& along_x, double& along_y, double& along_z) const;
|
||||
};
|
||||
|
||||
class IFC_GEOM_API Serialization : public Representation {
|
||||
private:
|
||||
std::string id_;
|
||||
std::string brep_data_;
|
||||
std::vector<double> surface_styles_;
|
||||
public:
|
||||
const std::string& brep_data() const { return brep_data_; }
|
||||
const std::vector<double>& surface_styles() const { return surface_styles_; }
|
||||
Serialization(const BRep& brep);
|
||||
virtual ~Serialization() {}
|
||||
const std::string& id() const { return id_; }
|
||||
private:
|
||||
Serialization();
|
||||
Serialization(const Serialization&);
|
||||
Serialization& operator=(const Serialization&);
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
class Triangulation : public Representation {
|
||||
private:
|
||||
// A nested pair of floats and a material index to be able to store an XYZ coordinate in a map.
|
||||
// TODO: Make this a std::tuple when compilers add support for that.
|
||||
typedef typename std::pair<P, std::pair<P, P> > Coordinate;
|
||||
typedef typename std::pair<int, Coordinate> VertexKey;
|
||||
typedef std::map<VertexKey, int> VertexKeyMap;
|
||||
typedef std::pair<int, int> Edge;
|
||||
|
||||
std::string id_;
|
||||
std::vector<P> _verts;
|
||||
std::vector<int> _faces;
|
||||
std::vector<int> _edges;
|
||||
std::vector<P> _normals;
|
||||
std::vector<P> uvs_;
|
||||
std::vector<int> _material_ids;
|
||||
std::vector<Material> _materials;
|
||||
VertexKeyMap welds;
|
||||
|
||||
public:
|
||||
const std::string& id() const { return id_; }
|
||||
const std::vector<P>& verts() const { return _verts; }
|
||||
const std::vector<int>& faces() const { return _faces; }
|
||||
const std::vector<int>& edges() const { return _edges; }
|
||||
const std::vector<P>& normals() const { return _normals; }
|
||||
const std::vector<P>& uvs() const { return uvs_; }
|
||||
const std::vector<int>& material_ids() const { return _material_ids; }
|
||||
const std::vector<Material>& materials() const { return _materials; }
|
||||
|
||||
Triangulation(const BRep& shape_model)
|
||||
: Representation(shape_model.settings())
|
||||
, id_(shape_model.id())
|
||||
{
|
||||
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++ iit ) {
|
||||
|
||||
int surface_style_id = -1;
|
||||
if (iit->hasStyle()) {
|
||||
Material adapter(&iit->Style());
|
||||
std::vector<Material>::const_iterator jt = std::find(_materials.begin(), _materials.end(), adapter);
|
||||
if (jt == _materials.end()) {
|
||||
surface_style_id = (int)_materials.size();
|
||||
_materials.push_back(adapter);
|
||||
} else {
|
||||
surface_style_id = (int)(jt - _materials.begin());
|
||||
}
|
||||
}
|
||||
|
||||
if (settings().get(IteratorSettings::APPLY_DEFAULT_MATERIALS) && surface_style_id == -1) {
|
||||
Material material(IfcGeom::get_default_style(settings().element_type()));
|
||||
std::vector<Material>::const_iterator mit = std::find(_materials.begin(), _materials.end(), material);
|
||||
if (mit == _materials.end()) {
|
||||
surface_style_id = (int)_materials.size();
|
||||
_materials.push_back(material);
|
||||
} else {
|
||||
surface_style_id = (int)(mit - _materials.begin());
|
||||
}
|
||||
}
|
||||
|
||||
const TopoDS_Shape& s = iit->Shape();
|
||||
const gp_GTrsf& trsf = iit->Placement();
|
||||
|
||||
// Triangulate the shape
|
||||
try {
|
||||
BRepMesh_IncrementalMesh(s, settings().deflection_tolerance());
|
||||
} catch(...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Iterates over the faces of the shape
|
||||
int num_faces = 0;
|
||||
TopExp_Explorer exp;
|
||||
for ( exp.Init(s,TopAbs_FACE); exp.More(); exp.Next(), ++num_faces ) {
|
||||
TopoDS_Face face = TopoDS::Face(exp.Current());
|
||||
TopLoc_Location loc;
|
||||
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face,loc);
|
||||
|
||||
if ( ! tri.IsNull() ) {
|
||||
|
||||
// A 3x3 matrix to rotate the vertex normals
|
||||
const gp_Mat rotation_matrix = trsf.VectorialPart();
|
||||
|
||||
// Keep track of the number of times an edge is used
|
||||
// Manifold edges (i.e. edges used twice) are deemed invisible
|
||||
std::map<std::pair<int,int>,int> edgecount;
|
||||
std::vector<std::pair<int,int> > edges_temp;
|
||||
|
||||
const TColgp_Array1OfPnt& nodes = tri->Nodes();
|
||||
const TColgp_Array1OfPnt2d& uvs = tri->UVNodes();
|
||||
std::vector<gp_XYZ> coords;
|
||||
BRepGProp_Face prop(face);
|
||||
std::map<int,int> dict;
|
||||
|
||||
// Vertex normals are only calculated if vertices are not welded and calculation is not disable explicitly.
|
||||
const bool calculate_normals = !settings().get(IteratorSettings::WELD_VERTICES) &&
|
||||
!settings().get(IteratorSettings::NO_NORMALS);
|
||||
|
||||
for( int i = 1; i <= nodes.Length(); ++ i ) {
|
||||
coords.push_back(nodes(i).Transformed(loc).XYZ());
|
||||
trsf.Transforms(*coords.rbegin());
|
||||
dict[i] = addVertex(surface_style_id, *coords.rbegin());
|
||||
|
||||
if ( calculate_normals ) {
|
||||
const gp_Pnt2d& uv = uvs(i);
|
||||
gp_Pnt p;
|
||||
gp_Vec normal_direction;
|
||||
prop.Normal(uv.X(),uv.Y(),p,normal_direction);
|
||||
gp_Vec normal(0., 0., 0.);
|
||||
if (normal_direction.Magnitude() > 1.e-9) {
|
||||
normal = gp_Dir(normal_direction.XYZ() * rotation_matrix);
|
||||
} else {
|
||||
Handle_Geom_Surface surf = BRep_Tool::Surface(face);
|
||||
// Special case the normal at the poles of a spherical surface
|
||||
if (surf->DynamicType() == STANDARD_TYPE(Geom_SphericalSurface)) {
|
||||
if (fabs(fabs(uv.Y()) - M_PI / 2.) < 1.e-9) {
|
||||
const bool is_top = uv.Y() > 0;
|
||||
const bool is_forward = face.Orientation() == TopAbs_FORWARD;
|
||||
const double z = (is_top == is_forward) ? 1. : -1.;
|
||||
normal = gp_Dir(gp_XYZ(0, 0, z) * rotation_matrix);
|
||||
}
|
||||
}
|
||||
// TODO: Do the same for conical surfaces, but they are rare in IFC.
|
||||
}
|
||||
_normals.push_back(static_cast<P>(normal.X()));
|
||||
_normals.push_back(static_cast<P>(normal.Y()));
|
||||
_normals.push_back(static_cast<P>(normal.Z()));
|
||||
}
|
||||
}
|
||||
|
||||
const Poly_Array1OfTriangle& triangles = tri->Triangles();
|
||||
for( int i = 1; i <= triangles.Length(); ++ i ) {
|
||||
int n1,n2,n3;
|
||||
if ( face.Orientation() == TopAbs_REVERSED )
|
||||
triangles(i).Get(n3,n2,n1);
|
||||
else triangles(i).Get(n1,n2,n3);
|
||||
|
||||
/* An alternative would be to calculate normals based
|
||||
* on the coordinates of the mesh vertices */
|
||||
/*
|
||||
const gp_XYZ pt1 = coords[n1-1];
|
||||
const gp_XYZ pt2 = coords[n2-1];
|
||||
const gp_XYZ pt3 = coords[n3-1];
|
||||
const gp_XYZ v1 = pt2-pt1;
|
||||
const gp_XYZ v2 = pt3-pt2;
|
||||
gp_Dir normal = gp_Dir(v1^v2);
|
||||
_normals.push_back((float)normal.X());
|
||||
_normals.push_back((float)normal.Y());
|
||||
_normals.push_back((float)normal.Z());
|
||||
*/
|
||||
|
||||
_faces.push_back(dict[n1]);
|
||||
_faces.push_back(dict[n2]);
|
||||
_faces.push_back(dict[n3]);
|
||||
|
||||
_material_ids.push_back(surface_style_id);
|
||||
|
||||
addEdge(dict[n1], dict[n2], edgecount, edges_temp);
|
||||
addEdge(dict[n2], dict[n3], edgecount, edges_temp);
|
||||
addEdge(dict[n3], dict[n1], edgecount, edges_temp);
|
||||
}
|
||||
for ( std::vector<std::pair<int,int> >::const_iterator jt = edges_temp.begin(); jt != edges_temp.end(); ++jt ) {
|
||||
if (edgecount[*jt] == 1) {
|
||||
// non manifold edge, face boundary
|
||||
_edges.push_back(jt->first);
|
||||
_edges.push_back(jt->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!_normals.empty() && settings().get(IfcGeom::IteratorSettings::GENERATE_UVS)) {
|
||||
uvs_ = box_project_uvs(_verts, _normals);
|
||||
}
|
||||
|
||||
if (num_faces == 0) {
|
||||
// Edges are only emitted if there are no faces. A mixed representation of faces
|
||||
// and loose edges is discouraged by the standard. An alternative would be to use
|
||||
// TopExp_Explorer texp(s, TopAbs_EDGE, TopAbs_FACE) to find edges that do not
|
||||
// belong to any face.
|
||||
for (TopExp_Explorer texp(s, TopAbs_EDGE); texp.More(); texp.Next()) {
|
||||
BRepAdaptor_Curve crv(TopoDS::Edge(texp.Current()));
|
||||
GCPnts_QuasiUniformDeflection tessellater(crv, settings().deflection_tolerance());
|
||||
int n = tessellater.NbPoints();
|
||||
int start = (int)_verts.size() / 3;
|
||||
for (int i = 1; i <= n; ++i) {
|
||||
gp_XYZ p = tessellater.Value(i).XYZ();
|
||||
|
||||
/*
|
||||
// In case you want direction arrows on your edges
|
||||
double u = tessellater.Parameter(i);
|
||||
gp_XYZ p2, p3;
|
||||
gp_Pnt tmp;
|
||||
gp_Vec tmp2;
|
||||
crv.D1(u, tmp, tmp2);
|
||||
gp_Dir d1, d2, d3, d4;
|
||||
d1 = tmp2;
|
||||
if (texp.Current().Orientation() == TopAbs_REVERSED) {
|
||||
d1 = -d1;
|
||||
}
|
||||
if (fabs(d1.Z()) < 0.5) {
|
||||
d2 = d1.Crossed(gp::DZ());
|
||||
} else {
|
||||
d2 = d1.Crossed(gp::DY());
|
||||
}
|
||||
d3 = d1.XYZ() + d2.XYZ();
|
||||
d4 = d1.XYZ() - d2.XYZ();
|
||||
p2 = p - d3.XYZ() / 10.;
|
||||
p3 = p - d4.XYZ() / 10.;
|
||||
trsf.Transforms(p2);
|
||||
trsf.Transforms(p3);
|
||||
_material_ids.push_back(surface_style_id);
|
||||
_material_ids.push_back(surface_style_id);
|
||||
_verts.push_back(static_cast<P>(p2.X()));
|
||||
_verts.push_back(static_cast<P>(p2.Y()));
|
||||
_verts.push_back(static_cast<P>(p2.Z()));
|
||||
_verts.push_back(static_cast<P>(p3.X()));
|
||||
_verts.push_back(static_cast<P>(p3.Y()));
|
||||
_verts.push_back(static_cast<P>(p3.Z()));
|
||||
*/
|
||||
|
||||
trsf.Transforms(p);
|
||||
|
||||
_material_ids.push_back(surface_style_id);
|
||||
|
||||
_verts.push_back(static_cast<P>(p.X()));
|
||||
_verts.push_back(static_cast<P>(p.Y()));
|
||||
_verts.push_back(static_cast<P>(p.Z()));
|
||||
|
||||
if (i > 1) {
|
||||
_edges.push_back(start + i - 2);
|
||||
_edges.push_back(start + i - 1);
|
||||
// _edges.push_back(start + 3 * (i - 2) + 2);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 2);
|
||||
}
|
||||
|
||||
// _edges.push_back(start + 3 * (i - 1) + 0);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 2);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 1);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BRepTools::Clean(s);
|
||||
}
|
||||
}
|
||||
virtual ~Triangulation() {}
|
||||
|
||||
/// Generates UVs for a single mesh using box projection.
|
||||
/// @todo Very simple impl. Assumes that input vertices and normals match 1:1.
|
||||
static std::vector<P> box_project_uvs(const std::vector<P> &vertices, const std::vector<P> &normals)
|
||||
{
|
||||
std::vector<P> uvs;
|
||||
uvs.resize(vertices.size() / 3 * 2);
|
||||
for (size_t uv_idx = 0, v_idx = 0;
|
||||
uv_idx < uvs.size() && v_idx < vertices.size() && v_idx < normals.size();
|
||||
uv_idx += 2, v_idx += 3) {
|
||||
|
||||
P n_x = normals[v_idx], n_y = normals[v_idx + 1], n_z = normals[v_idx + 2];
|
||||
P v_x = vertices[v_idx], v_y = vertices[v_idx + 1], v_z = vertices[v_idx + 2];
|
||||
|
||||
if (std::abs(n_x) > std::abs(n_y) && std::abs(n_x) > std::abs(n_z)) {
|
||||
uvs[uv_idx] = v_z;
|
||||
uvs[uv_idx + 1] = v_y;
|
||||
}
|
||||
if (std::abs(n_y) > std::abs(n_x) && std::abs(n_y) > std::abs(n_z)) {
|
||||
uvs[uv_idx] = v_x;
|
||||
uvs[uv_idx + 1] = v_z;
|
||||
}
|
||||
if (std::abs(n_z) > std::abs(n_x) && std::abs(n_z) > std::abs(n_y)) {
|
||||
uvs[uv_idx] = v_x;
|
||||
uvs[uv_idx + 1] = v_y;
|
||||
}
|
||||
}
|
||||
|
||||
return uvs;
|
||||
}
|
||||
|
||||
private:
|
||||
// Welds vertices that belong to different faces
|
||||
int addVertex(int material_index, const gp_XYZ& p) {
|
||||
const bool convert = settings().get(IteratorSettings::CONVERT_BACK_UNITS);
|
||||
const P X = static_cast<P>(convert ? (p.X() / settings().unit_magnitude()) : p.X());
|
||||
const P Y = static_cast<P>(convert ? (p.Y() / settings().unit_magnitude()) : p.Y());
|
||||
const P Z = static_cast<P>(convert ? (p.Z() / settings().unit_magnitude()) : p.Z());
|
||||
int i = (int) _verts.size() / 3;
|
||||
if (settings().get(IteratorSettings::WELD_VERTICES)) {
|
||||
const VertexKey key = std::make_pair(material_index, std::make_pair(X, std::make_pair(Y, Z)));
|
||||
typename VertexKeyMap::const_iterator it = welds.find(key);
|
||||
if ( it != welds.end() ) return it->second;
|
||||
i = (int) welds.size();
|
||||
welds[key] = i;
|
||||
}
|
||||
_verts.push_back(X);
|
||||
_verts.push_back(Y);
|
||||
_verts.push_back(Z);
|
||||
return i;
|
||||
}
|
||||
inline void addEdge(int n1, int n2, std::map<std::pair<int,int>,int>& edgecount, std::vector<std::pair<int,int> >& edges_temp) {
|
||||
const Edge e = Edge( (std::min)(n1,n2),(std::max)(n1,n2) );
|
||||
if ( edgecount.find(e) == edgecount.end() ) edgecount[e] = 1;
|
||||
else edgecount[e] ++;
|
||||
edges_temp.push_back(e);
|
||||
}
|
||||
Triangulation();
|
||||
Triangulation(const Triangulation&);
|
||||
Triangulation& operator=(const Triangulation&);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,55 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCSHAPELIST_H
|
||||
#define IFCSHAPELIST_H
|
||||
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
class IFC_GEOM_API IfcRepresentationShapeItem {
|
||||
private:
|
||||
int id;
|
||||
gp_GTrsf placement;
|
||||
TopoDS_Shape shape;
|
||||
const SurfaceStyle* style;
|
||||
public:
|
||||
IfcRepresentationShapeItem(int id, const gp_GTrsf& placement, const TopoDS_Shape& shape, const SurfaceStyle* style)
|
||||
: id(id), placement(placement), shape(shape), style(style) {}
|
||||
IfcRepresentationShapeItem(int id, const gp_GTrsf& placement, const TopoDS_Shape& shape)
|
||||
: id(id), placement(placement), shape(shape), style(0) {}
|
||||
IfcRepresentationShapeItem(int id, const TopoDS_Shape& shape, const SurfaceStyle* style)
|
||||
: id(id), shape(shape), style(style) {}
|
||||
IfcRepresentationShapeItem(int id, const TopoDS_Shape& shape)
|
||||
: id(id), shape(shape), style(0) {}
|
||||
void append(const gp_GTrsf& trsf) { placement.Multiply(trsf); }
|
||||
void prepend(const gp_GTrsf& trsf) { placement.PreMultiply(trsf); }
|
||||
const TopoDS_Shape& Shape() const { return shape; }
|
||||
const gp_GTrsf& Placement() const { return placement; }
|
||||
bool hasStyle() const { return style != 0; }
|
||||
const SurfaceStyle& Style() const { return *style; }
|
||||
void setStyle(const SurfaceStyle* newStyle) { style = newStyle; }
|
||||
int ItemId() const { return id; }
|
||||
};
|
||||
typedef std::vector<IfcRepresentationShapeItem> IfcRepresentationShapeItems;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,552 @@
|
||||
#include "AbstractKernel.h"
|
||||
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomElement.h"
|
||||
|
||||
#define AbstractKernel MAKE_TYPE_NAME(AbstractKernel)
|
||||
|
||||
void IfcGeom::AbstractKernel::set_conversion_placement_rel_to(const IfcParse::declaration* type) {
|
||||
placement_rel_to = type;
|
||||
}
|
||||
|
||||
void IfcGeom::AbstractKernel::setValue(GeomValue var, double value) {
|
||||
switch (var) {
|
||||
case GV_DEFLECTION_TOLERANCE:
|
||||
deflection_tolerance = value;
|
||||
break;
|
||||
case GV_POINT_EQUALITY_TOLERANCE:
|
||||
point_equality_tolerance = value;
|
||||
break;
|
||||
case GV_LENGTH_UNIT:
|
||||
ifc_length_unit = value;
|
||||
break;
|
||||
case GV_PLANEANGLE_UNIT:
|
||||
ifc_planeangle_unit = value;
|
||||
break;
|
||||
case GV_PRECISION:
|
||||
modelling_precision = value;
|
||||
break;
|
||||
case GV_DIMENSIONALITY:
|
||||
dimensionality = value;
|
||||
break;
|
||||
default:
|
||||
assert(!"never reach here");
|
||||
}
|
||||
}
|
||||
|
||||
double IfcGeom::AbstractKernel::getValue(GeomValue var) const {
|
||||
switch (var) {
|
||||
case GV_DEFLECTION_TOLERANCE:
|
||||
return deflection_tolerance;
|
||||
case GV_MINIMAL_FACE_AREA:
|
||||
// Considering a right-angled triangle, this about the smallest
|
||||
// area you can obtain without the vertices being confused.
|
||||
return modelling_precision * modelling_precision / 2.;
|
||||
case GV_POINT_EQUALITY_TOLERANCE:
|
||||
return point_equality_tolerance;
|
||||
case GV_LENGTH_UNIT:
|
||||
return ifc_length_unit;
|
||||
break;
|
||||
case GV_PLANEANGLE_UNIT:
|
||||
return ifc_planeangle_unit;
|
||||
break;
|
||||
case GV_PRECISION:
|
||||
return modelling_precision;
|
||||
break;
|
||||
case GV_DIMENSIONALITY:
|
||||
return dimensionality;
|
||||
break;
|
||||
}
|
||||
assert(!"never reach here");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const IfcSchema::IfcMaterial* IfcGeom::AbstractKernel::get_single_material_association(const IfcSchema::IfcProduct* product) {
|
||||
IfcSchema::IfcMaterial* single_material = 0;
|
||||
IfcSchema::IfcRelAssociatesMaterial::list::ptr associated_materials = product->HasAssociations()->as<IfcSchema::IfcRelAssociatesMaterial>();
|
||||
if (associated_materials->size() == 1) {
|
||||
IfcSchema::IfcMaterialSelect* associated_material = (*associated_materials->begin())->RelatingMaterial();
|
||||
single_material = associated_material->as<IfcSchema::IfcMaterial>();
|
||||
|
||||
// NB: Single-layer layersets are also considered, regardless of --enable-layerset-slicing, this
|
||||
// in accordance with other viewers.
|
||||
if (!single_material && associated_material->as<IfcSchema::IfcMaterialLayerSetUsage>()) {
|
||||
IfcSchema::IfcMaterialLayerSet* layerset = associated_material->as<IfcSchema::IfcMaterialLayerSetUsage>()->ForLayerSet();
|
||||
if (layerset->MaterialLayers()->size() == 1) {
|
||||
IfcSchema::IfcMaterialLayer* layer = (*layerset->MaterialLayers()->begin());
|
||||
if (layer->hasMaterial()) {
|
||||
single_material = layer->Material();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return single_material;
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentation* IfcGeom::AbstractKernel::representation_mapped_to(const IfcSchema::IfcRepresentation* representation) {
|
||||
IfcSchema::IfcRepresentation* representation_mapped_to = 0;
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items = representation->Items();
|
||||
if (items->size() == 1) {
|
||||
IfcSchema::IfcRepresentationItem* item = *items->begin();
|
||||
if (item->declaration().is(IfcSchema::IfcMappedItem::Class())) {
|
||||
if (item->StyledByItem()->size() == 0) {
|
||||
IfcSchema::IfcMappedItem* mapped_item = item->as<IfcSchema::IfcMappedItem>();
|
||||
if (is_identity_transform(mapped_item->MappingTarget())) {
|
||||
IfcSchema::IfcRepresentationMap* map = mapped_item->MappingSource();
|
||||
if (is_identity_transform(map->MappingOrigin())) {
|
||||
representation_mapped_to = map->MappedRepresentation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return representation_mapped_to;
|
||||
}
|
||||
|
||||
IfcSchema::IfcProduct::list::ptr IfcGeom::AbstractKernel::products_represented_by(const IfcSchema::IfcRepresentation* representation) {
|
||||
IfcSchema::IfcProduct::list::ptr products(new IfcSchema::IfcProduct::list);
|
||||
|
||||
IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation();
|
||||
|
||||
for (IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it) {
|
||||
// http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm
|
||||
// IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards.
|
||||
// It will be changed into an ABSTRACT supertype in future releases of IFC.
|
||||
|
||||
// IfcProductRepresentation also lacks the INVERSE relation to IfcProduct
|
||||
// Let's find the IfcProducts that reference the IfcProductRepresentation anyway
|
||||
products->push((*it)->data().getInverse((&IfcSchema::IfcProduct::Class()), -1)->as<IfcSchema::IfcProduct>());
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap();
|
||||
if (maps->size() == 1) {
|
||||
IfcSchema::IfcRepresentationMap* map = *maps->begin();
|
||||
if (is_identity_transform(map->MappingOrigin())) {
|
||||
IfcSchema::IfcMappedItem::list::ptr items = map->MapUsage();
|
||||
for (IfcSchema::IfcMappedItem::list::it it = items->begin(); it != items->end(); ++it) {
|
||||
IfcSchema::IfcMappedItem* item = *it;
|
||||
if (item->StyledByItem()->size() != 0) continue;
|
||||
|
||||
if (!is_identity_transform(item->MappingTarget())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps = item->data().getInverse((&IfcSchema::IfcRepresentation::Class()), -1)->as<IfcSchema::IfcRepresentation>();
|
||||
for (IfcSchema::IfcRepresentation::list::it jt = reps->begin(); jt != reps->end(); ++jt) {
|
||||
IfcSchema::IfcRepresentation* rep = *jt;
|
||||
if (rep->Items()->size() != 1) continue;
|
||||
IfcSchema::IfcProductRepresentation::list::ptr prodreps_mapped = rep->OfProductRepresentation();
|
||||
for (IfcSchema::IfcProductRepresentation::list::it kt = prodreps_mapped->begin(); kt != prodreps_mapped->end(); ++kt) {
|
||||
IfcSchema::IfcProduct::list::ptr ps = (*kt)->data().getInverse((&IfcSchema::IfcProduct::Class()), -1)->as<IfcSchema::IfcProduct>();
|
||||
products->push(ps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return products;
|
||||
}
|
||||
|
||||
namespace {
|
||||
const IfcSchema::IfcRepresentationItem* find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item) {
|
||||
if (item->StyledByItem()->size()) {
|
||||
return item;
|
||||
}
|
||||
|
||||
while (item->declaration().is(IfcSchema::IfcBooleanClippingResult::Class())) {
|
||||
// All instantiations of IfcBooleanOperand (type of FirstOperand) are subtypes of
|
||||
// IfcGeometricRepresentationItem
|
||||
item = (IfcSchema::IfcGeometricRepresentationItem*) ((IfcSchema::IfcBooleanClippingResult*) item)->FirstOperand();
|
||||
if (item->StyledByItem()->size()) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Ideally this would be done for other entities (such as IfcCsgSolid) as well.
|
||||
// But neither are these very prevalent, nor does the current IfcOpenShell style
|
||||
// mechanism enable to conveniently style subshapes, which would be necessary for
|
||||
// distinctly styled union operands.
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
std::pair<IfcSchema::IfcSurfaceStyle*, T*> _get_surface_style(const IfcSchema::IfcStyledItem* si) {
|
||||
#ifdef SCHEMA_HAS_IfcStyleAssignmentSelect
|
||||
IfcEntityList::ptr style_assignments = si->Styles();
|
||||
for (IfcEntityList::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
if (!(*kt)->declaration().is(IfcSchema::IfcPresentationStyleAssignment::Class())) {
|
||||
continue;
|
||||
}
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt;
|
||||
#else
|
||||
IfcSchema::IfcPresentationStyleAssignment::list::ptr style_assignments = si->Styles();
|
||||
for (IfcSchema::IfcPresentationStyleAssignment::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment = *kt;
|
||||
#endif
|
||||
IfcEntityList::ptr styles = style_assignment->Styles();
|
||||
for (IfcEntityList::it lt = styles->begin(); lt != styles->end(); ++lt) {
|
||||
IfcUtil::IfcBaseClass* style = *lt;
|
||||
if (style->declaration().is(IfcSchema::IfcSurfaceStyle::Class())) {
|
||||
IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style;
|
||||
if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) {
|
||||
IfcEntityList::ptr styles_elements = surface_style->Styles();
|
||||
for (IfcEntityList::it mt = styles_elements->begin(); mt != styles_elements->end(); ++mt) {
|
||||
if ((*mt)->declaration().is(T::Class())) {
|
||||
return std::make_pair(surface_style, (T*)*mt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0, 0);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::pair<IfcSchema::IfcSurfaceStyle*, T*> get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) {
|
||||
// For certain representation items, most notably boolean operands,
|
||||
// a style definition might reside on one of its operands.
|
||||
representation_item = find_item_carrying_style(representation_item);
|
||||
|
||||
if (representation_item->as<IfcSchema::IfcStyledItem>()) {
|
||||
return _get_surface_style<T>(representation_item->as<IfcSchema::IfcStyledItem>());
|
||||
}
|
||||
IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem();
|
||||
if (styled_items->size()) {
|
||||
// StyledByItem is a SET [0:1] OF IfcStyledItem, so we return after the first IfcStyledItem:
|
||||
return _get_surface_style<T>(*styled_items->begin());
|
||||
}
|
||||
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0, 0);
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourRgb* colour, double* rgb) {
|
||||
if (colour != 0) {
|
||||
rgb[0] = colour->Red();
|
||||
rgb[1] = colour->Green();
|
||||
rgb[2] = colour->Blue();
|
||||
}
|
||||
return colour != 0;
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, double* rgb) {
|
||||
if (factor != 0) {
|
||||
const double f = *factor;
|
||||
rgb[0] = rgb[1] = rgb[2] = f;
|
||||
}
|
||||
return factor != 0;
|
||||
}
|
||||
|
||||
bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, double* rgb) {
|
||||
if (colour_or_factor == 0) {
|
||||
return false;
|
||||
} else if (colour_or_factor->declaration().is(IfcSchema::IfcColourRgb::Class())) {
|
||||
return process_colour(static_cast<IfcSchema::IfcColourRgb*>(colour_or_factor), rgb);
|
||||
} else if (colour_or_factor->declaration().is(IfcSchema::IfcNormalisedRatioMeasure::Class())) {
|
||||
return process_colour(static_cast<IfcSchema::IfcNormalisedRatioMeasure*>(colour_or_factor), rgb);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::AbstractKernel::get_style(const IfcSchema::IfcRepresentationItem* item) {
|
||||
return internalize_surface_style(get_surface_style<IfcSchema::IfcSurfaceStyleShading>(item));
|
||||
}
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::AbstractKernel::get_style(const IfcSchema::IfcMaterial* material) {
|
||||
IfcSchema::IfcMaterialDefinitionRepresentation::list::ptr defs = material->HasRepresentation();
|
||||
for (IfcSchema::IfcMaterialDefinitionRepresentation::list::it jt = defs->begin(); jt != defs->end(); ++jt) {
|
||||
IfcSchema::IfcRepresentation::list::ptr reps = (*jt)->Representations();
|
||||
IfcSchema::IfcStyledItem::list::ptr styles(new IfcSchema::IfcStyledItem::list);
|
||||
for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) {
|
||||
styles->push((**it).Items()->as<IfcSchema::IfcStyledItem>());
|
||||
}
|
||||
for (IfcSchema::IfcStyledItem::list::it it = styles->begin(); it != styles->end(); ++it) {
|
||||
const std::pair<IfcSchema::IfcSurfaceStyle*, IfcSchema::IfcSurfaceStyleShading*> ss = get_surface_style<IfcSchema::IfcSurfaceStyleShading>(*it);
|
||||
if (ss.second) {
|
||||
return internalize_surface_style(ss);
|
||||
}
|
||||
}
|
||||
}
|
||||
IfcGeom::SurfaceStyle material_style = IfcGeom::SurfaceStyle(material->data().id(), material->Name());
|
||||
return &(style_cache[material->data().id()] = material_style);
|
||||
}
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::AbstractKernel::internalize_surface_style(const std::pair<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*>& shading_styles) {
|
||||
if (shading_styles.second == 0) {
|
||||
return 0;
|
||||
}
|
||||
int surface_style_id = shading_styles.first->data().id();
|
||||
std::map<int, SurfaceStyle>::const_iterator it = style_cache.find(surface_style_id);
|
||||
if (it != style_cache.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
SurfaceStyle surface_style;
|
||||
|
||||
IfcSchema::IfcSurfaceStyle* style = shading_styles.first->as<IfcSchema::IfcSurfaceStyle>();
|
||||
IfcSchema::IfcSurfaceStyleShading* shading = shading_styles.second->as<IfcSchema::IfcSurfaceStyleShading>();
|
||||
|
||||
if (style->hasName()) {
|
||||
surface_style = SurfaceStyle(surface_style_id, style->Name());
|
||||
} else {
|
||||
surface_style = SurfaceStyle(surface_style_id);
|
||||
}
|
||||
double rgb[3];
|
||||
if (process_colour(shading->SurfaceColour(), rgb)) {
|
||||
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
|
||||
}
|
||||
if (shading_styles.second->declaration().is(IfcSchema::IfcSurfaceStyleRendering::Class())) {
|
||||
IfcSchema::IfcSurfaceStyleRendering* rendering_style = static_cast<IfcSchema::IfcSurfaceStyleRendering*>(shading_styles.second);
|
||||
if (rendering_style->hasDiffuseColour() && process_colour(rendering_style->DiffuseColour(), rgb)) {
|
||||
SurfaceStyle::ColorComponent diffuse = surface_style.Diffuse().get_value_or(SurfaceStyle::ColorComponent(1, 1, 1));
|
||||
surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(diffuse.R() * rgb[0], diffuse.G() * rgb[1], diffuse.B() * rgb[2]));
|
||||
}
|
||||
if (rendering_style->hasDiffuseTransmissionColour()) {
|
||||
// Not supported
|
||||
}
|
||||
if (rendering_style->hasReflectionColour()) {
|
||||
// Not supported
|
||||
}
|
||||
if (rendering_style->hasSpecularColour() && process_colour(rendering_style->SpecularColour(), rgb)) {
|
||||
surface_style.Specular().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
|
||||
}
|
||||
if (rendering_style->hasSpecularHighlight()) {
|
||||
IfcSchema::IfcSpecularHighlightSelect* highlight = rendering_style->SpecularHighlight();
|
||||
if (highlight->declaration().is(IfcSchema::IfcSpecularRoughness::Class())) {
|
||||
double roughness = *((IfcSchema::IfcSpecularRoughness*)highlight);
|
||||
if (roughness >= 1e-9) {
|
||||
surface_style.Specularity().reset(1.0 / roughness);
|
||||
}
|
||||
} else if (highlight->declaration().is(IfcSchema::IfcSpecularExponent::Class())) {
|
||||
surface_style.Specularity().reset(*((IfcSchema::IfcSpecularExponent*)highlight));
|
||||
}
|
||||
}
|
||||
if (rendering_style->hasTransmissionColour()) {
|
||||
// Not supported
|
||||
}
|
||||
if (rendering_style->hasTransparency()) {
|
||||
const double d = rendering_style->Transparency();
|
||||
surface_style.Transparency().reset(d);
|
||||
}
|
||||
}
|
||||
return &(style_cache[surface_style_id] = surface_style);
|
||||
}
|
||||
|
||||
|
||||
template <typename P, typename PP>
|
||||
IfcGeom::NativeElement<P, PP>* IfcGeom::AbstractKernel::create_brep_for_representation_and_product(
|
||||
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product) {
|
||||
std::stringstream representation_id_builder;
|
||||
|
||||
representation_id_builder << representation->data().id();
|
||||
|
||||
IfcGeom::Representation::BRep* shape;
|
||||
IfcGeom::ConversionResults shapes;
|
||||
|
||||
if (!convert_shapes(representation, shapes)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (settings.get(IteratorSettings::APPLY_LAYERSETS)) {
|
||||
if (apply_layerset(product, shapes)) {
|
||||
|
||||
IfcSchema::IfcRelAssociates::list::ptr associations = product->HasAssociations();
|
||||
for (IfcSchema::IfcRelAssociates::list::it it = associations->begin(); it != associations->end(); ++it) {
|
||||
IfcSchema::IfcRelAssociatesMaterial* associates_material = (**it).as<IfcSchema::IfcRelAssociatesMaterial>();
|
||||
if (associates_material) {
|
||||
unsigned layerset_id = associates_material->RelatingMaterial()->data().id();
|
||||
representation_id_builder << "-layerset-" << layerset_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool material_style_applied = false;
|
||||
|
||||
const IfcSchema::IfcMaterial* single_material = get_single_material_association(product);
|
||||
if (single_material) {
|
||||
const IfcGeom::SurfaceStyle* s = get_style(single_material);
|
||||
for (IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++it) {
|
||||
if (!it->hasStyle() && s) {
|
||||
it->setStyle(s);
|
||||
material_style_applied = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bool some_items_without_style = false;
|
||||
for (IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++it) {
|
||||
if (!it->hasStyle()) {
|
||||
some_items_without_style = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (some_items_without_style) {
|
||||
Logger::Warning("No material and surface styles for:", product);
|
||||
}
|
||||
}
|
||||
|
||||
if (material_style_applied) {
|
||||
representation_id_builder << "-material-" << single_material->data().id();
|
||||
}
|
||||
|
||||
int parent_id = -1;
|
||||
try {
|
||||
IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product);
|
||||
if (parent_object && parent_object->as<IfcSchema::IfcObjectDefinition>()) {
|
||||
parent_id = parent_object->data().id();
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
}
|
||||
|
||||
const std::string name = product->hasName() ? product->Name() : "";
|
||||
const std::string guid = product->GlobalId();
|
||||
|
||||
ConversionResultPlacement* trsf = nullptr;
|
||||
try {
|
||||
convert_placement(product->ObjectPlacement(), trsf);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
Logger::Error("Failed to construct placement");
|
||||
}
|
||||
|
||||
// Does the IfcElement have any IfcOpenings?
|
||||
// Note that openings for IfcOpeningElements are not processed
|
||||
IfcSchema::IfcRelVoidsElement::list::ptr openings = find_openings(product)->as<IfcSchema::IfcRelVoidsElement>();
|
||||
|
||||
const std::string product_type = product->declaration().name();
|
||||
ElementSettings element_settings(settings, getValue(GV_LENGTH_UNIT), product_type);
|
||||
|
||||
if (!settings.get(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && openings && openings->size()) {
|
||||
representation_id_builder << "-openings";
|
||||
for (IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++it) {
|
||||
representation_id_builder << "-" << (*it)->data().id();
|
||||
}
|
||||
|
||||
IfcGeom::ConversionResults opened_shapes;
|
||||
bool caught_error = false;
|
||||
try {
|
||||
convert_openings(product, openings, shapes, trsf, opened_shapes);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Message(Logger::LOG_ERROR, std::string("Error processing openings for: ") + e.what() + ":", product);
|
||||
caught_error = true;
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Error processing openings for:", product);
|
||||
}
|
||||
|
||||
if (caught_error && opened_shapes.size() < shapes.size()) {
|
||||
opened_shapes = shapes;
|
||||
}
|
||||
|
||||
if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
|
||||
for (IfcGeom::ConversionResults::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++it) {
|
||||
it->prepend(trsf);
|
||||
}
|
||||
trsf = nullptr;
|
||||
representation_id_builder << "-world-coords";
|
||||
}
|
||||
shape = new IfcGeom::Representation::BRep(element_settings, representation_id_builder.str(), opened_shapes);
|
||||
} else if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
|
||||
for (IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++it) {
|
||||
it->prepend(trsf);
|
||||
}
|
||||
trsf = nullptr;
|
||||
representation_id_builder << "-world-coords";
|
||||
shape = new IfcGeom::Representation::BRep(element_settings, representation_id_builder.str(), shapes);
|
||||
} else {
|
||||
shape = new IfcGeom::Representation::BRep(element_settings, representation_id_builder.str(), shapes);
|
||||
}
|
||||
|
||||
std::string context_string = "";
|
||||
if (representation->hasRepresentationIdentifier()) {
|
||||
context_string = representation->RepresentationIdentifier();
|
||||
} else if (representation->ContextOfItems()->hasContextType()) {
|
||||
context_string = representation->ContextOfItems()->ContextType();
|
||||
}
|
||||
|
||||
auto elem = new NativeElement<P, PP>(
|
||||
product->data().id(),
|
||||
parent_id,
|
||||
name,
|
||||
product_type,
|
||||
guid,
|
||||
context_string,
|
||||
trsf,
|
||||
boost::shared_ptr<IfcGeom::Representation::BRep>(shape),
|
||||
product
|
||||
);
|
||||
|
||||
if (settings.get(IteratorSettings::VALIDATE_QUANTITIES)) {
|
||||
validate_quantities(product, elem->geometry());
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
template <typename P, typename PP>
|
||||
IfcGeom::NativeElement<P, PP>* IfcGeom::AbstractKernel::create_brep_for_processed_representation(
|
||||
const IteratorSettings& /*settings*/, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product,
|
||||
IfcGeom::NativeElement<P, PP>* brep) {
|
||||
int parent_id = -1;
|
||||
try {
|
||||
IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product);
|
||||
if (parent_object && parent_object->as<IfcSchema::IfcObjectDefinition>()) {
|
||||
parent_id = parent_object->data().id();
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
}
|
||||
|
||||
const std::string name = product->hasName() ? product->Name() : "";
|
||||
const std::string guid = product->GlobalId();
|
||||
|
||||
ConversionResultPlacement* trsf = nullptr;
|
||||
try {
|
||||
convert_placement(product->ObjectPlacement(), trsf);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
Logger::Error("Failed to construct placement");
|
||||
}
|
||||
|
||||
std::string context_string = "";
|
||||
if (representation->hasRepresentationIdentifier()) {
|
||||
context_string = representation->RepresentationIdentifier();
|
||||
} else if (representation->ContextOfItems()->hasContextType()) {
|
||||
context_string = representation->ContextOfItems()->ContextType();
|
||||
}
|
||||
|
||||
const std::string product_type = product->declaration().name();
|
||||
|
||||
return new NativeElement<P, PP>(
|
||||
product->data().id(),
|
||||
parent_id,
|
||||
name,
|
||||
product_type,
|
||||
guid,
|
||||
context_string,
|
||||
trsf,
|
||||
brep->geometry_pointer(),
|
||||
product
|
||||
);
|
||||
}
|
||||
|
||||
template IFC_GEOM_API IfcGeom::NativeElement<float, float>* IfcGeom::AbstractKernel::create_brep_for_representation_and_product<float, float>(
|
||||
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product);
|
||||
template IFC_GEOM_API IfcGeom::NativeElement<float, double>* IfcGeom::AbstractKernel::create_brep_for_representation_and_product<float, double>(
|
||||
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product);
|
||||
template IFC_GEOM_API IfcGeom::NativeElement<double, double>* IfcGeom::AbstractKernel::create_brep_for_representation_and_product<double, double>(
|
||||
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product);
|
||||
|
||||
template IFC_GEOM_API IfcGeom::NativeElement<float, float>* IfcGeom::AbstractKernel::create_brep_for_processed_representation<float, float>(
|
||||
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement<float, float>* brep);
|
||||
template IFC_GEOM_API IfcGeom::NativeElement<float, double>* IfcGeom::AbstractKernel::create_brep_for_processed_representation<float, double>(
|
||||
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement<float, double>* brep);
|
||||
template IFC_GEOM_API IfcGeom::NativeElement<double, double>* IfcGeom::AbstractKernel::create_brep_for_processed_representation<double, double>(
|
||||
const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement<double, double>* brep);
|
||||
@@ -0,0 +1,77 @@
|
||||
#ifndef ABSTRACT_KERNEL_H
|
||||
#define ABSTRACT_KERNEL_H
|
||||
|
||||
#include "../../ifcparse/macros.h"
|
||||
#include "../../ifcgeom/schema_agnostic/ifc_geom_api.h"
|
||||
#include "../../ifcgeom/schema_agnostic/Kernel.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
|
||||
|
||||
#define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x.h)
|
||||
#include INCLUDE_SCHEMA(IfcSchema)
|
||||
#undef INCLUDE_SCHEMA
|
||||
#define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x-definitions.h)
|
||||
#include INCLUDE_SCHEMA(IfcSchema)
|
||||
#undef INCLUDE_SCHEMA
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
class IFC_GEOM_API MAKE_TYPE_NAME(AbstractKernel) : public IfcGeom::Kernel {
|
||||
protected:
|
||||
// For stopping PlacementRelTo recursion in convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf)
|
||||
const IfcParse::declaration* placement_rel_to;
|
||||
|
||||
double deflection_tolerance;
|
||||
double wire_creation_tolerance;
|
||||
double point_equality_tolerance;
|
||||
double max_faces_to_sew;
|
||||
double ifc_length_unit;
|
||||
double ifc_planeangle_unit;
|
||||
double modelling_precision;
|
||||
double dimensionality;
|
||||
|
||||
std::map<int, SurfaceStyle> style_cache;
|
||||
|
||||
public:
|
||||
MAKE_TYPE_NAME(AbstractKernel)(const std::string& geometry_library)
|
||||
: IfcGeom::Kernel(geometry_library, nullptr)
|
||||
, deflection_tolerance(0.001)
|
||||
, wire_creation_tolerance(0.0001)
|
||||
, point_equality_tolerance(0.00001)
|
||||
, max_faces_to_sew(-1.0)
|
||||
, ifc_length_unit(1.0)
|
||||
, ifc_planeangle_unit(-1.0)
|
||||
, modelling_precision(0.00001)
|
||||
, dimensionality(1.)
|
||||
, placement_rel_to(0)
|
||||
{}
|
||||
|
||||
void set_conversion_placement_rel_to(const IfcParse::declaration* type);
|
||||
virtual void setValue(GeomValue var, double value);
|
||||
virtual double getValue(GeomValue var) const;
|
||||
|
||||
const IfcSchema::IfcMaterial* get_single_material_association(const IfcSchema::IfcProduct*);
|
||||
IfcSchema::IfcRepresentation* representation_mapped_to(const IfcSchema::IfcRepresentation* representation);
|
||||
IfcSchema::IfcProduct::list::ptr products_represented_by(const IfcSchema::IfcRepresentation*);
|
||||
const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem*);
|
||||
const SurfaceStyle* get_style(const IfcSchema::IfcMaterial*);
|
||||
|
||||
virtual bool is_identity_transform(const IfcUtil::IfcBaseClass*) = 0;
|
||||
virtual bool convert_shapes(const IfcUtil::IfcBaseClass*, IfcGeom::ConversionResults&) = 0;
|
||||
virtual bool apply_layerset(const IfcSchema::IfcProduct* product, IfcGeom::ConversionResults& shapes) = 0;
|
||||
virtual bool validate_quantities(const IfcSchema::IfcProduct* product, const IfcGeom::Representation::BRep& brep) = 0;
|
||||
virtual bool convert_openings(const IfcSchema::IfcProduct* product, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcGeom::ConversionResults& shapes, const ConversionResultPlacement* trsf, IfcGeom::ConversionResults& opened_shapes) = 0;
|
||||
|
||||
const SurfaceStyle* internalize_surface_style(const std::pair<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*>& shading_style);
|
||||
|
||||
template <typename P, typename PP>
|
||||
IfcGeom::NativeElement<P, PP>* create_brep_for_representation_and_product(
|
||||
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*);
|
||||
|
||||
template <typename P, typename PP>
|
||||
IfcGeom::NativeElement<P, PP>* create_brep_for_processed_representation(
|
||||
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::NativeElement<P, PP>*);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+2
-3
@@ -1,5 +1,4 @@
|
||||
#include "IfcGeomIteratorImplementation.h"
|
||||
#include "../ifcgeom_schema_agnostic/IteratorImplementation.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
template class MAKE_TYPE_NAME(IteratorImplementation_)<float, float>;
|
||||
@@ -14,8 +13,8 @@ namespace IfcGeom {
|
||||
namespace {
|
||||
template <typename P, typename PP>
|
||||
struct MAKE_TYPE_NAME(factory_t) {
|
||||
IfcGeom::IteratorImplementation<P, PP>* operator()(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads) const {
|
||||
return new IfcGeom::MAKE_TYPE_NAME(IteratorImplementation_)<P, PP>(settings, file, filters, num_threads);
|
||||
IfcGeom::IteratorImplementation<P, PP>* operator()(const std::string& geometry_engine, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads) const {
|
||||
return new IfcGeom::MAKE_TYPE_NAME(IteratorImplementation_)<P, PP>(geometry_engine, settings, file, filters, num_threads);
|
||||
}
|
||||
};
|
||||
}
|
||||
+67
-105
@@ -78,16 +78,22 @@
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../../ifcparse/macros.h"
|
||||
#include "../../ifcparse/IfcFile.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h"
|
||||
#include "../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
#include "../ifcgeom/IfcRepresentationShapeItem.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomElement.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomMaterial.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
|
||||
#include "../../ifcgeom/schema_agnostic/ConversionResult.h"
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomFilter.h"
|
||||
#include "../ifcgeom_schema_agnostic/IteratorImplementation.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomFilter.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IteratorImplementation.h"
|
||||
|
||||
#include "../../ifcgeom/kernel_agnostic/AbstractKernel.h"
|
||||
|
||||
#define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x.h)
|
||||
#include INCLUDE_SCHEMA(IfcSchema)
|
||||
#undef INCLUDE_SCHEMA
|
||||
|
||||
#include <atomic>
|
||||
|
||||
@@ -105,14 +111,14 @@ namespace {
|
||||
int index;
|
||||
IfcSchema::IfcRepresentation *representation;
|
||||
IfcSchema::IfcProduct::list::ptr products;
|
||||
std::vector<IfcGeom::BRepElement<P, PP>*> breps;
|
||||
std::vector<IfcGeom::NativeElement<P, PP>*> breps;
|
||||
std::vector<IfcGeom::Element<P, PP>*> elements;
|
||||
};
|
||||
|
||||
template <typename P, typename PP=P>
|
||||
IfcGeom::Element<P, PP>* process_based_on_settings(
|
||||
const IfcGeom::IteratorSettings& settings,
|
||||
IfcGeom::BRepElement<P, PP>* elem,
|
||||
IfcGeom::NativeElement<P, PP>* elem,
|
||||
IfcGeom::TriangulationElement<P, PP>* previous=nullptr)
|
||||
{
|
||||
if (settings.get(IfcGeom::IteratorSettings::USE_BREP_DATA)) {
|
||||
@@ -140,7 +146,7 @@ namespace {
|
||||
|
||||
template <typename P, typename PP = P>
|
||||
void create_element(
|
||||
IfcGeom::MAKE_TYPE_NAME(Kernel)* kernel,
|
||||
IfcGeom::MAKE_TYPE_NAME(AbstractKernel)* kernel,
|
||||
const IfcGeom::IteratorSettings& settings,
|
||||
geometry_conversion_task<P, PP>* rep)
|
||||
{
|
||||
@@ -182,14 +188,16 @@ namespace IfcGeom {
|
||||
std::atomic<int> progress_;
|
||||
std::vector<geometry_conversion_task<P, PP>> tasks_;
|
||||
std::vector<IfcGeom::Element<P, PP>*> all_processed_elements_;
|
||||
std::vector<IfcGeom::BRepElement<P, PP>*> all_processed_native_elements_;
|
||||
std::vector<IfcGeom::NativeElement<P, PP>*> all_processed_native_elements_;
|
||||
typename std::vector<IfcGeom::Element<P, PP>*>::const_iterator task_result_iterator_;
|
||||
typename std::vector<IfcGeom::BRepElement<P, PP>*>::const_iterator native_task_result_iterator_;
|
||||
typename std::vector<IfcGeom::NativeElement<P, PP>*>::const_iterator native_task_result_iterator_;
|
||||
|
||||
std::string geometry_library_;
|
||||
|
||||
MAKE_TYPE_NAME(IteratorImplementation_)(const MAKE_TYPE_NAME(IteratorImplementation_)&); // N/I
|
||||
MAKE_TYPE_NAME(IteratorImplementation_)& operator=(const MAKE_TYPE_NAME(IteratorImplementation_)&); // N/I
|
||||
|
||||
MAKE_TYPE_NAME(Kernel) kernel;
|
||||
MAKE_TYPE_NAME(AbstractKernel)* kernel;
|
||||
IteratorSettings settings;
|
||||
|
||||
IfcParse::IfcFile* ifc_file;
|
||||
@@ -200,7 +208,7 @@ namespace IfcGeom {
|
||||
|
||||
// The object is fetched beforehand to be sure that get() returns a valid element
|
||||
TriangulationElement<P, PP>* current_triangulation;
|
||||
BRepElement<P, PP>* current_shape_model;
|
||||
NativeElement<P, PP>* current_shape_model;
|
||||
SerializedElement<P, PP>* current_serialization;
|
||||
|
||||
// A container and iterator for IfcBuildingElements for the current IfcRepresentation referenced by *representation_iterator
|
||||
@@ -229,29 +237,12 @@ namespace IfcGeom {
|
||||
IfcSchema::IfcProduct* product;
|
||||
};
|
||||
|
||||
void initUnits() {
|
||||
IfcSchema::IfcProject::list::ptr projects = ifc_file->instances_by_type<IfcSchema::IfcProject>();
|
||||
if (projects->size() == 1) {
|
||||
IfcSchema::IfcProject* project = *projects->begin();
|
||||
std::pair<std::string, double> length_unit = kernel.initializeUnits(project->UnitsInContext());
|
||||
unit_name = length_unit.first;
|
||||
unit_magnitude = length_unit.second;
|
||||
} else {
|
||||
Logger::Warning("A single IfcProject is expected (encountered " + boost::lexical_cast<std::string>(projects->size()) + "); unable to read unit information.");
|
||||
}
|
||||
}
|
||||
|
||||
/// @todo public/private sections all over the place: move all public to the beginning of the class
|
||||
public:
|
||||
typedef P Precision;
|
||||
typedef PP PlacementPrecision;
|
||||
|
||||
bool initialize() {
|
||||
try {
|
||||
initUnits();
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
}
|
||||
|
||||
std::set<std::string> allowed_context_types;
|
||||
allowed_context_types.insert("model");
|
||||
@@ -273,9 +264,6 @@ namespace IfcGeom {
|
||||
context_types.insert("plan");
|
||||
}
|
||||
|
||||
double lowest_precision_encountered = std::numeric_limits<double>::infinity();
|
||||
bool any_precision_encountered = false;
|
||||
|
||||
representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
|
||||
ok_mapped_representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list);
|
||||
|
||||
@@ -325,15 +313,7 @@ namespace IfcGeom {
|
||||
IfcSchema::IfcGeometricRepresentationContext* context = *it;
|
||||
|
||||
representations->push(context->RepresentationsInContext());
|
||||
try {
|
||||
if (context->hasPrecision() && context->Precision() < lowest_precision_encountered) {
|
||||
lowest_precision_encountered = context->Precision();
|
||||
any_precision_encountered = true;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
}
|
||||
|
||||
|
||||
IfcSchema::IfcGeometricRepresentationSubContext::list::ptr sub_contexts = context->HasSubContexts();
|
||||
for (jt = sub_contexts->begin(); jt != sub_contexts->end(); ++jt) {
|
||||
representations->push((*jt)->RepresentationsInContext());
|
||||
@@ -342,21 +322,6 @@ namespace IfcGeom {
|
||||
// WR31: The parent context shall not be another geometric representation sub context.
|
||||
}
|
||||
|
||||
if (any_precision_encountered) {
|
||||
// Some arbitrary factor that has proven to work better for the models in the set of test files.
|
||||
lowest_precision_encountered *= 10.;
|
||||
|
||||
lowest_precision_encountered *= unit_magnitude;
|
||||
if (lowest_precision_encountered < 1.e-7) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Precision lower than 0.0000001 meter not enforced");
|
||||
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-7);
|
||||
} else {
|
||||
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, lowest_precision_encountered);
|
||||
}
|
||||
} else {
|
||||
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-5);
|
||||
}
|
||||
|
||||
if (representations->size() == 0) {
|
||||
Logger::Warning("No representations encountered in relevant contexts, using all");
|
||||
representations = ifc_file->instances_by_type<IfcSchema::IfcRepresentation>();
|
||||
@@ -412,10 +377,10 @@ namespace IfcGeom {
|
||||
conc_threads = tasks_.size();
|
||||
}
|
||||
|
||||
std::vector<MAKE_TYPE_NAME(Kernel)*> kernel_pool;
|
||||
std::vector<MAKE_TYPE_NAME(AbstractKernel)*> kernel_pool;
|
||||
kernel_pool.reserve(conc_threads);
|
||||
for (unsigned i = 0; i < conc_threads; ++i) {
|
||||
kernel_pool.push_back(new MAKE_TYPE_NAME(Kernel)(kernel));
|
||||
kernel_pool.push_back((MAKE_TYPE_NAME(AbstractKernel)*) impl::kernel_implementations().construct(ifc_file->schema()->name(), geometry_library_, ifc_file));
|
||||
}
|
||||
|
||||
std::vector<std::future<void>> threadpool;
|
||||
@@ -426,7 +391,7 @@ namespace IfcGeom {
|
||||
Logger::ProgressBar(0);
|
||||
|
||||
for (auto& rep : tasks_) {
|
||||
MAKE_TYPE_NAME(Kernel)* K = nullptr;
|
||||
MAKE_TYPE_NAME(AbstractKernel)* K = nullptr;
|
||||
if (threadpool.size() < kernel_pool.size()) {
|
||||
K = kernel_pool[threadpool.size()];
|
||||
}
|
||||
@@ -496,11 +461,11 @@ namespace IfcGeom {
|
||||
IfcSchema::IfcProduct* product = *iter;
|
||||
if (product->hasObjectPlacement()) {
|
||||
// Use a fresh trsf every time in order to prevent the result to be concatenated
|
||||
gp_Trsf trsf;
|
||||
ConversionResultPlacement* trsf;
|
||||
bool success = false;
|
||||
|
||||
try {
|
||||
success = kernel.convert(product->ObjectPlacement(), trsf);
|
||||
success = kernel->convert_placement(product->ObjectPlacement(), trsf);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
@@ -511,13 +476,14 @@ namespace IfcGeom {
|
||||
continue;
|
||||
}
|
||||
|
||||
const gp_XYZ& pos = trsf.TranslationPart();
|
||||
bounds_min_.SetX(std::min(bounds_min_.X(), pos.X()));
|
||||
bounds_min_.SetY(std::min(bounds_min_.Y(), pos.Y()));
|
||||
bounds_min_.SetZ(std::min(bounds_min_.Z(), pos.Z()));
|
||||
bounds_max_.SetX(std::max(bounds_max_.X(), pos.X()));
|
||||
bounds_max_.SetY(std::max(bounds_max_.Y(), pos.Y()));
|
||||
bounds_max_.SetZ(std::max(bounds_max_.Z(), pos.Z()));
|
||||
double X, Y, Z;
|
||||
trsf->TranslationPart(X, Y, Z);
|
||||
bounds_min_.SetX(std::min(bounds_min_.X(), X));
|
||||
bounds_min_.SetY(std::min(bounds_min_.Y(), Y));
|
||||
bounds_min_.SetZ(std::min(bounds_min_.Z(), Z));
|
||||
bounds_max_.SetX(std::max(bounds_max_.X(), X));
|
||||
bounds_max_.SetY(std::max(bounds_max_.Y(), Y));
|
||||
bounds_max_.SetZ(std::max(bounds_max_.Z(), Z));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -548,13 +514,6 @@ namespace IfcGeom {
|
||||
private:
|
||||
// Move to the next IfcRepresentation
|
||||
void _nextShape() {
|
||||
// In order to conserve memory and reduce cache insertion times, the cache is
|
||||
// cleared after an arbitrary number of processed representations. This has been
|
||||
// benchmarked extensively: https://github.com/IfcOpenShell/IfcOpenShell/pull/47
|
||||
static const int clear_interval = 64;
|
||||
if (done % clear_interval == clear_interval - 1) {
|
||||
kernel.purge_cache();
|
||||
}
|
||||
ifcproducts.reset();
|
||||
++ representation_iterator;
|
||||
++ done;
|
||||
@@ -574,7 +533,7 @@ namespace IfcGeom {
|
||||
for (IfcSchema::IfcProduct::list::it it = products->begin(); it != products->end(); ++it) {
|
||||
IfcSchema::IfcProduct* product = *it;
|
||||
|
||||
if (!settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && kernel.find_openings(product)->size()) {
|
||||
if (!settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && kernel->find_openings(product)->size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -592,7 +551,7 @@ namespace IfcGeom {
|
||||
}
|
||||
|
||||
// Note that this can be a nullptr (!), but the fact that set size should be one still holds
|
||||
associated_single_materials.insert(kernel.get_single_material_association(product));
|
||||
associated_single_materials.insert(kernel->get_single_material_association(product));
|
||||
if (associated_single_materials.size() > 1) return false;
|
||||
}
|
||||
|
||||
@@ -612,14 +571,14 @@ namespace IfcGeom {
|
||||
if (!ifcproducts) {
|
||||
// Init. the list of filtered IfcProducts for this representation
|
||||
ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list);
|
||||
IfcSchema::IfcProduct::list::ptr unfiltered_products = kernel.products_represented_by(representation);
|
||||
// Include only the desired products for processing.
|
||||
for (IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin(); jt != unfiltered_products->end(); ++jt) {
|
||||
IfcSchema::IfcProduct* prod = *jt;
|
||||
if (boost::all(filters_, filter_match(prod))) {
|
||||
ifcproducts->push(prod);
|
||||
}
|
||||
}
|
||||
IfcSchema::IfcProduct::list::ptr unfiltered_products = kernel->products_represented_by(representation);
|
||||
// Include only the desired products for processing.
|
||||
for (IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin(); jt != unfiltered_products->end(); ++jt) {
|
||||
IfcSchema::IfcProduct* prod = *jt;
|
||||
if (boost::all(filters_, filter_match(prod))) {
|
||||
ifcproducts->push(prod);
|
||||
}
|
||||
}
|
||||
|
||||
if (ifcproducts->size() == 0) {
|
||||
_nextShape();
|
||||
@@ -646,10 +605,10 @@ namespace IfcGeom {
|
||||
|
||||
// Check if this represenation has (or will be) processed as part its mapped representation
|
||||
bool representation_processed_as_mapped_item = false;
|
||||
IfcSchema::IfcRepresentation* representation_mapped_to = kernel.representation_mapped_to(representation);
|
||||
IfcSchema::IfcRepresentation* representation_mapped_to = kernel->representation_mapped_to(representation);
|
||||
if (representation_mapped_to) {
|
||||
representation_processed_as_mapped_item = geometry_reuse_ok_for_current_representation_ && (
|
||||
ok_mapped_representations->contains(representation_mapped_to) || reuse_ok_(kernel.products_represented_by(representation_mapped_to)));
|
||||
representation_processed_as_mapped_item = geometry_reuse_ok_for_current_representation_ && (
|
||||
ok_mapped_representations->contains(representation_mapped_to) || reuse_ok_(kernel->products_represented_by(representation_mapped_to)));
|
||||
}
|
||||
|
||||
if (representation_processed_as_mapped_item) {
|
||||
@@ -674,7 +633,7 @@ namespace IfcGeom {
|
||||
}
|
||||
}
|
||||
|
||||
BRepElement<P, PP>* create_shape_model_for_next_entity() {
|
||||
NativeElement<P, PP>* create_shape_model_for_next_entity() {
|
||||
for (;;) {
|
||||
auto rp = get_next_task();
|
||||
if (!rp) {
|
||||
@@ -685,11 +644,11 @@ namespace IfcGeom {
|
||||
|
||||
Logger::SetProduct(product);
|
||||
|
||||
BRepElement<P, PP>* element;
|
||||
NativeElement<P, PP>* element;
|
||||
if (ifcproduct_iterator == ifcproducts->begin() || !geometry_reuse_ok_for_current_representation_) {
|
||||
element = kernel.create_brep_for_representation_and_product<P, PP>(settings, representation, product);
|
||||
element = kernel->create_brep_for_representation_and_product<P, PP>(settings, representation, product);
|
||||
} else {
|
||||
element = kernel.create_brep_for_processed_representation(settings, representation, product, current_shape_model);
|
||||
element = kernel->create_brep_for_processed_representation(settings, representation, product, current_shape_model);
|
||||
}
|
||||
|
||||
Logger::SetProduct(boost::none);
|
||||
@@ -818,7 +777,7 @@ namespace IfcGeom {
|
||||
}
|
||||
|
||||
/// Gets the native (Open Cascade) representation of the current geometrical entity.
|
||||
BRepElement<P, PP>* get_native()
|
||||
NativeElement<P, PP>* get_native()
|
||||
{
|
||||
// TODO: Test settings and throw
|
||||
if (num_threads_ != 1) {
|
||||
@@ -829,7 +788,7 @@ namespace IfcGeom {
|
||||
}
|
||||
|
||||
const Element<P, PP>* get_object(int id) {
|
||||
gp_Trsf trsf;
|
||||
ConversionResultPlacement* trsf;
|
||||
int parent_id = -1;
|
||||
std::string instance_type, product_name, product_guid;
|
||||
IfcSchema::IfcProduct* ifc_product = 0;
|
||||
@@ -848,7 +807,7 @@ namespace IfcGeom {
|
||||
ifc_product = ifc_entity->as<IfcSchema::IfcProduct>();
|
||||
parent_id = -1;
|
||||
try {
|
||||
IfcSchema::IfcObjectDefinition* parent_object = kernel.get_decomposing_entity(ifc_product)->template as<IfcSchema::IfcObjectDefinition>();
|
||||
IfcSchema::IfcObjectDefinition* parent_object = kernel->get_decomposing_entity(ifc_product)->template as<IfcSchema::IfcObjectDefinition>();
|
||||
if (parent_object) {
|
||||
parent_id = parent_object->data().id();
|
||||
}
|
||||
@@ -859,7 +818,7 @@ namespace IfcGeom {
|
||||
}
|
||||
|
||||
try {
|
||||
kernel.convert(ifc_product->ObjectPlacement(), trsf);
|
||||
kernel->convert_placement(ifc_product->ObjectPlacement(), trsf);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
@@ -885,7 +844,7 @@ namespace IfcGeom {
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* create() {
|
||||
IfcGeom::BRepElement<P, PP>* next_shape_model = 0;
|
||||
IfcGeom::NativeElement<P, PP>* next_shape_model = 0;
|
||||
IfcGeom::SerializedElement<P, PP>* next_serialization = 0;
|
||||
IfcGeom::TriangulationElement<P, PP>* next_triangulation = 0;
|
||||
|
||||
@@ -940,28 +899,31 @@ namespace IfcGeom {
|
||||
unit_name = "METER";
|
||||
unit_magnitude = 1.f;
|
||||
|
||||
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_ORIENT, settings.get(IteratorSettings::SEW_SHELLS) ? std::numeric_limits<double>::infinity() : -1);
|
||||
kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.get(IteratorSettings::INCLUDE_CURVES)
|
||||
kernel->setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_ORIENT, settings.get(IteratorSettings::SEW_SHELLS) ? std::numeric_limits<double>::infinity() : -1);
|
||||
kernel->setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.get(IteratorSettings::INCLUDE_CURVES)
|
||||
? (settings.get(IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES) ? -1. : 0.) : +1.));
|
||||
if (settings.get(IteratorSettings::BUILDING_LOCAL_PLACEMENT)) {
|
||||
if (settings.get(IteratorSettings::SITE_LOCAL_PLACEMENT)) {
|
||||
Logger::Message(Logger::LOG_WARNING, "building-local-placement takes precedence over site-local-placement");
|
||||
}
|
||||
kernel.set_conversion_placement_rel_to(&IfcSchema::IfcBuilding::Class());
|
||||
kernel->set_conversion_placement_rel_to(&IfcSchema::IfcBuilding::Class());
|
||||
} else if (settings.get(IteratorSettings::SITE_LOCAL_PLACEMENT)) {
|
||||
kernel.set_conversion_placement_rel_to(&IfcSchema::IfcSite::Class());
|
||||
kernel->set_conversion_placement_rel_to(&IfcSchema::IfcSite::Class());
|
||||
}
|
||||
}
|
||||
|
||||
bool owns_ifc_file;
|
||||
public:
|
||||
MAKE_TYPE_NAME(IteratorImplementation_)(const IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads)
|
||||
MAKE_TYPE_NAME(IteratorImplementation_)(const std::string& geometry_library, const IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads)
|
||||
: settings(settings)
|
||||
, ifc_file(file)
|
||||
, filters_(filters)
|
||||
, owns_ifc_file(false)
|
||||
, num_threads_(num_threads)
|
||||
, geometry_library_(geometry_library)
|
||||
{
|
||||
kernel = (MAKE_TYPE_NAME(AbstractKernel)*) impl::kernel_implementations().construct(file->schema()->name(), geometry_library, file);
|
||||
// kernel = new Kernel(geometry_library, file);
|
||||
_initialize();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
#include "CgalKernel.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h"
|
||||
|
||||
#define CgalKernel MAKE_TYPE_NAME(CgalKernel)
|
||||
|
||||
bool IfcGeom::CgalKernel::convert_wire_to_face(const cgal_wire_t& wire, cgal_face_t& face) {
|
||||
face.outer = wire;
|
||||
return true;
|
||||
}
|
||||
|
||||
void IfcGeom::CgalKernel::remove_duplicate_points_from_loop(cgal_wire_t& polygon) {
|
||||
std::set<cgal_point_t> points;
|
||||
for (int i = 0; i < polygon.size(); ++i) {
|
||||
if (points.count(polygon[i])) {
|
||||
polygon.erase(polygon.begin()+i);
|
||||
--i;
|
||||
} else points.insert(polygon[i]);
|
||||
}
|
||||
}
|
||||
|
||||
CGAL::Polyhedron_3<Kernel_> IfcGeom::CgalKernel::create_polyhedron(std::list<cgal_face_t> &face_list) {
|
||||
|
||||
// Naive creation
|
||||
CGAL::Polyhedron_3<Kernel_> polyhedron;
|
||||
PolyhedronBuilder builder(&face_list);
|
||||
polyhedron.delegate(builder);
|
||||
|
||||
// Stitch edges
|
||||
// std::cout << "Before: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl;
|
||||
CGAL::Polygon_mesh_processing::stitch_borders(polyhedron);
|
||||
if (!polyhedron.is_valid()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "create_polyhedron: Polyhedron not valid!");
|
||||
// std::ofstream fresult;
|
||||
// fresult.open("/Users/ken/Desktop/invalid.off");
|
||||
// fresult << polyhedron << std::endl;
|
||||
// fresult.close();
|
||||
return CGAL::Polyhedron_3<Kernel_>();
|
||||
} if (polyhedron.is_closed()) {
|
||||
if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) {
|
||||
CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron);
|
||||
}
|
||||
}
|
||||
|
||||
// std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl;
|
||||
|
||||
return polyhedron;
|
||||
}
|
||||
|
||||
CGAL::Polyhedron_3<Kernel_> IfcGeom::CgalKernel::create_polyhedron(CGAL::Nef_polyhedron_3<Kernel_> &nef_polyhedron) {
|
||||
if (nef_polyhedron.is_simple()) {
|
||||
try {
|
||||
CGAL::Polyhedron_3<Kernel_> polyhedron;
|
||||
nef_polyhedron.convert_to_polyhedron(polyhedron);
|
||||
return polyhedron;
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Conversion from Nef to polyhedron failed!");
|
||||
return CGAL::Polyhedron_3<Kernel_>();
|
||||
}
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Nef polyhedron not simple: cannot create polyhedron!");
|
||||
return CGAL::Polyhedron_3<Kernel_>();
|
||||
}
|
||||
}
|
||||
|
||||
CGAL::Nef_polyhedron_3<Kernel_> IfcGeom::CgalKernel::create_nef_polyhedron(std::list<cgal_face_t> &face_list) {
|
||||
CGAL::Polyhedron_3<Kernel_> polyhedron = create_polyhedron(face_list);
|
||||
CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron);
|
||||
CGAL::Nef_polyhedron_3<Kernel_> nef_polyhedron;
|
||||
try {
|
||||
nef_polyhedron = CGAL::Nef_polyhedron_3<Kernel_>(polyhedron);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef polyhedron failed!");
|
||||
return nef_polyhedron;
|
||||
} return nef_polyhedron;
|
||||
}
|
||||
|
||||
CGAL::Nef_polyhedron_3<Kernel_> IfcGeom::CgalKernel::create_nef_polyhedron(CGAL::Polyhedron_3<Kernel_> &polyhedron) {
|
||||
if (polyhedron.is_valid()) {
|
||||
CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron);
|
||||
CGAL::Nef_polyhedron_3<Kernel_> nef_polyhedron;
|
||||
try {
|
||||
nef_polyhedron = CGAL::Nef_polyhedron_3<Kernel_>(polyhedron);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef polyhedron failed!");
|
||||
return nef_polyhedron;
|
||||
} return nef_polyhedron;
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Polyhedron not valid: cannot create Nef polyhedron!");
|
||||
return CGAL::Nef_polyhedron_3<Kernel_>();
|
||||
}
|
||||
}
|
||||
|
||||
//CGAL::Polyhedron_3<Kernel_> IfcGeom::CgalKernel::triangulate_faces(CGAL::Polyhedron_3<Kernel_> &polyhedron) {
|
||||
// std::list<cgal_face_t> face_list;
|
||||
//
|
||||
// for (CGAL::Polyhedron_3<Kernel_>::Facet_const_iterator current_facet = polyhedron.facets_begin();
|
||||
// current_facet != polyhedron.facets_end();
|
||||
// ++current_facet) {
|
||||
//
|
||||
// // Triangle
|
||||
// if (current_facet->is_triangle()) {
|
||||
// face_list.push_back(cgal_face_t());
|
||||
// CGAL::Polyhedron_3<Kernel_>::Halfedge_around_facet_const_circulator current_halfedge = current_facet->facet_begin();
|
||||
// do {
|
||||
// face_list.back().outer.push_back(current_halfedge->vertex()->point());
|
||||
// ++current_halfedge;
|
||||
// } while (current_halfedge != current_facet->facet_begin());
|
||||
// }
|
||||
//
|
||||
// // Polygon
|
||||
// else {
|
||||
// std::list<Kernel_::Point_3> points_in_polygon;
|
||||
//
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return create_polyhedron(face_list);
|
||||
//}
|
||||
@@ -0,0 +1,96 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "CgalKernel.h"
|
||||
|
||||
#define CgalKernel MAKE_TYPE_NAME(CgalKernel)
|
||||
|
||||
using namespace IfcUtil;
|
||||
|
||||
bool IfcGeom::CgalKernel::convert_shapes(const IfcBaseClass* l, ConversionResults& r) {
|
||||
if (shape_type(l) != ST_SHAPELIST) {
|
||||
cgal_shape_t shp;
|
||||
if (convert_shape(l, shp)) {
|
||||
r.push_back(IfcGeom::ConversionResult(l->data().id(), new CgalShape(shp), get_style(l->as<IfcSchema::IfcRepresentationItem>())));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "CgalEntityMappingShapes.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
IfcGeom::ShapeType IfcGeom::CgalKernel::shape_type(const IfcBaseClass* l) {
|
||||
#include "CgalEntityMappingShapeType.h"
|
||||
return ST_OTHER;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert_shape(const IfcBaseClass* l, cgal_shape_t& r) {
|
||||
const unsigned int id = l->data().id();
|
||||
bool success = false;
|
||||
bool processed = false;
|
||||
bool ignored = false;
|
||||
|
||||
#ifndef NO_CACHE
|
||||
std::map<int, cgal_shape_t>::const_iterator it = cache.Shape.find(id);
|
||||
if ( it != cache.Shape.end() ) { r = it->second; return true; }
|
||||
#endif
|
||||
const bool include_curves = getValue(GV_DIMENSIONALITY) != +1;
|
||||
const bool include_solids_and_surfaces = getValue(GV_DIMENSIONALITY) != -1;
|
||||
|
||||
IfcGeom::ShapeType st = shape_type(l);
|
||||
ignored = (!include_solids_and_surfaces && (st == ST_SHAPE || st == ST_FACE)) || (!include_curves && (st == ST_WIRE || st == ST_CURVE));
|
||||
if (st == ST_SHAPE && include_solids_and_surfaces) {
|
||||
#include "CgalEntityMappingShape.h"
|
||||
}
|
||||
|
||||
if ( processed && success ) {
|
||||
// const double precision = getValue(GV_PRECISION);
|
||||
// apply_tolerance(r, precision);
|
||||
#ifndef NO_CACHE
|
||||
cache.Shape[id] = r;
|
||||
#endif
|
||||
} else if (!ignored) {
|
||||
const char* const msg = processed
|
||||
? "Failed to convert:"
|
||||
: "No operation defined for:";
|
||||
Logger::Message(Logger::LOG_ERROR, msg, l);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert_wire(const IfcBaseClass* l, cgal_wire_t& r) {
|
||||
#include "CgalEntityMappingWire.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert_face(const IfcBaseClass* l, cgal_face_t& r) {
|
||||
#include "CgalEntityMappingFace.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert_curve(const IfcBaseClass* l, cgal_curve_t& r) {
|
||||
#include "CgalEntityMappingCurve.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file registers function prototypes for all supported IFC geometrical *
|
||||
* entities. For entities of type CLASS an std::map is also created to cache *
|
||||
* the output of the conversion functions *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../../../ifcparse/IfcParse.h"
|
||||
|
||||
SHAPES(IfcShellBasedSurfaceModel);
|
||||
SHAPES(IfcFaceBasedSurfaceModel);
|
||||
SHAPES(IfcRepresentation);
|
||||
SHAPES(IfcMappedItem);
|
||||
// IfcFacetedBrep included
|
||||
// IfcAdvancedBrep included
|
||||
// IfcFacetedBrepWithVoids included
|
||||
// IfcAdvancedBrepWithVoids included
|
||||
SHAPES(IfcManifoldSolidBrep);
|
||||
SHAPES(IfcGeometricSet);
|
||||
|
||||
#ifdef USE_IFC4
|
||||
//SHAPE(IfcCylindricalSurface);
|
||||
//SHAPE(IfcAdvancedBrep);
|
||||
//SHAPE(IfcBSplineSurfaceWithKnots);
|
||||
SHAPE(IfcTriangulatedFaceSet);
|
||||
SHAPE(IfcExtrudedAreaSolidTapered);
|
||||
#endif
|
||||
//SHAPE(IfcPlane);
|
||||
SHAPE(IfcExtrudedAreaSolid);
|
||||
//SHAPE(IfcRevolvedAreaSolid);
|
||||
SHAPE(IfcConnectedFaceSet);
|
||||
SHAPE(IfcBooleanResult);
|
||||
//SHAPE(IfcPolygonalBoundedHalfSpace);
|
||||
SHAPE(IfcHalfSpaceSolid);
|
||||
//SHAPE(IfcSurfaceOfLinearExtrusion);
|
||||
//SHAPE(IfcSurfaceOfRevolution);
|
||||
SHAPE(IfcBlock);
|
||||
SHAPE(IfcRectangularPyramid);
|
||||
SHAPE(IfcRightCircularCylinder);
|
||||
SHAPE(IfcRightCircularCone);
|
||||
SHAPE(IfcSphere);
|
||||
SHAPE(IfcCsgSolid);
|
||||
//SHAPE(IfcCurveBoundedPlane);
|
||||
//SHAPE(IfcRectangularTrimmedSurface);
|
||||
//SHAPE(IfcSurfaceCurveSweptAreaSolid);
|
||||
//SHAPE(IfcSweptDiskSolid);
|
||||
|
||||
FACE(IfcArbitraryProfileDefWithVoids);
|
||||
FACE(IfcArbitraryClosedProfileDef);
|
||||
FACE(IfcRoundedRectangleProfileDef);
|
||||
FACE(IfcRectangleHollowProfileDef);
|
||||
FACE(IfcRectangleProfileDef);
|
||||
FACE(IfcTrapeziumProfileDef)
|
||||
FACE(IfcCShapeProfileDef);
|
||||
// IfcAsymmetricIShapeProfileDef included
|
||||
FACE(IfcIShapeProfileDef);
|
||||
FACE(IfcLShapeProfileDef);
|
||||
FACE(IfcTShapeProfileDef);
|
||||
FACE(IfcUShapeProfileDef);
|
||||
FACE(IfcZShapeProfileDef);
|
||||
FACE(IfcCircleHollowProfileDef);
|
||||
FACE(IfcCircleProfileDef);
|
||||
FACE(IfcEllipseProfileDef);
|
||||
//FACE(IfcCenterLineProfileDef);
|
||||
//FACE(IfcCompositeProfileDef);
|
||||
FACE(IfcDerivedProfileDef);
|
||||
// IfcFaceSurface included
|
||||
// IfcAdvancedFace included in case of IFC4
|
||||
FACE(IfcFace);
|
||||
|
||||
//WIRE(IfcEdgeCurve);
|
||||
//WIRE(IfcSubedge);
|
||||
WIRE(IfcOrientedEdge);
|
||||
WIRE(IfcEdge);
|
||||
WIRE(IfcEdgeLoop);
|
||||
WIRE(IfcPolyline);
|
||||
WIRE(IfcPolyLoop);
|
||||
WIRE(IfcCompositeCurve);
|
||||
WIRE(IfcTrimmedCurve);
|
||||
//WIRE(IfcArbitraryOpenProfileDef);
|
||||
|
||||
CURVE(IfcCircle);
|
||||
CURVE(IfcEllipse);
|
||||
CURVE(IfcLine);
|
||||
#ifdef USE_IFC4
|
||||
// IfcRationalBSplineCurveWithKnots included
|
||||
//CURVE(IfcBSplineCurveWithKnots);
|
||||
#endif
|
||||
|
||||
CLASS(IfcCartesianPoint,cgal_point_t);
|
||||
CLASS(IfcDirection,cgal_direction_t);
|
||||
CLASS(IfcAxis2Placement2D,cgal_placement_t);
|
||||
CLASS(IfcAxis2Placement3D,cgal_placement_t);
|
||||
CLASS(IfcAxis1Placement,cgal_placement_t);
|
||||
CLASS(IfcCartesianTransformationOperator2DnonUniform,cgal_placement_t);
|
||||
CLASS(IfcCartesianTransformationOperator3DnonUniform,cgal_placement_t);
|
||||
CLASS(IfcCartesianTransformationOperator2D,cgal_placement_t);
|
||||
CLASS(IfcCartesianTransformationOperator3D,cgal_placement_t);
|
||||
CLASS(IfcObjectPlacement,cgal_placement_t);
|
||||
CLASS(IfcVector,cgal_vector_t);
|
||||
CLASS(IfcPlane,cgal_plane_t);
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "CgalEntityMappingUndefine.h"
|
||||
#define CLASS(T,V) \
|
||||
std::map<int,V> T;
|
||||
#include "CgalEntityMappingDefine.h"
|
||||
|
||||
#include "CgalEntityMapping.h"
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "CgalEntityMappingUndefine.h"
|
||||
#define CURVE(T) \
|
||||
if (l->declaration().is(IfcSchema::T::Class())) return convert((IfcSchema::T*)l,r);
|
||||
#include "CgalEntityMappingDefine.h"
|
||||
|
||||
#include "CgalEntityMapping.h"
|
||||
@@ -0,0 +1,10 @@
|
||||
#include "CgalEntityMappingUndefine.h"
|
||||
#define CLASS(T,V) bool convert(const IfcSchema::T* L, V& r);
|
||||
#define SHAPES(T) CLASS(T,ConversionResults)
|
||||
#define SHAPE(T) CLASS(T,cgal_shape_t)
|
||||
#define WIRE(T) CLASS(T,cgal_wire_t)
|
||||
#define FACE(T) CLASS(T,cgal_face_t)
|
||||
#define CURVE(T) CLASS(T,cgal_curve_t)
|
||||
#include "CgalEntityMappingDefine.h"
|
||||
|
||||
#include "CgalEntityMapping.h"
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "CgalEntityMappingUndefine.h"
|
||||
#define FACE(T) \
|
||||
if (l->declaration().is(IfcSchema::T::Class())) return convert((IfcSchema::T*)l,r);
|
||||
#include "CgalEntityMappingDefine.h"
|
||||
|
||||
#include "CgalEntityMapping.h"
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "CgalEntityMappingUndefine.h"
|
||||
#define CLASS(T,V) \
|
||||
T.clear();
|
||||
#include "CgalEntityMappingDefine.h"
|
||||
|
||||
#include "CgalEntityMapping.h"
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "CgalEntityMappingUndefine.h"
|
||||
#define SHAPE(T) \
|
||||
if ( !processed && l->declaration().is(IfcSchema::T::Class()) ) { \
|
||||
processed = true; \
|
||||
try { \
|
||||
if (convert((IfcSchema::T*)l, r) ) { \
|
||||
success = true; \
|
||||
} \
|
||||
} catch (const std::exception& e) { \
|
||||
Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \
|
||||
return false; \
|
||||
} \
|
||||
if (!success) { \
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert:", l); \
|
||||
return false; \
|
||||
} \
|
||||
}
|
||||
#include "CgalEntityMappingDefine.h"
|
||||
|
||||
#include "CgalEntityMapping.h"
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "CgalEntityMappingUndefine.h"
|
||||
#define SHAPES(T) \
|
||||
if (l->declaration().is(IfcSchema::T::Class())) return ST_SHAPELIST;
|
||||
#define SHAPE(T) \
|
||||
if (l->declaration().is(IfcSchema::T::Class())) return ST_SHAPE;
|
||||
#define WIRE(T) \
|
||||
if (l->declaration().is(IfcSchema::T::Class())) return ST_WIRE;
|
||||
#define FACE(T) \
|
||||
if (l->declaration().is(IfcSchema::T::Class())) return ST_FACE;
|
||||
#define CURVE(T) \
|
||||
if (l->declaration().is(IfcSchema::T::Class())) return ST_CURVE;
|
||||
#include "CgalEntityMappingDefine.h"
|
||||
|
||||
#include "CgalEntityMapping.h"
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "CgalEntityMappingUndefine.h"
|
||||
#define SHAPES(T) \
|
||||
if (l->declaration().is(IfcSchema::T::Class())) { \
|
||||
try { \
|
||||
return convert((IfcSchema::T*)l,r); \
|
||||
} catch (const std::exception& e) { \
|
||||
Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
#include "CgalEntityMappingDefine.h"
|
||||
|
||||
#include "CgalEntityMapping.h"
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "CgalEntityMappingUndefine.h"
|
||||
#define WIRE(T) \
|
||||
if (l->declaration().is(IfcSchema::T::Class())) return convert((IfcSchema::T*)l,r);
|
||||
#include "CgalEntityMappingDefine.h"
|
||||
|
||||
#include "CgalEntityMapping.h"
|
||||
@@ -0,0 +1,78 @@
|
||||
#include "CgalKernel.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h"
|
||||
|
||||
#define CgalKernel MAKE_TYPE_NAME(CgalKernel)
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCircle* l, cgal_curve_t& curve) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
if ( r < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l);
|
||||
return false;
|
||||
}
|
||||
cgal_placement_t trsf;
|
||||
IfcSchema::IfcAxis2Placement* placement = l->Position();
|
||||
if (placement->as<IfcSchema::IfcAxis2Placement3D>()) {
|
||||
IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
} else {
|
||||
cgal_placement_t trsf2d;
|
||||
IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d);
|
||||
trsf = trsf2d;
|
||||
}
|
||||
|
||||
const int segments = 12;
|
||||
|
||||
curve = cgal_curve_t();
|
||||
for (int current_segment = 0; current_segment < segments; ++current_segment) {
|
||||
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
|
||||
curve.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0));
|
||||
}
|
||||
|
||||
for (auto &vertex: curve) {
|
||||
vertex = vertex.transform(trsf);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEllipse* l, cgal_curve_t& curve) {
|
||||
double x = l->SemiAxis1() * getValue(GV_LENGTH_UNIT);
|
||||
double y = l->SemiAxis2() * getValue(GV_LENGTH_UNIT);
|
||||
if (x < ALMOST_ZERO || y < ALMOST_ZERO) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l);
|
||||
return false;
|
||||
}
|
||||
cgal_placement_t trsf;
|
||||
IfcSchema::IfcAxis2Placement* placement = l->Position();
|
||||
if (placement->as<IfcSchema::IfcAxis2Placement3D>()) {
|
||||
convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
} else {
|
||||
cgal_placement_t trsf2d;
|
||||
convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d);
|
||||
trsf = trsf2d;
|
||||
}
|
||||
|
||||
const int segments = 12;
|
||||
|
||||
curve = cgal_curve_t();
|
||||
for (int current_segment = 0; current_segment < segments; ++current_segment) {
|
||||
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
|
||||
curve.push_back(Kernel_::Point_3(x*cos(current_angle), y*sin(current_angle), 0));
|
||||
}
|
||||
|
||||
for (auto &vertex: curve) {
|
||||
vertex = vertex.transform(trsf);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcLine* l, cgal_curve_t& curve) {
|
||||
cgal_point_t pnt;
|
||||
cgal_direction_t vec;
|
||||
convert(l->Pnt(),pnt);
|
||||
convert(l->Dir(),vec);
|
||||
curve = cgal_curve_t();
|
||||
curve.push_back(pnt);
|
||||
curve.push_back(pnt+vec);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,991 @@
|
||||
#include "CgalKernel.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h"
|
||||
|
||||
#define CgalKernel MAKE_TYPE_NAME(CgalKernel)
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, cgal_face_t& face) {
|
||||
cgal_wire_t wire;
|
||||
if ( ! convert_wire(l->OuterCurve(),wire) ) return false;
|
||||
|
||||
cgal_face_t f;
|
||||
bool success = convert_wire_to_face(wire, f);
|
||||
if (success) face = f;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids* l, cgal_face_t& face) {
|
||||
cgal_wire_t profile;
|
||||
if ( ! convert_wire(l->OuterCurve(),profile) ) return false;
|
||||
cgal_face_t mf;
|
||||
mf.outer = profile;
|
||||
IfcSchema::IfcCurve::list::ptr voids = l->InnerCurves();
|
||||
for( IfcSchema::IfcCurve::list::it it = voids->begin(); it != voids->end(); ++ it ) {
|
||||
cgal_wire_t hole;
|
||||
if ( convert_wire(*it,hole) ) {
|
||||
mf.inner.push_back(hole);
|
||||
}
|
||||
} face = mf;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cgal_face_t& face) {
|
||||
const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
cgal_placement_t trsf2d;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
|
||||
face = cgal_face_t();
|
||||
face.outer.push_back(Kernel_::Point_3(-x, -y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3( x, -y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3( x, y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(-x, y, 0.0));
|
||||
|
||||
if (has_position) {
|
||||
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
|
||||
for (auto &vertex: face.outer) {
|
||||
vertex = vertex.transform(trsf2d);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef* l, cgal_face_t& face) {
|
||||
const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double r = l->RoundingRadius() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || r < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
cgal_placement_t trsf2d;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
|
||||
const int segments = 3;
|
||||
|
||||
if (r == 0.0) {
|
||||
face = cgal_face_t();
|
||||
face.outer.push_back(Kernel_::Point_3(-x, -y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3( x, -y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3( x, y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(-x, y, 0.0));
|
||||
}
|
||||
|
||||
else {
|
||||
face = cgal_face_t();
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(x-r+r*cos(current_angle), y-r+r*sin(current_angle), 0));
|
||||
}
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(-x+r+r*cos(current_angle), y-r+r*sin(current_angle), 0));
|
||||
}
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(-x+r+r*cos(current_angle), -y+r+r*sin(current_angle), 0));
|
||||
}
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(x-r+r*cos(current_angle), -y+r+r*sin(current_angle), 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (has_position) {
|
||||
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
|
||||
for (auto &vertex: face.outer) {
|
||||
vertex = vertex.transform(trsf2d);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l, cgal_face_t& face) {
|
||||
const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double d = l->WallThickness() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
const bool fr1 = l->hasOuterFilletRadius();
|
||||
const bool fr2 = l->hasInnerFilletRadius();
|
||||
|
||||
const double r1 = fr1 ? l->OuterFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.;
|
||||
const double r2 = fr2 ? l->InnerFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.;
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
cgal_placement_t trsf2d;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
|
||||
const int segments = 3;
|
||||
|
||||
if (!fr1 || r1 == 0.0) {
|
||||
face = cgal_face_t();
|
||||
face.outer.push_back(Kernel_::Point_3(-x, -y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3( x, -y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3( x, y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(-x, y, 0.0));
|
||||
}
|
||||
|
||||
else {
|
||||
face = cgal_face_t();
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(x-r1+r1*cos(current_angle), y-r1+r1*sin(current_angle), 0));
|
||||
}
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(-x+r1+r1*cos(current_angle), y-r1+r1*sin(current_angle), 0));
|
||||
}
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(-x+r1+r1*cos(current_angle), -y+r1+r1*sin(current_angle), 0));
|
||||
}
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(x-r1+r1*cos(current_angle), -y+r1+r1*sin(current_angle), 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (!fr2 || r2 == 0.0) {
|
||||
face.inner.push_back(cgal_wire_t());
|
||||
face.inner.back().push_back(Kernel_::Point_3(-x+d, -y+d, 0.0));
|
||||
face.inner.back().push_back(Kernel_::Point_3( x-d, -y+d, 0.0));
|
||||
face.inner.back().push_back(Kernel_::Point_3( x-d, y-d, 0.0));
|
||||
face.inner.back().push_back(Kernel_::Point_3(-x+d, y-d, 0.0));
|
||||
}
|
||||
|
||||
else {
|
||||
face.inner.push_back(cgal_wire_t());
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.inner.back().push_back(Kernel_::Point_3(x-d-r1+r1*cos(current_angle), y-d-r1+r1*sin(current_angle), 0));
|
||||
}
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.inner.back().push_back(Kernel_::Point_3(-x+d+r1+r1*cos(current_angle), y-d-r1+r1*sin(current_angle), 0));
|
||||
}
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.inner.back().push_back(Kernel_::Point_3(-x+d+r1+r1*cos(current_angle), -y+d+r1+r1*sin(current_angle), 0));
|
||||
}
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.inner.back().push_back(Kernel_::Point_3(x-d-r1+r1*cos(current_angle), -y+d+r1+r1*sin(current_angle), 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (has_position) {
|
||||
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
|
||||
for (auto &vertex: face.outer) {
|
||||
vertex = vertex.transform(trsf2d);
|
||||
} for (auto &inner: face.inner) {
|
||||
for (auto &vertex: inner) {
|
||||
vertex = vertex.transform(trsf2d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrapeziumProfileDef* l, cgal_face_t& face) {
|
||||
const double x1 = l->BottomXDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double w = l->TopXDim() * getValue(GV_LENGTH_UNIT);
|
||||
const double dx = l->TopXOffset() * getValue(GV_LENGTH_UNIT);
|
||||
const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( x1 < ALMOST_ZERO || w < ALMOST_ZERO || y < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
cgal_placement_t trsf2d;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
|
||||
face = cgal_face_t();
|
||||
face.outer.push_back(Kernel_::Point_3(-x1, -y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(x1, -y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(dx+w-x1, y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(dx-x1, y, 0.0));
|
||||
|
||||
if (has_position) {
|
||||
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
|
||||
for (auto &vertex: face.outer) {
|
||||
vertex = vertex.transform(trsf2d);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCircleProfileDef* l, cgal_face_t& face) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
if ( r == 0.0f ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
cgal_placement_t trsf2d;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
|
||||
const int segments = 12;
|
||||
|
||||
face = cgal_face_t();
|
||||
for (int current_segment = 0; current_segment < segments; ++current_segment) {
|
||||
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0));
|
||||
}
|
||||
|
||||
if (has_position) {
|
||||
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
|
||||
for (auto &vertex: face.outer) {
|
||||
vertex = vertex.transform(trsf2d);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, cgal_face_t& face) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
const double t = l->WallThickness() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( r == 0.0f || t == 0.0f ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
cgal_placement_t trsf2d;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
|
||||
const int segments = 12;
|
||||
|
||||
face = cgal_face_t();
|
||||
for (int current_segment = 0; current_segment < segments; ++current_segment) {
|
||||
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0));
|
||||
}
|
||||
|
||||
face.inner.push_back(cgal_wire_t());
|
||||
for (int current_segment = 0; current_segment < segments; ++current_segment) {
|
||||
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
|
||||
face.inner.back().push_back(Kernel_::Point_3((r-t)*cos(current_angle), (r-t)*sin(current_angle), 0));
|
||||
}
|
||||
|
||||
if (has_position) {
|
||||
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
|
||||
for (auto &vertex: face.outer) {
|
||||
vertex = vertex.transform(trsf2d);
|
||||
} for (auto &inner: face.inner) {
|
||||
for (auto &vertex: inner) {
|
||||
vertex = vertex.transform(trsf2d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEllipseProfileDef* l, cgal_face_t& face) {
|
||||
double rx = l->SemiAxis1() * getValue(GV_LENGTH_UNIT);
|
||||
double ry = l->SemiAxis2() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
if ( rx < ALMOST_ZERO || ry < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
cgal_placement_t trsf2d;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
|
||||
const int segments = 12;
|
||||
|
||||
face = cgal_face_t();
|
||||
for (int current_segment = 0; current_segment < segments; ++current_segment) {
|
||||
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(rx*cos(current_angle), ry*sin(current_angle), 0));
|
||||
}
|
||||
|
||||
if (has_position) {
|
||||
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
|
||||
for (auto &vertex: face.outer) {
|
||||
vertex = vertex.transform(trsf2d);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face) {
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds();
|
||||
|
||||
int num_outer_bounds = 0;
|
||||
|
||||
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
|
||||
IfcSchema::IfcFaceBound* bound = *it;
|
||||
if (bound->as<IfcSchema::IfcFaceOuterBound>()) num_outer_bounds ++;
|
||||
}
|
||||
|
||||
if (num_outer_bounds != 1) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
cgal_face_t mf;
|
||||
|
||||
for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) {
|
||||
IfcSchema::IfcFaceBound* bound = *it;
|
||||
IfcSchema::IfcLoop* loop = bound->Bound();
|
||||
|
||||
const bool is_interior = !bound->as<IfcSchema::IfcFaceOuterBound>();
|
||||
|
||||
cgal_wire_t wire;
|
||||
if (!convert_wire(loop, wire)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_interior) {
|
||||
mf.outer = wire;
|
||||
} else {
|
||||
mf.inner.push_back(wire);
|
||||
}
|
||||
}
|
||||
|
||||
face = mf;
|
||||
|
||||
// std::cout << "Face: " << std::endl;
|
||||
// for (auto &point: face.outer) {
|
||||
// std::cout << "\tPoint(" << point << ")" << std::endl;
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCShapeProfileDef* l, cgal_face_t& face) {
|
||||
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double x = l->Width() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double d1 = l->WallThickness() * getValue(GV_LENGTH_UNIT);
|
||||
const double d2 = l->Girth() * getValue(GV_LENGTH_UNIT);
|
||||
bool doFillet = l->hasInternalFilletRadius();
|
||||
double f1 = 0;
|
||||
double f2 = 0;
|
||||
if ( doFillet ) {
|
||||
f1 = l->InternalFilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
f2 = f1 + d1;
|
||||
}
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
cgal_placement_t trsf2d;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
|
||||
const int segments = 3;
|
||||
|
||||
if (!doFillet || f1 == 0.0) {
|
||||
face = cgal_face_t();
|
||||
face.outer.push_back(Kernel_::Point_3(-x, -y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(x, -y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(x, -y+d2, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(x-d1, -y+d2, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(x-d1, -y+d1, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(-x+d1, -y+d1, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(-x+d1, y-d1, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(x-d1, y-d1, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(x-d1, y-d2, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(x, y-d2, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(x, y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(-x, y, 0.0));
|
||||
}
|
||||
|
||||
else {
|
||||
face = cgal_face_t();
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(-x+f2+f2*cos(current_angle), -y+f2+f2*sin(current_angle), 0));
|
||||
}
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(x-f2+f2*cos(current_angle), -y+f2+f2*sin(current_angle), 0));
|
||||
}
|
||||
face.outer.push_back(Kernel_::Point_3(x, -y+d2, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(x-d1, -y+d2, 0.0));
|
||||
for (int current_segment = segments; current_segment >= 0; --current_segment) {
|
||||
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(x-f2+f1*cos(current_angle), -y+f2+f1*sin(current_angle), 0));
|
||||
}
|
||||
for (int current_segment = segments; current_segment >= 0; --current_segment) {
|
||||
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(-x+f2+f1*cos(current_angle), -y+f2+f1*sin(current_angle), 0));
|
||||
}
|
||||
for (int current_segment = segments; current_segment >= 0; --current_segment) {
|
||||
double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(-x+f2+f1*cos(current_angle), y-f2+f1*sin(current_angle), 0));
|
||||
}
|
||||
for (int current_segment = segments; current_segment >= 0; --current_segment) {
|
||||
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(x-f2+f1*cos(current_angle), y-f2+f1*sin(current_angle), 0));
|
||||
}
|
||||
face.outer.push_back(Kernel_::Point_3(x-d1, y-d2, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(x, y-d2, 0.0));
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(x-f2+f2*cos(current_angle), y-f2+f2*sin(current_angle), 0));
|
||||
}
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(-x+f2+f2*cos(current_angle), y-f2+f2*sin(current_angle), 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (has_position) {
|
||||
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
|
||||
for (auto &vertex: face.outer) {
|
||||
vertex = vertex.transform(trsf2d);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcLShapeProfileDef* l, cgal_face_t& face) {
|
||||
const bool hasSlope = l->hasLegSlope();
|
||||
const bool doEdgeFillet = l->hasEdgeRadius();
|
||||
const bool doFillet = l->hasFilletRadius();
|
||||
|
||||
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double x = (l->hasWidth() ? l->Width() : l->Depth()) / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double d = l->Thickness() * getValue(GV_LENGTH_UNIT);
|
||||
const double slope = hasSlope ? (l->LegSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
|
||||
|
||||
double f1 = 0.0f;
|
||||
double f2 = 0.0f;
|
||||
if (doFillet) {
|
||||
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
if ( doEdgeFillet) {
|
||||
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
double xx = -x+d;
|
||||
double xy = -y+d;
|
||||
double dy1 = 0.;
|
||||
double dy2 = 0.;
|
||||
double dx1 = 0.;
|
||||
double dx2 = 0.;
|
||||
if (hasSlope) {
|
||||
dy1 = tan(slope) * x;
|
||||
dy2 = tan(slope) * (x - d);
|
||||
dx1 = tan(slope) * y;
|
||||
dx2 = tan(slope) * (y - d);
|
||||
|
||||
const double x1s = x; const double y1s = -y + d - dy1;
|
||||
const double x1e = -x + d; const double y1e = -y + d + dy2;
|
||||
const double x2s = -x + d - dx1; const double y2s = y;
|
||||
const double x2e = -x + d + dx2; const double y2e = -y + d;
|
||||
|
||||
const double a1 = y1e - y1s;
|
||||
const double b1 = x1s - x1e;
|
||||
const double c1 = a1*x1s + b1*y1s;
|
||||
|
||||
const double a2 = y2e - y2s;
|
||||
const double b2 = x2s - x2e;
|
||||
const double c2 = a2*x2s + b2*y2s;
|
||||
|
||||
const double det = a1*b2 - a2*b1;
|
||||
|
||||
if (ALMOST_THE_SAME(det, 0.)) {
|
||||
Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
xx = (b2*c1 - b1*c2) / det;
|
||||
xy = (a1*c2 - a2*c1) / det;
|
||||
}
|
||||
|
||||
cgal_placement_t trsf2d;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
|
||||
const int segments = 3;
|
||||
|
||||
face = cgal_face_t();
|
||||
face.outer.push_back(Kernel_::Point_3(-x, -y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(x, -y, 0.0));
|
||||
if (f2 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(x, -y+d-dy1, 0.0));
|
||||
} else {
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(x-f2+f2*cos(current_angle), -y+d-dy1-f2+f2*sin(current_angle), 0));
|
||||
}
|
||||
} if (f1 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(xx, xy, 0.0));
|
||||
} else {
|
||||
for (int current_segment = segments; current_segment >= 0; --current_segment) {
|
||||
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(xx+f1+f1*cos(current_angle), xy+f1+f1*sin(current_angle), 0));
|
||||
}
|
||||
} if (f2 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(-x+d-dx1, y, 0.0));
|
||||
} else {
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(-x+d-dx1-f2+f2*cos(current_angle), y-f2+f2*sin(current_angle), 0));
|
||||
}
|
||||
} face.outer.push_back(Kernel_::Point_3(-x, y, 0.0));
|
||||
|
||||
if (has_position) {
|
||||
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
|
||||
for (auto &vertex: face.outer) {
|
||||
vertex = vertex.transform(trsf2d);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Untested
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcIShapeProfileDef* l, cgal_face_t& face) {
|
||||
const double x1 = l->OverallWidth() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double y = l->OverallDepth() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double d1 = l->WebThickness() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double dy1 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
bool doFillet1 = l->hasFilletRadius();
|
||||
double f1 = 0.;
|
||||
if ( doFillet1 ) {
|
||||
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
|
||||
bool doFillet2 = doFillet1;
|
||||
double x2 = x1, dy2 = dy1, f2 = f1;
|
||||
|
||||
if (l->as<IfcSchema::IfcAsymmetricIShapeProfileDef>()) {
|
||||
IfcSchema::IfcAsymmetricIShapeProfileDef* assym = (IfcSchema::IfcAsymmetricIShapeProfileDef*) l;
|
||||
x2 = assym->TopFlangeWidth() / 2. * getValue(GV_LENGTH_UNIT);
|
||||
doFillet2 = assym->hasTopFlangeFilletRadius();
|
||||
if (doFillet2) {
|
||||
f2 = assym->TopFlangeFilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
if (assym->hasTopFlangeThickness()) {
|
||||
dy2 = assym->TopFlangeThickness() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
}
|
||||
|
||||
if ( x1 < ALMOST_ZERO || x2 < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || dy1 < ALMOST_ZERO || dy2 < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
cgal_placement_t trsf2d;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
|
||||
const int segments = 3;
|
||||
|
||||
face = cgal_face_t();
|
||||
face.outer.push_back(Kernel_::Point_3(-x1, -y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(x1, -y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(x1, -y+dy1, 0.0));
|
||||
if (f1 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(d1, -y+dy1, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(d1, y-dy2, 0.0));
|
||||
} else {
|
||||
for (int current_segment = segments; current_segment >= 0; --current_segment) {
|
||||
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(d1+f1+f1*cos(current_angle), -y+dy1+f1+f1*sin(current_angle), 0));
|
||||
} for (int current_segment = segments; current_segment >= 0; --current_segment) {
|
||||
double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(d1+f1+f1*cos(current_angle), y-dy2-f1+f1*sin(current_angle), 0));
|
||||
}
|
||||
} face.outer.push_back(Kernel_::Point_3(x2, y-dy2, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(x2, y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(-x2, y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(-x2, y-dy2, 0.0));
|
||||
if (f2 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(-d1, y-dy2, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(-d1, -y+dy1, 0.0));
|
||||
} else {
|
||||
for (int current_segment = segments; current_segment >= 0; --current_segment) {
|
||||
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(-d1-f2+f2*cos(current_angle), y-dy2-f2+f2*sin(current_angle), 0));
|
||||
} for (int current_segment = segments; current_segment >= 0; --current_segment) {
|
||||
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(-d1-f2+f2*cos(current_angle), -y+dy1+f2+f2*sin(current_angle), 0));
|
||||
}
|
||||
} face.outer.push_back(Kernel_::Point_3(-x1, -y+dy1, 0.0));
|
||||
|
||||
if (has_position) {
|
||||
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
|
||||
for (auto &vertex: face.outer) {
|
||||
vertex = vertex.transform(trsf2d);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTShapeProfileDef* l, cgal_face_t& face) {
|
||||
const bool doFlangeEdgeFillet = l->hasFlangeEdgeRadius();
|
||||
const bool doWebEdgeFillet = l->hasWebEdgeRadius();
|
||||
const bool doFillet = l->hasFilletRadius();
|
||||
const bool hasFlangeSlope = l->hasFlangeSlope();
|
||||
const bool hasWebSlope = l->hasWebSlope();
|
||||
|
||||
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double x = l->FlangeWidth() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double d1 = l->WebThickness() * getValue(GV_LENGTH_UNIT);
|
||||
const double d2 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
|
||||
const double flangeSlope = hasFlangeSlope ? (l->FlangeSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
|
||||
const double webSlope = hasWebSlope ? (l->WebSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
double dy1 = 0.0f;
|
||||
double dy2 = 0.0f;
|
||||
double dx1 = 0.0f;
|
||||
double dx2 = 0.0f;
|
||||
double f1 = 0.0f;
|
||||
double f2 = 0.0f;
|
||||
double f3 = 0.0f;
|
||||
|
||||
if (doFillet) {
|
||||
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
if (doWebEdgeFillet) {
|
||||
f2 = l->WebEdgeRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
if (doFlangeEdgeFillet) {
|
||||
f3 = l->FlangeEdgeRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
|
||||
double xx, xy;
|
||||
if (hasFlangeSlope) {
|
||||
dy1 = (x / 2. - d1) * tan(flangeSlope);
|
||||
dy2 = x / 2. * tan(flangeSlope);
|
||||
}
|
||||
if (hasWebSlope) {
|
||||
dx1 = (y - d2) * tan(webSlope);
|
||||
dx2 = y * tan(webSlope);
|
||||
}
|
||||
if (hasWebSlope || hasFlangeSlope) {
|
||||
const double x1s = d1/2. - dx2; const double y1s = -y;
|
||||
const double x1e = d1/2. + dx1; const double y1e = y - d2;
|
||||
const double x2s = x; const double y2s = y - d2 + dy2;
|
||||
const double x2e = d1/2.; const double y2e = y - d2 - dy1;
|
||||
|
||||
const double a1 = y1e - y1s;
|
||||
const double b1 = x1s - x1e;
|
||||
const double c1 = a1*x1s + b1*y1s;
|
||||
|
||||
const double a2 = y2e - y2s;
|
||||
const double b2 = x2s - x2e;
|
||||
const double c2 = a2*x2s + b2*y2s;
|
||||
|
||||
const double det = a1*b2 - a2*b1;
|
||||
|
||||
if (ALMOST_THE_SAME(det, 0.)) {
|
||||
Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
xx = (b2*c1 - b1*c2) / det;
|
||||
xy = (a1*c2 - a2*c1) / det;
|
||||
} else {
|
||||
xx = d1 / 2;
|
||||
xy = y - d2;
|
||||
}
|
||||
|
||||
cgal_placement_t trsf2d;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
|
||||
const int segments = 3;
|
||||
|
||||
face = cgal_face_t();
|
||||
if (f2 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(d1/2.-dx2, -y, 0.0));
|
||||
} else {
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(d1/2.-dx2-f2+f2*cos(current_angle), -y+f2+f2*sin(current_angle), 0));
|
||||
}
|
||||
} if (f1 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(xx, xy, 0.0));
|
||||
} else {
|
||||
for (int current_segment = segments; current_segment >= 0; --current_segment) {
|
||||
double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(xx+f1+f1*cos(current_angle), xy-f1+f1*sin(current_angle), 0));
|
||||
}
|
||||
} if (f3 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(x, y-d2+dy2, 0.0));
|
||||
} else {
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(x-f3+f3*cos(current_angle), y-d2+dy2+f3+f3*sin(current_angle), 0));
|
||||
}
|
||||
} face.outer.push_back(Kernel_::Point_3(x, y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(-x, y, 0.0));
|
||||
if (f3 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(-x, y-d2+dy2, 0.0));
|
||||
} else {
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(-x+f3+f3*cos(current_angle), y-d2+dy2+f3+f3*sin(current_angle), 0));
|
||||
}
|
||||
} if (f1 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(-xx, xy, 0.0));
|
||||
} else {
|
||||
for (int current_segment = segments; current_segment >= 0; --current_segment) {
|
||||
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(-xx-f1+f1*cos(current_angle), xy-f1+f1*sin(current_angle), 0));
|
||||
}
|
||||
} if (f2 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(-d1/2.+dx2, -y, 0.0));
|
||||
} else {
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(-d1/2.+dx2+f2+f2*cos(current_angle), -y+f2+f2*sin(current_angle), 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (has_position) {
|
||||
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
|
||||
for (auto &vertex: face.outer) {
|
||||
vertex = vertex.transform(trsf2d);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcUShapeProfileDef* l, cgal_face_t& face) {
|
||||
const bool doEdgeFillet = l->hasEdgeRadius();
|
||||
const bool doFillet = l->hasFilletRadius();
|
||||
const bool hasSlope = l->hasFlangeSlope();
|
||||
|
||||
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double x = l->FlangeWidth() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double d1 = l->WebThickness() * getValue(GV_LENGTH_UNIT);
|
||||
const double d2 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
|
||||
const double slope = hasSlope ? (l->FlangeSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.;
|
||||
|
||||
double dy1 = 0.0f;
|
||||
double dy2 = 0.0f;
|
||||
double f1 = 0.0f;
|
||||
double f2 = 0.0f;
|
||||
|
||||
if (doFillet) {
|
||||
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
if (doEdgeFillet) {
|
||||
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
|
||||
if (hasSlope) {
|
||||
dy1 = (x - d1) * tan(slope);
|
||||
dy2 = x * tan(slope);
|
||||
}
|
||||
|
||||
if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
cgal_placement_t trsf2d;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
|
||||
const int segments = 3;
|
||||
|
||||
face = cgal_face_t();
|
||||
face.outer.push_back(Kernel_::Point_3(-x, -y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(x, -y, 0.0));
|
||||
if (f2 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(x, -y+d2-dy2, 0.0));
|
||||
} else {
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(x-f2+f2*cos(current_angle), -y+d2-dy2-f2+f2*sin(current_angle), 0));
|
||||
}
|
||||
} if (f1 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(-x+d1, -y+d2+dy1, 0.0));
|
||||
} else {
|
||||
for (int current_segment = segments; current_segment >= 0; --current_segment) {
|
||||
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(-x+d1+f1+f1*cos(current_angle), -y+d2+dy1+f1+f1*sin(current_angle), 0));
|
||||
}
|
||||
} if (f1 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(-x+d1, y-d2-dy1, 0.0));
|
||||
} else {
|
||||
for (int current_segment = segments; current_segment >= 0; --current_segment) {
|
||||
double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(-x+d1+f1+f1*cos(current_angle), y-d2-dy1-f1+f1*sin(current_angle), 0));
|
||||
}
|
||||
} if (f2 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(x,y-d2+dy2, 0.0));
|
||||
} else {
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(x-f2+f2*cos(current_angle), y-d2+dy2+f2+f2*sin(current_angle), 0));
|
||||
}
|
||||
} face.outer.push_back(Kernel_::Point_3(x,y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(-x,y, 0.0));
|
||||
|
||||
if (has_position) {
|
||||
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
|
||||
for (auto &vertex: face.outer) {
|
||||
vertex = vertex.transform(trsf2d);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcZShapeProfileDef* l, cgal_face_t& face) {
|
||||
const double x = l->FlangeWidth() * getValue(GV_LENGTH_UNIT);
|
||||
const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double dx = l->WebThickness() / 2.0f * getValue(GV_LENGTH_UNIT);
|
||||
const double dy = l->FlangeThickness() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
bool doFillet = l->hasFilletRadius();
|
||||
bool doEdgeFillet = l->hasEdgeRadius();
|
||||
|
||||
double f1 = 0.;
|
||||
double f2 = 0.;
|
||||
|
||||
if ( doFillet ) {
|
||||
f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
if ( doEdgeFillet ) {
|
||||
f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT);
|
||||
}
|
||||
|
||||
if ( x == 0.0f || y == 0.0f || dx == 0.0f || dy == 0.0f ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l);
|
||||
return false;
|
||||
}
|
||||
|
||||
cgal_placement_t trsf2d;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
|
||||
const int segments = 3;
|
||||
|
||||
face = cgal_face_t();
|
||||
face.outer.push_back(Kernel_::Point_3(-dx, -y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(x, -y, 0.0));
|
||||
if (f2 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(x, -y+dy, 0.0));
|
||||
} else {
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(x-f2+f2*cos(current_angle), -y+dy-f2+f2*sin(current_angle), 0));
|
||||
}
|
||||
} if (f1 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(dx, -y+dy, 0.0));
|
||||
} else {
|
||||
for (int current_segment = segments; current_segment >= 0; --current_segment) {
|
||||
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(dx+f1+f1*cos(current_angle), -y+dy+f1+f1*sin(current_angle), 0));
|
||||
}
|
||||
} face.outer.push_back(Kernel_::Point_3(dx, y, 0.0));
|
||||
face.outer.push_back(Kernel_::Point_3(-x, y, 0.0));
|
||||
if (f2 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(-x, y-dy, 0.0));
|
||||
} else {
|
||||
for (int current_segment = 0; current_segment <= segments; ++current_segment) {
|
||||
double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(-x+f2+f2*cos(current_angle), y-dy+f2+f2*sin(current_angle), 0));
|
||||
}
|
||||
} if (f1 == 0.0) {
|
||||
face.outer.push_back(Kernel_::Point_3(-dx, y-dy, 0.0));
|
||||
} else {
|
||||
for (int current_segment = segments; current_segment >= 0; --current_segment) {
|
||||
double current_angle = current_segment*0.5*3.141592653589793/((double)segments);
|
||||
face.outer.push_back(Kernel_::Point_3(-dx-f1+f1*cos(current_angle), y-dy-f1+f1*sin(current_angle), 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (has_position) {
|
||||
IfcGeom::CgalKernel::convert(l->Position(), trsf2d);
|
||||
for (auto &vertex: face.outer) {
|
||||
vertex = vertex.transform(trsf2d);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDerivedProfileDef* l, cgal_face_t& face) {
|
||||
cgal_face_t f;
|
||||
cgal_placement_t trsf2d;
|
||||
if (convert_face(l->ParentProfile(), f) && IfcGeom::CgalKernel::convert(l->Operator(), trsf2d)) {
|
||||
cgal_placement_t trsf = trsf2d;
|
||||
for (auto &vertex: f.outer) vertex = vertex.transform(trsf);
|
||||
for (auto &ring: f.inner) {
|
||||
for (auto &vertex: ring) vertex = vertex.transform(trsf);
|
||||
} face = f;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
#include "CgalKernel.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h"
|
||||
|
||||
#define CgalKernel MAKE_TYPE_NAME(CgalKernel)
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) {
|
||||
std::vector<double> xyz = l->Coordinates();
|
||||
point = Kernel_::Point_3(xyz.size() ? (xyz[0]*getValue(GV_LENGTH_UNIT)) : 0.0f,
|
||||
xyz.size() > 1 ? (xyz[1]*getValue(GV_LENGTH_UNIT)) : 0.0f,
|
||||
xyz.size() > 2 ? (xyz[2]*getValue(GV_LENGTH_UNIT)) : 0.0f);
|
||||
// std::cout << "Converted Point(" << point << ")" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDirection* l, cgal_direction_t& dir) {
|
||||
// IN_CACHE(IfcDirection,l,cgal_direction_t,dir)
|
||||
std::vector<double> xyz = l->DirectionRatios();
|
||||
dir = Kernel_::Vector_3(xyz.size() ? xyz[0] : 0.0f,
|
||||
xyz.size() > 1 ? xyz[1] : 0.0f,
|
||||
xyz.size() > 2 ? xyz[2] : 0.0f);
|
||||
// CACHE(IfcDirection,l,dir)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcVector* l, cgal_vector_t& v) {
|
||||
// IN_CACHE(IfcVector,l,cgal_vector_t,v)
|
||||
cgal_direction_t d;
|
||||
IfcGeom::CgalKernel::convert(l->Orientation(),d);
|
||||
v = l->Magnitude() * getValue(GV_LENGTH_UNIT) * d;
|
||||
// CACHE(IfcVector,l,v)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPlane* pln, cgal_plane_t& plane) {
|
||||
// IN_CACHE(IfcPlane,pln,gp_Pln,plane)
|
||||
IfcSchema::IfcAxis2Placement3D* l = pln->Position();
|
||||
cgal_point_t o;
|
||||
cgal_direction_t axis = Kernel_::Vector_3(0,0,1);
|
||||
cgal_direction_t refDirection = Kernel_::Vector_3(1,0,0);
|
||||
IfcGeom::CgalKernel::convert(l->Location(),o);
|
||||
bool hasRef = l->hasRefDirection();
|
||||
if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(),axis);
|
||||
if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection);
|
||||
Kernel_::Vector_3 y = CGAL::cross_product(axis, refDirection);
|
||||
Kernel_::Vector_3 x = CGAL::cross_product(y, axis);
|
||||
|
||||
cgal_plane_t ax3;
|
||||
if ( hasRef ) ax3 = Kernel_::Plane_3(o,o+x,o+y);
|
||||
else ax3 = Kernel_::Plane_3(o,axis);
|
||||
plane = ax3;
|
||||
|
||||
// std::cout << "IfcPlane C = " << o << std::endl;
|
||||
// std::cout << "IfcPlane z (axis, exact) = " << axis << std::endl;
|
||||
// std::cout << "IfcPlane x (refDirection, approximate) = " << refDirection << std::endl;
|
||||
// std::cout << "IfcPlane y (computed, exact) = " << y << std::endl;
|
||||
// std::cout << "IfcPlane x (computed, exact) = " << x << std::endl;
|
||||
//
|
||||
// std::cout << "Plane_3 o = " << o << std::endl;
|
||||
// std::cout << "Plane_3 o+x = " << o+x << std::endl;
|
||||
// std::cout << "Plane_3 o+y = " << o+y << std::endl;
|
||||
|
||||
// ax + by + cz + d = 0
|
||||
// std::cout << "Plane: a = " << plane.a() << ", b = " << plane.b() << ", c = " << plane.c() << ", d = " << plane.d() << std::endl;
|
||||
|
||||
// std::ofstream fresult;
|
||||
// fresult.open("/Users/ken/Desktop/plane.obj");
|
||||
// // x = -5, y = -5, z = (5a +5b -d)/c
|
||||
// fresult << "v -5 -5 " << (5.0*CGAL::to_double(plane.a())+5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl;
|
||||
// // x = -5, y = +5, z = (5a -5b -d)/c
|
||||
// fresult << "v -5 5 " << (5.0*CGAL::to_double(plane.a())-5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl;
|
||||
// // x = 5, y = -5, z = (-5a +5b -d)/c
|
||||
// fresult << "v 5 -5 " << (-5.0*CGAL::to_double(plane.a())+5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl;
|
||||
// // x = 5, y = +5, z = (-5a -5b -d)/c
|
||||
// fresult << "v 5 5 " << (-5.0*CGAL::to_double(plane.a())-5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl;
|
||||
// fresult << "f 1 2 3" << std::endl;
|
||||
// fresult << "f 4 3 2" << std::endl;
|
||||
// fresult.close();
|
||||
|
||||
// CACHE(IfcPlane,pln,plane)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, cgal_placement_t& trsf) {
|
||||
// IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf)
|
||||
cgal_point_t o;
|
||||
cgal_direction_t refDirection = Kernel_::Vector_3(1,0,0);
|
||||
IfcGeom::CgalKernel::convert(l->Location(),o);
|
||||
bool hasRef = l->hasRefDirection();
|
||||
if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection);
|
||||
cgal_direction_t y = Kernel_::Vector_3(-refDirection.y(), refDirection.x(), 0.0);
|
||||
|
||||
const double tolerance = 0.01;
|
||||
if (refDirection.squared_length() < 1.0-tolerance || refDirection.squared_length() > 1.0+tolerance ||
|
||||
y.squared_length() < 1.0-tolerance || y.squared_length() > 1.0+tolerance) {
|
||||
std::cout << "Ref direction (x): " << refDirection << " squared length: " << refDirection.squared_length() << std::endl;
|
||||
std::cout << "y: " << y << " squared length: " << y.squared_length() << std::endl;
|
||||
std::cout << "Origin: " << o << std::endl;
|
||||
}
|
||||
|
||||
// TODO: Should be checked.
|
||||
trsf = Kernel_::Aff_transformation_3(refDirection.cartesian(0), y.cartesian(0), 0.0, o.cartesian(0),
|
||||
refDirection.cartesian(1), y.cartesian(1), 0.0, o.cartesian(1),
|
||||
0.0, 0.0, 1.0, 0.0);
|
||||
|
||||
// CACHE(IfcAxis2Placement3D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_placement_t& trsf) {
|
||||
// IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf)
|
||||
cgal_point_t o;
|
||||
cgal_direction_t axis = Kernel_::Vector_3(0,0,1);
|
||||
cgal_direction_t refDirection = Kernel_::Vector_3(1,0,0);
|
||||
IfcGeom::CgalKernel::convert(l->Location(),o);
|
||||
bool hasRef = l->hasRefDirection();
|
||||
if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(),axis);
|
||||
if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection);
|
||||
Kernel_::Vector_3 y = CGAL::cross_product(axis, refDirection);
|
||||
Kernel_::Vector_3 x = CGAL::cross_product(y, axis);
|
||||
|
||||
const double tolerance = 0.01;
|
||||
if (x.squared_length() < 1.0-tolerance || x.squared_length() > 1.0+tolerance ||
|
||||
y.squared_length() < 1.0-tolerance || y.squared_length() > 1.0+tolerance ||
|
||||
axis.squared_length() < 1.0-tolerance || axis.squared_length() > 1.0+tolerance) {
|
||||
std::cout << "Ref direction: " << refDirection << " squared length: " << refDirection.squared_length() << std::endl;
|
||||
std::cout << "Axis (z): " << axis << " squared length: " << axis.squared_length() << std::endl;
|
||||
std::cout << "y: " << y << " squared length: " << y.squared_length() << std::endl;
|
||||
std::cout << "x: " << x << " squared length: " << x.squared_length() << std::endl;
|
||||
std::cout << "Origin: " << o << std::endl;
|
||||
}
|
||||
|
||||
// TODO: Should be checked.
|
||||
trsf = Kernel_::Aff_transformation_3(x.cartesian(0), y.cartesian(0), axis.cartesian(0), o.cartesian(0),
|
||||
x.cartesian(1), y.cartesian(1), axis.cartesian(1), o.cartesian(1),
|
||||
x.cartesian(2), y.cartesian(2), axis.cartesian(2), o.cartesian(2));
|
||||
|
||||
// for (int i = 0; i < 3; ++i) {
|
||||
// for (int j = 0; j < 4; ++j) {
|
||||
// std::cout << trsf.cartesian(i, j) << " ";
|
||||
// } std::cout << std::endl;
|
||||
// }
|
||||
|
||||
// CACHE(IfcAxis2Placement3D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis1Placement* l, cgal_placement_t& ax) {
|
||||
// IN_CACHE(IfcAxis1Placement,l,gp_Ax1,ax)
|
||||
cgal_point_t o;
|
||||
cgal_direction_t axis = Kernel_::Vector_3(0,0,1);
|
||||
IfcGeom::CgalKernel::convert(l->Location(),o);
|
||||
if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(), axis);
|
||||
|
||||
const double tolerance = 0.01;
|
||||
if (axis.squared_length() < 1.0-tolerance || axis.squared_length() > 1.0+tolerance) {
|
||||
std::cout << "Axis (z): " << axis << " squared length: " << axis.squared_length() << std::endl;
|
||||
std::cout << "Origin: " << o << std::endl;
|
||||
}
|
||||
|
||||
// TODO: Should be checked.
|
||||
ax = Kernel_::Aff_transformation_3(1.0, 0.0, axis.cartesian(0), o.cartesian(0),
|
||||
0.0, 1.0, axis.cartesian(1), o.cartesian(1),
|
||||
0.0, 0.0, axis.cartesian(2), o.cartesian(2));
|
||||
|
||||
// CACHE(IfcAxis1Placement,l,ax)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_placement_t& trsf) {
|
||||
// IN_CACHE(IfcObjectPlacement,l,cgal_placement_t,trsf)
|
||||
if ( ! l->as<IfcSchema::IfcLocalPlacement>() ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
// std::cout << "initial trsf (identity?)" << std::endl;
|
||||
// for (int i = 0; i < 3; ++i) {
|
||||
// for (int j = 0; j < 4; ++j) {
|
||||
// std::cout << trsf.cartesian(i, j) << " ";
|
||||
// } std::cout << std::endl;
|
||||
// }
|
||||
|
||||
IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l;
|
||||
for (;;) {
|
||||
cgal_placement_t trsf2;
|
||||
|
||||
IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement();
|
||||
if ( relplacement->as<IfcSchema::IfcAxis2Placement3D>() ) {
|
||||
IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2);
|
||||
|
||||
// std::cout << "trsf2" << std::endl;
|
||||
// for (int i = 0; i < 3; ++i) {
|
||||
// for (int j = 0; j < 4; ++j) {
|
||||
// std::cout << trsf2.cartesian(i, j) << " ";
|
||||
// } std::cout << std::endl;
|
||||
// }
|
||||
|
||||
trsf = trsf2 * trsf;
|
||||
|
||||
// std::cout << "trsf (after multiplication)" << std::endl;
|
||||
// for (int i = 0; i < 3; ++i) {
|
||||
// for (int j = 0; j < 4; ++j) {
|
||||
// std::cout << trsf.cartesian(i, j) << " ";
|
||||
// } std::cout << std::endl;
|
||||
// }
|
||||
}
|
||||
if ( current->hasPlacementRelTo() ) {
|
||||
IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo();
|
||||
if ( relto->as<IfcSchema::IfcLocalPlacement>() )
|
||||
current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo();
|
||||
else break;
|
||||
} else break;
|
||||
}
|
||||
// CACHE(IfcObjectPlacement,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOperator2D* l, cgal_placement_t& trsf) {
|
||||
// IN_CACHE(IfcCartesianTransformationOperator2D,l,cgal_placement_t,trsf)
|
||||
|
||||
cgal_point_t origin;
|
||||
cgal_direction_t axis1 (1.,0.,0.);
|
||||
cgal_direction_t axis2 (0.,1.,0.);
|
||||
|
||||
IfcGeom::CgalKernel::convert(l->LocalOrigin(),origin);
|
||||
if ( l->hasAxis1() ) IfcGeom::CgalKernel::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::CgalKernel::convert(l->Axis2(),axis2);
|
||||
double scale = 1.0;
|
||||
if (l->hasScale()) {
|
||||
scale = l->Scale();
|
||||
}
|
||||
|
||||
// TODO: Untested
|
||||
trsf = Kernel_::Aff_transformation_3(scale*axis1.cartesian(0), axis2.cartesian(0), 0.0, origin.cartesian(0),
|
||||
axis1.cartesian(1), scale*axis2.cartesian(1), 0.0, origin.cartesian(1),
|
||||
0.0, 0.0, 1.0, 0.0);
|
||||
|
||||
// CACHE(IfcCartesianTransformationOperator2D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* l, cgal_placement_t& trsf) {
|
||||
// IN_CACHE(IfcCartesianTransformationOperator2DnonUniform,l,cgal_placement_t,gtrsf)
|
||||
|
||||
cgal_point_t origin;
|
||||
cgal_direction_t axis1 (1.,0.,0.);
|
||||
cgal_direction_t axis2 (0.,1.,0.);
|
||||
|
||||
IfcGeom::CgalKernel::convert(l->LocalOrigin(),origin);
|
||||
if ( l->hasAxis1() ) IfcGeom::CgalKernel::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::CgalKernel::convert(l->Axis2(),axis2);
|
||||
|
||||
const double scale1 = l->hasScale() ? l->Scale() : 1.0f;
|
||||
const double scale2 = l->hasScale2() ? l->Scale2() : scale1;
|
||||
|
||||
// TODO: Untested
|
||||
trsf = Kernel_::Aff_transformation_3(scale1*axis1.cartesian(0), axis2.cartesian(0), 0.0, origin.cartesian(0),
|
||||
axis1.cartesian(1), scale2*axis2.cartesian(1), 0.0, origin.cartesian(1),
|
||||
0.0, 0.0, 1.0, 0.0);
|
||||
|
||||
// CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gtrsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOperator3D* l, cgal_placement_t& trsf) {
|
||||
// IN_CACHE(IfcCartesianTransformationOperator3D,l,gp_Trsf,trsf)
|
||||
cgal_point_t origin;
|
||||
IfcGeom::CgalKernel::convert(l->LocalOrigin(),origin);
|
||||
cgal_direction_t axis1 (1.,0.,0.);
|
||||
cgal_direction_t axis2 (0.,1.,0.);
|
||||
cgal_direction_t axis3 (0.,0.,1.);
|
||||
if ( l->hasAxis1() ) IfcGeom::CgalKernel::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::CgalKernel::convert(l->Axis2(),axis2);
|
||||
if ( l->hasAxis3() ) IfcGeom::CgalKernel::convert(l->Axis3(),axis3);
|
||||
double scale = 1.0;
|
||||
if (l->hasScale()) {
|
||||
scale = l->Scale();
|
||||
}
|
||||
|
||||
// TODO: Untested
|
||||
trsf = Kernel_::Aff_transformation_3(scale*axis1.cartesian(0), axis2.cartesian(0), axis3.cartesian(0), origin.cartesian(0),
|
||||
axis1.cartesian(1), scale*axis2.cartesian(1), axis3.cartesian(1), origin.cartesian(1),
|
||||
axis1.cartesian(2), axis2.cartesian(2), scale*axis3.cartesian(2), origin.cartesian(2));
|
||||
|
||||
// std::cout << std::endl;
|
||||
// for (int i = 0; i < 3; ++i) {
|
||||
// for (int j = 0; j < 4; ++j) {
|
||||
// std::cout << trsf.cartesian(i, j) << " ";
|
||||
// } std::cout << std::endl;
|
||||
// }
|
||||
|
||||
// CACHE(IfcCartesianTransformationOperator3D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* l, cgal_placement_t& gtrsf) {
|
||||
// IN_CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gp_GTrsf,gtrsf)
|
||||
cgal_point_t origin;
|
||||
IfcGeom::CgalKernel::convert(l->LocalOrigin(),origin);
|
||||
cgal_direction_t axis1 (1.,0.,0.);
|
||||
cgal_direction_t axis2 (0.,1.,0.);
|
||||
cgal_direction_t axis3 (0.,0.,1.);
|
||||
if ( l->hasAxis1() ) IfcGeom::CgalKernel::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::CgalKernel::convert(l->Axis2(),axis2);
|
||||
if ( l->hasAxis3() ) IfcGeom::CgalKernel::convert(l->Axis3(),axis3);
|
||||
const double scale1 = l->hasScale() ? l->Scale() : 1.0f;
|
||||
const double scale2 = l->hasScale2() ? l->Scale2() : scale1;
|
||||
const double scale3 = l->hasScale3() ? l->Scale3() : scale1;
|
||||
|
||||
// TODO: Untested
|
||||
gtrsf = Kernel_::Aff_transformation_3(scale1*axis1.cartesian(0), axis2.cartesian(0), axis3.cartesian(0), origin.cartesian(0),
|
||||
axis1.cartesian(1), scale2*axis2.cartesian(1), axis3.cartesian(1), origin.cartesian(1),
|
||||
axis1.cartesian(2), axis2.cartesian(2), scale3*axis3.cartesian(2), origin.cartesian(2));
|
||||
|
||||
// for (int i = 0; i < 3; ++i) {
|
||||
// for (int j = 0; j < 4; ++j) {
|
||||
// std::cout << gtrsf.cartesian(i, j) << " ";
|
||||
// } std::cout << std::endl;
|
||||
// }
|
||||
|
||||
// CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gtrsf)
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,919 @@
|
||||
#include "CgalKernel.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h"
|
||||
|
||||
#define CgalKernel MAKE_TYPE_NAME(CgalKernel)
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal_shape_t &shape) {
|
||||
const double height = l->Depth() * getValue(GV_LENGTH_UNIT);
|
||||
if (height < getValue(GV_PRECISION)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Outer
|
||||
cgal_face_t bottom_face;
|
||||
if ( !convert_face(l->SweptArea(),bottom_face) ) return false;
|
||||
// std::cout << "Face vertices: " << face.outer.size() << std::endl;
|
||||
|
||||
cgal_placement_t trsf;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::CgalKernel::convert(l->Position(), trsf);
|
||||
}
|
||||
|
||||
cgal_direction_t dir;
|
||||
convert(l->ExtrudedDirection(),dir);
|
||||
// std::cout << "Direction: " << dir << std::endl;
|
||||
|
||||
std::list<cgal_face_t> face_list;
|
||||
face_list.push_back(bottom_face);
|
||||
|
||||
for (std::vector<Kernel_::Point_3>::const_iterator current_vertex = bottom_face.outer.begin();
|
||||
current_vertex != bottom_face.outer.end();
|
||||
++current_vertex) {
|
||||
std::vector<Kernel_::Point_3>::const_iterator next_vertex = current_vertex;
|
||||
++next_vertex;
|
||||
if (next_vertex == bottom_face.outer.end()) {
|
||||
next_vertex = bottom_face.outer.begin();
|
||||
} cgal_face_t side_face;
|
||||
side_face.outer.push_back(*next_vertex);
|
||||
side_face.outer.push_back(*current_vertex);
|
||||
side_face.outer.push_back(*current_vertex+height*dir);
|
||||
side_face.outer.push_back(*next_vertex+height*dir);
|
||||
face_list.push_back(side_face);
|
||||
}
|
||||
|
||||
cgal_face_t top_face;
|
||||
for (std::vector<Kernel_::Point_3>::const_reverse_iterator vertex = bottom_face.outer.rbegin();
|
||||
vertex != bottom_face.outer.rend();
|
||||
++vertex) {
|
||||
top_face.outer.push_back(*vertex+height*dir);
|
||||
} face_list.push_back(top_face);
|
||||
|
||||
if (bottom_face.inner.empty()) {
|
||||
shape = create_polyhedron(face_list);
|
||||
if (has_position) for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf);
|
||||
return true;
|
||||
}
|
||||
|
||||
CGAL::Nef_polyhedron_3<Kernel_> nef_shape = create_nef_polyhedron(face_list);
|
||||
|
||||
// Inner
|
||||
// TODO: Would be faster to triangulate top/bottom face template rather than use Nef polyhedra for subtraction
|
||||
for (auto &inner: bottom_face.inner) {
|
||||
// std::cout << "Inner wire" << std::endl;
|
||||
face_list.clear();
|
||||
|
||||
cgal_face_t hole_bottom_face;
|
||||
hole_bottom_face.outer = inner;
|
||||
remove_duplicate_points_from_loop(hole_bottom_face.outer);
|
||||
face_list.push_back(hole_bottom_face);
|
||||
|
||||
for (std::vector<Kernel_::Point_3>::const_iterator current_vertex = inner.begin();
|
||||
current_vertex != inner.end();
|
||||
++current_vertex) {
|
||||
std::vector<Kernel_::Point_3>::const_iterator next_vertex = current_vertex;
|
||||
++next_vertex;
|
||||
if (next_vertex == inner.end()) {
|
||||
next_vertex = inner.begin();
|
||||
} cgal_face_t hole_side_face;
|
||||
hole_side_face.outer.push_back(*next_vertex);
|
||||
hole_side_face.outer.push_back(*current_vertex);
|
||||
hole_side_face.outer.push_back(*current_vertex+height*dir);
|
||||
hole_side_face.outer.push_back(*next_vertex+height*dir);
|
||||
face_list.push_back(hole_side_face);
|
||||
}
|
||||
|
||||
cgal_face_t hole_top_face;
|
||||
for (std::vector<Kernel_::Point_3>::const_reverse_iterator vertex = inner.rbegin();
|
||||
vertex != inner.rend();
|
||||
++vertex) {
|
||||
hole_top_face.outer.push_back(*vertex+height*dir);
|
||||
} face_list.push_back(hole_top_face);
|
||||
|
||||
try {
|
||||
nef_shape -= create_nef_polyhedron(face_list);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot subtract opening for:", l);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_position) {
|
||||
// IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D
|
||||
// and therefore has a unit scale factor
|
||||
nef_shape.transform(trsf);
|
||||
}
|
||||
|
||||
try {
|
||||
nef_shape.convert_to_polyhedron(shape);
|
||||
return true;
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot convert Nef to polyhedron for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef USE_IFC4
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* l, cgal_shape_t& shape) {
|
||||
const double height = l->Depth() * getValue(GV_LENGTH_UNIT);
|
||||
if (height < getValue(GV_PRECISION)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
cgal_face_t face1, face2;
|
||||
if (!convert_face(l->SweptArea(), face1)) return false;
|
||||
if (!convert_face(l->EndSweptArea(), face2)) return false;
|
||||
|
||||
cgal_placement_t trsf;
|
||||
bool has_position = true;
|
||||
#ifdef USE_IFC4
|
||||
has_position = l->hasPosition();
|
||||
#endif
|
||||
if (has_position) {
|
||||
IfcGeom::CgalKernel::convert(l->Position(), trsf);
|
||||
}
|
||||
|
||||
cgal_direction_t dir;
|
||||
convert(l->ExtrudedDirection(), dir);
|
||||
|
||||
for (auto &vertex: face2.outer) vertex = vertex + height*dir;
|
||||
for (auto &ring: face2.inner) {
|
||||
for (auto &vertex: ring) vertex = vertex + height*dir;
|
||||
}
|
||||
|
||||
// Outer
|
||||
std::list<cgal_face_t> face_list;
|
||||
face_list.push_back(face1);
|
||||
|
||||
std::vector<Kernel_::Point_3>::const_iterator current_face1_vertex = face1.outer.begin();
|
||||
std::vector<Kernel_::Point_3>::const_iterator current_face2_vertex = face2.outer.begin();
|
||||
while (current_face1_vertex != face1.outer.end() &&
|
||||
current_face2_vertex != face2.outer.end()) {
|
||||
std::vector<Kernel_::Point_3>::const_iterator next_face1_vertex = current_face1_vertex;
|
||||
std::vector<Kernel_::Point_3>::const_iterator next_face2_vertex = current_face2_vertex;
|
||||
++next_face1_vertex;
|
||||
++next_face2_vertex;
|
||||
if (next_face1_vertex == face1.outer.end()) next_face1_vertex = face1.outer.begin();
|
||||
if (next_face2_vertex == face2.outer.end()) next_face2_vertex = face2.outer.begin();
|
||||
cgal_face_t side_face;
|
||||
side_face.outer.push_back(*next_face1_vertex);
|
||||
side_face.outer.push_back(*current_face1_vertex);
|
||||
side_face.outer.push_back(*current_face2_vertex);
|
||||
side_face.outer.push_back(*next_face2_vertex);
|
||||
face_list.push_back(side_face);
|
||||
++current_face1_vertex;
|
||||
++current_face2_vertex;
|
||||
}
|
||||
|
||||
cgal_face_t top_face;
|
||||
for (std::vector<Kernel_::Point_3>::const_reverse_iterator vertex = face2.outer.rbegin();
|
||||
vertex != face2.outer.rend();
|
||||
++vertex) {
|
||||
top_face.outer.push_back(*vertex);
|
||||
} face_list.push_back(top_face);
|
||||
|
||||
if (face1.inner.empty() || face2.inner.empty()) {
|
||||
shape = create_polyhedron(face_list);
|
||||
if (has_position) for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf);
|
||||
return true;
|
||||
}
|
||||
|
||||
// std::ofstream f1;
|
||||
// CGAL::Polyhedron_3<Kernel_> outer_polyhedron;
|
||||
// PolyhedronBuilder builder(&face_list);
|
||||
// outer_polyhedron.delegate(builder);
|
||||
// f1.open("/Users/ken/Desktop/outer.off");
|
||||
// f1 << outer_polyhedron << std::endl;
|
||||
// f1.close();
|
||||
|
||||
CGAL::Nef_polyhedron_3<Kernel_> nef_shape = create_nef_polyhedron(face_list);
|
||||
|
||||
// Inner
|
||||
// TODO: Would be faster to triangulate top/bottom face template rather than use Nef polyhedra for subtraction
|
||||
std::vector<cgal_wire_t>::iterator inner_face1 = face1.inner.begin();
|
||||
std::vector<cgal_wire_t>::iterator inner_face2 = face2.inner.begin();
|
||||
while (inner_face1 != face1.inner.end() &&
|
||||
inner_face2 != face2.inner.end()) {
|
||||
face_list.clear();
|
||||
|
||||
cgal_face_t hole_face1;
|
||||
hole_face1.outer = *inner_face1;
|
||||
remove_duplicate_points_from_loop(hole_face1.outer);
|
||||
face_list.push_back(hole_face1);
|
||||
|
||||
cgal_face_t hole_face2;
|
||||
hole_face2.outer = *inner_face2;
|
||||
remove_duplicate_points_from_loop(hole_face2.outer);
|
||||
|
||||
current_face1_vertex = hole_face1.outer.begin();
|
||||
current_face2_vertex = hole_face2.outer.begin();
|
||||
while (current_face1_vertex != hole_face1.outer.end() &&
|
||||
current_face2_vertex != hole_face2.outer.end()) {
|
||||
std::vector<Kernel_::Point_3>::const_iterator next_face1_vertex = current_face1_vertex;
|
||||
std::vector<Kernel_::Point_3>::const_iterator next_face2_vertex = current_face2_vertex;
|
||||
++next_face1_vertex;
|
||||
++next_face2_vertex;
|
||||
if (next_face1_vertex == hole_face1.outer.end()) next_face1_vertex = hole_face1.outer.begin();
|
||||
if (next_face2_vertex == hole_face2.outer.end()) next_face2_vertex = hole_face2.outer.begin();
|
||||
cgal_face_t side_face;
|
||||
side_face.outer.push_back(*next_face1_vertex);
|
||||
side_face.outer.push_back(*current_face1_vertex);
|
||||
side_face.outer.push_back(*current_face2_vertex);
|
||||
side_face.outer.push_back(*next_face2_vertex);
|
||||
face_list.push_back(side_face);
|
||||
++current_face1_vertex;
|
||||
++current_face2_vertex;
|
||||
}
|
||||
|
||||
cgal_face_t top_hole_face;
|
||||
for (std::vector<Kernel_::Point_3>::const_reverse_iterator vertex = hole_face2.outer.rbegin();
|
||||
vertex != hole_face2.outer.rend();
|
||||
++vertex) {
|
||||
top_hole_face.outer.push_back(*vertex);
|
||||
} face_list.push_back(top_hole_face);
|
||||
|
||||
// std::ofstream f2;
|
||||
// CGAL::Polyhedron_3<Kernel_> inner_polyhedron;
|
||||
// PolyhedronBuilder builder(&face_list);
|
||||
// inner_polyhedron.delegate(builder);
|
||||
// f2.open("/Users/ken/Desktop/inner.off");
|
||||
// f2 << inner_polyhedron << std::endl;
|
||||
// f2.close();
|
||||
|
||||
try {
|
||||
nef_shape -= create_nef_polyhedron(face_list);
|
||||
} catch (...) {
|
||||
std::cout << "IfcExtrudedAreaSolidTapered: cannot subtract opening for:" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
++inner_face1;
|
||||
++inner_face2;
|
||||
}
|
||||
|
||||
if (has_position) {
|
||||
// IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D
|
||||
// and therefore has a unit scale factor
|
||||
nef_shape.transform(trsf);
|
||||
}
|
||||
|
||||
try {
|
||||
nef_shape.convert_to_polyhedron(shape);
|
||||
return true;
|
||||
} catch (...) {
|
||||
std::cout << "IfcExtrudedAreaSolidTapered: cannot convert Nef to polyhedron!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_shape_t& shape) {
|
||||
IfcSchema::IfcFace::list::ptr faces = l->CfsFaces();
|
||||
|
||||
std::list<cgal_face_t> face_list;
|
||||
for (IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++it) {
|
||||
bool success = false;
|
||||
cgal_face_t face;
|
||||
|
||||
try {
|
||||
success = convert_face(*it, face);
|
||||
} catch (...) {}
|
||||
|
||||
if (!success) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", (*it));
|
||||
continue;
|
||||
}
|
||||
|
||||
// std::cout << "Face in ConnectedFaceSet: " << std::endl;
|
||||
// for (auto &point: face.outer) {
|
||||
// std::cout << "\tPoint(" << point << ")" << std::endl;
|
||||
// }
|
||||
|
||||
face_list.push_back(face);
|
||||
}
|
||||
|
||||
shape = create_polyhedron(face_list);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCsgSolid* l, cgal_shape_t& shape) {
|
||||
return convert_shape(l->TreeRootExpression(), shape);
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& shape) {
|
||||
const double dx = l->XLength() * getValue(GV_LENGTH_UNIT);
|
||||
const double dy = l->YLength() * getValue(GV_LENGTH_UNIT);
|
||||
const double dz = l->ZLength() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
std::list<cgal_face_t> face_list;
|
||||
|
||||
// x = 0
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, dy, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, dy, dz));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, dz));
|
||||
|
||||
// x = dx
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(dx, 0, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(dx, 0, dz));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(dx, dy, dz));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(dx, dy, 0));
|
||||
|
||||
// y = 0
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, dz));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(dx, 0, dz));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(dx, 0, 0));
|
||||
|
||||
// y = dy
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, dy, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(dx, dy, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(dx, dy, dz));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, dy, dz));
|
||||
|
||||
// z = 0
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(dx, 0, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(dx, dy, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, dy, 0));
|
||||
|
||||
// z = dz
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, dz));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, dy, dz));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(dx, dy, dz));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(dx, 0, dz));
|
||||
|
||||
cgal_placement_t trsf;
|
||||
IfcGeom::CgalKernel::convert(l->Position(),trsf);
|
||||
|
||||
shape = create_polyhedron(face_list);
|
||||
for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_shape_t& shape) {
|
||||
|
||||
cgal_shape_t s1, s2;
|
||||
ConversionResults items1, items2;
|
||||
cgal_wire_t boundary_wire;
|
||||
IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand();
|
||||
IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand();
|
||||
bool is_halfspace = operand2->as<IfcSchema::IfcHalfSpaceSolid>();
|
||||
|
||||
if ( shape_type(operand1) == ST_SHAPELIST ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "s1: ST_SHAPELIST Unsupported", operand1);
|
||||
// if (!(convert_shapes(operand1, items1) && flatten_shape_list(items1, s1, true))) {
|
||||
return false;
|
||||
// }
|
||||
} else if ( shape_type(operand1) == ST_SHAPE ) {
|
||||
if (!convert_shape(operand1, s1) ) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "s1: Invalid representation item for boolean operation", operand1);
|
||||
return false;
|
||||
}
|
||||
|
||||
// const double first_operand_volume = shape_volume(s1);
|
||||
// if ( first_operand_volume <= ALMOST_ZERO )
|
||||
// Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand());
|
||||
|
||||
bool shape2_processed = false;
|
||||
if ( shape_type(operand2) == ST_SHAPELIST ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "s2: ST_SHAPELIST Unsupported", operand1);
|
||||
// shape2_processed = convert_shapes(operand2, items2) && flatten_shape_list(items2, s2, true);
|
||||
} else if ( shape_type(operand2) == ST_SHAPE ) {
|
||||
shape2_processed = convert_shape(operand2,s2);
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "s2: Invalid representation item for boolean operation", operand2);
|
||||
}
|
||||
|
||||
if (!shape2_processed) {
|
||||
shape = s1;
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l);
|
||||
return true;
|
||||
}
|
||||
|
||||
// if (!is_halfspace) {
|
||||
// const double second_operand_volume = shape_volume(s2);
|
||||
// if ( second_operand_volume <= ALMOST_ZERO )
|
||||
// Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2);
|
||||
// }
|
||||
|
||||
const IfcSchema::IfcBooleanOperator::Value op = l->Operator();
|
||||
|
||||
if (!s1.is_valid()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "s1: Not valid?", operand1);
|
||||
return false;
|
||||
} else {
|
||||
// std::ofstream f1;
|
||||
// CGAL::Polyhedron_3<Kernel_> p1;
|
||||
// s1.convert_to_Polyhedron(p1);
|
||||
// f1.open("/Users/ken/Desktop/s1.off");
|
||||
// f1 << p1 << std::endl;
|
||||
// f1.close();
|
||||
}
|
||||
|
||||
bool is_plane = false;
|
||||
cgal_plane_t plane;
|
||||
if (!s2.is_valid()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "s2: Not valid?", operand2);
|
||||
return false;
|
||||
} else if (is_halfspace) {
|
||||
// std::cout << "s2: halfspace" << std::endl;
|
||||
IfcSchema::IfcHalfSpaceSolid *hss = static_cast<IfcSchema::IfcHalfSpaceSolid *>(operand2);
|
||||
IfcSchema::IfcSurface* surface = hss->BaseSurface();
|
||||
if (surface->as<IfcSchema::IfcPlane>() ) {
|
||||
is_plane = true;
|
||||
IfcGeom::CgalKernel::convert((IfcSchema::IfcPlane *)surface, plane);
|
||||
if (hss->AgreementFlag()) plane = plane.opposite();
|
||||
// std::ofstream fresult;
|
||||
// fresult.open("/Users/ken/Desktop/s2.off");
|
||||
// fresult << "OFF" << std::endl << "4 2 4" << std::endl;
|
||||
// // x = -5, y = -5, z = (5a +5b -d)/c
|
||||
// fresult << "-5 -5 " << (5.0*CGAL::to_double(plane.a())+5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl;
|
||||
// // x = -5, y = +5, z = (5a -5b -d)/c
|
||||
// fresult << "-5 5 " << (5.0*CGAL::to_double(plane.a())-5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl;
|
||||
// // x = 5, y = -5, z = (-5a +5b -d)/c
|
||||
// fresult << "5 -5 " << (-5.0*CGAL::to_double(plane.a())+5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl;
|
||||
// // x = 5, y = +5, z = (-5a -5b -d)/c
|
||||
// fresult << "5 5 " << (-5.0*CGAL::to_double(plane.a())-5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl;
|
||||
// fresult << "3 0 1 2" << std::endl;
|
||||
// fresult << "3 3 2 1" << std::endl;
|
||||
// fresult.close();
|
||||
}
|
||||
} else {
|
||||
// std::ofstream f2;
|
||||
// CGAL::Polyhedron_3<Kernel_> p2;
|
||||
// s2.convert_to_Polyhedron(p2);
|
||||
// f2.open("/Users/ken/Desktop/s2.off");
|
||||
// f2 << p2 << std::endl;
|
||||
// f2.close();
|
||||
}
|
||||
|
||||
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
|
||||
|
||||
// std::cout << "Difference" << std::endl;
|
||||
CGAL::Nef_polyhedron_3<Kernel_> nef_result;
|
||||
try {
|
||||
nef_result = CGAL::Nef_polyhedron_3<Kernel_>(s1);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "s1: cannot convert to Nef?", operand1);
|
||||
return false;
|
||||
} if (is_halfspace) {
|
||||
if (is_plane) nef_result = nef_result.intersection(plane, CGAL::Nef_polyhedron_3<Kernel_>::Intersection_mode::CLOSED_HALFSPACE);
|
||||
} else {
|
||||
CGAL::Nef_polyhedron_3<Kernel_> nef_s2;
|
||||
try {
|
||||
nef_s2 = CGAL::Nef_polyhedron_3<Kernel_>(s2);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "s2: cannot convert to Nef?", operand2);
|
||||
} nef_result -= nef_s2;
|
||||
}
|
||||
if (!nef_result.is_simple()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "s2: not simple?", operand2);
|
||||
return false;
|
||||
} else {
|
||||
// CGAL::Polyhedron_3<Kernel_> result;
|
||||
// nef_result.convert_to_polyhedron(result);
|
||||
// std::ofstream fresult;
|
||||
// fresult.open("/Users/ken/Desktop/result.off");
|
||||
// fresult << result << std::endl;
|
||||
// fresult.close();
|
||||
} try {
|
||||
nef_result.convert_to_polyhedron(shape);
|
||||
return true;
|
||||
} catch (...) {
|
||||
std::cout << "IfcBooleanResult: cannot convert Nef to polyhedron!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) {
|
||||
|
||||
// std::cout << "Union" << std::endl;
|
||||
CGAL::Nef_polyhedron_3<Kernel_> nef_result = CGAL::Nef_polyhedron_3<Kernel_>(s1)+CGAL::Nef_polyhedron_3<Kernel_>(s2);
|
||||
if (!nef_result.is_simple()) {
|
||||
std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl;
|
||||
return false;
|
||||
} else {
|
||||
// CGAL::Polyhedron_3<Kernel_> result;
|
||||
// nef_result.convert_to_polyhedron(result);
|
||||
// std::ofstream fresult;
|
||||
// fresult.open("/Users/ken/Desktop/result.off");
|
||||
// fresult << result << std::endl;
|
||||
// fresult.close();
|
||||
} try {
|
||||
nef_result.convert_to_polyhedron(shape);
|
||||
return true;
|
||||
} catch (...) {
|
||||
std::cout << "IfcBooleanResult: cannot convert Nef to polyhedron!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) {
|
||||
|
||||
// std::cout << "Intersection" << std::endl;
|
||||
CGAL::Nef_polyhedron_3<Kernel_> nef_result = CGAL::Nef_polyhedron_3<Kernel_>(s1)*CGAL::Nef_polyhedron_3<Kernel_>(s2);
|
||||
if (!nef_result.is_simple()) {
|
||||
std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl;
|
||||
return false;
|
||||
} else {
|
||||
// CGAL::Polyhedron_3<Kernel_> result;
|
||||
// nef_result.convert_to_polyhedron(result);
|
||||
// std::ofstream fresult;
|
||||
// fresult.open("/Users/ken/Desktop/result.off");
|
||||
// fresult << result << std::endl;
|
||||
// fresult.close();
|
||||
} try {
|
||||
nef_result.convert_to_polyhedron(shape);
|
||||
return true;
|
||||
} catch (...) {
|
||||
std::cout << "IfcBooleanResult: cannot convert Nef to polyhedron!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
} return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& shape) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
// Make icosahedron
|
||||
float golden_ratio = (1.0+sqrtf(5.0))/2.0;
|
||||
float normalising_factor = sqrtf(golden_ratio*golden_ratio+1.0);
|
||||
std::vector<Kernel_::Point_3> icosahedron_vertices;
|
||||
icosahedron_vertices.push_back(Kernel_::Point_3(-1.0/normalising_factor, golden_ratio/normalising_factor, 0.0));
|
||||
icosahedron_vertices.push_back(Kernel_::Point_3( 1.0/normalising_factor, golden_ratio/normalising_factor, 0.0));
|
||||
icosahedron_vertices.push_back(Kernel_::Point_3(-1.0/normalising_factor, -golden_ratio/normalising_factor, 0.0));
|
||||
icosahedron_vertices.push_back(Kernel_::Point_3( 1.0/normalising_factor, -golden_ratio/normalising_factor, 0.0));
|
||||
icosahedron_vertices.push_back(Kernel_::Point_3(0.0, -1.0/normalising_factor, golden_ratio/normalising_factor));
|
||||
icosahedron_vertices.push_back(Kernel_::Point_3(0.0, 1.0/normalising_factor, golden_ratio/normalising_factor));
|
||||
icosahedron_vertices.push_back(Kernel_::Point_3(0.0, -1.0/normalising_factor, -golden_ratio/normalising_factor));
|
||||
icosahedron_vertices.push_back(Kernel_::Point_3(0.0, 1.0/normalising_factor, -golden_ratio/normalising_factor));
|
||||
icosahedron_vertices.push_back(Kernel_::Point_3( golden_ratio/normalising_factor, 0.0, -1.0/normalising_factor));
|
||||
icosahedron_vertices.push_back(Kernel_::Point_3( golden_ratio/normalising_factor, 0.0, 1.0/normalising_factor));
|
||||
icosahedron_vertices.push_back(Kernel_::Point_3(-golden_ratio/normalising_factor, 0.0, -1.0/normalising_factor));
|
||||
icosahedron_vertices.push_back(Kernel_::Point_3(-golden_ratio/normalising_factor, 0.0, 1.0/normalising_factor));
|
||||
|
||||
std::list<cgal_face_t> face_list;
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[0]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[11]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[5]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[0]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[5]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[1]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[0]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[1]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[7]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[0]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[7]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[10]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[0]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[10]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[11]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[1]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[5]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[9]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[5]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[11]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[4]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[11]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[10]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[2]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[10]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[7]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[6]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[7]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[1]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[8]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[3]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[9]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[4]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[3]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[4]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[2]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[3]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[2]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[6]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[3]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[6]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[8]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[3]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[8]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[9]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[4]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[9]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[5]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[2]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[4]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[11]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[6]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[2]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[10]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[8]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[6]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[7]);
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(icosahedron_vertices[9]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[8]);
|
||||
face_list.back().outer.push_back(icosahedron_vertices[1]);
|
||||
|
||||
const unsigned int refinements = 2;
|
||||
for (unsigned int current_refinement = 0; current_refinement < refinements; ++current_refinement) {
|
||||
std::list<cgal_face_t> refined_face_list;
|
||||
for (auto &face: face_list) {
|
||||
Kernel_::Point_3 vertex0 = face.outer[0];
|
||||
Kernel_::Point_3 vertex1 = face.outer[1];
|
||||
Kernel_::Point_3 vertex2 = face.outer[2];
|
||||
|
||||
Kernel_::Point_3 midpoint01 = CGAL::midpoint(vertex0, vertex1);
|
||||
Kernel_::Point_3 midpoint12 = CGAL::midpoint(vertex1, vertex2);
|
||||
Kernel_::Point_3 midpoint20 = CGAL::midpoint(vertex2, vertex0);
|
||||
|
||||
double midpoint01_distance_to_origin = sqrt(CGAL::to_double(CGAL::squared_distance(midpoint01, Kernel_::Point_3(0, 0, 0))));
|
||||
midpoint01 = Kernel_::Point_3(midpoint01.x()/midpoint01_distance_to_origin,
|
||||
midpoint01.y()/midpoint01_distance_to_origin,
|
||||
midpoint01.z()/midpoint01_distance_to_origin);
|
||||
double midpoint12_distance_to_origin = sqrt(CGAL::to_double(CGAL::squared_distance(midpoint12, Kernel_::Point_3(0, 0, 0))));
|
||||
midpoint12 = Kernel_::Point_3(midpoint12.x()/midpoint12_distance_to_origin,
|
||||
midpoint12.y()/midpoint12_distance_to_origin,
|
||||
midpoint12.z()/midpoint12_distance_to_origin);
|
||||
double midpoint20_distance_to_origin = sqrt(CGAL::to_double(CGAL::squared_distance(midpoint20, Kernel_::Point_3(0, 0, 0))));
|
||||
midpoint20 = Kernel_::Point_3(midpoint20.x()/midpoint20_distance_to_origin,
|
||||
midpoint20.y()/midpoint20_distance_to_origin,
|
||||
midpoint20.z()/midpoint20_distance_to_origin);
|
||||
|
||||
refined_face_list.push_back(cgal_face_t());
|
||||
refined_face_list.back().outer.push_back(vertex0);
|
||||
refined_face_list.back().outer.push_back(midpoint01);
|
||||
refined_face_list.back().outer.push_back(midpoint20);
|
||||
|
||||
refined_face_list.push_back(cgal_face_t());
|
||||
refined_face_list.back().outer.push_back(vertex1);
|
||||
refined_face_list.back().outer.push_back(midpoint12);
|
||||
refined_face_list.back().outer.push_back(midpoint01);
|
||||
|
||||
refined_face_list.push_back(cgal_face_t());
|
||||
refined_face_list.back().outer.push_back(vertex2);
|
||||
refined_face_list.back().outer.push_back(midpoint20);
|
||||
refined_face_list.back().outer.push_back(midpoint12);
|
||||
|
||||
refined_face_list.push_back(cgal_face_t());
|
||||
refined_face_list.back().outer.push_back(midpoint01);
|
||||
refined_face_list.back().outer.push_back(midpoint12);
|
||||
refined_face_list.back().outer.push_back(midpoint20);
|
||||
} face_list = refined_face_list;
|
||||
}
|
||||
|
||||
cgal_placement_t trsf;
|
||||
IfcGeom::CgalKernel::convert(l->Position(),trsf);
|
||||
|
||||
shape = create_polyhedron(face_list);
|
||||
for (auto &vertex: vertices(shape)) {
|
||||
vertex->point() = Kernel_::Point_3(r*vertex->point().x(),
|
||||
r*vertex->point().y(),
|
||||
r*vertex->point().z());
|
||||
vertex->point() = vertex->point().transform(trsf);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangularPyramid* l, cgal_shape_t& shape) {
|
||||
const double dx = l->XLength() * getValue(GV_LENGTH_UNIT);
|
||||
const double dy = l->YLength() * getValue(GV_LENGTH_UNIT);
|
||||
const double dz = l->Height() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
std::list<cgal_face_t> face_list;
|
||||
|
||||
// Base
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(dx, 0, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(dx, dy, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, dy, 0));
|
||||
|
||||
// Lateral faces
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, dy, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0.5*dx, 0.5*dy, dz));
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, dy, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(dx, dy, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0.5*dx, 0.5*dy, dz));
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(dx, dy, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(dx, 0, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0.5*dx, 0.5*dy, dz));
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(dx, 0, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0.5*dx, 0.5*dy, dz));
|
||||
|
||||
cgal_placement_t trsf;
|
||||
IfcGeom::CgalKernel::convert(l->Position(),trsf);
|
||||
|
||||
shape = create_polyhedron(face_list);
|
||||
for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, cgal_shape_t& shape) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
const double h = l->Height() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
std::list<cgal_face_t> face_list;
|
||||
|
||||
const int segments = 12;
|
||||
|
||||
// Base
|
||||
face_list.push_back(cgal_face_t());
|
||||
for (int current_segment = 0; current_segment < segments; ++current_segment) {
|
||||
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0));
|
||||
}
|
||||
|
||||
// Side faces
|
||||
for (int current_segment = 0; current_segment < segments; ++current_segment) {
|
||||
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
|
||||
int next_segment = (current_segment+1)%segments;
|
||||
double next_angle = next_segment*2.0*3.141592653589793/((double)segments);
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(r*cos(next_angle), r*sin(next_angle), 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), h));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(r*cos(next_angle), r*sin(next_angle), h));
|
||||
}
|
||||
|
||||
// Top
|
||||
face_list.push_back(cgal_face_t());
|
||||
for (int current_segment = segments-1; current_segment >= 0; --current_segment) {
|
||||
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), h));
|
||||
}
|
||||
|
||||
cgal_placement_t trsf;
|
||||
IfcGeom::CgalKernel::convert(l->Position(),trsf);
|
||||
|
||||
shape = create_polyhedron(face_list);
|
||||
for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal_shape_t& shape) {
|
||||
const double r = l->BottomRadius() * getValue(GV_LENGTH_UNIT);
|
||||
const double h = l->Height() * getValue(GV_LENGTH_UNIT);
|
||||
|
||||
std::list<cgal_face_t> face_list;
|
||||
|
||||
const int segments = 12;
|
||||
|
||||
// Base
|
||||
face_list.push_back(cgal_face_t());
|
||||
for (int current_segment = 0; current_segment < segments; ++current_segment) {
|
||||
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0));
|
||||
}
|
||||
|
||||
// Side faces
|
||||
for (int current_segment = 0; current_segment < segments; ++current_segment) {
|
||||
double current_angle = current_segment*2.0*3.141592653589793/((double)segments);
|
||||
int next_segment = (current_segment+1)%segments;
|
||||
double next_angle = next_segment*2.0*3.141592653589793/((double)segments);
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(r*cos(next_angle), r*sin(next_angle), 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0));
|
||||
face_list.back().outer.push_back(Kernel_::Point_3(0, 0, h));
|
||||
}
|
||||
|
||||
cgal_placement_t trsf;
|
||||
IfcGeom::CgalKernel::convert(l->Position(),trsf);
|
||||
|
||||
shape = create_polyhedron(face_list);
|
||||
for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef USE_IFC4
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, cgal_shape_t& shape) {
|
||||
IfcSchema::IfcCartesianPointList3D* point_list = l->Coordinates();
|
||||
const std::vector< std::vector<double> > coordinates = point_list->CoordList();
|
||||
std::vector<cgal_point_t> points;
|
||||
points.reserve(coordinates.size());
|
||||
for (std::vector< std::vector<double> >::const_iterator it = coordinates.begin(); it != coordinates.end(); ++it) {
|
||||
const std::vector<double>& coords = *it;
|
||||
if (coords.size() != 3) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on Coordinates", l);
|
||||
return false;
|
||||
}
|
||||
points.push_back(Kernel_::Point_3(coords[0] * getValue(GV_LENGTH_UNIT),
|
||||
coords[1] * getValue(GV_LENGTH_UNIT),
|
||||
coords[2] * getValue(GV_LENGTH_UNIT)));
|
||||
}
|
||||
|
||||
std::vector< std::vector<int> > indices = l->CoordIndex();
|
||||
|
||||
std::list<cgal_face_t> face_list;
|
||||
|
||||
for(std::vector< std::vector<int> >::const_iterator it = indices.begin(); it != indices.end(); ++ it) {
|
||||
const std::vector<int>& tri = *it;
|
||||
if (tri.size() != 3) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on CoordIndex", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
const int min_index = *std::min_element(tri.begin(), tri.end());
|
||||
const int max_index = *std::max_element(tri.begin(), tri.end());
|
||||
|
||||
if (min_index < 1 || max_index > (int) points.size()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Contents of CoordIndex out of bounds", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
const Kernel_::Point_3& a = points[tri[0] - 1]; // account for zero- vs
|
||||
const Kernel_::Point_3& b = points[tri[1] - 1]; // one-based indices in
|
||||
const Kernel_::Point_3& c = points[tri[2] - 1]; // c++ and express
|
||||
|
||||
face_list.push_back(cgal_face_t());
|
||||
face_list.back().outer.push_back(a);
|
||||
face_list.back().outer.push_back(b);
|
||||
face_list.back().outer.push_back(c);
|
||||
}
|
||||
|
||||
shape = create_polyhedron(face_list);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, cgal_shape_t& shape) {
|
||||
IfcSchema::IfcSurface* surface = l->BaseSurface();
|
||||
if ( ! surface->as<IfcSchema::IfcPlane>() ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface);
|
||||
return false;
|
||||
}
|
||||
cgal_plane_t pln;
|
||||
IfcGeom::CgalKernel::convert((IfcSchema::IfcPlane*)surface,pln);
|
||||
|
||||
// TODO: Don't fully understand the logic here. Might be incorrect.
|
||||
if (l->AgreementFlag()) pln = pln.opposite();
|
||||
// const gp_Pnt pnt = pln.Location().Translated( l->AgreementFlag() ? -pln.Axis().Direction() : pln.Axis().Direction());
|
||||
// shape = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln),pnt).Solid();
|
||||
|
||||
// TODO: For now we do nothing and process halfspaces in IfcBooleanResult, which likely doesn't capture all cases.
|
||||
// Find a better solution later (with an abstract shape class?)
|
||||
shape = CGAL::Polyhedron_3<Kernel_>();
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
#include "CgalKernel.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h"
|
||||
|
||||
#define CgalKernel MAKE_TYPE_NAME(CgalKernel)
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, ConversionResults& shapes) {
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items = l->Items();
|
||||
bool part_succes = false;
|
||||
if (items->size()) {
|
||||
for (IfcSchema::IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++it) {
|
||||
IfcSchema::IfcRepresentationItem* representation_item = *it;
|
||||
if (shape_type(representation_item) == ST_SHAPELIST) {
|
||||
part_succes |= convert_shapes(*it, shapes);
|
||||
} else {
|
||||
cgal_shape_t s;
|
||||
if (convert_shape(representation_item, s)) {
|
||||
shapes.push_back(ConversionResult(representation_item->data().id(), new CgalShape(s), get_style(representation_item)));
|
||||
part_succes |= true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return part_succes;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcGeometricSet* l, ConversionResults& shapes) {
|
||||
IfcEntityList::ptr elements = l->Elements();
|
||||
if ( !elements->size() ) return false;
|
||||
bool part_succes = false;
|
||||
const IfcGeom::SurfaceStyle* parent_style = get_style(l);
|
||||
for ( IfcEntityList::it it = elements->begin(); it != elements->end(); ++ it ) {
|
||||
IfcSchema::IfcGeometricSetSelect* element = *it;
|
||||
cgal_shape_t s;
|
||||
if (convert_shape(element, s)) {
|
||||
part_succes = true;
|
||||
const IfcGeom::SurfaceStyle* style = 0;
|
||||
if (element->as<IfcSchema::IfcPoint>()) {
|
||||
style = get_style((IfcSchema::IfcPoint*) element);
|
||||
} else if (element->as<IfcSchema::IfcCurve>()) {
|
||||
style = get_style((IfcSchema::IfcCurve*) element);
|
||||
} else if (element->as<IfcSchema::IfcSurface>()) {
|
||||
style = get_style((IfcSchema::IfcSurface*) element);
|
||||
}
|
||||
shapes.push_back(ConversionResult(element->data().id(), new CgalShape(s), style ? style : parent_style));
|
||||
}
|
||||
}
|
||||
return part_succes;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, ConversionResults& shapes) {
|
||||
IfcEntityList::ptr shells = l->SbsmBoundary();
|
||||
const SurfaceStyle* collective_style = get_style(l);
|
||||
for( IfcEntityList::it it = shells->begin(); it != shells->end(); ++ it ) {
|
||||
cgal_shape_t s;
|
||||
const SurfaceStyle* shell_style = 0;
|
||||
if ((*it)->as<IfcSchema::IfcRepresentationItem>()) {
|
||||
shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it);
|
||||
}
|
||||
if (convert_shape(*it,s)) {
|
||||
shapes.push_back(ConversionResult((*it)->data().id(), new CgalShape(s), shell_style ? shell_style : collective_style));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, ConversionResults& shape) {
|
||||
cgal_shape_t s;
|
||||
const SurfaceStyle* collective_style = get_style(l);
|
||||
const SurfaceStyle* indiv_style = get_style(l->Outer());
|
||||
|
||||
if (convert_shape(l->Outer(),s) ) {
|
||||
IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list);
|
||||
if (l->as<IfcSchema::IfcFacetedBrepWithVoids>()) {
|
||||
voids = l->as<IfcSchema::IfcFacetedBrepWithVoids>()->Voids();
|
||||
}
|
||||
#ifdef USE_IFC4
|
||||
if (l->as<IfcSchema::IfcAdvancedBrepWithVoids>()) {
|
||||
voids = l->as<IfcSchema::IfcAdvancedBrepWithVoids>()->Voids();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (voids->size()) {
|
||||
CGAL::Nef_polyhedron_3<Kernel_> nef_s = create_nef_polyhedron(s);
|
||||
|
||||
for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) {
|
||||
cgal_shape_t s2;
|
||||
if (convert_shape(*it, s2)) {
|
||||
nef_s -= CGAL::Nef_polyhedron_3<Kernel_>(s2);
|
||||
}
|
||||
}
|
||||
|
||||
s = create_polyhedron(nef_s);
|
||||
}
|
||||
|
||||
shape.push_back(ConversionResult(l->data().id(), new CgalShape(s), indiv_style ? indiv_style : collective_style));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionResults& shapes) {
|
||||
cgal_placement_t gtrsf;
|
||||
IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget();
|
||||
if ( transform->as<IfcSchema::IfcCartesianTransformationOperator3DnonUniform>() ) {
|
||||
IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf);
|
||||
} else if ( transform->as<IfcSchema::IfcCartesianTransformationOperator2DnonUniform>() ) {
|
||||
IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator2DnonUniform*)transform,gtrsf);
|
||||
} else if ( transform->as<IfcSchema::IfcCartesianTransformationOperator3D>() ) {
|
||||
IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,gtrsf);
|
||||
} else if ( transform->as<IfcSchema::IfcCartesianTransformationOperator2D>() ) {
|
||||
IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,gtrsf);
|
||||
}
|
||||
IfcSchema::IfcRepresentationMap* map = l->MappingSource();
|
||||
IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin();
|
||||
cgal_placement_t trsf;
|
||||
if (placement->as<IfcSchema::IfcAxis2Placement3D>()) {
|
||||
IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
} else {
|
||||
cgal_placement_t trsf_2d;
|
||||
IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf_2d);
|
||||
trsf = trsf_2d;
|
||||
}
|
||||
|
||||
// TODO: Check
|
||||
gtrsf = trsf * gtrsf;
|
||||
|
||||
// std::cout << std::endl;
|
||||
// for (int i = 0; i < 3; ++i) {
|
||||
// for (int j = 0; j < 4; ++j) {
|
||||
// std::cout << gtrsf.cartesian(i, j) << " ";
|
||||
// } std::cout << std::endl;
|
||||
// }
|
||||
|
||||
const IfcGeom::SurfaceStyle* mapped_item_style = get_style(l);
|
||||
|
||||
const size_t previous_size = shapes.size();
|
||||
bool b = convert_shapes(map->MappedRepresentation(), shapes);
|
||||
|
||||
for (size_t i = previous_size; i < shapes.size(); ++ i ) {
|
||||
IfcGeom::CgalPlacement place(gtrsf);
|
||||
shapes[i].prepend(&place);
|
||||
|
||||
// Apply styles assigned to the mapped item only if on
|
||||
// a more granular level no styles have been applied
|
||||
if (!shapes[i].hasStyle()) {
|
||||
shapes[i].setStyle(mapped_item_style);
|
||||
}
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFaceBasedSurfaceModel* l, ConversionResults& shapes) {
|
||||
bool part_success = false;
|
||||
IfcSchema::IfcConnectedFaceSet::list::ptr facesets = l->FbsmFaces();
|
||||
const SurfaceStyle* collective_style = get_style(l);
|
||||
for( IfcSchema::IfcConnectedFaceSet::list::it it = facesets->begin(); it != facesets->end(); ++ it ) {
|
||||
cgal_shape_t s;
|
||||
const SurfaceStyle* shell_style = get_style(*it);
|
||||
if (convert_shape(*it,s)) {
|
||||
shapes.push_back(ConversionResult((*it)->data().id(), new CgalShape(s), shell_style ? shell_style : collective_style));
|
||||
part_success |= true;
|
||||
}
|
||||
}
|
||||
return part_success;
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
// For MSVC to have M_PI
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
|
||||
#include "CgalKernel.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h"
|
||||
|
||||
#define CgalKernel MAKE_TYPE_NAME(CgalKernel)
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& result) {
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points = l->Polygon();
|
||||
|
||||
// Parse and store the points in a sequence
|
||||
cgal_wire_t polygon = std::vector<Kernel_::Point_3>();
|
||||
for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) {
|
||||
cgal_point_t pnt;
|
||||
IfcGeom::CgalKernel::convert(*it, pnt);
|
||||
polygon.push_back(pnt);
|
||||
}
|
||||
|
||||
// A loop should consist of at least three vertices
|
||||
std::size_t original_count = polygon.size();
|
||||
if (original_count < 3) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove points that are too close to one another
|
||||
remove_duplicate_points_from_loop(polygon);
|
||||
|
||||
std::size_t count = polygon.size();
|
||||
if (original_count - count != 0) {
|
||||
std::stringstream ss; ss << (original_count - count) << " edges removed for:";
|
||||
Logger::Message(Logger::LOG_WARNING, ss.str(), l);
|
||||
}
|
||||
|
||||
if (count < 3) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
result = polygon;
|
||||
|
||||
// std::cout << "PolyLoop: " << std::endl;
|
||||
// for (auto &point: polygon) {
|
||||
// std::cout << "\tPoint(" << point << ")" << std::endl;
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyline* l, cgal_wire_t& result) {
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points = l->Points();
|
||||
|
||||
// Parse and store the points in a sequence
|
||||
cgal_wire_t polygon = std::vector<Kernel_::Point_3>();
|
||||
for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) {
|
||||
cgal_point_t pnt;
|
||||
IfcGeom::CgalKernel::convert(*it, pnt);
|
||||
polygon.push_back(pnt);
|
||||
}
|
||||
|
||||
// Remove points that are too close to one another
|
||||
remove_duplicate_points_from_loop(polygon);
|
||||
|
||||
result = polygon;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEdgeLoop* l, cgal_wire_t& result) {
|
||||
IfcSchema::IfcOrientedEdge::list::ptr li = l->EdgeList();
|
||||
cgal_wire_t mw;
|
||||
for (IfcSchema::IfcOrientedEdge::list::it it = li->begin(); it != li->end(); ++it) {
|
||||
cgal_wire_t w;
|
||||
if (convert_wire(*it, w)) {
|
||||
// TODO: What to do here? Add some points only?
|
||||
// mw.Add(TopoDS::Edge(TopoDS_Iterator(w).Value()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
result = mw;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcOrientedEdge* l, cgal_wire_t& result) {
|
||||
if (convert_wire(l->EdgeElement(), result)) {
|
||||
if (!l->Orientation()) {
|
||||
std::reverse(result.begin(),result.end());
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEdge* l, cgal_wire_t& result) {
|
||||
if (!l->EdgeStart()->as<IfcSchema::IfcVertexPoint>() || !l->EdgeEnd()->as<IfcSchema::IfcVertexPoint>()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcVertexPoints are supported for EdgeStart and -End", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry();
|
||||
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry();
|
||||
if (!pnt1->as<IfcSchema::IfcCartesianPoint>() || !pnt2->as<IfcSchema::IfcCartesianPoint>()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l);
|
||||
return false;
|
||||
}
|
||||
|
||||
cgal_point_t p1, p2;
|
||||
if (!convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
|
||||
!convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
cgal_wire_t mw;
|
||||
mw.push_back(p1);
|
||||
mw.push_back(p2);
|
||||
|
||||
result = mw;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCompositeCurve* l, cgal_wire_t& wire) {
|
||||
if ( getValue(GV_PLANEANGLE_UNIT)<0 ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l);
|
||||
|
||||
// Temporarily pretend we do have unit information
|
||||
setValue(GV_PLANEANGLE_UNIT,1.0);
|
||||
|
||||
bool succes_radians = false;
|
||||
bool succes_degrees = false;
|
||||
bool use_radians = false;
|
||||
bool use_degrees = false;
|
||||
|
||||
// First try radians
|
||||
cgal_wire_t wire_radians, wire_degrees;
|
||||
try {
|
||||
succes_radians = IfcGeom::CgalKernel::convert(l,wire_radians);
|
||||
} catch (...) {}
|
||||
|
||||
// Now try degrees
|
||||
setValue(GV_PLANEANGLE_UNIT,0.0174532925199433);
|
||||
try {
|
||||
succes_degrees = IfcGeom::CgalKernel::convert(l,wire_degrees);
|
||||
} catch (...) {}
|
||||
|
||||
// Restore to unknown unit state
|
||||
setValue(GV_PLANEANGLE_UNIT,-1.0);
|
||||
|
||||
if ( succes_degrees && ! succes_radians ) {
|
||||
use_degrees = true;
|
||||
} else if ( succes_radians && ! succes_degrees ) {
|
||||
use_radians = true;
|
||||
} else if ( succes_radians && succes_degrees ) {
|
||||
if ( wire_degrees.back() == wire_degrees.front() && wire_radians.back() != wire_radians.front() ) {
|
||||
use_degrees = true;
|
||||
} else if ( wire_radians.back() == wire_radians.front() && wire_degrees.back() != wire_degrees.front() ) {
|
||||
use_radians = true;
|
||||
} else {
|
||||
// No heuristic left to prefer the one over the other,
|
||||
// apparently both variants are equally succesful.
|
||||
// The curve might be composed of only straight segments.
|
||||
// Let's go with the wire created using radians as that
|
||||
// at least is a SI unit.
|
||||
use_radians = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( use_radians ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Used radians to create composite curve");
|
||||
wire = wire_radians;
|
||||
} else if ( use_degrees ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Used degrees to create composite curve");
|
||||
wire = wire_degrees;
|
||||
}
|
||||
|
||||
return use_radians || use_degrees;
|
||||
}
|
||||
IfcSchema::IfcCompositeCurveSegment::list::ptr segments = l->Segments();
|
||||
cgal_wire_t w;
|
||||
//TopoDS_Vertex last_vertex;
|
||||
for( IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++ it ) {
|
||||
IfcSchema::IfcCurve* curve = (*it)->ParentCurve();
|
||||
cgal_wire_t wire2;
|
||||
if ( !convert_wire(curve,wire2) ) {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve);
|
||||
continue;
|
||||
}
|
||||
if ( ! (*it)->SameSense() ) std::reverse(wire2.begin(),wire2.end());
|
||||
|
||||
if (wire2.empty()) {
|
||||
continue;
|
||||
} else if (w.empty()) {
|
||||
w = wire2;
|
||||
} else if (w.back() == w.front()) {
|
||||
std::vector<Kernel_::Point_3>::const_iterator vertex = wire2.begin();
|
||||
++vertex;
|
||||
while (vertex != wire2.end()) {
|
||||
w.push_back(*vertex);
|
||||
++vertex;
|
||||
}
|
||||
} else {
|
||||
for (auto &vertex: wire2) w.push_back(vertex);
|
||||
}
|
||||
}
|
||||
|
||||
remove_duplicate_points_from_loop(w);
|
||||
|
||||
wire = w;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrimmedCurve* l, cgal_wire_t& wire) {
|
||||
IfcSchema::IfcCurve* basis_curve = l->BasisCurve();
|
||||
bool isConic = basis_curve->as<IfcSchema::IfcConic>();
|
||||
double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT);
|
||||
cgal_curve_t curve;
|
||||
if ( !convert_curve(basis_curve,curve) ) return false;
|
||||
bool trim_cartesian = l->MasterRepresentation() == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN;
|
||||
IfcEntityList::ptr trims1 = l->Trim1();
|
||||
IfcEntityList::ptr trims2 = l->Trim2();
|
||||
unsigned sense_agreement = l->SenseAgreement() ? 0 : 1;
|
||||
double flts[2];
|
||||
cgal_point_t pnts[2];
|
||||
bool has_flts[2] = {false,false};
|
||||
bool has_pnts[2] = {false,false};
|
||||
cgal_wire_t w;
|
||||
for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) {
|
||||
IfcUtil::IfcBaseClass* i = *it;
|
||||
if ( i->as<IfcSchema::IfcCartesianPoint>() ) {
|
||||
IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] );
|
||||
has_pnts[sense_agreement] = true;
|
||||
} else if ( i->as<IfcSchema::IfcParameterValue>() ) {
|
||||
const double value = *((IfcSchema::IfcParameterValue*)i);
|
||||
flts[sense_agreement] = value * parameterFactor;
|
||||
has_flts[sense_agreement] = true;
|
||||
}
|
||||
}
|
||||
for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) {
|
||||
IfcUtil::IfcBaseClass* i = *it;
|
||||
if ( i->as<IfcSchema::IfcCartesianPoint>() ) {
|
||||
IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] );
|
||||
has_pnts[1-sense_agreement] = true;
|
||||
} else if ( i->as<IfcSchema::IfcParameterValue>() ) {
|
||||
const double value = *((IfcSchema::IfcParameterValue*)i);
|
||||
flts[1-sense_agreement] = value * parameterFactor;
|
||||
has_flts[1-sense_agreement] = true;
|
||||
}
|
||||
}
|
||||
trim_cartesian &= has_pnts[0] && has_pnts[1];
|
||||
bool trim_cartesian_failed = !trim_cartesian;
|
||||
if ( trim_cartesian ) {
|
||||
// TODO: Project points to closest point in curve?
|
||||
if ( CGAL::squared_distance(pnts[0], pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE) ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l);
|
||||
return false;
|
||||
}
|
||||
if (l->SenseAgreement()) {
|
||||
bool found = false;
|
||||
int loops_to_go = 2;
|
||||
std::vector<Kernel_::Point_3>::const_iterator point = curve.begin();
|
||||
do {
|
||||
if (!found) {
|
||||
if (CGAL::squared_distance(*point, pnts[0]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) {
|
||||
found = true;
|
||||
w.push_back(*point);
|
||||
}
|
||||
} else {
|
||||
w.push_back(*point);
|
||||
if (CGAL::squared_distance(*point, pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) {
|
||||
break;
|
||||
}
|
||||
} ++point;
|
||||
if (point == curve.end()) {
|
||||
point = curve.begin();
|
||||
--loops_to_go;
|
||||
}
|
||||
} while (point != curve.begin() && loops_to_go > 0);
|
||||
} else {
|
||||
bool found = false;
|
||||
int loops_to_go = 2;
|
||||
std::vector<Kernel_::Point_3>::const_reverse_iterator point = curve.rbegin();
|
||||
do {
|
||||
if (!found) {
|
||||
if (CGAL::squared_distance(*point, pnts[0]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) {
|
||||
found = true;
|
||||
w.push_back(*point);
|
||||
}
|
||||
} else {
|
||||
w.push_back(*point);
|
||||
if (CGAL::squared_distance(*point, pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) {
|
||||
break;
|
||||
}
|
||||
} ++point;
|
||||
if (point == curve.rend() && loops_to_go > 0) point = curve.rbegin();
|
||||
} while (point != curve.rbegin());
|
||||
}
|
||||
}
|
||||
if ( (!trim_cartesian || trim_cartesian_failed) && (has_flts[0] && has_flts[1]) ) {
|
||||
// The Geom_Line is constructed from a gp_Pnt and gp_Dir, whereas the IfcLine
|
||||
// is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because
|
||||
// the vector is normalised when passed to Geom_Line constructor the magnitude
|
||||
// needs to be factored in with the IfcParameterValue here.
|
||||
if ( basis_curve->as<IfcSchema::IfcLine>() ) {
|
||||
IfcSchema::IfcLine* line = static_cast<IfcSchema::IfcLine*>(basis_curve);
|
||||
const double magnitude = line->Dir()->Magnitude();
|
||||
flts[0] *= magnitude; flts[1] *= magnitude;
|
||||
}
|
||||
if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],M_PI*2.),0.) ) {
|
||||
for (auto &point: curve) w.push_back(point);
|
||||
} else {
|
||||
const int segments_of_full_curve = 12;
|
||||
double segment_angle = 2.0*3.141592653589793/segments_of_full_curve;
|
||||
if ( basis_curve->as<IfcSchema::IfcEllipse>() ) {
|
||||
IfcSchema::IfcEllipse* ellipse = static_cast<IfcSchema::IfcEllipse*>(basis_curve);
|
||||
double x = ellipse->SemiAxis1() * getValue(GV_LENGTH_UNIT);
|
||||
double y = ellipse->SemiAxis2() * getValue(GV_LENGTH_UNIT);
|
||||
for (double current_angle = flts[0]; current_angle < flts[1]; current_angle += segment_angle) {
|
||||
w.push_back(Kernel_::Point_3(x*cos(current_angle), y*sin(current_angle), 0));
|
||||
} w.push_back(Kernel_::Point_3(x*cos(flts[1]), y*sin(flts[1]), 0));
|
||||
} if ( basis_curve->as<IfcSchema::IfcCircle>() ) {
|
||||
IfcSchema::IfcCircle* circle = static_cast<IfcSchema::IfcCircle*>(basis_curve);
|
||||
double r = circle->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
for (double current_angle = flts[0]; current_angle < flts[1]; current_angle += segment_angle) {
|
||||
w.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0));
|
||||
} w.push_back(Kernel_::Point_3(r*cos(flts[1]), r*sin(flts[1]), 0));
|
||||
}
|
||||
}
|
||||
} else if ( trim_cartesian_failed && (has_pnts[0] && has_pnts[1]) ) {
|
||||
w.push_back(pnts[0]);
|
||||
w.push_back(pnts[1]);
|
||||
}
|
||||
wire = w;
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "CgalKernel.h"
|
||||
|
||||
namespace {
|
||||
struct MAKE_TYPE_NAME(factory_t) {
|
||||
IfcGeom::Kernel* operator()(IfcParse::IfcFile* file) const {
|
||||
IfcGeom::MAKE_TYPE_NAME(CgalKernel)* k = new IfcGeom::MAKE_TYPE_NAME(CgalKernel);
|
||||
return k;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void MAKE_INIT_FN(KernelImplementation_cgal_)(IfcGeom::impl::KernelFactoryImplementation* mapping) {
|
||||
static const std::string schema_name = STRINGIFY(IfcSchema);
|
||||
MAKE_TYPE_NAME(factory_t) factory;
|
||||
mapping->bind(schema_name, "cgal", factory);
|
||||
}
|
||||
|
||||
#define CgalKernel MAKE_TYPE_NAME(CgalKernel)
|
||||
|
||||
bool IfcGeom::CgalKernel::is_identity_transform(const IfcUtil::IfcBaseClass* l) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Not implemented is_identity_transform()");
|
||||
return false;
|
||||
/*
|
||||
// OpenCascade kernel code below
|
||||
|
||||
IfcSchema::IfcAxis2Placement2D* ax2d;
|
||||
IfcSchema::IfcAxis2Placement3D* ax3d;
|
||||
|
||||
IfcSchema::IfcCartesianTransformationOperator2D* op2d;
|
||||
IfcSchema::IfcCartesianTransformationOperator3D* op3d;
|
||||
IfcSchema::IfcCartesianTransformationOperator2DnonUniform* op2dnonu;
|
||||
IfcSchema::IfcCartesianTransformationOperator3DnonUniform* op3dnonu;
|
||||
|
||||
if ((op2dnonu = l->as<IfcSchema::IfcCartesianTransformationOperator2DnonUniform>()) != 0) {
|
||||
gp_GTrsf2d gtrsf2d;
|
||||
convert(op2dnonu, gtrsf2d);
|
||||
return gtrsf2d.Form() == gp_Identity;
|
||||
} else if ((op2d = l->as<IfcSchema::IfcCartesianTransformationOperator2D>()) != 0) {
|
||||
gp_Trsf2d trsf2d;
|
||||
convert(op2d, trsf2d);
|
||||
return trsf2d.Form() == gp_Identity;
|
||||
} else if ((op3dnonu = l->as<IfcSchema::IfcCartesianTransformationOperator3DnonUniform>()) != 0) {
|
||||
gp_GTrsf gtrsf;
|
||||
convert(op3dnonu, gtrsf);
|
||||
return gtrsf.Form() == gp_Identity;
|
||||
} else if ((op3d = l->as<IfcSchema::IfcCartesianTransformationOperator3D>()) != 0) {
|
||||
gp_Trsf trsf;
|
||||
convert(op3d, trsf);
|
||||
return trsf.Form() == gp_Identity;
|
||||
} else if ((ax2d = l->as<IfcSchema::IfcAxis2Placement2D>()) != 0) {
|
||||
gp_Trsf2d trsf2d;
|
||||
convert(ax2d, trsf2d);
|
||||
return trsf2d.Form() == gp_Identity;
|
||||
} else if ((ax3d = l->as<IfcSchema::IfcAxis2Placement3D>()) != 0) {
|
||||
gp_Trsf trsf;
|
||||
convert(ax3d, trsf);
|
||||
return trsf.Form() == gp_Identity;
|
||||
} else {
|
||||
throw IfcParse::IfcException("Invalid valuation for IfcAxis2Placement / IfcCartesianTransformationOperator");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::apply_layerset(const IfcSchema::IfcProduct* product, IfcGeom::ConversionResults& shapes) {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::validate_quantities(const IfcSchema::IfcProduct* product, const IfcGeom::Representation::BRep& brep) {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf) {
|
||||
if (item->as<IfcSchema::IfcObjectPlacement>()) {
|
||||
cgal_placement_t cgal_trsf;
|
||||
if (convert(item->as<IfcSchema::IfcObjectPlacement>(), cgal_trsf)) {
|
||||
trsf = new CgalPlacement(cgal_trsf);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* product, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcGeom::ConversionResults& entity_shapes, const IfcGeom::ConversionResultPlacement* trsf, IfcGeom::ConversionResults& opened_shapes) {
|
||||
const cgal_placement_t& entity_trsf = ((CgalPlacement*) trsf)->trsf();
|
||||
std::list<cgal_shape_t> opening_shapelist;
|
||||
|
||||
for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) {
|
||||
IfcSchema::IfcRelVoidsElement* v = *it;
|
||||
IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement();
|
||||
if ( fes->as<IfcSchema::IfcOpeningElement>() ) {
|
||||
if (!fes->hasRepresentation()) continue;
|
||||
|
||||
// Convert the IfcRepresentation of the IfcOpeningElement
|
||||
cgal_placement_t opening_trsf;
|
||||
if (fes->hasObjectPlacement()) {
|
||||
try {
|
||||
convert(fes->ObjectPlacement(),opening_trsf);
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
// Move the opening into the coordinate system of the IfcProduct
|
||||
opening_trsf = entity_trsf.inverse() * opening_trsf;
|
||||
|
||||
IfcSchema::IfcProductRepresentation* prodrep = fes->Representation();
|
||||
IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations();
|
||||
|
||||
IfcGeom::ConversionResults opening_shapes;
|
||||
|
||||
for ( IfcSchema::IfcRepresentation::list::it it2 = reps->begin(); it2 != reps->end(); ++ it2 ) {
|
||||
convert_shapes(*it2,opening_shapes);
|
||||
}
|
||||
|
||||
for ( unsigned int i = 0; i < opening_shapes.size(); ++ i ) {
|
||||
cgal_placement_t gtrsf;
|
||||
if (opening_shapes[i].Placement()) {
|
||||
gtrsf = *(CgalPlacement*)opening_shapes[i].Placement();
|
||||
}
|
||||
gtrsf = opening_trsf * gtrsf;
|
||||
cgal_shape_t opening_shape(((CgalShape*)opening_shapes[i].Shape())->shape());
|
||||
for (auto &vertex: vertices(opening_shape)) vertex->point() = vertex->point().transform(gtrsf);
|
||||
opening_shapelist.push_back(opening_shape);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over the shapes of the IfcProduct
|
||||
for ( IfcGeom::ConversionResults::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) {
|
||||
const cgal_shape_t& entity_shape_unlocated(((CgalShape*)it3->Shape())->shape());
|
||||
cgal_shape_t entity_shape(entity_shape_unlocated);
|
||||
if (it3->Placement()) {
|
||||
const cgal_placement_t& entity_shape_gtrsf = *(CgalPlacement*)it3->Placement();
|
||||
for (auto &vertex: vertices(entity_shape)) vertex->point() = vertex->point().transform(entity_shape_gtrsf);
|
||||
}
|
||||
|
||||
cgal_shape_t original_entity_shape(entity_shape);
|
||||
|
||||
if (!entity_shape.is_valid()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Invalid geometry:", product);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!entity_shape.is_closed()) {
|
||||
// TODO: There can be substractions to remove parts of non-volumetric objects. Maybe iterate over all faces of an entity and put them in a Nef_polyhedron_3 through Boolean union? Highly inefficient but maybe desirable...
|
||||
Logger::Message(Logger::LOG_ERROR, "Subtraction of openings not supported for non-closed geometry:", product);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
try {
|
||||
success = CGAL::Polygon_mesh_processing::triangulate_faces(entity_shape);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Triangulation of geometry crashed:", product);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Triangulation of geometry failed:", product);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CGAL::Polygon_mesh_processing::does_self_intersect(entity_shape)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Self-intersecting geometry:", product);
|
||||
return false;
|
||||
}
|
||||
|
||||
CGAL::Nef_polyhedron_3<Kernel_> nef_brep_cut_result;
|
||||
|
||||
try {
|
||||
nef_brep_cut_result = CGAL::Nef_polyhedron_3<Kernel_>(entity_shape);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Could not convert geometry to Nef:", product);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
cgal_shape_t brep_cut_result;
|
||||
nef_brep_cut_result.convert_to_polyhedron(brep_cut_result);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Final conversion will likely fail. Could not convert geometry from Nef:", product);
|
||||
}
|
||||
|
||||
for (auto &opening: opening_shapelist) {
|
||||
|
||||
cgal_shape_t original_opening_shape(opening);
|
||||
if (!opening.is_valid()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Invalid opening in geometry:", product);
|
||||
return false;
|
||||
} if (!opening.is_closed()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Subtraction of opening makes no sense. Not closed opening in geometry:", product);
|
||||
return false;
|
||||
}
|
||||
|
||||
success = false;
|
||||
|
||||
try {
|
||||
success = CGAL::Polygon_mesh_processing::triangulate_faces(opening);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Triangulation of opening of geometry crashed:", product);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Triangulation of opening of geometry failed:", product);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CGAL::Polygon_mesh_processing::does_self_intersect(entity_shape)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Self-intersecting opening of geometry:", product);
|
||||
}
|
||||
|
||||
CGAL::Nef_polyhedron_3<Kernel_> nef_opening;
|
||||
|
||||
try {
|
||||
nef_opening = CGAL::Nef_polyhedron_3<Kernel_>(opening);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Could not convert opening of geometry to Nef:", product);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
cgal_shape_t opening_shape;
|
||||
nef_opening.convert_to_polyhedron(opening_shape);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Final conversion will likely fail. Could not convert opening of geometry from Nef:", product);
|
||||
// return false;
|
||||
}
|
||||
|
||||
try {
|
||||
nef_brep_cut_result -= nef_opening;
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Could not subtract Nef opening of geometry:", product);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
nef_brep_cut_result.convert_to_polyhedron(entity_shape);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Could not convert geometry with openings from Nef:", product);
|
||||
return false;
|
||||
}
|
||||
|
||||
opened_shapes.push_back(IfcGeom::ConversionResult(it3->ItemId(), new CgalShape(entity_shape), &it3->Style()));
|
||||
|
||||
} return true;
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef CGAL_KERNEL_H
|
||||
#define CGAL_KERNEL_H
|
||||
|
||||
/*
|
||||
#ifdef NO_CACHE
|
||||
|
||||
#define IN_CACHE(T,E,t,e)
|
||||
#define CACHE(T,E,e)
|
||||
|
||||
#else
|
||||
|
||||
#define IN_CACHE(T,E,t,e) std::map<int,t>::const_iterator it = cache.T.find(E->entity->id());\
|
||||
if ( it != cache.T.end() ) { e = it->second; return true; }
|
||||
#define CACHE(T,E,e) cache.T[E->entity->id()] = e;
|
||||
|
||||
#endif
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#define ALMOST_ZERO 1.e-9
|
||||
|
||||
template <typename T>
|
||||
inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMOST_ZERO) {
|
||||
return fabs(a-b) < tolerance;
|
||||
}
|
||||
|
||||
#include "../../../ifcparse/macros.h"
|
||||
|
||||
#include "../../../ifcgeom/kernel_agnostic/AbstractKernel.h"
|
||||
|
||||
#include "../../../ifcgeom/schema_agnostic/Kernel.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h"
|
||||
|
||||
// @todo create separate shapetype enum?
|
||||
#include "../../../ifcgeom/kernels/opencascade/IfcGeomShapeType.h"
|
||||
|
||||
#define INCLUDE_SCHEMA(x) STRINGIFY(../../../ifcparse/x.h)
|
||||
#include INCLUDE_SCHEMA(IfcSchema)
|
||||
#undef INCLUDE_SCHEMA
|
||||
|
||||
struct PolyhedronBuilder : public CGAL::Modifier_base<CGAL::Polyhedron_3<Kernel_>::HalfedgeDS> {
|
||||
private:
|
||||
std::list<cgal_face_t> *face_list;
|
||||
public:
|
||||
PolyhedronBuilder(std::list<cgal_face_t> *face_list) {
|
||||
this->face_list = face_list;
|
||||
}
|
||||
|
||||
void operator()(CGAL::Polyhedron_3<Kernel_>::HalfedgeDS &hds) {
|
||||
std::list<Kernel_::Point_3> points;
|
||||
std::list<std::list<std::size_t>> facet_vertices;
|
||||
CGAL::Polyhedron_incremental_builder_3<CGAL::Polyhedron_3<Kernel_>::HalfedgeDS> builder(hds, true);
|
||||
|
||||
for (auto &face: *face_list) {
|
||||
facet_vertices.push_back(std::list<std::size_t>());
|
||||
for (auto &point: face.outer) {
|
||||
facet_vertices.back().push_back(points.size());
|
||||
points.push_back(point);
|
||||
}
|
||||
}
|
||||
|
||||
builder.begin_surface(points.size(), facet_vertices.size());
|
||||
|
||||
for (auto &point: points) {
|
||||
// std::cout << "Adding point " << point << std::endl;
|
||||
builder.add_vertex(point);
|
||||
}
|
||||
|
||||
for (auto &facet: facet_vertices) {
|
||||
builder.begin_facet();
|
||||
// std::cout << "Adding facet ";
|
||||
for (auto &vertex: facet) {
|
||||
// std::cout << vertex << " ";
|
||||
builder.add_vertex_to_facet(vertex);
|
||||
}
|
||||
// std::cout << std::endl;
|
||||
builder.end_facet();
|
||||
}
|
||||
|
||||
builder.end_surface();
|
||||
}
|
||||
};
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
class IFC_GEOM_API CgalCache {
|
||||
public:
|
||||
#include "CgalEntityMappingCreateCache.h"
|
||||
std::map<int, cgal_shape_t> Shape;
|
||||
};
|
||||
|
||||
class IFC_GEOM_API MAKE_TYPE_NAME(CgalKernel) : public MAKE_TYPE_NAME(AbstractKernel) {
|
||||
public:
|
||||
|
||||
MAKE_TYPE_NAME(CgalKernel)()
|
||||
: MAKE_TYPE_NAME(AbstractKernel)("cgal") {}
|
||||
|
||||
#ifndef NO_CACHE
|
||||
CgalCache cache;
|
||||
#endif
|
||||
|
||||
IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseClass* L);
|
||||
|
||||
bool convert_shapes(const IfcUtil::IfcBaseClass* L, ConversionResults& result);
|
||||
bool convert_shape(const IfcUtil::IfcBaseClass* L, cgal_shape_t& result);
|
||||
bool convert_wire(const IfcUtil::IfcBaseClass* L, cgal_wire_t& result);
|
||||
bool convert_curve(const IfcUtil::IfcBaseClass* L, cgal_curve_t& result);
|
||||
bool convert_face(const IfcUtil::IfcBaseClass* L, cgal_face_t& result);
|
||||
|
||||
bool convert_wire_to_face(const cgal_wire_t& wire, cgal_face_t& face);
|
||||
|
||||
void remove_duplicate_points_from_loop(cgal_wire_t& polygon);
|
||||
|
||||
bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const cgal_placement_t& entity_trsf, ConversionResults& cut_shapes);
|
||||
|
||||
// CGAL::Polyhedron_3<Kernel_> triangulate_faces(CGAL::Polyhedron_3<Kernel_> &polyhedron);
|
||||
CGAL::Polyhedron_3<Kernel_> create_polyhedron(std::list<cgal_face_t> &face_list);
|
||||
CGAL::Polyhedron_3<Kernel_> create_polyhedron(CGAL::Nef_polyhedron_3<Kernel_> &nef_polyhedron);
|
||||
CGAL::Nef_polyhedron_3<Kernel_> create_nef_polyhedron(std::list<cgal_face_t> &face_list);
|
||||
CGAL::Nef_polyhedron_3<Kernel_> create_nef_polyhedron(CGAL::Polyhedron_3<Kernel_> &polyhedron);
|
||||
|
||||
void purge_cache() {
|
||||
// Rather hack-ish, but a stopgap solution to keep memory under control
|
||||
// for large files. SurfaceStyles need to be kept at all costs, as they
|
||||
// are read later on when serializing Collada files.
|
||||
#ifndef NO_CACHE
|
||||
cache = CgalCache();
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual bool is_identity_transform(const IfcUtil::IfcBaseClass*);
|
||||
virtual bool apply_layerset(const IfcSchema::IfcProduct* product, IfcGeom::ConversionResults& shapes);
|
||||
virtual bool validate_quantities(const IfcSchema::IfcProduct* product, const IfcGeom::Representation::BRep& brep);
|
||||
virtual bool convert_openings(const IfcSchema::IfcProduct* product, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcGeom::ConversionResults& shapes, const ConversionResultPlacement* trsf, IfcGeom::ConversionResults& opened_shapes);
|
||||
virtual bool convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf);
|
||||
|
||||
#include "CgalEntityMappingDeclaration.h"
|
||||
|
||||
private:
|
||||
double deflection_tolerance;
|
||||
double dimensionality;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -48,18 +48,21 @@ inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMO
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
|
||||
#include "../ifcparse/macros.h"
|
||||
#include "../ifcparse/IfcParse.h"
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../../../ifcparse/macros.h"
|
||||
#include "../../../ifcparse/IfcParse.h"
|
||||
#include "../../../ifcparse/IfcBaseClass.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
#include "../ifcgeom/IfcGeomRepresentation.h"
|
||||
#include "../ifcgeom/IfcRepresentationShapeItem.h"
|
||||
#include "../ifcgeom/IfcGeomShapeType.h"
|
||||
#include "../../../ifcgeom/kernel_agnostic/AbstractKernel.h"
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/Kernel.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/ConversionResult.h"
|
||||
#include "../../../ifcgeom/kernels/opencascade/IfcGeomShapeType.h"
|
||||
|
||||
#include "ifc_geom_api.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/Kernel.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h"
|
||||
|
||||
#include "../../../ifcgeom/schema_agnostic/ifc_geom_api.h"
|
||||
|
||||
// Define this in case you want to conserve memory usage at all cost. This has been
|
||||
// benchmarked extensively: https://github.com/IfcOpenShell/IfcOpenShell/pull/47
|
||||
@@ -78,11 +81,12 @@ if ( it != cache.T.end() ) { e = it->second; return true; }
|
||||
|
||||
#endif
|
||||
|
||||
#define INCLUDE_PARENT_DIR(x) STRINGIFY(../ifcparse/x.h)
|
||||
#include INCLUDE_PARENT_DIR(IfcSchema)
|
||||
#undef INCLUDE_PARENT_DIR
|
||||
#define INCLUDE_PARENT_DIR(x) STRINGIFY(../ifcparse/x-definitions.h)
|
||||
#include INCLUDE_PARENT_DIR(IfcSchema)
|
||||
#define INCLUDE_SCHEMA(x) STRINGIFY(../../../ifcparse/x.h)
|
||||
#include INCLUDE_SCHEMA(IfcSchema)
|
||||
#undef INCLUDE_SCHEMA
|
||||
#define INCLUDE_SCHEMA(x) STRINGIFY(../../../ifcparse/x-definitions.h)
|
||||
#include INCLUDE_SCHEMA(IfcSchema)
|
||||
#undef INCLUDE_SCHEMA
|
||||
|
||||
namespace IfcGeom {
|
||||
class IFC_GEOM_API geometry_exception : public std::exception {
|
||||
@@ -109,7 +113,7 @@ public:
|
||||
std::map<int, TopoDS_Shape> Shape;
|
||||
};
|
||||
|
||||
class IFC_GEOM_API MAKE_TYPE_NAME(Kernel) : public IfcGeom::Kernel {
|
||||
class IFC_GEOM_API MAKE_TYPE_NAME(Kernel) : public IfcGeom::MAKE_TYPE_NAME(AbstractKernel) {
|
||||
private:
|
||||
|
||||
/*
|
||||
@@ -213,42 +217,23 @@ private:
|
||||
double epsilon() const {
|
||||
return eps_;
|
||||
}
|
||||
};
|
||||
|
||||
double deflection_tolerance;
|
||||
double ifc_length_unit;
|
||||
double ifc_planeangle_unit;
|
||||
double modelling_precision;
|
||||
double dimensionality;
|
||||
double max_faces_to_orient;
|
||||
};
|
||||
|
||||
#ifndef NO_CACHE
|
||||
MAKE_TYPE_NAME(Cache) cache;
|
||||
#endif
|
||||
|
||||
std::map<int, SurfaceStyle> style_cache;
|
||||
|
||||
const SurfaceStyle* internalize_surface_style(const std::pair<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*>& shading_style);
|
||||
|
||||
// For stopping PlacementRelTo recursion in convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf)
|
||||
const IfcParse::declaration* placement_rel_to;
|
||||
|
||||
faceset_helper* faceset_helper_;
|
||||
|
||||
public:
|
||||
MAKE_TYPE_NAME(Kernel)()
|
||||
: IfcGeom::Kernel(0)
|
||||
, deflection_tolerance(0.001)
|
||||
, max_faces_to_orient(-1.0)
|
||||
, ifc_length_unit(1.0)
|
||||
, ifc_planeangle_unit(-1.0)
|
||||
, modelling_precision(0.00001)
|
||||
, dimensionality(1.)
|
||||
, placement_rel_to(0)
|
||||
: IfcGeom::MAKE_TYPE_NAME(AbstractKernel)("opencascade")
|
||||
, faceset_helper_(nullptr)
|
||||
{}
|
||||
|
||||
MAKE_TYPE_NAME(Kernel)(const MAKE_TYPE_NAME(Kernel)& other) : IfcGeom::Kernel(0) {
|
||||
MAKE_TYPE_NAME(Kernel)(const MAKE_TYPE_NAME(Kernel)& other)
|
||||
: IfcGeom::MAKE_TYPE_NAME(AbstractKernel)("opencascade")
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
@@ -265,21 +250,20 @@ public:
|
||||
|
||||
bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face);
|
||||
bool convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire);
|
||||
bool convert_shapes(const IfcUtil::IfcBaseClass* L, IfcRepresentationShapeItems& result);
|
||||
bool convert_shapes(const IfcUtil::IfcBaseClass* L, ConversionResults& result);
|
||||
IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseClass* L);
|
||||
bool convert_shape(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
|
||||
bool flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse);
|
||||
bool flatten_shape_list(const IfcGeom::ConversionResults& shapes, TopoDS_Shape& result, bool fuse);
|
||||
bool convert_wire(const IfcUtil::IfcBaseClass* L, TopoDS_Wire& result);
|
||||
bool convert_curve(const IfcUtil::IfcBaseClass* L, Handle(Geom_Curve)& result);
|
||||
bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
|
||||
bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
|
||||
bool convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
|
||||
bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const ConversionResultPlacement* entity_trsf, ConversionResults& cut_shapes);
|
||||
void assert_closed_wire(TopoDS_Wire& wire);
|
||||
|
||||
bool convert_layerset(const IfcSchema::IfcProduct*, std::vector<Handle_Geom_Surface>&, std::vector<const SurfaceStyle*>&, std::vector<double>&);
|
||||
bool apply_layerset(const IfcRepresentationShapeItems&, const std::vector<Handle_Geom_Surface>&, const std::vector<const SurfaceStyle*>&, IfcRepresentationShapeItems&);
|
||||
bool apply_folded_layerset(const IfcRepresentationShapeItems&, const std::vector< std::vector<Handle_Geom_Surface> >&, const std::vector<const SurfaceStyle*>&, IfcRepresentationShapeItems&);
|
||||
bool fold_layers(const IfcSchema::IfcWall*, const IfcRepresentationShapeItems&, const std::vector<Handle_Geom_Surface>&, const std::vector<double>&, std::vector< std::vector<Handle_Geom_Surface> >&);
|
||||
bool apply_layerset(const ConversionResults&, const std::vector<Handle_Geom_Surface>&, const std::vector<const SurfaceStyle*>&, ConversionResults&);
|
||||
bool apply_folded_layerset(const ConversionResults&, const std::vector< std::vector<Handle_Geom_Surface> >&, const std::vector<const SurfaceStyle*>&, ConversionResults&);
|
||||
bool fold_layers(const IfcSchema::IfcWall*, const ConversionResults&, const std::vector<Handle_Geom_Surface>&, const std::vector<double>&, std::vector< std::vector<Handle_Geom_Surface> >&);
|
||||
|
||||
bool split_solid_by_surface(const TopoDS_Shape&, const Handle_Geom_Surface&, TopoDS_Shape&, TopoDS_Shape&);
|
||||
bool split_solid_by_shell(const TopoDS_Shape&, const TopoDS_Shape& s, TopoDS_Shape&, TopoDS_Shape&);
|
||||
@@ -307,8 +291,6 @@ public:
|
||||
|
||||
bool find_wall_end_points(const IfcSchema::IfcWall*, gp_Pnt& start, gp_Pnt& end);
|
||||
|
||||
IfcSchema::IfcSurfaceStyleShading* get_surface_style(IfcSchema::IfcRepresentationItem* item);
|
||||
const IfcSchema::IfcRepresentationItem* find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item);
|
||||
bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid);
|
||||
bool create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& solid);
|
||||
bool is_compound(const TopoDS_Shape& shape);
|
||||
@@ -334,105 +316,38 @@ public:
|
||||
static double shape_volume(const TopoDS_Shape& s);
|
||||
static double face_area(const TopoDS_Face& f);
|
||||
|
||||
static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const OpenCascadePlacement*);
|
||||
static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_Trsf&);
|
||||
static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_GTrsf&);
|
||||
|
||||
bool is_identity_transform(IfcUtil::IfcBaseClass*);
|
||||
|
||||
IfcSchema::IfcRelVoidsElement::list::ptr find_openings(IfcSchema::IfcProduct* product);
|
||||
virtual bool is_identity_transform(const IfcUtil::IfcBaseClass*);
|
||||
virtual bool apply_layerset(const IfcSchema::IfcProduct* product, IfcGeom::ConversionResults& shapes);
|
||||
virtual bool validate_quantities(const IfcSchema::IfcProduct* product, const IfcGeom::Representation::BRep& brep);
|
||||
|
||||
IfcSchema::IfcRepresentation* find_representation(const IfcSchema::IfcProduct*, const std::string&);
|
||||
|
||||
|
||||
std::pair<std::string, double> initializeUnits(IfcSchema::IfcUnitAssignment*);
|
||||
|
||||
template <typename P, typename PP>
|
||||
IfcGeom::BRepElement<P, PP>* create_brep_for_representation_and_product(
|
||||
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*);
|
||||
|
||||
template <typename P, typename PP>
|
||||
IfcGeom::BRepElement<P, PP>* create_brep_for_processed_representation(
|
||||
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::BRepElement<P, PP>*);
|
||||
|
||||
const IfcSchema::IfcMaterial* get_single_material_association(const IfcSchema::IfcProduct*);
|
||||
IfcSchema::IfcRepresentation* representation_mapped_to(const IfcSchema::IfcRepresentation* representation);
|
||||
IfcSchema::IfcProduct::list::ptr products_represented_by(const IfcSchema::IfcRepresentation*);
|
||||
const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem*);
|
||||
const SurfaceStyle* get_style(const IfcSchema::IfcMaterial*);
|
||||
|
||||
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> _get_surface_style(const IfcSchema::IfcStyledItem* si) {
|
||||
#ifdef SCHEMA_HAS_IfcStyleAssignmentSelect
|
||||
IfcEntityList::ptr style_assignments = si->Styles();
|
||||
for (IfcEntityList::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
if (!(*kt)->declaration().is(IfcSchema::IfcPresentationStyleAssignment::Class())) {
|
||||
continue;
|
||||
}
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt;
|
||||
#else
|
||||
IfcSchema::IfcPresentationStyleAssignment::list::ptr style_assignments = si->Styles();
|
||||
for (IfcSchema::IfcPresentationStyleAssignment::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) {
|
||||
IfcSchema::IfcPresentationStyleAssignment* style_assignment = *kt;
|
||||
#endif
|
||||
IfcEntityList::ptr styles = style_assignment->Styles();
|
||||
for (IfcEntityList::it lt = styles->begin(); lt != styles->end(); ++lt) {
|
||||
IfcUtil::IfcBaseClass* style = *lt;
|
||||
if (style->declaration().is(IfcSchema::IfcSurfaceStyle::Class())) {
|
||||
IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style;
|
||||
if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) {
|
||||
IfcEntityList::ptr styles_elements = surface_style->Styles();
|
||||
for (IfcEntityList::it mt = styles_elements->begin(); mt != styles_elements->end(); ++mt) {
|
||||
if ((*mt)->declaration().is(T::Class())) {
|
||||
return std::make_pair(surface_style, (T*) *mt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0,0);
|
||||
}
|
||||
|
||||
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) {
|
||||
// For certain representation items, most notably boolean operands,
|
||||
// a style definition might reside on one of its operands.
|
||||
representation_item = find_item_carrying_style(representation_item);
|
||||
|
||||
if (representation_item->as<IfcSchema::IfcStyledItem>()) {
|
||||
return _get_surface_style<T>(representation_item->as<IfcSchema::IfcStyledItem>());
|
||||
}
|
||||
IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem();
|
||||
if (styled_items->size()) {
|
||||
// StyledByItem is a SET [0:1] OF IfcStyledItem, so we return after the first IfcStyledItem:
|
||||
return _get_surface_style<T>(*styled_items->begin());
|
||||
}
|
||||
return std::make_pair<IfcSchema::IfcSurfaceStyle*, T*>(0,0);
|
||||
}
|
||||
|
||||
void purge_cache() {
|
||||
void purge_cache() {
|
||||
// Rather hack-ish, but a stopgap solution to keep memory under control
|
||||
// for large files. SurfaceStyles need to be kept at all costs, as they
|
||||
// are read later on when serializing Collada files.
|
||||
#ifndef NO_CACHE
|
||||
cache = MAKE_TYPE_NAME(Cache)();
|
||||
#endif
|
||||
}
|
||||
|
||||
void set_conversion_placement_rel_to(const IfcParse::declaration* type);
|
||||
}
|
||||
|
||||
#include "IfcRegisterGeomHeader.h"
|
||||
|
||||
virtual void setValue(GeomValue var, double value);
|
||||
virtual double getValue(GeomValue var) const;
|
||||
|
||||
virtual IfcGeom::BRepElement<double>* convert(
|
||||
virtual IfcGeom::NativeElement<double>* convert(
|
||||
const IteratorSettings& settings, IfcUtil::IfcBaseClass* representation,
|
||||
IfcUtil::IfcBaseClass* product)
|
||||
{
|
||||
return create_brep_for_representation_and_product<double, double>(settings, (IfcSchema::IfcRepresentation*) representation, (IfcSchema::IfcProduct*) product);
|
||||
}
|
||||
|
||||
virtual IfcRepresentationShapeItems convert(IfcUtil::IfcBaseClass* item) {
|
||||
IfcRepresentationShapeItems items;
|
||||
virtual ConversionResults convert(IfcUtil::IfcBaseClass* item) {
|
||||
ConversionResults items;
|
||||
bool success = convert_shapes(item, items);
|
||||
if (!success) {
|
||||
throw IfcParse::IfcException("Failed to process representation item");
|
||||
@@ -440,12 +355,15 @@ public:
|
||||
return items;
|
||||
}
|
||||
|
||||
virtual bool convert_placement(IfcUtil::IfcBaseClass* item, gp_Trsf& trsf) {
|
||||
virtual bool convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf) {
|
||||
if (item->as<IfcSchema::IfcObjectPlacement>()) {
|
||||
return convert(item->as<IfcSchema::IfcObjectPlacement>(), trsf);
|
||||
} else {
|
||||
return false;
|
||||
gp_Trsf occt_trsf;
|
||||
if (convert(item->as<IfcSchema::IfcObjectPlacement>(), occt_trsf)) {
|
||||
trsf = new OpenCascadePlacement(occt_trsf);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -77,7 +77,7 @@
|
||||
|
||||
#include <TopLoc_Location.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h"
|
||||
|
||||
#ifdef SCHEMA_HAS_IfcBSplineCurveWithKnots
|
||||
#include <Geom_BSplineCurve.hxx>
|
||||
@@ -97,7 +97,7 @@
|
||||
|
||||
#include <BRepLib_FindSurface.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h"
|
||||
|
||||
#ifdef SCHEMA_HAS_IfcBSplineSurfaceWithKnots
|
||||
#include <Geom_BSplineSurface.hxx>
|
||||
+197
-837
File diff suppressed because it is too large
Load Diff
@@ -75,7 +75,7 @@
|
||||
|
||||
#include <TopLoc_Location.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
@@ -385,10 +385,6 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d
|
||||
return true;
|
||||
}
|
||||
|
||||
void IfcGeom::Kernel::set_conversion_placement_rel_to(const IfcParse::declaration* type) {
|
||||
placement_rel_to = type;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf) {
|
||||
IN_CACHE(IfcObjectPlacement,l,gp_Trsf,trsf)
|
||||
if ( ! l->declaration().is(IfcSchema::IfcLocalPlacement::Class()) ) {
|
||||
@@ -101,7 +101,7 @@
|
||||
|
||||
#include <TopTools_ListIteratorOfListOfShape.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -366,7 +366,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRevolvedAreaSolid* l, TopoDS_S
|
||||
return !shape.IsNull();
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, IfcRepresentationShapeItems& shape) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, ConversionResults& shape) {
|
||||
TopoDS_Shape s;
|
||||
const SurfaceStyle* collective_style = get_style(l);
|
||||
if (convert_shape(l->Outer(),s) ) {
|
||||
@@ -391,13 +391,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, IfcRepre
|
||||
}
|
||||
}
|
||||
|
||||
shape.push_back(IfcRepresentationShapeItem(l->data().id(), s, indiv_style ? indiv_style : collective_style));
|
||||
shape.push_back(ConversionResult(l->data().id(), new OpenCascadeShape(s), indiv_style ? indiv_style : collective_style));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFaceBasedSurfaceModel* l, IfcRepresentationShapeItems& shapes) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFaceBasedSurfaceModel* l, ConversionResults& shapes) {
|
||||
bool part_success = false;
|
||||
IfcSchema::IfcConnectedFaceSet::list::ptr facesets = l->FbsmFaces();
|
||||
const SurfaceStyle* collective_style = get_style(l);
|
||||
@@ -405,7 +405,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFaceBasedSurfaceModel* l, IfcR
|
||||
TopoDS_Shape s;
|
||||
const SurfaceStyle* shell_style = get_style(*it);
|
||||
if (convert_shape(*it,s)) {
|
||||
shapes.push_back(IfcRepresentationShapeItem(l->data().id(), s, shell_style ? shell_style : collective_style));
|
||||
shapes.push_back(ConversionResult(l->data().id(), new OpenCascadeShape(s), shell_style ? shell_style : collective_style));
|
||||
part_success |= true;
|
||||
}
|
||||
}
|
||||
@@ -459,7 +459,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, IfcRepresentationShapeItems& shapes) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, ConversionResults& shapes) {
|
||||
IfcEntityList::ptr shells = l->SbsmBoundary();
|
||||
const SurfaceStyle* collective_style = get_style(l);
|
||||
for( IfcEntityList::it it = shells->begin(); it != shells->end(); ++ it ) {
|
||||
@@ -469,7 +469,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, Ifc
|
||||
shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it);
|
||||
}
|
||||
if (convert_shape(*it,s)) {
|
||||
shapes.push_back(IfcRepresentationShapeItem(l->data().id(), s, shell_style ? shell_style : collective_style));
|
||||
shapes.push_back(ConversionResult(l->data().id(), new OpenCascadeShape(s), shell_style ? shell_style : collective_style));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -477,8 +477,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, Ifc
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) {
|
||||
|
||||
TopoDS_Shape s1;
|
||||
IfcRepresentationShapeItems items1;
|
||||
TopoDS_Shape s1, s2;
|
||||
ConversionResults items1;
|
||||
TopoDS_Wire boundary_wire;
|
||||
IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand();
|
||||
IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand();
|
||||
@@ -556,7 +556,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
|
||||
|
||||
{
|
||||
if (shape_type(op2) == ST_SHAPELIST) {
|
||||
IfcRepresentationShapeItems items2;
|
||||
ConversionResults items2;
|
||||
shape2_processed = convert_shapes(op2, items2) && flatten_shape_list(items2, s2, true);
|
||||
} else if (shape_type(op2) == ST_SHAPE) {
|
||||
shape2_processed = convert_shape(op2, s2);
|
||||
@@ -711,7 +711,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Sh
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentationShapeItems& shapes) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, ConversionResults& shapes) {
|
||||
gp_GTrsf gtrsf;
|
||||
IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget();
|
||||
if ( transform->declaration().is(IfcSchema::IfcCartesianTransformationOperator3DnonUniform::Class()) ) {
|
||||
@@ -746,7 +746,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentati
|
||||
bool b = convert_shapes(map->MappedRepresentation(), shapes);
|
||||
|
||||
for (size_t i = previous_size; i < shapes.size(); ++ i ) {
|
||||
shapes[i].prepend(gtrsf);
|
||||
OpenCascadePlacement p(gtrsf);
|
||||
shapes[i].prepend(&p);
|
||||
|
||||
// Apply styles assigned to the mapped item only if on
|
||||
// a more granular level no styles have been applied
|
||||
@@ -758,7 +759,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentati
|
||||
return b;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRepresentation* l, IfcRepresentationShapeItems& shapes) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRepresentation* l, ConversionResults& shapes) {
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items = l->Items();
|
||||
bool part_succes = false;
|
||||
if ( items->size() ) {
|
||||
@@ -769,7 +770,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRepresentation* l, IfcRepresen
|
||||
} else {
|
||||
TopoDS_Shape s;
|
||||
if (convert_shape(representation_item,s)) {
|
||||
shapes.push_back(IfcRepresentationShapeItem(representation_item->data().id(), s, get_style(representation_item)));
|
||||
shapes.push_back(ConversionResult(representation_item->data().id(), new OpenCascadeShape(s), get_style(representation_item)));
|
||||
part_succes |= true;
|
||||
}
|
||||
}
|
||||
@@ -778,7 +779,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRepresentation* l, IfcRepresen
|
||||
return part_succes;
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcGeometricSet* l, IfcRepresentationShapeItems& shapes) {
|
||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcGeometricSet* l, ConversionResults& shapes) {
|
||||
IfcEntityList::ptr elements = l->Elements();
|
||||
if ( !elements->size() ) return false;
|
||||
bool part_succes = false;
|
||||
@@ -796,7 +797,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcGeometricSet* l, IfcRepresenta
|
||||
} else if (element->declaration().is(IfcSchema::IfcSurface::Class())) {
|
||||
style = get_style((IfcSchema::IfcSurface*) element);
|
||||
}
|
||||
shapes.push_back(IfcRepresentationShapeItem(l->data().id(), s, style ? style : parent_style));
|
||||
shapes.push_back(ConversionResult(l->data().id(), new OpenCascadeShape(s), style ? style : parent_style));
|
||||
}
|
||||
}
|
||||
return part_succes;
|
||||
@@ -20,10 +20,11 @@
|
||||
#ifndef IFCGEOMTREE_H
|
||||
#define IFCGEOMTREE_H
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom_schema_agnostic/Kernel.h"
|
||||
#include "../../../ifcparse/IfcFile.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/Kernel.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h"
|
||||
|
||||
#include <NCollection_UBTree.hxx>
|
||||
#include <BRepBndLib.hxx>
|
||||
@@ -113,7 +114,8 @@ namespace IfcGeom {
|
||||
std::vector<T> ts_filtered;
|
||||
|
||||
const TopoDS_Shape& A = shapes_.find(t)->second;
|
||||
if (IfcGeom::Kernel::count(A, TopAbs_SHELL) == 0) {
|
||||
OpenCascadeShape SA(A);
|
||||
if (IfcGeom::Kernel::count(&SA, (int) TopAbs_SHELL) == 0) {
|
||||
return ts_filtered;
|
||||
}
|
||||
|
||||
@@ -122,21 +124,24 @@ namespace IfcGeom {
|
||||
typename std::vector<T>::const_iterator it = ts.begin();
|
||||
for (it = ts.begin(); it != ts.end(); ++it) {
|
||||
const TopoDS_Shape& B = shapes_.find(*it)->second;
|
||||
if (IfcGeom::Kernel::count(B, TopAbs_SHELL) == 0) {
|
||||
OpenCascadeShape SB(B);
|
||||
if (IfcGeom::Kernel::count(&SB, (int) TopAbs_SHELL) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (completely_within) {
|
||||
BRepAlgoAPI_Cut cut(B, A);
|
||||
if (cut.IsDone()) {
|
||||
if (IfcGeom::Kernel::count(cut.Shape(), TopAbs_SHELL) == 0) {
|
||||
OpenCascadeShape Sc(cut.Shape());
|
||||
if (IfcGeom::Kernel::count(&Sc, (int) TopAbs_SHELL) == 0) {
|
||||
ts_filtered.push_back(*it);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
BRepAlgoAPI_Common common(A, B);
|
||||
if (common.IsDone()) {
|
||||
if (IfcGeom::Kernel::count(common.Shape(), TopAbs_SHELL) > 0) {
|
||||
OpenCascadeShape Sc(common.Shape());
|
||||
if (IfcGeom::Kernel::count(&Sc, (int) TopAbs_SHELL) > 0) {
|
||||
ts_filtered.push_back(*it);
|
||||
}
|
||||
}
|
||||
@@ -152,7 +157,8 @@ namespace IfcGeom {
|
||||
|
||||
std::vector<T> ts;
|
||||
|
||||
if (IfcGeom::Kernel::count(s, TopAbs_SHELL) == 0) {
|
||||
OpenCascadeShape Ss(s);
|
||||
if (IfcGeom::Kernel::count(&Ss, (int) TopAbs_SHELL) == 0) {
|
||||
return ts;
|
||||
}
|
||||
|
||||
@@ -169,13 +175,15 @@ namespace IfcGeom {
|
||||
for (it = ts.begin(); it != ts.end(); ++it) {
|
||||
const TopoDS_Shape& B = shapes_.find(*it)->second;
|
||||
|
||||
if (IfcGeom::Kernel::count(B, TopAbs_SHELL) == 0) {
|
||||
OpenCascadeShape SB(B);
|
||||
if (IfcGeom::Kernel::count(&SB, (int) TopAbs_SHELL) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BRepAlgoAPI_Common common(s, B);
|
||||
if (common.IsDone()) {
|
||||
if (IfcGeom::Kernel::count(common.Shape(), TopAbs_SHELL) > 0) {
|
||||
OpenCascadeShape Sc(common.Shape());;
|
||||
if (IfcGeom::Kernel::count(&Sc, (int) TopAbs_SHELL) > 0) {
|
||||
ts_filtered.push_back(*it);
|
||||
}
|
||||
}
|
||||
@@ -268,8 +276,8 @@ namespace IfcGeom {
|
||||
|
||||
if (it.initialize()) {
|
||||
do {
|
||||
IfcGeom::BRepElement<double>* elem = (IfcGeom::BRepElement<double>*)it.get();
|
||||
add((IfcUtil::IfcBaseEntity*)f.instance_by_id(elem->id()), elem->geometry().as_compound());
|
||||
IfcGeom::NativeElement<double>* elem = (IfcGeom::NativeElement<double>*)it.get();
|
||||
add((IfcUtil::IfcBaseEntity*)f.instance_by_id(elem->id()), ((OpenCascadeShape*)elem->geometry().as_compound())->shape());
|
||||
} while (it.next());
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,7 @@
|
||||
#include <BRepAdaptor_HCompCurve.hxx>
|
||||
#include <Approx_Curve3d.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h"
|
||||
|
||||
#define Kernel MAKE_TYPE_NAME(Kernel)
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
|
||||
using namespace IfcUtil;
|
||||
|
||||
bool IfcGeom::Kernel::convert_shapes(const IfcBaseClass* l, IfcRepresentationShapeItems& r) {
|
||||
bool IfcGeom::Kernel::convert_shapes(const IfcBaseClass* l, ConversionResults& r) {
|
||||
if (shape_type(l) != ST_SHAPELIST) {
|
||||
TopoDS_Shape shp;
|
||||
if (convert_shape(l, shp)) {
|
||||
r.push_back(IfcGeom::IfcRepresentationShapeItem(l->data().id(), shp, get_style(l->as<IfcSchema::IfcRepresentationItem>())));
|
||||
r.push_back(IfcGeom::ConversionResult(l->data().id(), new OpenCascadeShape(shp), get_style(l->as<IfcSchema::IfcRepresentationItem>())));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -61,7 +61,7 @@ bool IfcGeom::Kernel::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) {
|
||||
ignored = (!include_solids_and_surfaces && (st == ST_SHAPE || st == ST_FACE)) || (!include_curves && (st == ST_WIRE || st == ST_CURVE));
|
||||
if (st == ST_SHAPELIST) {
|
||||
processed = true;
|
||||
IfcRepresentationShapeItems items;
|
||||
ConversionResults items;
|
||||
success = convert_shapes(l, items) && flatten_shape_list(items, r, false);
|
||||
} else if (st == ST_SHAPE && include_solids_and_surfaces) {
|
||||
#include "IfcRegisterConvertShape.h"
|
||||
@@ -38,8 +38,8 @@
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../ifcparse/IfcParse.h"
|
||||
#include "../../../ifcparse/IfcBaseClass.h"
|
||||
#include "../../../ifcparse/IfcParse.h"
|
||||
|
||||
SHAPES(IfcShellBasedSurfaceModel);
|
||||
SHAPES(IfcFaceBasedSurfaceModel);
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef SHAPES
|
||||
#define SHAPES(T)
|
||||
#endif
|
||||
#ifndef SHAPE
|
||||
#define SHAPE(T)
|
||||
#endif
|
||||
#ifndef WIRE
|
||||
#define WIRE(T)
|
||||
#endif
|
||||
#ifndef FACE
|
||||
#define FACE(T)
|
||||
#endif
|
||||
#ifndef CURVE
|
||||
#define CURVE(T)
|
||||
#endif
|
||||
#ifndef CLASS
|
||||
#define CLASS(T,V)
|
||||
#endif
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#include "IfcRegisterUndef.h"
|
||||
#define CLASS(T,V) bool convert(const IfcSchema::T* L, V& r);
|
||||
#define SHAPES(T) CLASS(T,IfcRepresentationShapeItems)
|
||||
#define SHAPES(T) CLASS(T,ConversionResults)
|
||||
#define SHAPE(T) CLASS(T,TopoDS_Shape)
|
||||
#define WIRE(T) CLASS(T,TopoDS_Wire)
|
||||
#define FACE(T) CLASS(T,TopoDS_Shape)
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifdef SHAPES
|
||||
#undef SHAPES
|
||||
#endif
|
||||
#ifdef SHAPE
|
||||
#undef SHAPE
|
||||
#endif
|
||||
#ifdef WIRE
|
||||
#undef WIRE
|
||||
#endif
|
||||
#ifdef FACE
|
||||
#undef FACE
|
||||
#endif
|
||||
#ifdef CURVE
|
||||
#undef CURVE
|
||||
#endif
|
||||
#ifdef CLASS
|
||||
#undef CLASS
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCSHAPELIST_H
|
||||
#define IFCSHAPELIST_H
|
||||
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomRenderStyles.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
namespace Representation {
|
||||
template <typename P>
|
||||
class IFC_GEOM_API Triangulation;
|
||||
}
|
||||
|
||||
class IFC_GEOM_API ConversionResultPlacement {
|
||||
public:
|
||||
virtual void Multiply(const ConversionResultPlacement*) = 0;
|
||||
virtual void PreMultiply(const ConversionResultPlacement*) = 0;
|
||||
virtual void TranslationPart(double& X, double& Y, double& Z) const = 0;
|
||||
virtual ConversionResultPlacement* inverted() const = 0;
|
||||
virtual ConversionResultPlacement* multiplied(const ConversionResultPlacement*) const = 0;
|
||||
virtual double Value(int i, int j) const = 0;
|
||||
virtual ConversionResultPlacement* clone() const = 0;
|
||||
virtual ~ConversionResultPlacement() {}
|
||||
};
|
||||
|
||||
class IFC_GEOM_API ConversionResultShape {
|
||||
public:
|
||||
virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement* place, IfcGeom::Representation::Triangulation<float>* t, int surface_style_id) const = 0;
|
||||
virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement* place, IfcGeom::Representation::Triangulation<double>* t, int surface_style_id) const = 0;
|
||||
virtual void Serialize(std::string&) const = 0;
|
||||
virtual ConversionResultShape* clone() const = 0;
|
||||
virtual int surface_genus() const = 0;
|
||||
virtual ~ConversionResultShape() {}
|
||||
};
|
||||
|
||||
class IFC_GEOM_API ConversionResult {
|
||||
private:
|
||||
int id;
|
||||
ConversionResultPlacement* placement;
|
||||
ConversionResultShape* shape;
|
||||
const SurfaceStyle* style;
|
||||
public:
|
||||
ConversionResult(int id, const ConversionResultPlacement* placement, const ConversionResultShape* shape, const SurfaceStyle* style)
|
||||
: id(id), placement(placement ? placement->clone() : nullptr), shape(shape->clone()), style(style) {}
|
||||
ConversionResult(int id, const ConversionResultPlacement* placement, const ConversionResultShape* shape)
|
||||
: id(id), placement(placement ? placement->clone() : nullptr), shape(shape->clone()), style(0) {}
|
||||
ConversionResult(int id, const ConversionResultShape* shape, const SurfaceStyle* style)
|
||||
: id(id), placement(0), shape(shape->clone()), style(style) {}
|
||||
ConversionResult(int id, const ConversionResultShape* shape)
|
||||
: id(id), placement(0), shape(shape->clone()), style(0) {}
|
||||
void append(const ConversionResultPlacement* trsf) {
|
||||
if (placement == 0) {
|
||||
placement = trsf->clone();
|
||||
} else {
|
||||
placement->Multiply(trsf);
|
||||
}
|
||||
}
|
||||
void prepend(const ConversionResultPlacement* trsf) {
|
||||
if (placement == 0) {
|
||||
placement = trsf->clone();
|
||||
} else {
|
||||
placement->PreMultiply(trsf);
|
||||
}
|
||||
}
|
||||
const ConversionResultShape* Shape() const { return shape; }
|
||||
const ConversionResultPlacement* Placement() const { return placement; }
|
||||
bool hasStyle() const { return style != 0; }
|
||||
const SurfaceStyle& Style() const { return *style; }
|
||||
void setStyle(const SurfaceStyle* newStyle) { style = newStyle; }
|
||||
int ItemId() const { return id; }
|
||||
};
|
||||
|
||||
typedef std::vector<ConversionResult> ConversionResults;
|
||||
}
|
||||
#endif
|
||||
@@ -23,11 +23,12 @@
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../ifcparse/Argument.h"
|
||||
#include "../ifcparse/IfcGlobalId.h"
|
||||
#include "../../ifcparse/IfcGlobalId.h"
|
||||
#include "../../ifcparse/Argument.h"
|
||||
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeomRepresentation.h"
|
||||
#include "../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
#include "ifc_geom_api.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
@@ -37,7 +38,7 @@ namespace IfcGeom {
|
||||
private:
|
||||
std::vector<P> _data;
|
||||
public:
|
||||
Matrix(const ElementSettings& settings, const gp_Trsf& trsf) {
|
||||
Matrix(const ElementSettings& settings, const IfcGeom::ConversionResultPlacement* trsf) {
|
||||
// Convert the gp_Trsf into a 4x3 Matrix
|
||||
// Note that in case the CONVERT_BACK_UNITS setting is enabled
|
||||
// the translation component of the matrix needs to be divided
|
||||
@@ -45,8 +46,10 @@ namespace IfcGeom {
|
||||
// internally in IfcOpenShell everything is measured in meters.
|
||||
for(int i = 1; i < 5; ++i) {
|
||||
for (int j = 1; j < 4; ++j) {
|
||||
const double trsf_value = trsf.Value(j,i);
|
||||
const double matrix_value = i == 4 && settings.get(IteratorSettings::CONVERT_BACK_UNITS)
|
||||
const double trsf_value = (trsf == nullptr)
|
||||
? (i == j ? 1. : 0.)
|
||||
: trsf->Value(j,i);
|
||||
const double matrix_value = (i == 4 && settings.get(IteratorSettings::CONVERT_BACK_UNITS))
|
||||
? trsf_value / settings.unit_magnitude()
|
||||
: trsf_value;
|
||||
_data.push_back(static_cast<P>(matrix_value));
|
||||
@@ -60,23 +63,23 @@ namespace IfcGeom {
|
||||
class Transformation {
|
||||
private:
|
||||
ElementSettings settings_;
|
||||
gp_Trsf trsf_;
|
||||
ConversionResultPlacement* trsf_;
|
||||
Matrix<P> matrix_;
|
||||
public:
|
||||
Transformation(const ElementSettings& settings, const gp_Trsf& trsf)
|
||||
Transformation(const ElementSettings& settings, const IfcGeom::ConversionResultPlacement* trsf)
|
||||
: settings_(settings)
|
||||
, trsf_(trsf)
|
||||
, trsf_(trsf ? trsf->clone() : nullptr)
|
||||
, matrix_(settings, trsf)
|
||||
{}
|
||||
const gp_Trsf& data() const { return trsf_; }
|
||||
const IfcGeom::ConversionResultPlacement* data() const { return trsf_; }
|
||||
const Matrix<P>& matrix() const { return matrix_; }
|
||||
|
||||
Transformation inverted() const {
|
||||
return Transformation(settings_, trsf_.Inverted());
|
||||
return Transformation(settings_, trsf_->inverted());
|
||||
}
|
||||
|
||||
Transformation multiplied(const Transformation& other) const {
|
||||
return Transformation(settings_, trsf_.Multiplied(other.data()));
|
||||
return Transformation(settings_, trsf_->multiplied(other.data()));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -130,7 +133,7 @@ namespace IfcGeom {
|
||||
void SetParents(std::vector<const IfcGeom::Element<P, PP>*> newparents) { _parents = newparents; }
|
||||
|
||||
Element(const ElementSettings& settings, int id, int parent_id, const std::string& name, const std::string& type,
|
||||
const std::string& guid, const std::string& context, const gp_Trsf& trsf, IfcUtil::IfcBaseEntity* product)
|
||||
const std::string& guid, const std::string& context, const IfcGeom::ConversionResultPlacement* trsf, IfcUtil::IfcBaseEntity* product)
|
||||
: _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _context(context), _transformation(settings, trsf)
|
||||
, product_(product)
|
||||
{
|
||||
@@ -160,28 +163,25 @@ namespace IfcGeom {
|
||||
};
|
||||
|
||||
template <typename P = double, typename PP = P>
|
||||
class BRepElement : public Element<P, PP> {
|
||||
class NativeElement : public Element<P, PP> {
|
||||
private:
|
||||
boost::shared_ptr<Representation::BRep> _geometry;
|
||||
public:
|
||||
const boost::shared_ptr<Representation::BRep>& geometry_pointer() const { return _geometry; }
|
||||
const Representation::BRep& geometry() const { return *_geometry; }
|
||||
BRepElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid,
|
||||
const std::string& context, const gp_Trsf& trsf, const boost::shared_ptr<Representation::BRep>& geometry,
|
||||
NativeElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid,
|
||||
const std::string& context, const IfcGeom::ConversionResultPlacement* trsf, const boost::shared_ptr<Representation::BRep>& geometry,
|
||||
IfcUtil::IfcBaseEntity* product)
|
||||
: Element<P, PP>(geometry->settings() ,id, parent_id, name, type, guid, context, trsf, product)
|
||||
, _geometry(geometry)
|
||||
{}
|
||||
|
||||
bool calculate_projected_surface_area(double& along_x, double& along_y, double& along_z) const {
|
||||
const auto& trsf = this->transformation().data();
|
||||
const gp_Mat& mat = trsf.HVectorialPart();
|
||||
gp_Ax3 ax(trsf.TranslationPart(), mat.Column(3), mat.Column(1));
|
||||
return geometry().calculate_projected_surface_area(ax, along_x, along_y, along_z);
|
||||
return geometry().calculate_projected_surface_area(this->transformation().data(), along_x, along_y, along_z);
|
||||
}
|
||||
private:
|
||||
BRepElement(const BRepElement& other);
|
||||
BRepElement& operator=(const BRepElement& other);
|
||||
NativeElement(const NativeElement& other);
|
||||
NativeElement& operator=(const NativeElement& other);
|
||||
};
|
||||
|
||||
template <typename P = double, typename PP = P>
|
||||
@@ -191,7 +191,7 @@ namespace IfcGeom {
|
||||
public:
|
||||
const Representation::Triangulation<P>& geometry() const { return *_geometry; }
|
||||
const boost::shared_ptr< Representation::Triangulation<P> >& geometry_pointer() const { return _geometry; }
|
||||
TriangulationElement(const BRepElement<P, PP>& shape_model)
|
||||
TriangulationElement(const NativeElement<P, PP>& shape_model)
|
||||
: Element<P, PP>(shape_model)
|
||||
, _geometry(boost::shared_ptr<Representation::Triangulation<P> >(new Representation::Triangulation<P>(shape_model.geometry())))
|
||||
{}
|
||||
@@ -210,7 +210,7 @@ namespace IfcGeom {
|
||||
Representation::Serialization* _geometry;
|
||||
public:
|
||||
const Representation::Serialization& geometry() const { return *_geometry; }
|
||||
SerializedElement(const BRepElement<P, PP>& shape_model)
|
||||
SerializedElement(const NativeElement<P, PP>& shape_model)
|
||||
: Element<P, PP>(shape_model)
|
||||
, _geometry(new Representation::Serialization(shape_model.geometry()))
|
||||
{}
|
||||
+2
-2
@@ -23,8 +23,8 @@
|
||||
#ifndef IFCGEOMFILTER_H
|
||||
#define IFCGEOMFILTER_H
|
||||
|
||||
#include "Kernel.h"
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../../ifcgeom/schema_agnostic/Kernel.h"
|
||||
#include "../../ifcparse/IfcFile.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/function.hpp>
|
||||
+6
-6
@@ -58,7 +58,7 @@
|
||||
#ifndef IFCGEOMITERATOR_H
|
||||
#define IFCGEOMITERATOR_H
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IteratorImplementation.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IteratorImplementation.h"
|
||||
|
||||
// The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration
|
||||
#ifdef min
|
||||
@@ -83,19 +83,19 @@ namespace IfcGeom {
|
||||
IteratorImplementation<P, PP>* implementation_;
|
||||
|
||||
public:
|
||||
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, int num_threads = 1)
|
||||
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::string& geometry_library="opencascade", int num_threads = 1)
|
||||
: file_(file)
|
||||
, settings_(settings)
|
||||
{
|
||||
implementation_ = iterator_implementations<P, PP>().construct(file_->schema()->name(), settings, file, filters_, num_threads);
|
||||
implementation_ = iterator_implementations<P, PP>().construct(file_->schema()->name(), geometry_library, settings, file, filters_, num_threads);
|
||||
}
|
||||
|
||||
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, size_t num_threads = 1)
|
||||
Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, const std::string& geometry_library = "opencascade", int num_threads = 1)
|
||||
: file_(file)
|
||||
, settings_(settings)
|
||||
, filters_(filters)
|
||||
{
|
||||
implementation_ = iterator_implementations<P, PP>().construct(file_->schema()->name(), settings, file, filters_, num_threads);
|
||||
implementation_ = iterator_implementations<P, PP>().construct(file_->schema()->name(), geometry_library, settings, file, filters_, num_threads);
|
||||
}
|
||||
|
||||
bool initialize() {
|
||||
@@ -119,7 +119,7 @@ namespace IfcGeom {
|
||||
|
||||
Element<P, PP>* get() { return implementation_->get(); }
|
||||
|
||||
BRepElement<P, PP>* get_native() { return implementation_->get_native(); }
|
||||
NativeElement<P, PP>* get_native() { return implementation_->get_native(); }
|
||||
|
||||
const Element<P, PP>* get_object(int id) { return implementation_->get_object(id); }
|
||||
|
||||
+3
-2
@@ -21,8 +21,9 @@
|
||||
#define IFCGEOMITERATORSETTINGS_H
|
||||
|
||||
#include "ifc_geom_api.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../../ifcparse/IfcException.h"
|
||||
#include "../../ifcparse/IfcBaseClass.h"
|
||||
#include "../../ifcparse/IfcLogger.h"
|
||||
|
||||
namespace IfcGeom
|
||||
{
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomRenderStyles.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
#ifndef IFCGEOMRENDERSTYLES_H
|
||||
#define IFCGEOMRENDERSTYLES_H
|
||||
|
||||
#include "../ifcgeom/ifc_geom_api.h"
|
||||
#include "../../ifcgeom/schema_agnostic/ifc_geom_api.h"
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
+31
-18
@@ -21,21 +21,25 @@
|
||||
#include <BRepTools.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Compound.hxx>
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <GProp_GProps.hxx>
|
||||
#include <BRepGProp.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeom.h"
|
||||
|
||||
#include "IfcGeomRepresentation.h"
|
||||
#include "../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h"
|
||||
#include "../../ifcgeom/schema_agnostic/Kernel.h"
|
||||
|
||||
IfcGeom::Representation::Serialization::Serialization(const BRep& brep)
|
||||
: Representation(brep.settings())
|
||||
, id_(brep.id())
|
||||
{
|
||||
TopoDS_Compound compound = brep.as_compound();
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++ it) {
|
||||
IfcGeom::ConversionResultShape* shape = brep.as_compound();
|
||||
TopoDS_Compound compound = TopoDS::Compound(((OpenCascadeShape*) shape)->shape());
|
||||
delete shape;
|
||||
|
||||
for (IfcGeom::ConversionResults::const_iterator it = brep.begin(); it != brep.end(); ++ it) {
|
||||
if (it->hasStyle() && it->Style().Diffuse()) {
|
||||
const IfcGeom::SurfaceStyle::ColorComponent& clr = *it->Style().Diffuse();
|
||||
surface_styles_.push_back(clr.R());
|
||||
@@ -57,7 +61,7 @@ IfcGeom::Representation::Serialization::Serialization(const BRep& brep)
|
||||
brep_data_ = sstream.str();
|
||||
}
|
||||
|
||||
// todo copied from kernel
|
||||
// @todo copied from kernel
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
#include <BRepBuilderAPI_GTransform.hxx>
|
||||
|
||||
@@ -82,13 +86,17 @@ TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const gp_GTrsf& t) {
|
||||
}
|
||||
}
|
||||
|
||||
TopoDS_Compound IfcGeom::Representation::BRep::as_compound(bool force_meters) const {
|
||||
IfcGeom::ConversionResultShape* IfcGeom::Representation::BRep::as_compound(bool force_meters) const {
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) {
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
gp_GTrsf trsf = it->Placement();
|
||||
|
||||
for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) {
|
||||
const TopoDS_Shape& s = *(OpenCascadeShape*) it->Shape();
|
||||
gp_GTrsf trsf;
|
||||
if (it->Placement()) {
|
||||
trsf = ((OpenCascadePlacement*)it->Placement())->trsf();
|
||||
}
|
||||
|
||||
if (!force_meters && settings().get(IteratorSettings::CONVERT_BACK_UNITS)) {
|
||||
gp_Trsf scale;
|
||||
@@ -99,7 +107,8 @@ TopoDS_Compound IfcGeom::Representation::BRep::as_compound(bool force_meters) co
|
||||
const TopoDS_Shape moved_shape = apply_transformation(s, trsf);
|
||||
builder.Add(compound, moved_shape);
|
||||
}
|
||||
return compound;
|
||||
|
||||
return new OpenCascadeShape(compound);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -166,7 +175,7 @@ namespace {
|
||||
const gp_Vec v2 = pt3 - pt2;
|
||||
const gp_Vec v3 = pt1 - pt3;
|
||||
const gp_Vec normal_vector = v1 ^ v2;
|
||||
if (normal_vector.Magnitude() > ALMOST_ZERO) {
|
||||
if (normal_vector.Magnitude() > 1.e-9) {
|
||||
gp_Dir normal = gp_Dir();
|
||||
|
||||
double edge_lengths[3] = { v1.Magnitude(), v2.Magnitude(), v3.Magnitude() };
|
||||
@@ -190,9 +199,9 @@ bool IfcGeom::Representation::BRep::calculate_surface_area(double& area) const {
|
||||
try {
|
||||
area = 0.;
|
||||
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) {
|
||||
for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) {
|
||||
GProp_GProps prop;
|
||||
BRepGProp::SurfaceProperties(it->Shape(), prop);
|
||||
BRepGProp::SurfaceProperties(*(OpenCascadeShape*)it->Shape(), prop);
|
||||
area += prop.Mass();
|
||||
}
|
||||
|
||||
@@ -207,10 +216,10 @@ bool IfcGeom::Representation::BRep::calculate_volume(double& volume) const {
|
||||
try {
|
||||
volume = 0.;
|
||||
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) {
|
||||
for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) {
|
||||
if (Kernel::is_manifold(it->Shape())) {
|
||||
GProp_GProps prop;
|
||||
BRepGProp::VolumeProperties(it->Shape(), prop);
|
||||
BRepGProp::VolumeProperties(*(OpenCascadeShape*)it->Shape(), prop);
|
||||
volume += prop.Mass();
|
||||
} else {
|
||||
return false;
|
||||
@@ -224,13 +233,17 @@ bool IfcGeom::Representation::BRep::calculate_volume(double& volume) const {
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Representation::BRep::calculate_projected_surface_area(const gp_Ax3 & ax, double & along_x, double & along_y, double & along_z) const {
|
||||
bool IfcGeom::Representation::BRep::calculate_projected_surface_area(const ConversionResultPlacement* place, double & along_x, double & along_y, double & along_z) const {
|
||||
try {
|
||||
gp_Trsf trsf = ((OpenCascadePlacement*)place)->trsf().Trsf();
|
||||
gp_Mat mat = trsf.HVectorialPart();
|
||||
gp_Ax3 ax(trsf.TranslationPart(), mat.Column(3), mat.Column(1));
|
||||
|
||||
along_x = along_y = along_z = 0.;
|
||||
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) {
|
||||
for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) {
|
||||
double x, y, z;
|
||||
surface_area_along_direction(settings().deflection_tolerance(), it->Shape(), ax, x, y, z);
|
||||
surface_area_along_direction(settings().deflection_tolerance(), *(OpenCascadeShape*)it->Shape(), ax, x, y, z);
|
||||
|
||||
if (Kernel::is_manifold(it->Shape())) {
|
||||
x /= 2.;
|
||||
@@ -0,0 +1,238 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMREPRESENTATION_H
|
||||
#define IFCGEOMREPRESENTATION_H
|
||||
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomMaterial.h"
|
||||
#include "../../ifcgeom/schema_agnostic/ConversionResult.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
namespace Representation {
|
||||
|
||||
class IFC_GEOM_API Representation {
|
||||
Representation(const Representation&); //N/A
|
||||
Representation& operator =(const Representation&); //N/A
|
||||
protected:
|
||||
const ElementSettings settings_;
|
||||
public:
|
||||
explicit Representation(const ElementSettings& settings)
|
||||
: settings_(settings)
|
||||
{}
|
||||
const ElementSettings& settings() const { return settings_; }
|
||||
virtual ~Representation() {}
|
||||
};
|
||||
|
||||
class IFC_GEOM_API BRep : public Representation {
|
||||
private:
|
||||
std::string id_;
|
||||
const IfcGeom::ConversionResults shapes_;
|
||||
BRep(const BRep& other);
|
||||
BRep& operator=(const BRep& other);
|
||||
public:
|
||||
BRep(const ElementSettings& settings, const std::string& id, const IfcGeom::ConversionResults& shapes)
|
||||
: Representation(settings)
|
||||
, id_(id)
|
||||
, shapes_(shapes)
|
||||
{}
|
||||
virtual ~BRep() {}
|
||||
IfcGeom::ConversionResults::const_iterator begin() const { return shapes_.begin(); }
|
||||
IfcGeom::ConversionResults::const_iterator end() const { return shapes_.end(); }
|
||||
const IfcGeom::ConversionResults& shapes() const { return shapes_; }
|
||||
const std::string& id() const { return id_; }
|
||||
IfcGeom::ConversionResultShape* as_compound(bool force_meters = false) const;
|
||||
|
||||
bool calculate_volume(double&) const;
|
||||
bool calculate_surface_area(double&) const;
|
||||
bool calculate_projected_surface_area(const IfcGeom::ConversionResultPlacement* ax, double& along_x, double& along_y, double& along_z) const;
|
||||
};
|
||||
|
||||
class IFC_GEOM_API Serialization : public Representation {
|
||||
private:
|
||||
std::string id_;
|
||||
std::string brep_data_;
|
||||
std::vector<double> surface_styles_;
|
||||
public:
|
||||
const std::string& brep_data() const { return brep_data_; }
|
||||
const std::vector<double>& surface_styles() const { return surface_styles_; }
|
||||
Serialization(const BRep& brep);
|
||||
virtual ~Serialization() {}
|
||||
const std::string& id() const { return id_; }
|
||||
private:
|
||||
Serialization();
|
||||
Serialization(const Serialization&);
|
||||
Serialization& operator=(const Serialization&);
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
class Triangulation : public Representation {
|
||||
private:
|
||||
// A nested pair of floats and a material index to be able to store an XYZ coordinate in a map.
|
||||
// TODO: Make this a std::tuple when compilers add support for that.
|
||||
typedef typename std::pair<P, std::pair<P, P> > Coordinate;
|
||||
typedef typename std::pair<int, Coordinate> VertexKey;
|
||||
typedef std::map<VertexKey, int> VertexKeyMap;
|
||||
typedef std::pair<int, int> Edge;
|
||||
|
||||
std::string id_;
|
||||
std::vector<P> _verts;
|
||||
std::vector<int> _faces;
|
||||
std::vector<int> _edges;
|
||||
std::vector<P> _normals;
|
||||
std::vector<P> uvs_;
|
||||
std::vector<int> _material_ids;
|
||||
std::vector<Material> _materials;
|
||||
VertexKeyMap welds;
|
||||
|
||||
public:
|
||||
const std::string& id() const { return id_; }
|
||||
const std::vector<P>& verts() const { return _verts; }
|
||||
const std::vector<int>& faces() const { return _faces; }
|
||||
const std::vector<int>& edges() const { return _edges; }
|
||||
const std::vector<P>& normals() const { return _normals; }
|
||||
const std::vector<P>& uvs() const { return uvs_; }
|
||||
const std::vector<int>& material_ids() const { return _material_ids; }
|
||||
const std::vector<Material>& materials() const { return _materials; }
|
||||
|
||||
Triangulation(const BRep& shape_model)
|
||||
: Representation(shape_model.settings())
|
||||
, id_(shape_model.id())
|
||||
{
|
||||
for ( IfcGeom::ConversionResults::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++ iit ) {
|
||||
|
||||
int surface_style_id = -1;
|
||||
if (iit->hasStyle()) {
|
||||
Material adapter(&iit->Style());
|
||||
std::vector<Material>::const_iterator jt = std::find(_materials.begin(), _materials.end(), adapter);
|
||||
if (jt == _materials.end()) {
|
||||
surface_style_id = (int)_materials.size();
|
||||
_materials.push_back(adapter);
|
||||
} else {
|
||||
surface_style_id = (int)(jt - _materials.begin());
|
||||
}
|
||||
}
|
||||
|
||||
if (settings().get(IteratorSettings::APPLY_DEFAULT_MATERIALS) && surface_style_id == -1) {
|
||||
Material material(IfcGeom::get_default_style(settings().element_type()));
|
||||
std::vector<Material>::const_iterator mit = std::find(_materials.begin(), _materials.end(), material);
|
||||
if (mit == _materials.end()) {
|
||||
surface_style_id = (int)_materials.size();
|
||||
_materials.push_back(material);
|
||||
} else {
|
||||
surface_style_id = (int)(mit - _materials.begin());
|
||||
}
|
||||
}
|
||||
|
||||
iit->Shape()->Triangulate(settings(), iit->Placement(), this, surface_style_id);
|
||||
}
|
||||
}
|
||||
virtual ~Triangulation() {}
|
||||
|
||||
/// Generates UVs for a single mesh using box projection.
|
||||
/// @todo Very simple impl. Assumes that input vertices and normals match 1:1.
|
||||
static std::vector<P> box_project_uvs(const std::vector<P> &vertices, const std::vector<P> &normals)
|
||||
{
|
||||
std::vector<P> uvs;
|
||||
uvs.resize(vertices.size() / 3 * 2);
|
||||
for (size_t uv_idx = 0, v_idx = 0;
|
||||
uv_idx < uvs.size() && v_idx < vertices.size() && v_idx < normals.size();
|
||||
uv_idx += 2, v_idx += 3) {
|
||||
|
||||
P n_x = normals[v_idx], n_y = normals[v_idx + 1], n_z = normals[v_idx + 2];
|
||||
P v_x = vertices[v_idx], v_y = vertices[v_idx + 1], v_z = vertices[v_idx + 2];
|
||||
|
||||
if (std::abs(n_x) > std::abs(n_y) && std::abs(n_x) > std::abs(n_z)) {
|
||||
uvs[uv_idx] = v_z;
|
||||
uvs[uv_idx + 1] = v_y;
|
||||
}
|
||||
if (std::abs(n_y) > std::abs(n_x) && std::abs(n_y) > std::abs(n_z)) {
|
||||
uvs[uv_idx] = v_x;
|
||||
uvs[uv_idx + 1] = v_z;
|
||||
}
|
||||
if (std::abs(n_z) > std::abs(n_x) && std::abs(n_z) > std::abs(n_y)) {
|
||||
uvs[uv_idx] = v_x;
|
||||
uvs[uv_idx + 1] = v_y;
|
||||
}
|
||||
}
|
||||
|
||||
return uvs;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// Welds vertices that belong to different faces
|
||||
int addVertex(int material_index, P X, P Y, P Z) {
|
||||
const bool convert = settings().get(IteratorSettings::CONVERT_BACK_UNITS);
|
||||
X = static_cast<P>(convert ? (X / settings().unit_magnitude()) : X);
|
||||
Y = static_cast<P>(convert ? (Y / settings().unit_magnitude()) : Y);
|
||||
Z = static_cast<P>(convert ? (Z / settings().unit_magnitude()) : Z);
|
||||
int i = (int) _verts.size() / 3;
|
||||
if (settings().get(IteratorSettings::WELD_VERTICES)) {
|
||||
const VertexKey key = std::make_pair(material_index, std::make_pair(X, std::make_pair(Y, Z)));
|
||||
typename VertexKeyMap::const_iterator it = welds.find(key);
|
||||
if ( it != welds.end() ) return it->second;
|
||||
i = (int) welds.size();
|
||||
welds[key] = i;
|
||||
}
|
||||
_verts.push_back(X);
|
||||
_verts.push_back(Y);
|
||||
_verts.push_back(Z);
|
||||
return i;
|
||||
}
|
||||
|
||||
inline void addEdge(int n1, int n2, std::map<std::pair<int,int>,int>& edgecount, std::vector<std::pair<int,int> >& edges_temp) {
|
||||
const Edge e = Edge( (std::min)(n1,n2),(std::max)(n1,n2) );
|
||||
if ( edgecount.find(e) == edgecount.end() ) edgecount[e] = 1;
|
||||
else edgecount[e] ++;
|
||||
edges_temp.push_back(e);
|
||||
}
|
||||
|
||||
inline void addNormal(P X, P Y, P Z) {
|
||||
_normals.push_back(X);
|
||||
_normals.push_back(Y);
|
||||
_normals.push_back(Z);
|
||||
}
|
||||
|
||||
inline void addFace(int style, int i0, int i1, int i2) {
|
||||
_faces.push_back(i0);
|
||||
_faces.push_back(i1);
|
||||
_faces.push_back(i2);
|
||||
|
||||
_material_ids.push_back(style);
|
||||
}
|
||||
|
||||
inline void registerEdge(int i0, int i1) {
|
||||
_edges.push_back(i0);
|
||||
_edges.push_back(i1);
|
||||
}
|
||||
|
||||
private:
|
||||
Triangulation();
|
||||
Triangulation(const Triangulation&);
|
||||
Triangulation& operator=(const Triangulation&);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
+2
-2
@@ -31,14 +31,14 @@ void IteratorFactoryImplementation<P, PP>::bind(const std::string& schema_name,
|
||||
}
|
||||
|
||||
template <typename P, typename PP>
|
||||
IfcGeom::IteratorImplementation<P, PP>* IteratorFactoryImplementation<P, PP>::construct(const std::string& schema_name, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads) {
|
||||
IfcGeom::IteratorImplementation<P, PP>* IteratorFactoryImplementation<P, PP>::construct(const std::string& schema_name, const std::string& geometry_library, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads) {
|
||||
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
|
||||
typename std::map<std::string, typename get_factory_type<P, PP>::type>::const_iterator it;
|
||||
it = this->find(schema_name_lower);
|
||||
if (it == this->end()) {
|
||||
throw IfcParse::IfcException("No geometry iterator registered for " + schema_name);
|
||||
}
|
||||
return it->second(settings, file, filters, num_threads);
|
||||
return it->second(geometry_library, settings, file, filters, num_threads);
|
||||
}
|
||||
|
||||
|
||||
+9
-9
@@ -1,9 +1,9 @@
|
||||
#ifndef ITERATOR_IMPLEMENTATION_H
|
||||
#define ITERATOR_IMPLEMENTATION_H
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomFilter.h"
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
#include "../../ifcparse/IfcFile.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomFilter.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
|
||||
|
||||
#include <gp_XYZ.hxx>
|
||||
|
||||
@@ -20,12 +20,12 @@ namespace IfcGeom {
|
||||
class Element;
|
||||
|
||||
template <typename P, typename PP>
|
||||
class BRepElement;
|
||||
class NativeElement;
|
||||
}
|
||||
|
||||
typedef boost::function4<IfcGeom::IteratorImplementation<float, float>*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int> iterator_float_float_fn;
|
||||
typedef boost::function4<IfcGeom::IteratorImplementation<float, double>*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int> iterator_float_double_fn;
|
||||
typedef boost::function4<IfcGeom::IteratorImplementation<double, double>*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int> iterator_double_double_fn;
|
||||
typedef boost::function5<IfcGeom::IteratorImplementation<float, float>*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int> iterator_float_float_fn;
|
||||
typedef boost::function5<IfcGeom::IteratorImplementation<float, double>*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int> iterator_float_double_fn;
|
||||
typedef boost::function5<IfcGeom::IteratorImplementation<double, double>*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int> iterator_double_double_fn;
|
||||
|
||||
template <typename P, typename PP>
|
||||
struct get_factory_type {};
|
||||
@@ -50,7 +50,7 @@ class IteratorFactoryImplementation : public std::map<std::string, typename get_
|
||||
public:
|
||||
IteratorFactoryImplementation();
|
||||
void bind(const std::string& schema_name, typename get_factory_type<P, PP>::type fn);
|
||||
IfcGeom::IteratorImplementation<P, PP>* construct(const std::string& schema_name, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int);
|
||||
IfcGeom::IteratorImplementation<P, PP>* construct(const std::string& schema_name, const std::string& geometry_library, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector<IfcGeom::filter_t>&, int);
|
||||
};
|
||||
|
||||
template <typename P, typename PP>
|
||||
@@ -71,7 +71,7 @@ namespace IfcGeom {
|
||||
virtual IfcParse::IfcFile* file() const = 0;
|
||||
virtual IfcUtil::IfcBaseClass* next() = 0;
|
||||
virtual Element<P, PP>* get() = 0;
|
||||
virtual BRepElement<P, PP>* get_native() = 0;
|
||||
virtual NativeElement<P, PP>* get_native() = 0;
|
||||
virtual const Element<P, PP>* get_object(int id) = 0;
|
||||
virtual IfcUtil::IfcBaseClass* create() = 0;
|
||||
};
|
||||
@@ -1,22 +1,32 @@
|
||||
#include "Kernel.h"
|
||||
|
||||
#include "../../ifcparse/Ifc2x3.h"
|
||||
#include "../../ifcparse/Ifc4.h"
|
||||
|
||||
// @todo remove
|
||||
#include "../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h"
|
||||
|
||||
#include <TopExp.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
#include <TopTools_IndexedMapOfShape.hxx>
|
||||
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
|
||||
|
||||
IfcGeom::Kernel::Kernel(IfcParse::IfcFile* file) {
|
||||
IfcGeom::Kernel::Kernel(const std::string& geometry_library, IfcParse::IfcFile* file) {
|
||||
if (file != 0) {
|
||||
if (file->schema() == 0) {
|
||||
throw IfcParse::IfcException("No schema associated with file");
|
||||
}
|
||||
|
||||
const std::string& schema_name = file->schema()->name();
|
||||
implementation_ = impl::kernel_implementations().construct(schema_name, file);
|
||||
implementation_ = impl::kernel_implementations().construct(schema_name, geometry_library, file);
|
||||
}
|
||||
}
|
||||
|
||||
int IfcGeom::Kernel::count(const TopoDS_Shape& s, TopAbs_ShapeEnum t, bool unique) {
|
||||
int IfcGeom::Kernel::count(const ConversionResultShape* s_, int t_, bool unique) {
|
||||
// @todo make kernel agnostic
|
||||
const TopoDS_Shape& s = ((OpenCascadeShape*) s_)->shape();
|
||||
TopAbs_ShapeEnum t = (TopAbs_ShapeEnum) t_;
|
||||
|
||||
if (unique) {
|
||||
TopTools_IndexedMapOfShape map;
|
||||
TopExp::MapShapes(s, t, map);
|
||||
@@ -32,10 +42,14 @@ int IfcGeom::Kernel::count(const TopoDS_Shape& s, TopAbs_ShapeEnum t, bool uniqu
|
||||
}
|
||||
|
||||
|
||||
int IfcGeom::Kernel::surface_genus(const TopoDS_Shape& s) {
|
||||
int nv = count(s, TopAbs_VERTEX, true);
|
||||
int ne = count(s, TopAbs_EDGE, true);
|
||||
int nf = count(s, TopAbs_FACE, true);
|
||||
int IfcGeom::Kernel::surface_genus(const ConversionResultShape* s_) {
|
||||
// @todo make kernel agnostic
|
||||
const TopoDS_Shape& s = ((OpenCascadeShape*) s_)->shape();
|
||||
OpenCascadeShape Ss(s);
|
||||
|
||||
int nv = count(&Ss, (int) TopAbs_VERTEX, true);
|
||||
int ne = count(&Ss, (int) TopAbs_EDGE, true);
|
||||
int nf = count(&Ss, (int) TopAbs_FACE, true);
|
||||
|
||||
const int euler = nv - ne + nf;
|
||||
const int genus = (2 - euler) / 2;
|
||||
@@ -48,23 +62,31 @@ IfcGeom::impl::KernelFactoryImplementation& IfcGeom::impl::kernel_implementation
|
||||
return impl;
|
||||
}
|
||||
|
||||
extern void init_KernelImplementation_Ifc2x3(IfcGeom::impl::KernelFactoryImplementation*);
|
||||
extern void init_KernelImplementation_Ifc4(IfcGeom::impl::KernelFactoryImplementation*);
|
||||
extern void init_KernelImplementation_opencascade_Ifc2x3(IfcGeom::impl::KernelFactoryImplementation*);
|
||||
extern void init_KernelImplementation_opencascade_Ifc4(IfcGeom::impl::KernelFactoryImplementation*);
|
||||
#ifdef IFOPSH_USE_CGAL
|
||||
extern void init_KernelImplementation_cgal_Ifc2x3(IfcGeom::impl::KernelFactoryImplementation*);
|
||||
extern void init_KernelImplementation_cgal_Ifc4(IfcGeom::impl::KernelFactoryImplementation*);
|
||||
#endif
|
||||
|
||||
IfcGeom::impl::KernelFactoryImplementation::KernelFactoryImplementation() {
|
||||
init_KernelImplementation_Ifc2x3(this);
|
||||
init_KernelImplementation_Ifc4(this);
|
||||
init_KernelImplementation_opencascade_Ifc2x3(this);
|
||||
init_KernelImplementation_opencascade_Ifc4(this);
|
||||
#ifdef IFOPSH_USE_CGAL
|
||||
init_KernelImplementation_cgal_Ifc2x3(this);
|
||||
init_KernelImplementation_cgal_Ifc4(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void IfcGeom::impl::KernelFactoryImplementation::bind(const std::string& schema_name, IfcGeom::impl::kernel_fn fn) {
|
||||
void IfcGeom::impl::KernelFactoryImplementation::bind(const std::string& schema_name, const std::string& geometry_library, IfcGeom::impl::kernel_fn fn) {
|
||||
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
|
||||
this->insert(std::make_pair(schema_name_lower, fn));
|
||||
this->insert(std::make_pair(std::make_pair(schema_name_lower, geometry_library), fn));
|
||||
}
|
||||
|
||||
IfcGeom::Kernel* IfcGeom::impl::KernelFactoryImplementation::construct(const std::string& schema_name, IfcParse::IfcFile* file) {
|
||||
IfcGeom::Kernel* IfcGeom::impl::KernelFactoryImplementation::construct(const std::string& schema_name, const std::string& geometry_library, IfcParse::IfcFile* file) {
|
||||
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
|
||||
std::map<std::string, IfcGeom::impl::kernel_fn>::const_iterator it;
|
||||
it = this->find(schema_name_lower);
|
||||
std::map<std::pair<std::string, std::string>, IfcGeom::impl::kernel_fn>::const_iterator it;
|
||||
it = this->find(std::make_pair(schema_name_lower, geometry_library));
|
||||
if (it == end()) {
|
||||
throw IfcParse::IfcException("No geometry kernel registered for " + schema_name);
|
||||
}
|
||||
@@ -158,7 +180,7 @@ namespace {
|
||||
std::map<std::string, IfcUtil::IfcBaseEntity*> layers;
|
||||
if (prod->hasRepresentation()) {
|
||||
IfcEntityList::ptr r = IfcParse::traverse(prod->Representation());
|
||||
typename Schema::IfcRepresentation::list::ptr representations = r->as<typename Schema::IfcRepresentation>();
|
||||
typename Schema::IfcRepresentation::list::ptr representations = r->template as<typename Schema::IfcRepresentation>();
|
||||
for (typename Schema::IfcRepresentation::list::it it = representations->begin(); it != representations->end(); ++it) {
|
||||
typename Schema::IfcPresentationLayerAssignment::list::ptr a = (*it)->LayerAssignments();
|
||||
for (typename Schema::IfcPresentationLayerAssignment::list::it jt = a->begin(); jt != a->end(); ++jt) {
|
||||
@@ -180,11 +202,15 @@ std::map<std::string, IfcUtil::IfcBaseEntity*> IfcGeom::Kernel::get_layers(IfcUt
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::Kernel::is_manifold(const TopoDS_Shape& a) {
|
||||
bool IfcGeom::Kernel::is_manifold(const ConversionResultShape* s_) {
|
||||
// @todo make kernel agnostic
|
||||
const TopoDS_Shape& a = ((OpenCascadeShape*) s_)->shape();
|
||||
|
||||
if (a.ShapeType() == TopAbs_COMPOUND || a.ShapeType() == TopAbs_SOLID) {
|
||||
TopoDS_Iterator it(a);
|
||||
for (; it.More(); it.Next()) {
|
||||
if (!is_manifold(it.Value())) {
|
||||
OpenCascadeShape s(it.Value());
|
||||
if (!is_manifold(&s)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -201,4 +227,42 @@ bool IfcGeom::Kernel::is_manifold(const TopoDS_Shape& a) {
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <typename Schema>
|
||||
IfcEntityList::ptr find_openings_helper(typename Schema::IfcProduct* product) {
|
||||
|
||||
typename IfcEntityList::ptr openings(new IfcEntityList);
|
||||
if (product->declaration().is(Schema::IfcElement::Class()) && !product->declaration().is(Schema::IfcOpeningElement::Class())) {
|
||||
typename Schema::IfcElement* element = (typename Schema::IfcElement*)product;
|
||||
openings = element->HasOpenings()->generalize();
|
||||
}
|
||||
|
||||
// Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements?
|
||||
typename Schema::IfcObjectDefinition* obdef = product->template as<typename Schema::IfcObjectDefinition>();
|
||||
for (;;) {
|
||||
auto decomposes = obdef->Decomposes()->generalize();
|
||||
if (decomposes->size() != 1) break;
|
||||
typename Schema::IfcObjectDefinition* rel_obdef = (*decomposes->begin())->template as<typename Schema::IfcRelAggregates>()->RelatingObject();
|
||||
if (rel_obdef->declaration().is(Schema::IfcElement::Class()) && !rel_obdef->declaration().is(Schema::IfcOpeningElement::Class())) {
|
||||
typename Schema::IfcElement* element = (typename Schema::IfcElement*)rel_obdef;
|
||||
openings->push(element->HasOpenings()->generalize());
|
||||
}
|
||||
|
||||
obdef = rel_obdef;
|
||||
}
|
||||
|
||||
return openings;
|
||||
}
|
||||
}
|
||||
|
||||
IfcEntityList::ptr IfcGeom::Kernel::find_openings(IfcUtil::IfcBaseEntity* inst) {
|
||||
if (inst->as<Ifc2x3::IfcProduct>()) {
|
||||
return find_openings_helper<Ifc2x3>(inst->as<Ifc2x3::IfcProduct>());
|
||||
} else if (inst->as<Ifc4::IfcProduct>()) {
|
||||
return find_openings_helper<Ifc4>(inst->as<Ifc4::IfcProduct>());
|
||||
} else {
|
||||
throw IfcParse::IfcException("Unexpected entity " + inst->declaration().name());
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,16 @@
|
||||
#ifndef ITERATOR_KERNEL_H
|
||||
#define ITERATOR_KERNEL_H
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
#include "../ifcgeom/IfcRepresentationShapeItem.h"
|
||||
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#include "../ifcparse/Ifc4.h"
|
||||
#include "../../ifcparse/IfcFile.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
|
||||
#include "../../ifcgeom/schema_agnostic/ConversionResult.h"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <TopExp_Explorer.hxx>
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
template <typename P, typename PP>
|
||||
class BRepElement;
|
||||
class NativeElement;
|
||||
|
||||
class Kernel {
|
||||
private:
|
||||
@@ -52,7 +47,7 @@ namespace IfcGeom {
|
||||
GV_DIMENSIONALITY
|
||||
};
|
||||
|
||||
Kernel(IfcParse::IfcFile* file_ = 0);
|
||||
Kernel(const std::string& geometry_library, IfcParse::IfcFile* file_ = 0);
|
||||
|
||||
virtual ~Kernel() {}
|
||||
|
||||
@@ -64,37 +59,38 @@ namespace IfcGeom {
|
||||
return implementation_->getValue(var);
|
||||
}
|
||||
|
||||
virtual BRepElement<double, double>* convert(
|
||||
virtual NativeElement<double, double>* convert(
|
||||
const IteratorSettings& settings, IfcUtil::IfcBaseClass* representation,
|
||||
IfcUtil::IfcBaseClass* product)
|
||||
{
|
||||
return implementation_->convert(settings, representation, product);
|
||||
}
|
||||
|
||||
virtual IfcRepresentationShapeItems convert(IfcUtil::IfcBaseClass* item) {
|
||||
virtual ConversionResults convert(IfcUtil::IfcBaseClass* item) {
|
||||
return implementation_->convert(item);
|
||||
}
|
||||
|
||||
virtual bool convert_placement(IfcUtil::IfcBaseClass* item, gp_Trsf& trsf) {
|
||||
virtual bool convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf) {
|
||||
return implementation_->convert_placement(item, trsf);
|
||||
}
|
||||
|
||||
static int count(const TopoDS_Shape&, TopAbs_ShapeEnum, bool unique=false);
|
||||
static int surface_genus(const TopoDS_Shape&);
|
||||
static int count(const ConversionResultShape*, int, bool unique=false);
|
||||
static int surface_genus(const ConversionResultShape*);
|
||||
|
||||
static bool is_manifold(const TopoDS_Shape& a);
|
||||
static bool is_manifold(const ConversionResultShape*);
|
||||
static IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity*, bool include_openings=true);
|
||||
static std::map<std::string, IfcUtil::IfcBaseEntity*> get_layers(IfcUtil::IfcBaseEntity*);
|
||||
static IfcEntityList::ptr find_openings(IfcUtil::IfcBaseEntity* product);
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
typedef boost::function1<Kernel*, IfcParse::IfcFile*> kernel_fn;
|
||||
|
||||
class KernelFactoryImplementation : public std::map<std::string, kernel_fn> {
|
||||
class KernelFactoryImplementation : public std::map<std::pair<std::string, std::string>, kernel_fn> {
|
||||
public:
|
||||
KernelFactoryImplementation();
|
||||
void bind(const std::string& schema_name, kernel_fn);
|
||||
Kernel* construct(const std::string& schema_name, IfcParse::IfcFile*);
|
||||
void bind(const std::string& schema_name, const std::string& geometry_library, kernel_fn);
|
||||
Kernel* construct(const std::string& schema_name, const std::string& geometry_library, IfcParse::IfcFile*);
|
||||
};
|
||||
|
||||
KernelFactoryImplementation& kernel_implementations();
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
#include "../ifcgeom/ifc_geom_api.h"
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../../ifcparse/IfcBaseClass.h"
|
||||
|
||||
#include "../../ifcgeom/schema_agnostic/ifc_geom_api.h"
|
||||
|
||||
#include <TopoDS_Shape.hxx>
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
|
||||
#include "../../ifcgeom/schema_agnostic/IfcGeomRenderStyles.h"
|
||||
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
@@ -0,0 +1,88 @@
|
||||
#include "CgalConversionResult.h"
|
||||
|
||||
#include "../../../ifcparse/IfcLogger.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
|
||||
|
||||
template <typename Precision>
|
||||
void triangulate_helper(const cgal_shape_t& shape_const, const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<Precision>* t, int surface_style_id) {
|
||||
// Copy is made because triangulate_faces() does not accept a const argument
|
||||
cgal_shape_t s = shape_const;
|
||||
|
||||
const cgal_placement_t& trsf = dynamic_cast<const IfcGeom::CgalPlacement*>(place)->trsf();
|
||||
// std::cout << "Model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl;
|
||||
// std::cout << "Valid: " << s.is_valid() << std::endl;
|
||||
|
||||
// Apply transformation
|
||||
if (place != NULL) for (auto &vertex: vertices(s)) {
|
||||
vertex->point() = vertex->point().transform(trsf);
|
||||
}
|
||||
|
||||
if (!s.is_valid()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid Polyhedron_3 in object (before triangulation)");
|
||||
return;
|
||||
}
|
||||
|
||||
// Triangulate the shape and compute the normals
|
||||
// std::map<cgal_vertex_descriptor_t, Kernel_::Vector_3> vertex_normals;
|
||||
// boost::associative_property_map<std::map<cgal_vertex_descriptor_t, Kernel_::Vector_3>> vertex_normals_map(vertex_normals);
|
||||
std::map<cgal_face_descriptor_t, Kernel_::Vector_3> face_normals;
|
||||
boost::associative_property_map<std::map<cgal_face_descriptor_t, Kernel_::Vector_3>> face_normals_map(face_normals);
|
||||
|
||||
bool success = false;
|
||||
try {
|
||||
success = CGAL::Polygon_mesh_processing::triangulate_faces(s);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Triangulation crashed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Triangulation failed");
|
||||
return;
|
||||
}
|
||||
// std::cout << "Triangulated model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl;
|
||||
|
||||
if (!s.is_valid()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid Polyhedron_3 in object (after triangulation)");
|
||||
return;
|
||||
}
|
||||
|
||||
// CGAL::Polygon_mesh_processing::compute_normals(s, vertex_normals_map, face_normals_map);
|
||||
CGAL::Polygon_mesh_processing::compute_face_normals(s, face_normals_map);
|
||||
|
||||
int num_faces = 0, num_vertices = 0;
|
||||
for (auto &face: faces(s)) {
|
||||
if (!face->is_triangle()) {
|
||||
std::cout << "Warning: non-triangular face!" << std::endl;
|
||||
continue;
|
||||
}
|
||||
CGAL::Polyhedron_3<Kernel_>::Halfedge_around_facet_const_circulator current_halfedge = face->facet_begin();
|
||||
do {
|
||||
t->addVertex(surface_style_id,
|
||||
CGAL::to_double(current_halfedge->vertex()->point().cartesian(0)),
|
||||
CGAL::to_double(current_halfedge->vertex()->point().cartesian(1)),
|
||||
CGAL::to_double(current_halfedge->vertex()->point().cartesian(2)));
|
||||
|
||||
const double nx = CGAL::to_double(face_normals_map[face].cartesian(0));
|
||||
const double ny = CGAL::to_double(face_normals_map[face].cartesian(1));
|
||||
const double nz = CGAL::to_double(face_normals_map[face].cartesian(2));
|
||||
t->addNormal(nx, ny, nz);
|
||||
|
||||
++num_vertices;
|
||||
++current_halfedge;
|
||||
} while (current_halfedge != face->facet_begin());
|
||||
|
||||
t->addFace(surface_style_id, num_vertices-3, num_vertices-2, num_vertices-1);
|
||||
|
||||
++num_faces;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<float>* t, int surface_style_id) const {
|
||||
triangulate_helper(shape_, settings, place, t, surface_style_id);
|
||||
}
|
||||
|
||||
void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<double>* t, int surface_style_id) const {
|
||||
triangulate_helper(shape_, settings, place, t, surface_style_id);
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef CGALCONVERSIONRESULT_H
|
||||
#define CGALCONVERSIONRESULT_H
|
||||
|
||||
#include "../../../ifcgeom/schema_agnostic/Kernel.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h"
|
||||
|
||||
// @todo create separate shapetype enum?
|
||||
#include "../../../ifcgeom/kernels/opencascade/IfcGeomShapeType.h"
|
||||
|
||||
#include <boost/property_map/property_map.hpp>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
|
||||
#include <CGAL/Polygon_mesh_processing/stitch_borders.h>
|
||||
#include <CGAL/Polygon_mesh_processing/orientation.h>
|
||||
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
|
||||
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
|
||||
#include <CGAL/Nef_polyhedron_3.h>
|
||||
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel_;
|
||||
|
||||
typedef Kernel_::Aff_transformation_3 cgal_placement_t;
|
||||
typedef Kernel_::Point_3 cgal_point_t;
|
||||
typedef Kernel_::Vector_3 cgal_direction_t;
|
||||
typedef Kernel_::Vector_3 cgal_vector_t;
|
||||
typedef Kernel_::Plane_3 cgal_plane_t;
|
||||
typedef std::vector<Kernel_::Point_3> cgal_curve_t;
|
||||
typedef std::vector<Kernel_::Point_3> cgal_wire_t;
|
||||
|
||||
struct cgal_face_t {
|
||||
cgal_wire_t outer;
|
||||
std::vector<cgal_wire_t> inner;
|
||||
};
|
||||
|
||||
typedef CGAL::Polyhedron_3<Kernel_> cgal_shape_t;
|
||||
typedef boost::graph_traits<CGAL::Polyhedron_3<Kernel_>>::vertex_descriptor cgal_vertex_descriptor_t;
|
||||
typedef boost::graph_traits<CGAL::Polyhedron_3<Kernel_>>::face_descriptor cgal_face_descriptor_t;
|
||||
|
||||
#include "../../../ifcgeom/schema_agnostic/ConversionResult.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
class CgalPlacement : public ConversionResultPlacement {
|
||||
public:
|
||||
CgalPlacement(const cgal_placement_t& trsf)
|
||||
: trsf_(trsf)
|
||||
{}
|
||||
|
||||
const cgal_placement_t& trsf() const { return trsf_; }
|
||||
operator const cgal_placement_t& () { return trsf_; }
|
||||
|
||||
virtual double Value(int i, int j) const {
|
||||
return CGAL::to_double(trsf_.cartesian(i-1, j-1));
|
||||
}
|
||||
|
||||
virtual void Multiply(const ConversionResultPlacement* other) {
|
||||
trsf_ = trsf_ * ((CgalPlacement *)other)->trsf_;
|
||||
}
|
||||
|
||||
virtual void PreMultiply(const ConversionResultPlacement* other) {
|
||||
trsf_ = ((CgalPlacement *)other)->trsf_ * trsf_;
|
||||
}
|
||||
|
||||
virtual ConversionResultPlacement* clone() const {
|
||||
return new CgalPlacement(trsf_);
|
||||
}
|
||||
|
||||
virtual ConversionResultPlacement* inverted() const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
virtual ConversionResultPlacement* multiplied(const ConversionResultPlacement*) const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
virtual void TranslationPart(double& X, double& Y, double& Z) const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
private:
|
||||
cgal_placement_t trsf_;
|
||||
};
|
||||
|
||||
class CgalShape : public ConversionResultShape {
|
||||
public:
|
||||
CgalShape(const cgal_shape_t& shape)
|
||||
: shape_(shape)
|
||||
{}
|
||||
|
||||
const cgal_shape_t& shape() const { return shape_; }
|
||||
operator const cgal_shape_t& () { return shape_; }
|
||||
|
||||
virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<float> * t, int surface_style_id) const;
|
||||
|
||||
virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<double>* t, int surface_style_id) const;
|
||||
|
||||
virtual void Serialize(std::string&) const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
virtual ConversionResultShape* clone() const {
|
||||
return new CgalShape(shape_);
|
||||
}
|
||||
|
||||
virtual int surface_genus() const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
private:
|
||||
cgal_shape_t shape_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,201 @@
|
||||
#include "OpenCascadeConversionResult.h"
|
||||
|
||||
#include "../../../ifcparse/IfcLogger.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
|
||||
#include <map>
|
||||
|
||||
template <typename Precision>
|
||||
void triangulate_helper(const TopoDS_Shape& s, const IfcGeom::IteratorSettings& settings, const IfcGeom::ConversionResultPlacement* place, IfcGeom::Representation::Triangulation<Precision>* t, int surface_style_id) {
|
||||
|
||||
gp_GTrsf trsf;
|
||||
if (place) {
|
||||
trsf = dynamic_cast<const IfcGeom::OpenCascadePlacement*>(place)->trsf();
|
||||
}
|
||||
|
||||
// Triangulate the shape
|
||||
try {
|
||||
BRepMesh_IncrementalMesh(s, settings.deflection_tolerance());
|
||||
} catch (...) {
|
||||
|
||||
// TODO: Catch outside
|
||||
// Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape:",ifc_file->entityById(_id)->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape");
|
||||
return;
|
||||
}
|
||||
|
||||
// Iterates over the faces of the shape
|
||||
int num_faces = 0;
|
||||
TopExp_Explorer exp;
|
||||
for (exp.Init(s, TopAbs_FACE); exp.More(); exp.Next(), ++num_faces) {
|
||||
TopoDS_Face face = TopoDS::Face(exp.Current());
|
||||
TopLoc_Location loc;
|
||||
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face, loc);
|
||||
|
||||
if (!tri.IsNull()) {
|
||||
|
||||
// A 3x3 matrix to rotate the vertex normals
|
||||
const gp_Mat rotation_matrix = trsf.VectorialPart();
|
||||
|
||||
// Keep track of the number of times an edge is used
|
||||
// Manifold edges (i.e. edges used twice) are deemed invisible
|
||||
std::map<std::pair<int, int>, int> edgecount;
|
||||
std::vector<std::pair<int, int> > edges_temp;
|
||||
|
||||
const TColgp_Array1OfPnt& nodes = tri->Nodes();
|
||||
const TColgp_Array1OfPnt2d& uvs = tri->UVNodes();
|
||||
std::vector<gp_XYZ> coords;
|
||||
BRepGProp_Face prop(face);
|
||||
std::map<int, int> dict;
|
||||
|
||||
// Vertex normals are only calculated if vertices are not welded and calculation is not disable explicitly.
|
||||
const bool calculate_normals = !settings.get(IfcGeom::IteratorSettings::WELD_VERTICES) &&
|
||||
!settings.get(IfcGeom::IteratorSettings::NO_NORMALS);
|
||||
|
||||
for (int i = 1; i <= nodes.Length(); ++i) {
|
||||
coords.push_back(nodes(i).Transformed(loc).XYZ());
|
||||
trsf.Transforms(*coords.rbegin());
|
||||
const gp_XYZ& last = *coords.rbegin();
|
||||
dict[i] = t->addVertex(surface_style_id, last.X(), last.Y(), last.Z());
|
||||
|
||||
if (calculate_normals) {
|
||||
const gp_Pnt2d& uv = uvs(i);
|
||||
gp_Pnt p;
|
||||
gp_Vec normal_direction;
|
||||
prop.Normal(uv.X(), uv.Y(), p, normal_direction);
|
||||
gp_Vec normal(0., 0., 0.);
|
||||
if (normal_direction.Magnitude() > 1.e-9) {
|
||||
normal = gp_Dir(normal_direction.XYZ() * rotation_matrix);
|
||||
}
|
||||
t->addNormal(normal.X(), normal.Y(), normal.Z());
|
||||
}
|
||||
}
|
||||
|
||||
const Poly_Array1OfTriangle& triangles = tri->Triangles();
|
||||
for (int i = 1; i <= triangles.Length(); ++i) {
|
||||
int n1, n2, n3;
|
||||
if (face.Orientation() == TopAbs_REVERSED)
|
||||
triangles(i).Get(n3, n2, n1);
|
||||
else triangles(i).Get(n1, n2, n3);
|
||||
|
||||
/* An alternative would be to calculate normals based
|
||||
* on the coordinates of the mesh vertices */
|
||||
/*
|
||||
const gp_XYZ pt1 = coords[n1-1];
|
||||
const gp_XYZ pt2 = coords[n2-1];
|
||||
const gp_XYZ pt3 = coords[n3-1];
|
||||
const gp_XYZ v1 = pt2-pt1;
|
||||
const gp_XYZ v2 = pt3-pt2;
|
||||
gp_Dir normal = gp_Dir(v1^v2);
|
||||
_normals.push_back((float)normal.X());
|
||||
_normals.push_back((float)normal.Y());
|
||||
_normals.push_back((float)normal.Z());
|
||||
*/
|
||||
|
||||
t->addFace(surface_style_id, dict[n1], dict[n2], dict[n3]);
|
||||
|
||||
t->addEdge(dict[n1], dict[n2], edgecount, edges_temp);
|
||||
t->addEdge(dict[n2], dict[n3], edgecount, edges_temp);
|
||||
t->addEdge(dict[n3], dict[n1], edgecount, edges_temp);
|
||||
}
|
||||
for (std::vector<std::pair<int, int> >::const_iterator jt = edges_temp.begin(); jt != edges_temp.end(); ++jt) {
|
||||
if (edgecount[*jt] == 1) {
|
||||
// non manifold edge, face boundary
|
||||
t->registerEdge(jt->first, jt->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: Unimplemented
|
||||
if (!t.normals().empty() && settings().get(IfcGeom::IteratorSettings::GENERATE_UVS)) {
|
||||
t.uvs() = box_project_uvs(t.verts(), t.normals());
|
||||
}
|
||||
|
||||
if (num_faces == 0) {
|
||||
// Edges are only emitted if there are no faces. A mixed representation of faces
|
||||
// and loose edges is discouraged by the standard. An alternative would be to use
|
||||
// TopExp_Explorer texp(s, TopAbs_EDGE, TopAbs_FACE) to find edges that do not
|
||||
// belong to any face.
|
||||
for (TopExp_Explorer texp(s, TopAbs_EDGE); texp.More(); texp.Next()) {
|
||||
BRepAdaptor_Curve crv(TopoDS::Edge(texp.Current()));
|
||||
GCPnts_QuasiUniformDeflection tessellater(crv, settings.deflection_tolerance());
|
||||
int n = tessellater.NbPoints();
|
||||
int start = (int)t->verts().size() / 3;
|
||||
for (int i = 1; i <= n; ++i) {
|
||||
gp_XYZ p = tessellater.Value(i).XYZ();
|
||||
|
||||
// // In case you want direction arrows on your edges
|
||||
// double u = tessellater.Parameter(i);
|
||||
// gp_XYZ p2, p3;
|
||||
// gp_Pnt tmp;
|
||||
// gp_Vec tmp2;
|
||||
// crv.D1(u, tmp, tmp2);
|
||||
// gp_Dir d1, d2, d3, d4;
|
||||
// d1 = tmp2;
|
||||
// if (texp.Current().Orientation() == TopAbs_REVERSED) {
|
||||
// d1 = -d1;
|
||||
// }
|
||||
// if (fabs(d1.Z()) < 0.5) {
|
||||
// d2 = d1.Crossed(gp::DZ());
|
||||
// } else {
|
||||
// d2 = d1.Crossed(gp::DY());
|
||||
// }
|
||||
// d3 = d1.XYZ() + d2.XYZ();
|
||||
// d4 = d1.XYZ() - d2.XYZ();
|
||||
// p2 = p - d3.XYZ() / 10.;
|
||||
// p3 = p - d4.XYZ() / 10.;
|
||||
// trsf.Transforms(p2);
|
||||
// trsf.Transforms(p3);
|
||||
// _material_ids.push_back(surface_style_id);
|
||||
// _material_ids.push_back(surface_style_id);
|
||||
// _verts.push_back(static_cast<P>(p2.X()));
|
||||
// _verts.push_back(static_cast<P>(p2.Y()));
|
||||
// _verts.push_back(static_cast<P>(p2.Z()));
|
||||
// _verts.push_back(static_cast<P>(p3.X()));
|
||||
// _verts.push_back(static_cast<P>(p3.Y()));
|
||||
// _verts.push_back(static_cast<P>(p3.Z()));
|
||||
|
||||
trsf.Transforms(p);
|
||||
|
||||
t->material_ids().push_back(surface_style_id);
|
||||
|
||||
t->verts().push_back(static_cast<double>(p.X()));
|
||||
t->verts().push_back(static_cast<double>(p.Y()));
|
||||
t->verts().push_back(static_cast<double>(p.Z()));
|
||||
|
||||
if (i > 1) {
|
||||
t->edges().push_back(start + i - 2);
|
||||
t->edges().push_back(start + i - 1);
|
||||
// _edges.push_back(start + 3 * (i - 2) + 2);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 2);
|
||||
}
|
||||
|
||||
// _edges.push_back(start + 3 * (i - 1) + 0);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 2);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 1);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
BRepTools::Clean(s);
|
||||
}
|
||||
|
||||
void IfcGeom::OpenCascadeShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<float>* t, int surface_style_id) const {
|
||||
triangulate_helper(shape_, settings, place, t, surface_style_id);
|
||||
}
|
||||
|
||||
void IfcGeom::OpenCascadeShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<double>* t, int surface_style_id) const {
|
||||
triangulate_helper(shape_, settings, place, t, surface_style_id);
|
||||
}
|
||||
|
||||
int IfcGeom::OpenCascadeShape::surface_genus() const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
// return IfcGeom::Kernel::surface_genus(shape_);
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMOPENCASCADEREPRESENTATION_H
|
||||
#define IFCGEOMOPENCASCADEREPRESENTATION_H
|
||||
|
||||
#include <BRepMesh_IncrementalMesh.hxx>
|
||||
#include <BRepGProp_Face.hxx>
|
||||
|
||||
#include <Poly_Triangulation.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColgp_Array1OfPnt2d.hxx>
|
||||
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <GCPnts_QuasiUniformDeflection.hxx>
|
||||
|
||||
#include "../../../ifcgeom/schema_agnostic/ConversionResult.h"
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
class OpenCascadePlacement : public ConversionResultPlacement {
|
||||
public:
|
||||
OpenCascadePlacement(const gp_GTrsf& trsf)
|
||||
: trsf_(trsf) {}
|
||||
|
||||
const gp_GTrsf& trsf() const { return trsf_; }
|
||||
operator const gp_GTrsf& () { return trsf_; }
|
||||
|
||||
virtual double Value(int i, int j) const {
|
||||
return trsf_.Value(i, j);
|
||||
}
|
||||
|
||||
virtual void Multiply(const ConversionResultPlacement* other) {
|
||||
trsf_.Multiply(((OpenCascadePlacement*)other)->trsf_);
|
||||
}
|
||||
|
||||
virtual void PreMultiply(const ConversionResultPlacement* other) {
|
||||
trsf_.PreMultiply(((OpenCascadePlacement*)other)->trsf_);
|
||||
}
|
||||
|
||||
virtual ConversionResultPlacement* clone() const {
|
||||
return new OpenCascadePlacement(trsf_);
|
||||
}
|
||||
|
||||
virtual ConversionResultPlacement* inverted() const {
|
||||
return new OpenCascadePlacement(trsf_.Inverted());
|
||||
}
|
||||
|
||||
virtual ConversionResultPlacement* multiplied(const ConversionResultPlacement* other) const {
|
||||
return new OpenCascadePlacement(trsf_.Multiplied(((OpenCascadePlacement*)other)->trsf_));
|
||||
}
|
||||
|
||||
virtual void TranslationPart(double& X, double& Y, double& Z) const {
|
||||
X = trsf_.TranslationPart().X();
|
||||
Y = trsf_.TranslationPart().Y();
|
||||
Z = trsf_.TranslationPart().Z();
|
||||
}
|
||||
private:
|
||||
gp_GTrsf trsf_;
|
||||
};
|
||||
|
||||
class OpenCascadeShape : public ConversionResultShape {
|
||||
public:
|
||||
OpenCascadeShape(const TopoDS_Shape& shape)
|
||||
: shape_(shape)
|
||||
{}
|
||||
|
||||
const TopoDS_Shape& shape() const { return shape_; }
|
||||
operator const TopoDS_Shape& () { return shape_; }
|
||||
|
||||
virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<float>* t, int surface_style_id) const;
|
||||
|
||||
virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<double>* t, int surface_style_id) const;
|
||||
|
||||
virtual void Serialize(std::string&) const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
virtual ConversionResultShape* clone() const {
|
||||
return new OpenCascadeShape(shape_);
|
||||
}
|
||||
|
||||
virtual int surface_genus() const;
|
||||
private:
|
||||
TopoDS_Shape shape_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -38,8 +38,8 @@
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom/schema_agnostic/IfcGeomElement.h"
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcparse/IfcLogger.h"
|
||||
|
||||
@@ -47,14 +47,24 @@
|
||||
#include <vld.h>
|
||||
#endif
|
||||
|
||||
#include "../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h"
|
||||
|
||||
#include <GProp_GProps.hxx>
|
||||
#include <BRepGProp.hxx>
|
||||
#include <BRepBndLib.hxx>
|
||||
#include <Bnd_Box.hxx>
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Compound.hxx>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifdef USE_VOXELS
|
||||
#include <voxel/storage.h>
|
||||
#include <voxel/traversal.h>
|
||||
#include <voxel/processor.h>
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
union data_field {
|
||||
char buffer[sizeof(T)];
|
||||
@@ -429,6 +439,7 @@ public:
|
||||
|
||||
static const std::string TOTAL_SURFACE_AREA = "TOTAL_SURFACE_AREA";
|
||||
static const std::string TOTAL_SHAPE_VOLUME = "TOTAL_SHAPE_VOLUME";
|
||||
static const std::string TOTAL_SHAPE_VOLUME_VOXELS = "TOTAL_SHAPE_VOLUME_VOXELS";
|
||||
static const std::string SURFACE_AREA_ALONG_X = "SURFACE_AREA_ALONG_X";
|
||||
static const std::string SURFACE_AREA_ALONG_Y = "SURFACE_AREA_ALONG_Y";
|
||||
static const std::string SURFACE_AREA_ALONG_Z = "SURFACE_AREA_ALONG_Z";
|
||||
@@ -440,9 +451,9 @@ static const std::array<std::string, 3> XYZ = { "X", "Y", "Z" };
|
||||
|
||||
class QuantityWriter_v0 : public EntityExtension {
|
||||
private:
|
||||
const IfcGeom::BRepElement<double, double>* elem_;
|
||||
const IfcGeom::NativeElement<double, double>* elem_;
|
||||
public:
|
||||
QuantityWriter_v0(const IfcGeom::BRepElement<double, double>* elem) :
|
||||
QuantityWriter_v0(const IfcGeom::NativeElement<double, double>* elem) :
|
||||
elem_(elem)
|
||||
{
|
||||
put_json(TOTAL_SURFACE_AREA, 0.);
|
||||
@@ -453,21 +464,32 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef USE_VOXELS
|
||||
namespace {
|
||||
void write_voxels(const std::string& fn, abstract_voxel_storage* voxels) {
|
||||
voxel_writer w;
|
||||
w.SetVoxels(voxels);
|
||||
w.Write(fn);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
class QuantityWriter_v1 : public EntityExtension {
|
||||
private:
|
||||
const IfcGeom::BRepElement<double, double>* elem_;
|
||||
const IfcGeom::NativeElement<double, double>* elem_;
|
||||
public:
|
||||
QuantityWriter_v1(const IfcGeom::BRepElement<double, double>* elem) :
|
||||
elem_(elem) {
|
||||
QuantityWriter_v1(const IfcGeom::NativeElement<double, double>* elem) :
|
||||
elem_(elem)
|
||||
{
|
||||
double a, b, c, largest_face_area = 0.;
|
||||
|
||||
if (elem_->geometry().calculate_surface_area(a)) {
|
||||
put_json(TOTAL_SURFACE_AREA, a);
|
||||
}
|
||||
|
||||
if (elem_->geometry().calculate_volume(a)) {
|
||||
put_json(TOTAL_SHAPE_VOLUME, a);
|
||||
}
|
||||
TopoDS_Compound compound = TopoDS::Compound(((IfcGeom::OpenCascadeShape*) elem_->geometry().as_compound(true))->shape());
|
||||
double bbox_xyz[6];
|
||||
bool has_boundingbox = false;
|
||||
|
||||
if (elem_->calculate_projected_surface_area(a, b, c)) {
|
||||
put_json(SURFACE_AREA_ALONG_X, a);
|
||||
@@ -478,7 +500,6 @@ public:
|
||||
boost::optional<gp_Dir> largest_face_dir;
|
||||
|
||||
{
|
||||
TopoDS_Compound compound = elem_->geometry().as_compound(true);
|
||||
TopExp_Explorer exp(compound, TopAbs_FACE);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
GProp_GProps prop;
|
||||
@@ -498,19 +519,70 @@ public:
|
||||
}
|
||||
|
||||
Bnd_Box box;
|
||||
double xyz[6];
|
||||
|
||||
BRepBndLib::AddClose(compound, box);
|
||||
|
||||
if (!box.IsVoid()) {
|
||||
box.Get(xyz[0], xyz[1], xyz[2], xyz[3], xyz[4], xyz[5]);
|
||||
has_boundingbox = true;
|
||||
box.Get(bbox_xyz[0], bbox_xyz[1], bbox_xyz[2], bbox_xyz[3], bbox_xyz[4], bbox_xyz[5]);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
const double bsz = xyz[i + 3] - xyz[i];
|
||||
const double bsz = bbox_xyz[i + 3] - bbox_xyz[i];
|
||||
put_json(BOUNDING_BOX_SIZE_ALONG_ + XYZ[i], bsz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (elem_->geometry().calculate_volume(a)) {
|
||||
put_json(TOTAL_SHAPE_VOLUME, a);
|
||||
}
|
||||
#ifdef USE_VOXELS
|
||||
// Sometimes geometries are not a topologically valid manifold,
|
||||
// but still (approximately) enclose a volume. In this case
|
||||
// we can voxlize the geometry and fill the interior solid volume.
|
||||
else if (has_boundingbox) {
|
||||
std::array< vec_n<3, double>, 2 > bounds;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
bounds[0].get(i) = bbox_xyz[i + 0];
|
||||
bounds[1].get(i) = bbox_xyz[i + 3];
|
||||
}
|
||||
progress_writer silent;
|
||||
// At least one padding voxel need to be in place as the traversal happens outside
|
||||
// of the surface voxel bounds and is subsequently inverted to find the interior
|
||||
// voxels.
|
||||
auto surface = storage_for(bounds, 256U, 4U, 16U);
|
||||
processor proc(surface, silent);
|
||||
// @todo is scanline entirely reliable due to rounding from float to int?
|
||||
// This is also observed in voxec dump_surfaces().
|
||||
// proc.use_scanline() = false;
|
||||
BRepMesh_IncrementalMesh(compound, 0.001);
|
||||
std::vector<std::pair<int, TopoDS_Compound > > geometries = { {1, compound} };
|
||||
proc.process(geometries.begin(), geometries.end(), SURFACE(), output(MERGED()));
|
||||
surface = (regular_voxel_storage*) proc.voxels();
|
||||
double vsize = surface->voxel_size();
|
||||
auto surface_count = surface->count();
|
||||
traversal_voxel_filler_inverse filler;
|
||||
double total_volume = 0.;
|
||||
if (surface->count() != 0) {
|
||||
auto volume = filler(surface);
|
||||
auto volume_count = volume->count();
|
||||
auto inner_surface = (regular_voxel_storage*) volume->boolean_intersection(surface);
|
||||
if (inner_surface->count() != 0) {
|
||||
// Or, use a boolean intersection of surface and volume and subtract any subsequent
|
||||
// interior void volumes.
|
||||
auto inner_volume = filler(inner_surface);
|
||||
volume_count -= inner_volume->count();
|
||||
delete inner_volume;
|
||||
}
|
||||
delete inner_surface;
|
||||
delete volume;
|
||||
total_volume = (volume_count + surface_count / 2) * (vsize * vsize * vsize);
|
||||
}
|
||||
delete surface;
|
||||
put_json(TOTAL_SHAPE_VOLUME, total_volume);
|
||||
put_json(TOTAL_SHAPE_VOLUME_VOXELS, total_volume);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (largest_face_dir) {
|
||||
put_json(LARGEST_FACE_DIRECTION, *largest_face_dir);
|
||||
put_json(LARGEST_FACE_AREA, largest_face_area);
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
"""
|
||||
Rough draft of a client application for the C++ IfcGeomServer binary
|
||||
"""
|
||||
|
||||
import os
|
||||
import numpy
|
||||
import subprocess
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
class message_headers(object):
|
||||
HELLO = 0xff00
|
||||
IFC_MODEL = HELLO + 1
|
||||
GET = IFC_MODEL + 1
|
||||
ENTITY = GET + 1
|
||||
MORE = ENTITY + 1
|
||||
NEXT = MORE + 1
|
||||
BYE = NEXT + 1
|
||||
GET_LOG = BYE + 1
|
||||
LOG = GET_LOG + 1
|
||||
DEFLECTION = LOG + 1
|
||||
SETTING = DEFLECTION + 1
|
||||
|
||||
CALCULATE_QUANTITIES = numpy.int32((1 << 4))
|
||||
APPLY_LAYERSETS = numpy.int32((1 << 13))
|
||||
|
||||
def cast(data, dtype, n=None):
|
||||
arr = numpy.frombuffer(data, dtype=dtype)
|
||||
if n is None: return arr[0]
|
||||
else: return arr
|
||||
|
||||
def read(stream, dtype, n=None):
|
||||
data = stream.read(dtype().nbytes * (n or 1))
|
||||
x = cast(data, dtype, n)
|
||||
# print(x)
|
||||
return x
|
||||
|
||||
def readString(s):
|
||||
l = read(s, numpy.int32)
|
||||
S = s.read(int(l)).decode('ascii')
|
||||
while (l % 4 != 0):
|
||||
s.read(1);
|
||||
l += 1
|
||||
# print(S)
|
||||
return S
|
||||
|
||||
def readDoubleArray(s):
|
||||
l = read(s, numpy.int32) // 8
|
||||
return read(s, numpy.float64, int(l))
|
||||
|
||||
def readByteBuffer(s):
|
||||
l = read(s, numpy.int32)
|
||||
return s.read(int(l))
|
||||
|
||||
class entity_contents(object):
|
||||
def __init__(self, data):
|
||||
import json
|
||||
from io import BytesIO
|
||||
s = BytesIO(data)
|
||||
|
||||
self.structure = [
|
||||
("id" , read(s, numpy.int32)),
|
||||
("guid" , readString(s)),
|
||||
("name" , readString(s)),
|
||||
("type" , readString(s)),
|
||||
("parentId" , read(s, numpy.int32)),
|
||||
("matrix" , readDoubleArray(s)),
|
||||
("repId" , read(s, numpy.int32)),
|
||||
("positions" , readByteBuffer(s)),
|
||||
("normals" , readByteBuffer(s)),
|
||||
("indices" , readByteBuffer(s)),
|
||||
("colors" , readByteBuffer(s)),
|
||||
("materialIndices" , readByteBuffer(s)),
|
||||
("extendedData" , json.loads(s.read().strip(b'\x00').decode('ascii').strip(' ')))
|
||||
]
|
||||
|
||||
def __getattr__(self, k):
|
||||
return [kv for kv in self.structure if kv[0] == k][0][1]
|
||||
|
||||
def __repr__(self):
|
||||
def format(x):
|
||||
a, b = x
|
||||
if isinstance(b, bytes):
|
||||
b = "<bytes>"
|
||||
elif isinstance(b, dict):
|
||||
padding = " " * (len(a) + 2)
|
||||
b = ("\n".join("%s%%s: %%s" % padding % format(x) for x in b.items())).strip()
|
||||
return a, b
|
||||
return "ENTITY: \n" + "\n".join("%s: %s" % format(x) for x in self.structure)
|
||||
|
||||
content_factory = {
|
||||
message_headers.ENTITY: entity_contents
|
||||
}
|
||||
|
||||
identity = lambda x: x
|
||||
|
||||
def parse_contents(header, contents):
|
||||
return (content_factory.get(header, identity))(contents)
|
||||
|
||||
message = namedtuple("message", ("header", "contents"))
|
||||
|
||||
def process(geomserver_exe, ifc_filename):
|
||||
|
||||
proc = subprocess.Popen([geomserver_exe], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
|
||||
|
||||
def read_message(header_assertion=None):
|
||||
header, size = read(proc.stdout, numpy.int32, 2)
|
||||
assert header_assertion is None or header_assertion == header
|
||||
contents = b""
|
||||
if size > 0:
|
||||
contents = proc.stdout.read(size)
|
||||
contents = parse_contents(header, contents)
|
||||
return message(header, contents)
|
||||
|
||||
def write(header, contents=None):
|
||||
if contents is None: contents = []
|
||||
proc.stdin.write(numpy.int32(header).tobytes())
|
||||
integers_as_int32 = list(map(lambda s: numpy.int32(s) if isinstance(s, int) else s, contents))
|
||||
to_bytes = list(map(lambda s: s.tobytes() if hasattr(s, 'tobytes') else s, integers_as_int32))
|
||||
total_length = numpy.int32(sum(map(len, to_bytes)))
|
||||
proc.stdin.write(total_length.tobytes())
|
||||
for b in to_bytes:
|
||||
proc.stdin.write(b)
|
||||
proc.stdin.flush()
|
||||
|
||||
read_message(message_headers.HELLO)
|
||||
|
||||
# @todo: no need to read the entire file in memory
|
||||
s = open(ifc_filename, "rb").read()
|
||||
|
||||
write(message_headers.SETTING, [CALCULATE_QUANTITIES, numpy.int32(1)])
|
||||
write(message_headers.SETTING, [APPLY_LAYERSETS, numpy.int32(1)])
|
||||
write(message_headers.IFC_MODEL, [numpy.int32(len(s)), s, b"\x00" * ((4 - (len(s) % 4)) % 4)])
|
||||
|
||||
while True:
|
||||
has_more = cast(read_message(message_headers.MORE).contents, numpy.int32) == 1
|
||||
if not has_more: break
|
||||
write(message_headers.GET)
|
||||
geom_data = read_message(message_headers.ENTITY).contents
|
||||
yield geom_data
|
||||
write(message_headers.NEXT)
|
||||
|
||||
write(message_headers.BYE)
|
||||
read_message(message_headers.BYE)
|
||||
proc.wait()
|
||||
assert proc.returncode == 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
import platform
|
||||
exe_extension = ".exe" if platform.system() == 'Windows' else ""
|
||||
exe = os.environ.get("IFCGEOMSERVER") or ("IfcGeomServer" + exe_extension)
|
||||
for fn in sys.argv[1:]:
|
||||
for geom_data in process(exe, fn):
|
||||
print(geom_data)
|
||||
@@ -100,6 +100,7 @@ namespace {
|
||||
template <typename Schema>
|
||||
class IFC_PARSE_API IfcHierarchyHelper : public IfcParse::IfcFile {
|
||||
public:
|
||||
IfcHierarchyHelper(const IfcParse::schema_definition* schema) :IfcFile(schema) {}
|
||||
template <class T>
|
||||
T* addTriplet(double x, double y, double z) {
|
||||
std::vector<double> a; a.push_back(x); a.push_back(y); a.push_back(z);
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#ifndef IFCPARSE_H
|
||||
#define IFCPARSE_H
|
||||
|
||||
#define IFCOPENSHELL_VERSION "0.6.0b0"
|
||||
#define IFCOPENSHELL_VERSION "0.7.0-dev"
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
@@ -49,8 +49,9 @@
|
||||
|
||||
#include "../ifcparse/IfcSpfStream.h"
|
||||
|
||||
/* gcc doesn't know _Thread_local from C11 yet */
|
||||
#ifdef __GNUC__
|
||||
#if defined(__clang__)
|
||||
# define my_thread_local thread_local
|
||||
#elif defined(__GNUC__)
|
||||
# define my_thread_local __thread
|
||||
#elif __STDC_VERSION__ >= 201112L
|
||||
# define my_thread_local _Thread_local
|
||||
|
||||
@@ -56,9 +56,9 @@ SET_SOURCE_FILES_PROPERTIES(IfcPython.i PROPERTIES CPLUSPLUS ON)
|
||||
SWIG_ADD_MODULE(ifcopenshell_wrapper python IfcPython.i)
|
||||
if("$ENV{LDFLAGS}" MATCHES ".undefined.suppress")
|
||||
# On osx there is some state in the python dylib. With `-Wl,undefined,suppress` we can ignore the missing symbols at compile time.
|
||||
SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES})
|
||||
SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${IFCOPENSHELL_LIBRARIES})
|
||||
else()
|
||||
SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${IFCOPENSHELL_LIBRARIES} ${PYTHON_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES})
|
||||
SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${IFCOPENSHELL_LIBRARIES} ${PYTHON_LIBRARIES})
|
||||
endif()
|
||||
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
|
||||
SET_INSTALL_RPATHS(${SWIG_MODULE_ifcopenshell_wrapper_REAL_NAME} "${IFCDIRS};${OCC_LIBRARY_DIR}")
|
||||
|
||||
@@ -38,16 +38,16 @@
|
||||
|
||||
%ignore IfcGeom::impl::tree::selector;
|
||||
|
||||
%include "../ifcgeom/ifc_geom_api.h"
|
||||
%include "../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
%include "../ifcgeom/IfcGeomElement.h"
|
||||
%include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h"
|
||||
%include "../ifcgeom/IfcGeomRepresentation.h"
|
||||
%include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
|
||||
%include "../ifcgeom/schema_agnostic/ifc_geom_api.h"
|
||||
%include "../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h"
|
||||
%include "../ifcgeom/schema_agnostic/IfcGeomElement.h"
|
||||
%include "../ifcgeom/schema_agnostic/IfcGeomMaterial.h"
|
||||
%include "../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
|
||||
%include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
|
||||
|
||||
// A Template instantantation should be defined before it is used as a base class.
|
||||
// But frankly I don't care as most methods are subtlely different anyway.
|
||||
%include "../ifcgeom/IfcGeomTree.h"
|
||||
%include "../ifcgeom/kernels/opencascade/IfcGeomTree.h"
|
||||
|
||||
%extend IfcGeom::tree {
|
||||
|
||||
@@ -277,8 +277,9 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
|
||||
template <typename Schema>
|
||||
static boost::variant<IfcGeom::Element<double>*, IfcGeom::Representation::Representation*> helper_fn_create_shape(IfcGeom::IteratorSettings& settings, IfcUtil::IfcBaseClass* instance, IfcUtil::IfcBaseClass* representation = 0) {
|
||||
IfcParse::IfcFile* file = instance->data().file;
|
||||
|
||||
IfcGeom::Kernel kernel(file);
|
||||
|
||||
// @todo Default to opencascade for now.
|
||||
IfcGeom::Kernel kernel("opencascade", file);
|
||||
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_ORIENT, settings.get(IfcGeom::IteratorSettings::SEW_SHELLS) ? std::numeric_limits<double>::infinity() : -1);
|
||||
kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.get(IfcGeom::IteratorSettings::INCLUDE_CURVES) ? (settings.get(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES) ? -1. : 0.) : +1.));
|
||||
|
||||
@@ -360,7 +361,7 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
|
||||
}
|
||||
}
|
||||
|
||||
IfcGeom::BRepElement<double>* brep = kernel.convert(settings, ifc_representation, product);
|
||||
IfcGeom::NativeElement<double>* brep = kernel.convert(settings, ifc_representation, product);
|
||||
if (!brep) {
|
||||
throw IfcParse::IfcException("Failed to process shape");
|
||||
}
|
||||
@@ -378,7 +379,7 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
|
||||
} else {
|
||||
if (!representation) {
|
||||
if (instance->declaration().is(Schema::IfcRepresentationItem::Class()) || instance->declaration().is(Schema::IfcRepresentation::Class())) {
|
||||
IfcGeom::IfcRepresentationShapeItems shapes = kernel.convert(instance);
|
||||
IfcGeom::ConversionResults shapes = kernel.convert(instance);
|
||||
|
||||
IfcGeom::ElementSettings element_settings(settings, kernel.getValue(IfcGeom::Kernel::GV_LENGTH_UNIT), instance->declaration().name());
|
||||
IfcGeom::Representation::BRep brep(element_settings, boost::lexical_cast<std::string>(instance->data().id()), shapes);
|
||||
|
||||
@@ -70,9 +70,9 @@
|
||||
}
|
||||
|
||||
%module ifcopenshell_wrapper %{
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom_schema_agnostic/Serialization.h"
|
||||
#include "../ifcgeom/IfcGeomTree.h"
|
||||
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom/schema_agnostic/Serialization.h"
|
||||
#include "../ifcgeom/kernels/opencascade/IfcGeomTree.h"
|
||||
|
||||
#include "../ifcparse/Ifc2x3.h"
|
||||
#include "../ifcparse/Ifc4.h"
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
|
||||
|
||||
#include "../serializers/GeometrySerializer.h"
|
||||
|
||||
@@ -230,7 +230,7 @@ public:
|
||||
bool ready();
|
||||
void writeHeader();
|
||||
void write(const IfcGeom::TriangulationElement<real_t>* o);
|
||||
void write(const IfcGeom::BRepElement<real_t>* /*o*/) {}
|
||||
void write(const IfcGeom::NativeElement<real_t>* /*o*/) {}
|
||||
void finalize();
|
||||
bool isTesselated() const { return true; }
|
||||
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
|
||||
|
||||
@@ -27,8 +27,8 @@ typedef float real_t;
|
||||
#endif
|
||||
|
||||
#include "../serializers/Serializer.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom/schema_agnostic/IfcGeomElement.h"
|
||||
|
||||
class SerializerSettings : public IfcGeom::IteratorSettings
|
||||
{
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
|
||||
virtual bool isTesselated() const = 0;
|
||||
virtual void write(const IfcGeom::TriangulationElement<real_t>* o) = 0;
|
||||
virtual void write(const IfcGeom::BRepElement<real_t>* o) = 0;
|
||||
virtual void write(const IfcGeom::NativeElement<real_t>* o) = 0;
|
||||
virtual void setUnitNameAndMagnitude(const std::string& name, float magnitude) = 0;
|
||||
|
||||
const SerializerSettings& settings() const { return settings_; }
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
bool ready();
|
||||
void writeHeader();
|
||||
void write(const IfcGeom::TriangulationElement<real_t>* o);
|
||||
void write(const IfcGeom::BRepElement<real_t>* /*o*/) {}
|
||||
void write(const IfcGeom::NativeElement<real_t>* /*o*/) {}
|
||||
void finalize();
|
||||
bool isTesselated() const { return true; }
|
||||
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
|
||||
|
||||
@@ -42,8 +42,8 @@ public:
|
||||
: OpenCascadeBasedSerializer(out_filename, settings)
|
||||
{}
|
||||
virtual ~IgesSerializer() {}
|
||||
void writeShape(const TopoDS_Shape& shape) {
|
||||
writer.AddShape(shape);
|
||||
void writeShape(const IfcGeom::ConversionResultShape* shape) {
|
||||
writer.AddShape(*(IfcGeom::OpenCascadeShape*)shape);
|
||||
}
|
||||
void finalize() {
|
||||
writer.Write(out_filename.c_str());
|
||||
|
||||
@@ -36,8 +36,10 @@ bool OpenCascadeBasedSerializer::ready() {
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement<real_t>* o) {
|
||||
TopoDS_Shape compound = o->geometry().as_compound();
|
||||
void OpenCascadeBasedSerializer::write(const IfcGeom::NativeElement<real_t>* o) {
|
||||
IfcGeom::OpenCascadeShape* occt_shape = ((IfcGeom::OpenCascadeShape*) o->geometry().as_compound());
|
||||
TopoDS_Shape compound = occt_shape->shape();
|
||||
delete occt_shape;
|
||||
|
||||
if (o->geometry().settings().get(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS)) {
|
||||
gp_Trsf scale;
|
||||
@@ -46,7 +48,8 @@ void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement<real_t>* o) {
|
||||
compound = BRepBuilderAPI_Transform(compound, scale, true).Shape();
|
||||
}
|
||||
|
||||
writeShape(compound);
|
||||
IfcGeom::OpenCascadeShape s(compound);
|
||||
writeShape(&s);
|
||||
}
|
||||
|
||||
#define RATHER_SMALL (1e-3)
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#ifndef OPENCASCADEBASEDSERIALIZER_H
|
||||
#define OPENCASCADEBASEDSERIALIZER_H
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
|
||||
|
||||
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h"
|
||||
#include "../serializers/GeometrySerializer.h"
|
||||
|
||||
class OpenCascadeBasedSerializer : public GeometrySerializer {
|
||||
@@ -38,9 +38,9 @@ public:
|
||||
virtual ~OpenCascadeBasedSerializer() {}
|
||||
void writeHeader() {}
|
||||
bool ready();
|
||||
virtual void writeShape(const TopoDS_Shape& shape) = 0;
|
||||
virtual void writeShape(const IfcGeom::ConversionResultShape* shape) = 0;
|
||||
void write(const IfcGeom::TriangulationElement<real_t>* /*o*/) {}
|
||||
void write(const IfcGeom::BRepElement<real_t>* o);
|
||||
void write(const IfcGeom::NativeElement<real_t>* o);
|
||||
bool isTesselated() const { return false; }
|
||||
void setFile(IfcParse::IfcFile*) {}
|
||||
};
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <STEPControl_Writer.hxx>
|
||||
#include <Interface_Static.hxx>
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
|
||||
|
||||
#include "../serializers/OpenCascadeBasedSerializer.h"
|
||||
|
||||
@@ -36,10 +36,10 @@ public:
|
||||
: OpenCascadeBasedSerializer(out_filename, settings)
|
||||
{}
|
||||
virtual ~StepSerializer() {}
|
||||
void writeShape(const TopoDS_Shape& shape) {
|
||||
void writeShape(const IfcGeom::ConversionResultShape* shape) {
|
||||
std::stringstream ss;
|
||||
std::streambuf *sb = std::cout.rdbuf(ss.rdbuf());
|
||||
writer.Transfer(shape, STEPControl_AsIs);
|
||||
writer.Transfer(((IfcGeom::OpenCascadeShape*)shape)->shape(), STEPControl_AsIs);
|
||||
std::cout.rdbuf(sb);
|
||||
}
|
||||
void finalize() {
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h"
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
@@ -283,7 +285,7 @@ SvgSerializer::path_object& SvgSerializer::start_path(IfcUtil::IfcBaseEntity* st
|
||||
return p;
|
||||
}
|
||||
|
||||
void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
|
||||
void SvgSerializer::write(const IfcGeom::NativeElement<real_t>* o)
|
||||
{
|
||||
IfcUtil::IfcBaseEntity* storey = storey_;
|
||||
boost::optional<double> storey_elevation = boost::none;
|
||||
@@ -310,7 +312,10 @@ void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
|
||||
|
||||
path_object& p = start_path(storey, nameElement(o));
|
||||
|
||||
TopoDS_Shape compound = o->geometry().as_compound();
|
||||
IfcGeom::OpenCascadeShape* occt_shape = ((IfcGeom::OpenCascadeShape*) o->geometry().as_compound());
|
||||
TopoDS_Shape compound = occt_shape->shape();
|
||||
delete occt_shape;
|
||||
|
||||
TopoDS_Iterator it(compound);
|
||||
|
||||
// Iterate over components of compound to have better chance of matching section edges to closed wires
|
||||
@@ -469,7 +474,7 @@ void SvgSerializer::setFile(IfcParse::IfcFile* f) {
|
||||
auto storeys = f->instances_by_type("IfcBuildingStorey");
|
||||
if (!storeys || storeys->size() == 0) {
|
||||
|
||||
IfcGeom::Kernel kernel(f);
|
||||
IfcGeom::Kernel kernel("opencascade", f);
|
||||
|
||||
std::vector<const IfcParse::declaration*> to_derive_from;
|
||||
to_derive_from.push_back(f->schema()->declaration_by_name("IfcBuilding"));
|
||||
@@ -480,9 +485,11 @@ void SvgSerializer::setFile(IfcParse::IfcFile* f) {
|
||||
for (auto jt = insts->begin(); jt != insts->end(); ++jt) {
|
||||
IfcUtil::IfcBaseEntity* product = (IfcUtil::IfcBaseEntity*) *jt;
|
||||
if (!product->get("ObjectPlacement")->isNull()) {
|
||||
gp_Trsf trsf;
|
||||
IfcGeom::ConversionResultPlacement* trsf;
|
||||
if (kernel.convert_placement(*product->get("ObjectPlacement"), trsf)) {
|
||||
setSectionHeight(trsf.TranslationPart().Z() + 1.);
|
||||
double X, Y, Z;
|
||||
trsf->TranslationPart(X, Y, Z);
|
||||
setSectionHeight(Z + 1.);
|
||||
Logger::Warning("No building storeys encountered, used for reference:", product);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
void writeHeader();
|
||||
bool ready();
|
||||
void write(const IfcGeom::TriangulationElement<real_t>* /*o*/) {}
|
||||
void write(const IfcGeom::BRepElement<real_t>* o);
|
||||
void write(const IfcGeom::NativeElement<real_t>* o);
|
||||
void write(path_object& p, const TopoDS_Wire& wire);
|
||||
path_object& start_path(IfcUtil::IfcBaseEntity* storey, const std::string& id);
|
||||
bool isTesselated() const { return false; }
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#include "WavefrontObjSerializer.h"
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
|
||||
#include "../ifcgeom/schema_agnostic/IfcGeomRenderStyles.h"
|
||||
|
||||
#include "../ifcparse/utils.h"
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
void writeHeader();
|
||||
void writeMaterial(const IfcGeom::Material& style);
|
||||
void write(const IfcGeom::TriangulationElement<real_t>* o);
|
||||
void write(const IfcGeom::BRepElement<real_t>* /*o*/) {}
|
||||
void write(const IfcGeom::NativeElement<real_t>* /*o*/) {}
|
||||
void finalize() {}
|
||||
bool isTesselated() const { return true; }
|
||||
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "../../ifcparse/IfcSIPrefix.h"
|
||||
#include "../../ifcgeom/IfcGeom.h"
|
||||
#include "../../ifcparse/utils.h"
|
||||
#include "../../ifcgeom/kernels/opencascade/IfcGeom.h"
|
||||
|
||||
using boost::property_tree::ptree;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user